summaryrefslogtreecommitdiffstats
path: root/src/com/android/mail/ui/ViewMode.java
blob: 98df8095d933fa92c234d85aca0bdd634df02c05 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
/*
 * Copyright (C) 2012 Google Inc.
 * Licensed to The Android Open Source Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.mail.ui;

import com.android.mail.utils.LogUtils;
import com.google.common.collect.Lists;

import android.content.Context;
import android.os.Bundle;
import java.util.ArrayList;

/**
 * Represents the view mode for the tablet Gmail activity.
 * Transitions between modes should be done through this central object, and UI components that are
 * dependent on the mode should listen to changes on this object.
 */
public class ViewMode {
    /**
     * A listener for changes on a ViewMode. To listen to mode changes, implement this
     * interface and register your object with the single ViewMode held by the ActivityController
     * instance. On mode changes, the onViewModeChanged method will be called with the new mode.
     */
    public interface ModeChangeListener {
        /**
         * Called when the mode has changed.
         */
        void onViewModeChanged(int newMode);
    }

    /**
     * Mode when showing a single conversation.
     */
    public static final int CONVERSATION = 1;
    /**
     * Mode when showing a list of conversations
     */
    public static final int CONVERSATION_LIST = 2;
    /**
     * Mode when showing a list of folders.
     */
    public static final int FOLDER_LIST = 3;
    /**
     * Mode when showing results from user search.
     */
    public static final int SEARCH_RESULTS_LIST = 4;
    /**
     * Mode when showing results from user search.
     */
    public static final int SEARCH_RESULTS_CONVERSATION = 5;
    /**
     * Mode when showing the "waiting for sync" message.
     */
    public static final int WAITING_FOR_ACCOUNT_INITIALIZATION = 6;
    /**
     * Uncertain mode. The mode has not been initialized.
     */
    public static final int UNKNOWN = 0;

    // Key used to save this {@link ViewMode}.
    private static final String VIEW_MODE_KEY = "view-mode";
    private final ArrayList<ModeChangeListener> mListeners = Lists.newArrayList();
    /**
     * The actual mode the activity is in. We start out with an UNKNOWN mode, and require entering
     * a valid mode after the object has been created.
     */
    private int mMode = UNKNOWN;

    public static final String LOG_TAG = "ViewMode";

    public ViewMode(Context context) {
        // Do nothing
    }

    @Override
    public String toString() {
        return "[mode=" + mMode + "]";
    }

    /**
     * Adds a listener from this view mode.
     * Must happen in the UI thread.
     */
    public void addListener(ModeChangeListener listener) {
        mListeners.add(listener);
    }

    /**
     * Dispatches a change event for the mode.
     * Always happens in the UI thread.
     */
    private void dispatchModeChange() {
        ArrayList<ModeChangeListener> list = new ArrayList<ModeChangeListener>(mListeners);
        for (ModeChangeListener listener : list) {
            assert (listener != null);
            listener.onViewModeChanged(mMode);
        }
    }

    /**
     * Requests a transition of the mode to show the conversation list as the prominent view.
     *
     */
    public void enterConversationListMode() {
        setModeInternal(CONVERSATION_LIST);
    }

    /**
     * Requests a transition of the mode to show a conversation as the prominent view.
     *
     */
    public void enterConversationMode() {
        setModeInternal(CONVERSATION);
    }

    /**
     * Requests a transition of the mode to show the folder list as the prominent view.
     *
     */
    public void enterFolderListMode() {
        setModeInternal(FOLDER_LIST);
    }

    /**
     * Requests a transition of the mode to show a list of search results as the
     * prominent view.
     *
     */
    public void enterSearchResultsListMode() {
        setModeInternal(SEARCH_RESULTS_LIST);
    }

    /**
     * Requests a transition of the mode to show a conversation that was part of
     * search results.
     *
     */
    public void enterSearchResultsConversationMode() {
        setModeInternal(SEARCH_RESULTS_CONVERSATION);
    }

    /**
     * Requests a transition of the mode to show the "waiting for sync" messages
     *
     */
    public void enterWaitingForInitializationMode() {
        setModeInternal(WAITING_FOR_ACCOUNT_INITIALIZATION);
    }

    /**
     * @return The current mode.
     */
    public int getMode() {
        return mMode;
    }

    /**
     * Return whether the current mode is considered a list mode.
     */
    public boolean isListMode() {
        return isListMode(mMode);
    }

    public static boolean isListMode(final int mode) {
        return mode == CONVERSATION_LIST || mode == SEARCH_RESULTS_LIST;
    }

    public boolean isConversationMode() {
        return isConversationMode(mMode);
    }

    public static boolean isConversationMode(final int mode) {
        return mode == CONVERSATION || mode == SEARCH_RESULTS_CONVERSATION;
    }

    public static boolean isSearchMode(final int mode) {
        return mode == SEARCH_RESULTS_LIST || mode == SEARCH_RESULTS_CONVERSATION;
    }

    public boolean isWaitingForSync() {
        return isWaitingForSync(mMode);
    }

    public static boolean isWaitingForSync(final int mode) {
        return mode == WAITING_FOR_ACCOUNT_INITIALIZATION;
    }

    /**
     * Restoring from a saved state restores only the mode. It does not restore the listeners of
     * this object.
     * @param inState
     */
    public void handleRestore(Bundle inState) {
        if (inState == null) {
            return;
        }
        // Restore the previous mode, and UNKNOWN if nothing exists.
        final int newMode = inState.getInt(VIEW_MODE_KEY, UNKNOWN);
        if (newMode != UNKNOWN) {
            setModeInternal(newMode);
        }
    }

    /**
     * Save the existing mode only. Does not save the existing listeners.
     * @param outState
     */
    public void handleSaveInstanceState(Bundle outState) {
        if (outState == null) {
            return;
        }
        outState.putInt(VIEW_MODE_KEY, mMode);
    }

    /**
     * Removes a listener from this view mode.
     * Must happen in the UI thread.
     */
    public void removeListener(ModeChangeListener listener) {
        mListeners.remove(listener);
    }

    /**
     * Sets the internal mode.
     * @return Whether or not a change occurred.
     */
    private boolean setModeInternal(int mode) {
        if (mMode == mode) {
            if (LogUtils.isLoggable(LOG_TAG, LogUtils.DEBUG)) {
                LogUtils.d(LOG_TAG, new Error(), "ViewMode: debouncing change attempt mode=%s",
                        mode);
            } else {
                LogUtils.i(LOG_TAG, "ViewMode: debouncing change attempt mode=%s", mode);
            }
            return false;
        }

        if (LogUtils.isLoggable(LOG_TAG, LogUtils.DEBUG)) {
            LogUtils.d(LOG_TAG, new Error(), "ViewMode: executing change old=%s new=%s", mMode,
                    mode);
        } else {
            LogUtils.i(LOG_TAG, "ViewMode: executing change old=%s new=%s", mMode, mode);
        }

        mMode = mode;
        dispatchModeChange();
        return true;
    }
}