Make a folder list fragment. Hook into Viki's app.

Also, hook up listeners for changing account in the
account spinner dropdown.
Change-Id: I0e6bbabc525c141fa581f49e6265c26bc767b8cf
diff --git a/res/layout/folder_list.xml b/res/layout/folder_list.xml
new file mode 100644
index 0000000..5b9ecc7
--- /dev/null
+++ b/res/layout/folder_list.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+
+<FrameLayout  xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <ListView
+        android:id="@android:id/list"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:cacheColorHint="@android:color/transparent"
+        android:drawSelectorOnTop="false"
+        android:fadingEdge="none" />
+
+    <TextView android:id="@+id/empty_view"
+        android:visibility="gone"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/folders_activity_instructions"/>
+
+</FrameLayout>
diff --git a/src/com/android/mail/AccountSpinnerAdapter.java b/src/com/android/mail/AccountSpinnerAdapter.java
index 7ad3e9c..800f293 100644
--- a/src/com/android/mail/AccountSpinnerAdapter.java
+++ b/src/com/android/mail/AccountSpinnerAdapter.java
@@ -30,6 +30,7 @@
 import android.widget.SpinnerAdapter;
 import android.widget.TextView;
 
+import com.android.mail.providers.Account;
 import com.android.mail.providers.AccountCacheProvider;
 import com.android.mail.providers.UIProvider;
 import com.android.mail.utils.LogUtils;
@@ -99,9 +100,9 @@
         TextView unread_count;
     }
 
-    private static final int TYPE_ACCOUNT = 0;
-    private static final int TYPE_HEADER = 1;
-    private static final int TYPE_FOLDER = 2;
+    public static final int TYPE_ACCOUNT = 0;
+    public static final int TYPE_HEADER = 1;
+    public static final int TYPE_FOLDER = 2;
 
     private int getType(int position) {
         // First the accounts
@@ -177,12 +178,12 @@
         switch (getType(position)) {
             case TYPE_ACCOUNT:
                 // The default Inbox for the given account
-                accountName = getAccount(position);
+                accountName = getAccountLabel(position);
                 folderName = "Inbox";
                 break;
             case TYPE_HEADER:
                 // We can never select the header, and we want the default view to be the Inbox.
-                accountName = getAccount(0);
+                accountName = getAccountLabel(0);
                 folderName = "Inbox";
                 break;
             default:
@@ -279,7 +280,7 @@
                 header.account.setText(mCurrentAccount);
                 return convertView;
             case TYPE_ACCOUNT:
-                textLabel = getAccount(position);
+                textLabel = getAccountLabel(position);
                 break;
             case TYPE_FOLDER:
                 final int offset = position - numAccounts - 1;
@@ -316,12 +317,22 @@
      * @param position
      * @return
      */
-    private String getAccount(int position) {
+    private String getAccountLabel(int position) {
         mAccountCursor.moveToPosition(position);
         final int accountNameCol = mAccountCursor.getColumnIndex(UIProvider.AccountColumns.NAME);
         return mAccountCursor.getString(accountNameCol);
     }
 
+    /**
+     * Returns the account given position in the spinner.
+     * @param position
+     * @return
+     */
+    private Account getAccount(int position) {
+        mAccountCursor.moveToPosition(position);
+        return new Account(mAccountCursor);
+    }
+
 
     @Override
     public boolean isEnabled(int position) {
diff --git a/src/com/android/mail/ui/AbstractActivityController.java b/src/com/android/mail/ui/AbstractActivityController.java
index dcee0ea..cae5cf0 100644
--- a/src/com/android/mail/ui/AbstractActivityController.java
+++ b/src/com/android/mail/ui/AbstractActivityController.java
@@ -33,6 +33,7 @@
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.Menu;
+import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.MotionEvent;
 import android.view.Window;
@@ -196,9 +197,17 @@
     protected abstract boolean isConversationListVisible();
 
     @Override
-    public boolean navigateToAccount(String account) {
-        // TODO(viki): Auto-generated method stub
-        return false;
+    public boolean navigateToAccount(Account account) {
+        if (!account.equals(mAccount)) {
+            mAccount = account;
+
+            final Intent intent = mActivity.getIntent();
+            // TODO(viki): Show the list context from Intent
+            mConvListContext = ConversationListContext.forIntent(mContext, mAccount, intent);
+            showConversationList(mConvListContext);
+            mViewMode.enterConversationListMode();
+        }
+        return true;
     }
 
     @Override
@@ -272,8 +281,9 @@
 
     @Override
     public boolean onCreateOptionsMenu(Menu menu) {
-        // TODO(viki): Auto-generated method stub
-        return false;
+        MenuInflater inflater = mActivity.getMenuInflater();
+        inflater.inflate(R.menu.conversation_list_menu, menu);
+        return true;
     }
 
     @Override
@@ -296,7 +306,12 @@
 
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
-        // TODO(viki): Auto-generated method stub
+        int id = item.getItemId();
+        switch (id) {
+            case R.id.show_all_folders:
+                showFolderList();
+                break;
+        }
         return false;
     }
 
@@ -459,12 +474,6 @@
     }
 
     @Override
-    public void showFolderList() {
-        // TODO(viki): Auto-generated method stub
-
-    }
-
-    @Override
     public void startActionBarStatusCursorLoader(String account) {
         // TODO(viki): Auto-generated method stub
 
diff --git a/src/com/android/mail/ui/ActionbarActivity.java b/src/com/android/mail/ui/ActionbarActivity.java
index 261724b..9d9b6a2 100644
--- a/src/com/android/mail/ui/ActionbarActivity.java
+++ b/src/com/android/mail/ui/ActionbarActivity.java
@@ -19,6 +19,7 @@
 
 import com.android.mail.ConversationListContext;
 import com.android.mail.R;
+import com.android.mail.providers.Account;
 import com.android.mail.ui.ActionBarView.Mode;
 import com.android.mail.ui.MailActionBar.Callback;
 
@@ -127,7 +128,7 @@
     }
 
     @Override
-    public boolean navigateToAccount(String account) {
+    public boolean navigateToAccount(Account account) {
         // TODO(viki): Auto-generated method stub
         return false;
     }
diff --git a/src/com/android/mail/ui/ActivityController.java b/src/com/android/mail/ui/ActivityController.java
index 9cfd749..95e1b1f 100644
--- a/src/com/android/mail/ui/ActivityController.java
+++ b/src/com/android/mail/ui/ActivityController.java
@@ -212,4 +212,9 @@
      * @param listContext context providing information on what conversation list to display.
      */
     void showConversationList(ConversationListContext listContext);
+
+    /**
+     * Show the folder list associated with the currently selected account.
+     */
+    void showFolderList();
 }
diff --git a/src/com/android/mail/ui/ControllableActivity.java b/src/com/android/mail/ui/ControllableActivity.java
index 56b086f..34acefa 100644
--- a/src/com/android/mail/ui/ControllableActivity.java
+++ b/src/com/android/mail/ui/ControllableActivity.java
@@ -66,4 +66,6 @@
      * @return
      */
     StarHandler getStarHandler();
+
+    void attachFolderList(FolderListFragment folderListFragment);
 }
diff --git a/src/com/android/mail/ui/FolderListFragment.java b/src/com/android/mail/ui/FolderListFragment.java
new file mode 100644
index 0000000..c0f47fb
--- /dev/null
+++ b/src/com/android/mail/ui/FolderListFragment.java
@@ -0,0 +1,212 @@
+/*
+ * 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 android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.FragmentTransaction;
+import android.app.ListFragment;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Parcelable;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewGroup.MarginLayoutParams;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemLongClickListener;
+import android.widget.ListView;
+import android.widget.SimpleCursorAdapter;
+import android.widget.TextView;
+
+import com.android.mail.R;
+import com.android.mail.providers.Folder;
+import com.android.mail.providers.UIProvider;
+import com.android.mail.utils.LogUtils;
+
+/**
+ * The conversation list UI component.
+ */
+public final class FolderListFragment extends ListFragment {
+    private static final String LOG_TAG = new LogUtils().getLogTag();
+
+    private ControllableActivity mActivity;
+
+    // Control state.
+    private Cursor mFolderListCursor;
+
+    // The internal view objects.
+    private ListView mListView;
+
+    private ContentResolver mResolver;
+
+    private String mFolderListUri;
+    /**
+     * Hidden constructor.
+     */
+    private FolderListFragment(String uri) {
+        super();
+        mFolderListUri = uri;
+    }
+
+    /**
+     * Creates a new instance of {@link ConversationListFragment}, initialized to display
+     * conversation list context.
+     */
+    public static FolderListFragment newInstance(String uri) {
+        FolderListFragment fragment = new FolderListFragment(uri);
+        return fragment;
+    }
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+        // Strictly speaking, we get back an android.app.Activity from getActivity. However, the
+        // only activity creating a ConversationListContext is a MailActivity which is of type
+        // ControllableActivity, so this cast should be safe. If this cast fails, some other
+        // activity is creating ConversationListFragments. This activity must be of type
+        // ControllableActivity.
+        final Activity activity = getActivity();
+        if (! (activity instanceof ControllableActivity)){
+            LogUtils.wtf(LOG_TAG, "FolderListFragment expects only a ControllableActivity to" +
+                    "create it. Cannot proceed.");
+        }
+        mActivity = (ControllableActivity) activity;
+        mActivity.attachFolderList(this);
+        mResolver = mActivity.getContentResolver();
+
+        if (mActivity.isFinishing()) {
+            // Activity is finishing, just bail.
+            return;
+        }
+
+        // Show list and start loading list.
+        showList();
+    }
+
+    @Override
+    public void onCreate(Bundle savedState) {
+        LogUtils.v(LOG_TAG, "onCreate in FolderListFragment(this=%s)", this);
+        super.onCreate(savedState);
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater,
+            ViewGroup container, Bundle savedInstanceState) {
+        LogUtils.v(LOG_TAG, "onCreateView in FolderListFragment(this=%s)", this);
+        View rootView = inflater.inflate(R.layout.folder_list, null);
+        mListView = (ListView) rootView.findViewById(android.R.id.list);
+        mListView.setHeaderDividersEnabled(false);
+        mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
+
+        // Note - we manually save/restore the listview state.
+        mListView.setSaveEnabled(false);
+
+        return rootView;
+    }
+
+    @Override
+    public void onDestroyView() {
+        // Clear the adapter.
+        mListView.setAdapter(null);
+
+        mActivity.attachFolderList(null);
+
+        super.onDestroyView();
+    }
+
+    @Override
+    public void onListItemClick(ListView l, View v, int position, long id) {
+        viewFolder(position);
+    }
+
+    private void viewFolder(int position) {
+        mFolderListCursor.moveToPosition(position);
+        Folder selected = new Folder(mFolderListCursor);
+        if (selected.hasChildren) {
+            // Replace this fragment with a new FolderListFragment
+            // showing this folder's children.
+            FragmentTransaction fragmentTransaction = mActivity.getFragmentManager()
+                    .beginTransaction();
+            fragmentTransaction.addToBackStack(null);
+            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.
+            final int transition = accountChanged ? FragmentTransaction.TRANSIT_FRAGMENT_FADE
+                    : FragmentTransaction.TRANSIT_FRAGMENT_OPEN;
+            fragmentTransaction.setTransition(transition);
+
+            Fragment folderListFragment = FolderListFragment
+                    .newInstance(selected.childFoldersListUri);
+            fragmentTransaction.add(R.id.content_pane, folderListFragment);
+
+            fragmentTransaction.commitAllowingStateLoss();
+
+        } else {
+            // Go to the conversation list for this folder.
+        }
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+    }
+
+    /**
+     * Handles a request to show a new conversation list, either from a search query or for viewing
+     * a label. This will initiate a data load, and hence must be called on the UI thread.
+     */
+    private void showList() {
+        mListView.setEmptyView(null);
+
+        mFolderListCursor = mResolver.query(Uri.parse(mFolderListUri),
+                UIProvider.FOLDERS_PROJECTION, null, null, null);
+        mListView.setAdapter(new FolderListAdapter(mActivity.getActivityContext(),
+                R.layout.folder_item, mFolderListCursor, null, null));
+    }
+
+    private class FolderListAdapter extends SimpleCursorAdapter {
+
+        public FolderListAdapter(Context context, int layout, Cursor c, String[] from, int[] to) {
+            super(context, layout, c, new String[0], new int[0], 0);
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            FolderItemView folderItemView;
+            if (convertView != null) {
+                folderItemView = (FolderItemView) convertView;
+            } else {
+                folderItemView = (FolderItemView) LayoutInflater.from(
+                        mActivity.getActivityContext()).inflate(R.layout.folder_item, null);
+            }
+            getCursor().moveToPosition(position);
+            folderItemView.bind(new Folder(getCursor()), null);
+            return folderItemView;
+        }
+    }
+}
diff --git a/src/com/android/mail/ui/MailActionBar.java b/src/com/android/mail/ui/MailActionBar.java
index cb73b79..0277379 100644
--- a/src/com/android/mail/ui/MailActionBar.java
+++ b/src/com/android/mail/ui/MailActionBar.java
@@ -34,6 +34,7 @@
 import com.android.mail.AccountRecentLabelSpinner;
 import com.android.mail.AccountSpinnerAdapter;
 import com.android.mail.ConversationListContext;
+import com.android.mail.providers.Account;
 
 /**
  * View to manage the various states of the Gmail Action Bar
@@ -73,7 +74,7 @@
          *
          * @return whether the account can be switched successfully.
          */
-        boolean navigateToAccount(final String account);
+        boolean navigateToAccount(final Account account);
 
         void navigateToFolder(final String folderCanonicalName);
 
@@ -185,6 +186,12 @@
     @Override
     public boolean onNavigationItemSelected(int itemPosition, long itemId) {
         // Don't do anything. Toast on the action.
+        int type = mSpinner.getItemViewType(itemPosition);
+        switch (type) {
+            case AccountSpinnerAdapter.TYPE_ACCOUNT:
+                mCallback.navigateToAccount((Account) mSpinner.getItem(itemPosition));
+                break;
+        }
         Toast.makeText(getContext(), "Selected item " + itemPosition, Toast.LENGTH_SHORT).show();
         return false;
     }
diff --git a/src/com/android/mail/ui/MailActivity.java b/src/com/android/mail/ui/MailActivity.java
index 58abceb..75bf0e2 100644
--- a/src/com/android/mail/ui/MailActivity.java
+++ b/src/com/android/mail/ui/MailActivity.java
@@ -219,4 +219,9 @@
     public StarHandler getStarHandler() {
         return mController;
     }
+
+    @Override
+    public void attachFolderList(FolderListFragment folderListFragment) {
+        // TODO Auto-generated method stub
+    }
 }
diff --git a/src/com/android/mail/ui/OnePaneController.java b/src/com/android/mail/ui/OnePaneController.java
index 6ee2b90..c71c819 100644
--- a/src/com/android/mail/ui/OnePaneController.java
+++ b/src/com/android/mail/ui/OnePaneController.java
@@ -87,6 +87,25 @@
     }
 
     @Override
+    public void showFolderList() {
+        FragmentTransaction fragmentTransaction = mActivity.getFragmentManager().beginTransaction();
+        fragmentTransaction.addToBackStack(null);
+        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.
+        final int transition = accountChanged ? FragmentTransaction.TRANSIT_FRAGMENT_FADE :
+                FragmentTransaction.TRANSIT_FRAGMENT_OPEN;
+        fragmentTransaction.setTransition(transition);
+
+        Fragment folderListFragment = FolderListFragment.newInstance(
+                mAccount.folderListUri);
+        fragmentTransaction.replace(R.id.content_pane, folderListFragment);
+
+        fragmentTransaction.commitAllowingStateLoss();
+        resetActionBarIcon();
+    }
+
+    @Override
     public void showConversationList(ConversationListContext listContext) {
         FragmentTransaction fragmentTransaction = mActivity.getFragmentManager().beginTransaction();
         fragmentTransaction.addToBackStack(null);
diff --git a/src/com/android/mail/ui/TwoPaneController.java b/src/com/android/mail/ui/TwoPaneController.java
index 40068e4..c8fa201 100644
--- a/src/com/android/mail/ui/TwoPaneController.java
+++ b/src/com/android/mail/ui/TwoPaneController.java
@@ -74,6 +74,11 @@
     }
 
     @Override
+    public void showFolderList() {
+        // TODO: auto-generated method stub.
+    }
+
+    @Override
     public boolean onCreate(Bundle savedState) {
         mActivity.setContentView(R.layout.two_pane_activity);