Start tying in fragments to Viewmode changes

Change-Id: I09eaeb0c338ab3205e0887a99b9684b4ac0549ca
diff --git a/res/menu/conversation_list_menu.xml b/res/menu/conversation_list_menu.xml
index 44221ab..329b11d 100644
--- a/res/menu/conversation_list_menu.xml
+++ b/res/menu/conversation_list_menu.xml
@@ -17,45 +17,52 @@
 -->
 
 <menu xmlns:android="http://schemas.android.com/apk/res/android">
-
+    <!-- Always available -->
     <item android:id="@+id/compose"
         android:title="@string/menu_compose"
         android:showAsAction="always"
         android:icon="@drawable/ic_menu_compose_normal_holo_light"
         android:alphabeticShortcut="@string/trigger_compose_char" />
 
-    <item android:id="@+id/search"
-        android:title="@string/menu_search"
-        android:showAsAction="always|collapseActionView"
-        android:icon="@drawable/ic_menu_search_holo_light"
-        android:actionLayout="@layout/mail_actionbar_searchview" />
+    <!-- Available only for accounts with SERVER_SEARCH and in a folder
+      that suppors FOLDER_SERVER_SEARCH -->
+    <item android:id="@+id/search" android:title="@string/menu_search"
+    android:showAsAction="always|collapseActionView"
+    android:icon="@drawable/ic_menu_search_holo_light"
+    android:actionLayout="@layout/mail_actionbar_searchview" />
 
+    <!-- Always available -->
     <item android:id="@+id/show_all_folders"
         android:title="@string/show_all_folders"
         android:showAsAction="ifRoom"
         android:icon="@drawable/ic_menu_labels_holo_light" />
 
+    <!-- Always available -->
     <item android:id="@+id/refresh"
         android:title="@string/refresh"
         android:showAsAction="ifRoom"
         android:icon="@drawable/ic_menu_refresh_holo_light"
         android:alphabeticShortcut="@string/trigger_refresh_char" />
 
+    <!-- Always available -->
     <item android:id="@+id/label_options"
         android:title="@string/menu_label_options"
         android:showAsAction="never" />
 
+    <!-- Always available -->
     <item android:id="@+id/preferences"
         android:title="@string/menu_preferences"
         android:showAsAction="never"
         android:icon="@android:drawable/ic_menu_preferences" />
 
+    <!-- Always available -->
     <item
         android:id="@+id/help_info_menu_item"
         android:icon="@android:drawable/ic_menu_help"
         android:showAsAction="never"
         android:title="@string/help_and_info" />
 
+    <!-- Always available -->
     <item
         android:id="@+id/feedback_menu_item"
         android:icon="@android:drawable/ic_menu_send"
diff --git a/src/com/android/mail/AccountSpinnerAdapter.java b/src/com/android/mail/AccountSpinnerAdapter.java
index 800f293..18dde51 100644
--- a/src/com/android/mail/AccountSpinnerAdapter.java
+++ b/src/com/android/mail/AccountSpinnerAdapter.java
@@ -21,7 +21,6 @@
 import android.content.Context;
 import android.database.Cursor;
 import android.database.DataSetObserver;
-import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
diff --git a/src/com/android/mail/ui/AbstractActivityController.java b/src/com/android/mail/ui/AbstractActivityController.java
index 9413a01..bb210c5 100644
--- a/src/com/android/mail/ui/AbstractActivityController.java
+++ b/src/com/android/mail/ui/AbstractActivityController.java
@@ -30,7 +30,6 @@
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Bundle;
-import android.util.Log;
 import android.view.ActionMode;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
@@ -101,13 +100,28 @@
     }
 
     @Override
-    public void attachConversationList(ConversationListFragment conversationList) {
-        mConversationListFragment = conversationList;
+    public synchronized void attachConversationList(ConversationListFragment fragment) {
+        // If there is an existing fragment, unregister it
+        if (mConversationListFragment != null) {
+            mViewMode.removeListener(mConversationListFragment);
+        }
+        mConversationListFragment = fragment;
+        // If the current fragment is non-null, add it as a listener.
+        if (fragment != null) {
+            mViewMode.addListener(mConversationListFragment);
+        }
     }
 
     @Override
-    public void attachFolderList(FolderListFragment folderList) {
-        mFolderListFragment = folderList;
+    public synchronized void attachFolderList(FolderListFragment fragment) {
+        // If there is an existing fragment, unregister it
+        if (mFolderListFragment != null) {
+            mViewMode.removeListener(mFolderListFragment);
+        }
+        mFolderListFragment = fragment;
+        if (fragment != null) {
+            mViewMode.addListener(mFolderListFragment);
+        }
     }
 
     @Override
@@ -278,7 +292,14 @@
         // Allow shortcut keys to function for the ActionBar and menus.
         mActivity.setDefaultKeyMode(Activity.DEFAULT_KEYS_SHORTCUT);
         mResolver = mActivity.getContentResolver();
+
+        // All the individual UI components listen for ViewMode changes. This simplifies the
+        // amount of logic in the AbstractActivityController, but increases the possibility of
+        // timing-related bugs.
         mViewMode.addListener(this);
+        assert (mActionBarView != null);
+        mViewMode.addListener(mActionBarView);
+
         restoreState(savedState);
         return true;
     }
@@ -407,8 +428,6 @@
      */
     @Override
     public void onViewModeChanged(int newMode) {
-        // Update action bar mode.
-        mActionBarView.setMode(newMode);
         // Perform any mode specific work here.
         // reset the action bar icon based on the mode. Why don't the individual controllers do
         // this themselves?
diff --git a/src/com/android/mail/ui/ActionBarView.java b/src/com/android/mail/ui/ActionBarView.java
index 73dbbbd..b6ccdc3 100644
--- a/src/com/android/mail/ui/ActionBarView.java
+++ b/src/com/android/mail/ui/ActionBarView.java
@@ -18,6 +18,7 @@
 package com.android.mail.ui;
 
 import android.app.ActionBar;
+import android.app.ActionBar.OnNavigationListener;
 import android.os.Bundle;
 import android.view.Menu;
 
@@ -26,7 +27,7 @@
  * pre-v14 devices).
  */
 
-public interface ActionBarView {
+public interface ActionBarView extends OnNavigationListener, ViewMode.ModeChangeListener {
     /**
      * Initialize the ActionBarView
      * @param activity
@@ -38,25 +39,12 @@
             ViewMode viewMode, ActionBar actionBar);
 
     /**
-     * Return the mode that the action bar is in.
-     * @return The mode the action bar is in.
-     */
-    int getMode();
-
-    /**
      * Handle handleRestore from the Android framework.
      * @param savedInstanceState
      */
     void handleRestore(Bundle savedInstanceState);
 
     /**
-     * Change the mode of the actionbar.
-     * @param mode
-     * @return true if the change in mode was successful.
-     */
-    boolean setMode(int mode);
-
-    /**
      * Handle onResume from the Android framework.
      */
     void onResume();
@@ -113,7 +101,7 @@
     boolean createOptionsMenu(Menu menu);
 
     /**
-     * Update sthe action bar based on a new status received from the server.
+     * Updates the action bar based on a new status received from the server.
      * @param account
      * @param status
      */
diff --git a/src/com/android/mail/ui/FolderListFragment.java b/src/com/android/mail/ui/FolderListFragment.java
index 95d168e..1fe42d5 100644
--- a/src/com/android/mail/ui/FolderListFragment.java
+++ b/src/com/android/mail/ui/FolderListFragment.java
@@ -43,7 +43,7 @@
  * The folder list UI component.
  */
 public final class FolderListFragment extends ListFragment implements
-        LoaderManager.LoaderCallbacks<Cursor> {
+        LoaderManager.LoaderCallbacks<Cursor>, ViewMode.ModeChangeListener {
     private static final String LOG_TAG = new LogUtils().getLogTag();
 
     private ControllableActivity mActivity;
@@ -209,4 +209,9 @@
             return folderItemView;
         }
     }
+
+    @Override
+    public void onViewModeChanged(int newMode) {
+        // Listen on mode changes, when we move to Label list mode, change accordingly.
+    }
 }
diff --git a/src/com/android/mail/ui/MailActionBar.java b/src/com/android/mail/ui/MailActionBar.java
index fe91058..00a7575 100644
--- a/src/com/android/mail/ui/MailActionBar.java
+++ b/src/com/android/mail/ui/MailActionBar.java
@@ -22,6 +22,7 @@
 import android.content.Context;
 import android.os.Bundle;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
@@ -35,19 +36,24 @@
 import com.android.mail.AccountSpinnerAdapter;
 import com.android.mail.ConversationListContext;
 import com.android.mail.providers.Account;
+import com.android.mail.providers.UIProvider.AccountCapabilities;
 
 /**
- * View to manage the various states of the Gmail Action Bar
+ * View to manage the various states of the Mail Action Bar
  *
- * TODO(viki): Include ConversatinSubjectDisplayer here as well.
+ * TODO(viki): Include ConversationSubjectDisplayer here as well.
  */
-public class MailActionBar extends LinearLayout implements ActionBarView, OnNavigationListener {
+public final class MailActionBar extends LinearLayout implements ActionBarView {
     /**
      * This interface is used to send notifications back to the calling
      * activity. MenuHandler takes care of updating the provider, so this
      * interface should be used for notification purposes only (such as updating
      * the UI).
      */
+    // TODO(viki): This callback is currently unused and may be entirely unnecessary in the new
+    // code, where the Actionbar is switched into navigation mode, relying on the framework for most
+    // heavy lifting. Also, we can switch ViewMode to the appropriate mode and rely on all UI
+    // components updating through ViewMode change listeners.
     public interface Callback {
         /**
          * Enter search mode
@@ -94,16 +100,23 @@
 
     private String[] mAccountNames;
     private ActionBar mActionBar;
-    protected RestrictedActivity mActivity;
+    private RestrictedActivity mActivity;
     private Callback mCallback;
-    protected View mFolderView;
-    private int mMode;
+    private View mFolderView;
+    /**
+     * The current mode of the ActionBar. This references constants in {@link ViewMode}
+     */
+    private int mMode = ViewMode.UNKNOWN;
 
     private MenuItem mRefreshItem;
 
     private MenuItem mSearch;
     SpinnerAdapter mSpinner;
-    protected AccountRecentLabelSpinner mSpinnerView;
+    private AccountRecentLabelSpinner mSpinnerView;
+    /**
+     * We need to know what each account is capable of, so we can tailor the menu accordingly.
+     */
+    private int mAccountCapabilities;
 
     // TODO(viki): This is a SnippetTextView in the Gmail source code. Resolve.
     private TextView mSubjectView;
@@ -116,10 +129,8 @@
         this(context, attrs, 0);
     }
 
-
     public MailActionBar(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
-        mMode = ViewMode.UNKNOWN;
     }
 
     @Override
@@ -135,25 +146,21 @@
     }
 
     @Override
-    public int getMode() {
-        return mMode;
-    }
-
-    @Override
     public int getOptionsMenuId() {
-        switch (mMode){
-            case ViewMode.UNKNOWN:
-                // Fallthrough
-            case ViewMode.SEARCH_RESULTS:
-                return R.menu.conversation_list_menu;
-            case ViewMode.FOLDER_LIST:
-                return R.menu.folder_list_menu;
-            case ViewMode.CONVERSATION_LIST:
-                return R.menu.conversation_list_menu;
-            case ViewMode.CONVERSATION:
-                return R.menu.conversation_actions;
-        }
-        return 0;
+        // Relies on the ordering of the view modes, since they are integer constants.
+        final int[] modeMenu = {
+                // 0: UNKNOWN
+                R.menu.conversation_list_menu,
+                // 1: CONVERSATION
+                R.menu.conversation_actions,
+                // 2: CONVERSATION_LIST
+                R.menu.conversation_list_menu,
+                // 3: FOLDER_LIST
+                R.menu.folder_list_menu,
+                // 4: SEARCH_RESULTS
+                R.menu.conversation_list_menu
+        };
+        return modeMenu[mMode];
     }
 
     @Override
@@ -184,12 +191,16 @@
     }
 
     @Override
-    public boolean onNavigationItemSelected(int itemPosition, long itemId) {
-        // Don't do anything. Toast on the action.
-        int type = mSpinner.getItemViewType(itemPosition);
+    public boolean onNavigationItemSelected(int position, long id) {
+        final int type = mSpinner.getItemViewType(position);
         switch (type) {
             case AccountSpinnerAdapter.TYPE_ACCOUNT:
-                mCallback.navigateToAccount((Account) mSpinner.getItem(itemPosition));
+                mCallback.navigateToAccount((Account) mSpinner.getItem(position));
+                // Get the capabilities associated with this account.
+                final Object item = mSpinner.getItem(position);
+                assert (item instanceof Account);
+                mAccountCapabilities = ((Account) item).capabilities;
+                Log.d("viki", "Account capabilities are " + mAccountCapabilities);
                 break;
         }
         return false;
@@ -214,7 +225,30 @@
     }
 
     @Override
+    public void onViewModeChanged(int newMode) {
+        mMode = newMode;
+
+        // Always update the options menu and redraw. This will read the new mode and redraw
+        // the options menu.
+        mActivity.invalidateOptionsMenu();
+    }
+
+    /**
+     * If shouldSetView is true, then the view is made visible, otherwise its visiblity is View.GONE
+     * @param view the view whose visibility is modified
+     * @param shouldSetView if true, the view is made visible, GONE otherwise
+     */
+    private void setVisibility(int resourceId, boolean shouldSetView) {
+        final View view = findViewById(resourceId);
+        assert (view != null);
+        final int visibility = shouldSetView ? View.VISIBLE : View.GONE;
+        view.setVisibility(visibility);
+    }
+
+    @Override
     public boolean prepareOptionsMenu(Menu menu) {
+        // We start out with every option enabled. Based on the current view, we disable actions
+        // that are possible.
         if (mSubjectView != null){
             mSubjectView.setVisibility(GONE);
         }
@@ -230,7 +264,10 @@
                 }
                 break;
             case ViewMode.CONVERSATION_LIST:
-                // Do nothing?
+                // Show compose, search, labels, and sync based on the account
+                // The only option that needs to be disabled is search
+                setVisibility (R.id.search,
+                        (mAccountCapabilities & AccountCapabilities.FOLDER_SERVER_SEARCH) != 0);
                 break;
             case ViewMode.CONVERSATION:
                 // Do nothing?
@@ -275,12 +312,6 @@
     }
 
     @Override
-    public boolean setMode(int mode) {
-        mMode = mode;
-        return true;
-    }
-
-    @Override
     public void updateActionBar(String[] accounts, String currentAccount) {
     }
 }
diff --git a/src/com/android/mail/ui/MailActivity.java b/src/com/android/mail/ui/MailActivity.java
index 7bc587f..01197ca 100644
--- a/src/com/android/mail/ui/MailActivity.java
+++ b/src/com/android/mail/ui/MailActivity.java
@@ -54,6 +54,10 @@
 
     private ViewMode mViewMode;
 
+    public MailActivity() {
+        super();
+    }
+
     @Override
     public void attachConversationList(ConversationListFragment fragment) {
         mController.attachConversationList(fragment);
diff --git a/src/com/android/mail/ui/OnePaneController.java b/src/com/android/mail/ui/OnePaneController.java
index eeb18a4..12239f9 100644
--- a/src/com/android/mail/ui/OnePaneController.java
+++ b/src/com/android/mail/ui/OnePaneController.java
@@ -32,14 +32,13 @@
 
 // Called OnePaneActivityController in Gmail.
 public final class OnePaneController extends AbstractActivityController {
-
+    private boolean mConversationListVisible = false;
     /**
      * @param activity
      * @param viewMode
      */
     public OnePaneController(MailActivity activity, ViewMode viewMode) {
         super(activity, viewMode);
-        // TODO(viki): Auto-generated constructor stub
     }
 
     @Override
@@ -63,65 +62,54 @@
 
     @Override
     protected boolean isConversationListVisible() {
-        // TODO(viki): Auto-generated method stub
-        return false;
+        return mConversationListVisible;
     }
 
     @Override
     public void onViewModeChanged(int newMode) {
         super.onViewModeChanged(newMode);
-
-        // We don't want to invalidate the options menu when switching to conversation
-        // mode, as it will happen when the conversation finishes loading.
-        if (newMode != ViewMode.CONVERSATION) {
-            mActivity.invalidateOptionsMenu();
-        }
     }
 
     @Override
     public void showConversationList(ConversationListContext listContext) {
         mViewMode.enterConversationListMode();
 
-        FragmentTransaction fragmentTransaction = mActivity.getFragmentManager().beginTransaction();
-        fragmentTransaction.addToBackStack(null);
+        // TODO(viki): Check if the account has been changed since the previous time.
         final boolean accountChanged = false;
         // TODO(viki): This account transition looks strange in two pane mode.
-        // Revisit as the app
-        // is coming together and improve the look and feel.
+        // Revisit as the app is coming together and improve the look and feel.
         final int transition = accountChanged ? FragmentTransaction.TRANSIT_FRAGMENT_FADE
                 : FragmentTransaction.TRANSIT_FRAGMENT_OPEN;
         if (listContext == null) {
             listContext = getCurrentListContext();
         }
-        fragmentTransaction.setTransition(transition);
 
         Fragment conversationListFragment = ConversationListFragment.newInstance(listContext);
-        fragmentTransaction.replace(R.id.content_pane, conversationListFragment);
-
-        fragmentTransaction.commitAllowingStateLoss();
-        resetActionBarIcon();
+        replaceFragment(conversationListFragment, transition);
+        mConversationListVisible = true;
     }
 
     @Override
     public void showConversation(Conversation conversation) {
         mViewMode.enterConversationMode();
-        replaceFragment(ConversationViewFragment.newInstance(mAccount, conversation));
+        replaceFragment(ConversationViewFragment.newInstance(mAccount, conversation),
+                FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
+        mConversationListVisible = false;
     }
 
     @Override
     public void showFolderList() {
         mViewMode.enterFolderListMode();
-        replaceFragment(FolderListFragment.newInstance(this, mAccount.folderListUri));
+        replaceFragment(FolderListFragment.newInstance(this, mAccount.folderListUri),
+                FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
+        mConversationListVisible = false;
     }
 
-    private void replaceFragment(Fragment fragment) {
+    private void replaceFragment(Fragment fragment, int transition) {
         FragmentTransaction fragmentTransaction = mActivity.getFragmentManager().beginTransaction();
         fragmentTransaction.addToBackStack(null);
-        final int transition = FragmentTransaction.TRANSIT_FRAGMENT_OPEN;
         fragmentTransaction.setTransition(transition);
-
         fragmentTransaction.replace(R.id.content_pane, fragment);
-
         fragmentTransaction.commitAllowingStateLoss();
         resetActionBarIcon();
     }
@@ -153,7 +141,6 @@
 
     private void transitionBackToConversationListMode() {
         mViewMode.enterConversationListMode();
-        mActivity.invalidateOptionsMenu();
         resetActionBarIcon();
     }
 }
diff --git a/src/com/android/mail/ui/TwoPaneController.java b/src/com/android/mail/ui/TwoPaneController.java
index 0b22e02..9fdd3d7 100644
--- a/src/com/android/mail/ui/TwoPaneController.java
+++ b/src/com/android/mail/ui/TwoPaneController.java
@@ -26,7 +26,6 @@
 import android.os.Bundle;
 import android.view.Window;
 
-
 /**
  * Controller for one-pane Mail activity. One Pane is used for phones, where screen real estate is
  * limited.
diff --git a/src/com/android/mail/ui/ViewMode.java b/src/com/android/mail/ui/ViewMode.java
index 6357b47..40aad55 100644
--- a/src/com/android/mail/ui/ViewMode.java
+++ b/src/com/android/mail/ui/ViewMode.java
@@ -21,7 +21,6 @@
 
 import android.content.Context;
 import android.os.Bundle;
-
 import java.util.ArrayList;
 
 /**
@@ -92,6 +91,7 @@
         mMode = newMode;
         ArrayList<ModeChangeListener> list = new ArrayList<ModeChangeListener>(mListeners);
         for (ModeChangeListener listener : list) {
+            assert (listener != null);
             listener.onViewModeChanged(newMode);
         }
     }