• 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     };
96 
ViewMode()97     public ViewMode() {
98         // Do nothing
99     }
100 
101     @Override
toString()102     public String toString() {
103         return "[mode=" + MODE_NAMES[mMode] + "]";
104     }
105 
getModeString()106     public String getModeString() {
107         return MODE_NAMES[mMode];
108     }
109 
110     /**
111      * Adds a listener from this view mode.
112      * Must happen in the UI thread.
113      */
addListener(ModeChangeListener listener)114     public void addListener(ModeChangeListener listener) {
115         mListeners.add(listener);
116     }
117 
118     /**
119      * Dispatches a change event for the mode.
120      * Always happens in the UI thread.
121      */
dispatchModeChange()122     private void dispatchModeChange() {
123         ArrayList<ModeChangeListener> list = new ArrayList<ModeChangeListener>(mListeners);
124         for (ModeChangeListener listener : list) {
125             assert (listener != null);
126             listener.onViewModeChanged(mMode);
127         }
128     }
129 
130     /**
131      * Requests a transition of the mode to show the conversation list as the prominent view.
132      *
133      */
enterConversationListMode()134     public void enterConversationListMode() {
135         setModeInternal(CONVERSATION_LIST);
136     }
137 
138     /**
139      * Requests a transition of the mode to show a conversation as the prominent view.
140      *
141      */
enterConversationMode()142     public void enterConversationMode() {
143         setModeInternal(CONVERSATION);
144     }
145 
146     /**
147      * Requests a transition of the mode to show a list of search results as the
148      * prominent view.
149      *
150      */
enterSearchResultsListMode()151     public void enterSearchResultsListMode() {
152         setModeInternal(SEARCH_RESULTS_LIST);
153     }
154 
155     /**
156      * Requests a transition of the mode to show a conversation that was part of
157      * search results.
158      *
159      */
enterSearchResultsConversationMode()160     public void enterSearchResultsConversationMode() {
161         setModeInternal(SEARCH_RESULTS_CONVERSATION);
162     }
163 
164     /**
165      * Requests a transition of the mode to show the "waiting for sync" messages
166      *
167      */
enterWaitingForInitializationMode()168     public void enterWaitingForInitializationMode() {
169         setModeInternal(WAITING_FOR_ACCOUNT_INITIALIZATION);
170     }
171 
172     /**
173      * Requests a transition of the mode to show an ad.
174      */
enterAdMode()175     public void enterAdMode() {
176         setModeInternal(AD);
177     }
178 
179     /**
180      * @return The current mode.
181      */
getMode()182     public int getMode() {
183         return mMode;
184     }
185 
186     /**
187      * Return whether the current mode is considered a list mode.
188      */
isListMode()189     public boolean isListMode() {
190         return isListMode(mMode);
191     }
192 
isListMode(final int mode)193     public static boolean isListMode(final int mode) {
194         return mode == CONVERSATION_LIST || mode == SEARCH_RESULTS_LIST;
195     }
196 
isConversationMode()197     public boolean isConversationMode() {
198         return isConversationMode(mMode);
199     }
200 
isConversationMode(final int mode)201     public static boolean isConversationMode(final int mode) {
202         return mode == CONVERSATION || mode == SEARCH_RESULTS_CONVERSATION;
203     }
204 
isSearchMode(final int mode)205     public static boolean isSearchMode(final int mode) {
206         return mode == SEARCH_RESULTS_LIST || mode == SEARCH_RESULTS_CONVERSATION;
207     }
208 
isWaitingForSync()209     public boolean isWaitingForSync() {
210         return isWaitingForSync(mMode);
211     }
212 
isWaitingForSync(final int mode)213     public static boolean isWaitingForSync(final int mode) {
214         return mode == WAITING_FOR_ACCOUNT_INITIALIZATION;
215     }
216 
isAdMode()217     public boolean isAdMode() {
218         return isAdMode(mMode);
219     }
220 
isAdMode(final int mode)221     public static boolean isAdMode(final int mode) {
222         return mode == AD;
223     }
224 
225     /**
226      * Restoring from a saved state restores only the mode. It does not restore the listeners of
227      * this object.
228      * @param inState
229      */
handleRestore(Bundle inState)230     public void handleRestore(Bundle inState) {
231         if (inState == null) {
232             return;
233         }
234         // Restore the previous mode, and UNKNOWN if nothing exists.
235         final int newMode = inState.getInt(VIEW_MODE_KEY, UNKNOWN);
236         if (newMode != UNKNOWN) {
237             setModeInternal(newMode);
238         }
239     }
240 
241     /**
242      * Save the existing mode only. Does not save the existing listeners.
243      * @param outState
244      */
handleSaveInstanceState(Bundle outState)245     public void handleSaveInstanceState(Bundle outState) {
246         if (outState == null) {
247             return;
248         }
249         outState.putInt(VIEW_MODE_KEY, mMode);
250     }
251 
252     /**
253      * Removes a listener from this view mode.
254      * Must happen in the UI thread.
255      */
removeListener(ModeChangeListener listener)256     public void removeListener(ModeChangeListener listener) {
257         mListeners.remove(listener);
258     }
259 
260     /**
261      * Sets the internal mode.
262      * @return Whether or not a change occurred.
263      */
setModeInternal(int mode)264     private boolean setModeInternal(int mode) {
265         if (mMode == mode) {
266             if (LogUtils.isLoggable(LOG_TAG, LogUtils.DEBUG)) {
267                 LogUtils.d(LOG_TAG, new Error(), "ViewMode: debouncing change attempt mode=%s",
268                         mode);
269             } else {
270                 LogUtils.i(LOG_TAG, "ViewMode: debouncing change attempt mode=%s", mode);
271             }
272             return false;
273         }
274 
275         if (LogUtils.isLoggable(LOG_TAG, LogUtils.DEBUG)) {
276             LogUtils.d(LOG_TAG, new Error(), "ViewMode: executing change old=%s new=%s", mMode,
277                     mode);
278         } else {
279             LogUtils.i(LOG_TAG, "ViewMode: executing change old=%s new=%s", mMode, mode);
280         }
281 
282         mMode = mode;
283         dispatchModeChange();
284         Analytics.getInstance().sendView("ViewMode" + toString());
285         return true;
286     }
287 }
288