Home | History | Annotate | Download | only in ui
      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          */
     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 
     98     public ViewMode() {
     99         // Do nothing
    100     }
    101 
    102     @Override
    103     public String toString() {
    104         return "[mode=" + MODE_NAMES[mMode] + "]";
    105     }
    106 
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    176     public void enterAdMode() {
    177         setModeInternal(AD);
    178     }
    179 
    180     /**
    181      * @return The current mode.
    182      */
    183     public int getMode() {
    184         return mMode;
    185     }
    186 
    187     /**
    188      * Return whether the current mode is considered a list mode.
    189      */
    190     public boolean isListMode() {
    191         return isListMode(mMode);
    192     }
    193 
    194     public static boolean isListMode(final int mode) {
    195         return mode == CONVERSATION_LIST || mode == SEARCH_RESULTS_LIST;
    196     }
    197 
    198     public boolean isConversationMode() {
    199         return isConversationMode(mMode);
    200     }
    201 
    202     public static boolean isConversationMode(final int mode) {
    203         return mode == CONVERSATION || mode == SEARCH_RESULTS_CONVERSATION;
    204     }
    205 
    206     public boolean isSearchMode() {
    207         return isSearchMode(mMode);
    208     }
    209 
    210     public static boolean isSearchMode(final int mode) {
    211         return mode == SEARCH_RESULTS_LIST || mode == SEARCH_RESULTS_CONVERSATION;
    212     }
    213 
    214     public boolean isWaitingForSync() {
    215         return isWaitingForSync(mMode);
    216     }
    217 
    218     public static boolean isWaitingForSync(final int mode) {
    219         return mode == WAITING_FOR_ACCOUNT_INITIALIZATION;
    220     }
    221 
    222     public boolean isAdMode() {
    223         return isAdMode(mMode);
    224     }
    225 
    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      */
    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      */
    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      */
    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      */
    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