• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 Google Inc.
3  * Licensed to The Android Open Source Project.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 package com.android.mail.ui;
19 
20 import android.os.Bundle;
21 
22 import com.android.mail.analytics.Analytics;
23 import com.android.mail.utils.LogUtils;
24 import com.google.common.collect.Lists;
25 
26 import java.util.ArrayList;
27 
28 /**
29  * Represents the view mode for the tablet Gmail activity.
30  * Transitions between modes should be done through this central object, and UI components that are
31  * dependent on the mode should listen to changes on this object.
32  */
33 public class ViewMode {
34     /**
35      * A listener for changes on a ViewMode. To listen to mode changes, implement this
36      * interface and register your object with the single ViewMode held by the ActivityController
37      * instance. On mode changes, the onViewModeChanged method will be called with the new mode.
38      */
39     public interface ModeChangeListener {
40         /**
41          * Called when the mode has changed.
42          */
onViewModeChanged(int newMode)43         void onViewModeChanged(int newMode);
44     }
45 
46     /**
47      * Mode when showing a single conversation.
48      */
49     public static final int CONVERSATION = 1;
50     /**
51      * Mode when showing a list of conversations
52      */
53     public static final int CONVERSATION_LIST = 2;
54     /**
55      * Mode when showing results from user search.
56      */
57     public static final int SEARCH_RESULTS_LIST = 3;
58     /**
59      * Mode when showing results from user search.
60      */
61     public static final int SEARCH_RESULTS_CONVERSATION = 4;
62     /**
63      * Mode when showing the "waiting for sync" message.
64      */
65     public static final int WAITING_FOR_ACCOUNT_INITIALIZATION = 5;
66     /**
67      * Mode when showing ads.
68      */
69     public static final int AD = 6;
70     /**
71      * Uncertain mode. The mode has not been initialized.
72      */
73     public static final int UNKNOWN = 0;
74 
75     // Key used to save this {@link ViewMode}.
76     private static final String VIEW_MODE_KEY = "view-mode";
77     private final ArrayList<ModeChangeListener> mListeners = Lists.newArrayList();
78     /**
79      * The actual mode the activity is in. We start out with an UNKNOWN mode, and require entering
80      * a valid mode after the object has been created.
81      */
82     private int mMode = UNKNOWN;
83 
84     public static final String LOG_TAG = "ViewMode";
85 
86     // friendly names (not user-facing) for each view mode, indexed by ordinal value.
87     private static final String[] MODE_NAMES = {
88         "Unknown",
89         "Conversation",
90         "Conversation list",
91         "Search results list",
92         "Search results conversation",
93         "Waiting for sync",
94         "Ad",
95         "Warm welcome"
96     };
97 
ViewMode()98     public ViewMode() {
99         // Do nothing
100     }
101 
102     @Override
toString()103     public String toString() {
104         return "[mode=" + MODE_NAMES[mMode] + "]";
105     }
106 
getModeString()107     public String getModeString() {
108         return MODE_NAMES[mMode];
109     }
110 
111     /**
112      * Adds a listener from this view mode.
113      * Must happen in the UI thread.
114      */
addListener(ModeChangeListener listener)115     public void addListener(ModeChangeListener listener) {
116         mListeners.add(listener);
117     }
118 
119     /**
120      * Dispatches a change event for the mode.
121      * Always happens in the UI thread.
122      */
dispatchModeChange()123     private void dispatchModeChange() {
124         ArrayList<ModeChangeListener> list = new ArrayList<ModeChangeListener>(mListeners);
125         for (ModeChangeListener listener : list) {
126             assert (listener != null);
127             listener.onViewModeChanged(mMode);
128         }
129     }
130 
131     /**
132      * Requests a transition of the mode to show the conversation list as the prominent view.
133      *
134      */
enterConversationListMode()135     public void enterConversationListMode() {
136         setModeInternal(CONVERSATION_LIST);
137     }
138 
139     /**
140      * Requests a transition of the mode to show a conversation as the prominent view.
141      *
142      */
enterConversationMode()143     public void enterConversationMode() {
144         setModeInternal(CONVERSATION);
145     }
146 
147     /**
148      * Requests a transition of the mode to show a list of search results as the
149      * prominent view.
150      *
151      */
enterSearchResultsListMode()152     public void enterSearchResultsListMode() {
153         setModeInternal(SEARCH_RESULTS_LIST);
154     }
155 
156     /**
157      * Requests a transition of the mode to show a conversation that was part of
158      * search results.
159      *
160      */
enterSearchResultsConversationMode()161     public void enterSearchResultsConversationMode() {
162         setModeInternal(SEARCH_RESULTS_CONVERSATION);
163     }
164 
165     /**
166      * Requests a transition of the mode to show the "waiting for sync" messages
167      *
168      */
enterWaitingForInitializationMode()169     public void enterWaitingForInitializationMode() {
170         setModeInternal(WAITING_FOR_ACCOUNT_INITIALIZATION);
171     }
172 
173     /**
174      * Requests a transition of the mode to show an ad.
175      */
enterAdMode()176     public void enterAdMode() {
177         setModeInternal(AD);
178     }
179 
180     /**
181      * @return The current mode.
182      */
getMode()183     public int getMode() {
184         return mMode;
185     }
186 
187     /**
188      * Return whether the current mode is considered a list mode.
189      */
isListMode()190     public boolean isListMode() {
191         return isListMode(mMode);
192     }
193 
isListMode(final int mode)194     public static boolean isListMode(final int mode) {
195         return mode == CONVERSATION_LIST || mode == SEARCH_RESULTS_LIST;
196     }
197 
isConversationMode()198     public boolean isConversationMode() {
199         return isConversationMode(mMode);
200     }
201 
isConversationMode(final int mode)202     public static boolean isConversationMode(final int mode) {
203         return mode == CONVERSATION || mode == SEARCH_RESULTS_CONVERSATION;
204     }
205 
isSearchMode()206     public boolean isSearchMode() {
207         return isSearchMode(mMode);
208     }
209 
isSearchMode(final int mode)210     public static boolean isSearchMode(final int mode) {
211         return mode == SEARCH_RESULTS_LIST || mode == SEARCH_RESULTS_CONVERSATION;
212     }
213 
isWaitingForSync()214     public boolean isWaitingForSync() {
215         return isWaitingForSync(mMode);
216     }
217 
isWaitingForSync(final int mode)218     public static boolean isWaitingForSync(final int mode) {
219         return mode == WAITING_FOR_ACCOUNT_INITIALIZATION;
220     }
221 
isAdMode()222     public boolean isAdMode() {
223         return isAdMode(mMode);
224     }
225 
isAdMode(final int mode)226     public static boolean isAdMode(final int mode) {
227         return mode == AD;
228     }
229 
230     /**
231      * Restoring from a saved state restores only the mode. It does not restore the listeners of
232      * this object.
233      * @param inState
234      */
handleRestore(Bundle inState)235     public void handleRestore(Bundle inState) {
236         if (inState == null) {
237             return;
238         }
239         // Restore the previous mode, and UNKNOWN if nothing exists.
240         final int newMode = inState.getInt(VIEW_MODE_KEY, UNKNOWN);
241         if (newMode != UNKNOWN) {
242             setModeInternal(newMode);
243         }
244     }
245 
246     /**
247      * Save the existing mode only. Does not save the existing listeners.
248      * @param outState
249      */
handleSaveInstanceState(Bundle outState)250     public void handleSaveInstanceState(Bundle outState) {
251         if (outState == null) {
252             return;
253         }
254         outState.putInt(VIEW_MODE_KEY, mMode);
255     }
256 
257     /**
258      * Removes a listener from this view mode.
259      * Must happen in the UI thread.
260      */
removeListener(ModeChangeListener listener)261     public void removeListener(ModeChangeListener listener) {
262         mListeners.remove(listener);
263     }
264 
265     /**
266      * Sets the internal mode.
267      * @return Whether or not a change occurred.
268      */
setModeInternal(int mode)269     private boolean setModeInternal(int mode) {
270         if (mMode == mode) {
271             if (LogUtils.isLoggable(LOG_TAG, LogUtils.DEBUG)) {
272                 LogUtils.d(LOG_TAG, new Error(), "ViewMode: debouncing change attempt mode=%s",
273                         mode);
274             } else {
275                 LogUtils.i(LOG_TAG, "ViewMode: debouncing change attempt mode=%s", mode);
276             }
277             return false;
278         }
279 
280         if (LogUtils.isLoggable(LOG_TAG, LogUtils.DEBUG)) {
281             LogUtils.d(LOG_TAG, new Error(), "ViewMode: executing change old=%s new=%s", mMode,
282                     mode);
283         } else {
284             LogUtils.i(LOG_TAG, "ViewMode: executing change old=%s new=%s", mMode, mode);
285         }
286 
287         mMode = mode;
288         dispatchModeChange();
289         Analytics.getInstance().sendView("ViewMode" + toString());
290         return true;
291     }
292 }
293