Add tabs to People app

- Move account filter into overflow menu
- Use action bar in tab and standard mode so the SearchView
is right aligned and part of the options menu instead of the
custom view in the action bar
- Make visibility of action bar home icon a style so the icon
can be hidden on the phone
- TODO: Make physical search button work on the phone so the
search box can be removed from the action bar
- TODO: Fix SearchView focus problems

Change-Id: I7b3ba49f80e1911fb4a096679a00560967584426
diff --git a/src/com/android/contacts/activities/ActionBarAdapter.java b/src/com/android/contacts/activities/ActionBarAdapter.java
index 7ca5921..680c8bd 100644
--- a/src/com/android/contacts/activities/ActionBarAdapter.java
+++ b/src/com/android/contacts/activities/ActionBarAdapter.java
@@ -17,22 +17,18 @@
 package com.android.contacts.activities;
 
 import com.android.contacts.R;
+import com.android.contacts.activities.ActionBarAdapter.Listener.Action;
 import com.android.contacts.list.ContactListFilterController;
 import com.android.contacts.list.ContactListFilterController.ContactListFilterListener;
-import com.android.contacts.list.ContactListFilterView;
 import com.android.contacts.list.ContactsRequest;
 
 import android.app.ActionBar;
-import android.app.ActionBar.LayoutParams;
 import android.content.Context;
 import android.os.Bundle;
 import android.text.TextUtils;
-import android.view.LayoutInflater;
-import android.view.View;
 import android.widget.SearchView;
 import android.widget.SearchView.OnCloseListener;
 import android.widget.SearchView.OnQueryTextListener;
-import android.widget.TextView;
 
 /**
  * Adapter for the action bar at the top of the Contacts activity.
@@ -41,7 +37,11 @@
         implements OnQueryTextListener, OnCloseListener, ContactListFilterListener {
 
     public interface Listener {
-        void onAction();
+        public enum Action {
+            CHANGE_SEARCH_QUERY, START_SEARCH_MODE, STOP_SEARCH_MODE
+        }
+
+        void onAction(Action action);
     }
 
     private static final String EXTRA_KEY_SEARCH_MODE = "navBar.searchMode";
@@ -50,24 +50,25 @@
     private boolean mSearchMode;
     private String mQueryString;
 
-    private View mNavigationBar;
-    private TextView mSearchLabel;
+    private String mSearchLabelText;
     private SearchView mSearchView;
 
     private final Context mContext;
 
     private Listener mListener;
-    private ContactListFilterView mFilterView;
     private ContactListFilterController mFilterController;
 
-    private boolean mEnabled;
+    private ActionBar mActionBar;
 
     public ActionBarAdapter(Context context) {
         mContext = context;
+        mSearchLabelText = mContext.getString(R.string.search_label);
     }
 
     public void onCreate(Bundle savedState, ContactsRequest request, ActionBar actionBar) {
+        mActionBar = actionBar;
         mQueryString = null;
+
         if (savedState != null) {
             mSearchMode = savedState.getBoolean(EXTRA_KEY_SEARCH_MODE);
             mQueryString = savedState.getString(EXTRA_KEY_QUERY);
@@ -76,33 +77,18 @@
             mQueryString = request.getQueryString();
         }
 
-        if (actionBar != null) {
-            actionBar.setDisplayOptions(
-                    ActionBar.DISPLAY_SHOW_CUSTOM, ActionBar.DISPLAY_SHOW_CUSTOM);
+        if (mSearchView != null) {
+            mSearchView.setQuery(mQueryString, false);
         }
 
-        mNavigationBar = LayoutInflater.from(mContext).inflate(R.layout.navigation_bar, null);
-        LayoutParams layoutParams = new LayoutParams(
-                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
-        if (actionBar != null) {
-            actionBar.setCustomView(mNavigationBar, layoutParams);
-        }
-
-        mFilterView = (ContactListFilterView) mNavigationBar.findViewById(R.id.filter_view);
-        mSearchLabel = (TextView) mNavigationBar.findViewById(R.id.search_label);
-        mSearchView = (SearchView) mNavigationBar.findViewById(R.id.search_view);
-
-        mSearchView.setOnQueryTextListener(this);
-        mSearchView.setOnCloseListener(this);
-        mSearchView.setQuery(mQueryString, false);
-        mSearchView.setQueryHint(mContext.getString(R.string.hint_findContacts));
-
         update();
     }
 
-    public void setEnabled(boolean enabled) {
-        mEnabled = enabled;
-        update();
+    public void setSearchView(SearchView searchView) {
+        mSearchView = searchView;
+        mSearchView.setOnQueryTextListener(this);
+        mSearchView.setOnCloseListener(this);
+        mSearchView.setQuery(mQueryString, false);
     }
 
     public void setListener(Listener listener) {
@@ -111,7 +97,6 @@
 
     public void setContactListFilterController(ContactListFilterController controller) {
         mFilterController = controller;
-        mFilterController.setAnchor(mFilterView);
         mFilterController.addListener(this);
     }
 
@@ -128,9 +113,6 @@
             } else {
                 mSearchView.setQuery(null, false);
             }
-            if (mListener != null) {
-                mListener.onAction();
-            }
         }
     }
 
@@ -144,39 +126,36 @@
     }
 
     public void update() {
-        if (!mEnabled) {
-            mNavigationBar.setVisibility(View.GONE);
-        } else if (mSearchMode) {
-            mNavigationBar.setVisibility(View.VISIBLE);
-            mSearchLabel.setVisibility(View.VISIBLE);
-            mFilterView.setVisibility(View.GONE);
-            if (mFilterController != null) {
-                mFilterController.setEnabled(false);
+        if (mSearchMode) {
+            mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
+            mActionBar.setTitle(mSearchLabelText);
+            if (mListener != null) {
+                mListener.onAction(Action.START_SEARCH_MODE);
             }
         } else {
-            mNavigationBar.setVisibility(View.VISIBLE);
-            mSearchLabel.setVisibility(View.GONE);
-            mFilterView.setVisibility(View.VISIBLE);
-            if (mFilterController != null){
-                mFilterController.setEnabled(true);
-                if (mFilterController.isLoaded()) {
-                    mFilterView.setContactListFilter(mFilterController.getFilter());
-                    mFilterView.setSingleAccount(mFilterController.getAccountCount() == 1);
-                    mFilterView.bindView(false);
-                }
+            mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
+            mActionBar.setTitle(null);
+            if (mListener != null) {
+                mListener.onAction(Action.STOP_SEARCH_MODE);
             }
         }
     }
 
     @Override
     public boolean onQueryTextChange(String queryString) {
+        // TODO: Clean up SearchView code because it keeps setting the SearchView query,
+        // invoking onQueryChanged, setting up the fragment again, invalidating the options menu,
+        // storing the SearchView again, and etc... unless we add in the early return statements.
+        if (queryString.equals(mQueryString)) {
+            return false;
+        }
         mQueryString = queryString;
         if (!mSearchMode) {
             if (!TextUtils.isEmpty(queryString)) {
                 setSearchMode(true);
             }
         } else if (mListener != null) {
-            mListener.onAction();
+            mListener.onAction(Action.CHANGE_SEARCH_QUERY);
         }
 
         return true;
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index 1379e08..f537c9e 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -19,7 +19,10 @@
 import com.android.contacts.ContactSaveService;
 import com.android.contacts.ContactsActivity;
 import com.android.contacts.R;
+import com.android.contacts.calllog.CallLogFragment;
 import com.android.contacts.detail.ContactDetailFragment;
+import com.android.contacts.dialpad.DialpadFragment;
+import com.android.contacts.group.GroupBrowseListFragment;
 import com.android.contacts.interactions.ContactDeletionInteraction;
 import com.android.contacts.interactions.GroupDeletionDialogFragment;
 import com.android.contacts.interactions.GroupRenamingDialogFragment;
@@ -34,11 +37,13 @@
 import com.android.contacts.list.ContactsRequest;
 import com.android.contacts.list.ContactsUnavailableFragment;
 import com.android.contacts.list.CustomContactListFilterActivity;
+import com.android.contacts.list.DefaultContactBrowseListFragment;
 import com.android.contacts.list.DirectoryListLoader;
 import com.android.contacts.list.OnContactBrowserActionListener;
 import com.android.contacts.list.OnContactsUnavailableActionListener;
 import com.android.contacts.list.ProviderStatusLoader;
 import com.android.contacts.list.ProviderStatusLoader.ProviderStatusListener;
+import com.android.contacts.list.StrequentContactListFragment;
 import com.android.contacts.model.AccountTypeManager;
 import com.android.contacts.preference.ContactsPreferenceActivity;
 import com.android.contacts.util.AccountSelectionUtil;
@@ -47,12 +52,17 @@
 
 import android.accounts.Account;
 import android.app.ActionBar;
+import android.app.ActionBar.Tab;
+import android.app.ActionBar.TabListener;
 import android.app.Activity;
 import android.app.Dialog;
 import android.app.Fragment;
+import android.app.FragmentManager;
+import android.app.FragmentTransaction;
 import android.content.ActivityNotFoundException;
 import android.content.ContentValues;
 import android.content.Intent;
+import android.content.res.TypedArray;
 import android.net.Uri;
 import android.os.Bundle;
 import android.provider.ContactsContract;
@@ -68,6 +78,7 @@
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.Window;
+import android.widget.SearchView;
 import android.widget.Toast;
 
 import java.util.ArrayList;
@@ -94,7 +105,6 @@
     private ContactsIntentResolver mIntentResolver;
     private ContactsRequest mRequest;
 
-    private boolean mHasActionBar;
     private ActionBarAdapter mActionBarAdapter;
 
     private boolean mSearchMode;
@@ -126,8 +136,14 @@
     private boolean mOptionsMenuContactsAvailable;
     private boolean mOptionsMenuGroupActionsEnabled;
 
+    private DefaultContactBrowseListFragment mContactsFragment;
+    private StrequentContactListFragment mFavoritesFragment;
+    private GroupBrowseListFragment mGroupsFragment;
+
     public PeopleActivity() {
         mIntentResolver = new ContactsIntentResolver(this);
+        // TODO: Get rid of the ContactListFilterController class because there aren't any
+        // dropdown filters anymore. Just store the selected filter as a member variable.
         mContactListFilterController = new ContactListFilterController(this);
         mContactListFilterController.addListener(this);
         mProviderStatusLoader = new ProviderStatusLoader(this);
@@ -201,6 +217,21 @@
 
         if (createContentView) {
             setContentView(R.layout.people_activity);
+
+            final FragmentManager fragmentManager = getFragmentManager();
+            mFavoritesFragment = (StrequentContactListFragment) fragmentManager
+                    .findFragmentById(R.id.favorites_fragment);
+            mContactsFragment = (DefaultContactBrowseListFragment) fragmentManager
+                    .findFragmentById(R.id.contacts_fragment);
+            mGroupsFragment = (GroupBrowseListFragment) fragmentManager
+                    .findFragmentById(R.id.groups_fragment);
+
+            // Hide all tabs (the current tab will later be reshown once a tab is selected)
+            final FragmentTransaction transaction = fragmentManager.beginTransaction();
+            transaction.hide(mFavoritesFragment);
+            transaction.hide(mContactsFragment);
+            transaction.hide(mGroupsFragment);
+            transaction.commit();
         }
 
         if (mRequest.getActionCode() == ContactsRequest.ACTION_VIEW_CONTACT
@@ -214,21 +245,66 @@
         }
 
         setTitle(mRequest.getActivityTitle());
+        ActionBar actionBar = getActionBar();
+        mActionBarAdapter = new ActionBarAdapter(this);
+        mActionBarAdapter.onCreate(savedState, mRequest, getActionBar());
+        mActionBarAdapter.setContactListFilterController(mContactListFilterController);
 
         if (createContentView) {
-            mHasActionBar = getWindow().hasFeature(Window.FEATURE_ACTION_BAR);
-            if (mHasActionBar) {
-                ActionBar actionBar = getActionBar();
+            actionBar.removeAllTabs();
+            Tab favoritesTab = actionBar.newTab();
+            favoritesTab.setText(getString(R.string.strequentList));
+            favoritesTab.setTabListener(new TabChangeListener(mFavoritesFragment));
+            actionBar.addTab(favoritesTab);
 
-                mActionBarAdapter = new ActionBarAdapter(this);
-                mActionBarAdapter.onCreate(savedState, mRequest, actionBar);
-                mActionBarAdapter.setContactListFilterController(mContactListFilterController);
-            }
+            Tab peopleTab = actionBar.newTab();
+            peopleTab.setText(getString(R.string.people));
+            peopleTab.setTabListener(new TabChangeListener(mContactsFragment));
+            actionBar.addTab(peopleTab);
+
+            Tab groupsTab = actionBar.newTab();
+            groupsTab.setText(getString(R.string.contactsGroupsLabel));
+            groupsTab.setTabListener(new TabChangeListener(mGroupsFragment));
+            actionBar.addTab(groupsTab);
+            actionBar.setDisplayShowTitleEnabled(true);
+
+            TypedArray a = obtainStyledAttributes(null, R.styleable.ActionBarHomeIcon);
+            boolean showHomeIcon = a.getBoolean(R.styleable.ActionBarHomeIcon_show_home_icon, true);
+            actionBar.setDisplayShowHomeEnabled(showHomeIcon);
+
+            invalidateOptionsMenu();
         }
 
         configureFragments(savedState == null);
     }
 
+    /**
+     * Tab change listener that is instantiated once for each tab. Handles showing/hiding fragments.
+     * TODO: Use ViewPager so that tabs can be swiped left and right. Figure out how to use the
+     * support library in our app.
+     */
+    private class TabChangeListener implements TabListener {
+        private final Fragment mFragment;
+
+        public TabChangeListener(Fragment fragment) {
+            mFragment = fragment;
+        }
+
+        @Override
+        public void onTabUnselected(Tab tab, FragmentTransaction ft) {
+            ft.hide(mFragment);
+        }
+
+        @Override
+        public void onTabSelected(Tab tab, FragmentTransaction ft) {
+            ft.show(mFragment);
+        }
+
+        @Override
+        public void onTabReselected(Tab tab, FragmentTransaction ft) {
+        }
+    }
+
     @Override
     protected void onPause() {
         if (mActionBarAdapter != null) {
@@ -259,12 +335,6 @@
         super.onStart();
     }
 
-    @Override
-    protected void onStop() {
-        mContactListFilterController.onStop();
-        super.onStop();
-    }
-
     private void configureFragments(boolean fromRequest) {
         if (fromRequest) {
             ContactListFilter filter = null;
@@ -303,7 +373,7 @@
             mListFragment.setContactsRequest(mRequest);
             configureListFragmentForRequest();
 
-        } else if (mHasActionBar) {
+        } else {
             mSearchMode = mActionBarAdapter.isSearchMode();
         }
 
@@ -348,9 +418,23 @@
      * Handler for action bar actions.
      */
     @Override
-    public void onAction() {
-        configureFragments(false /* from request */);
-        mListFragment.setQueryString(mActionBarAdapter.getQueryString(), true);
+    public void onAction(Action action) {
+        switch (action) {
+            case START_SEARCH_MODE:
+                // Bring the contact list fragment to the front.
+                FragmentTransaction ft = getFragmentManager().beginTransaction();
+                ft.show(mContactsFragment);
+                ft.commit();
+                break;
+            case STOP_SEARCH_MODE:
+            case CHANGE_SEARCH_QUERY:
+                // Refresh the contact list fragment.
+                configureFragments(false /* from request */);
+                mListFragment.setQueryString(mActionBarAdapter.getQueryString(), true);
+                break;
+            default:
+                throw new IllegalStateException("Unkonwn ActionBarAdapter action: " + action);
+        }
     }
 
     private void configureListFragmentForRequest() {
@@ -403,17 +487,13 @@
 
         if (mProviderStatus == ProviderStatus.STATUS_NORMAL) {
             contactsUnavailableView.setVisibility(View.GONE);
-            mainView.setVisibility(View.VISIBLE);
+            if (mainView != null) {
+                mainView.setVisibility(View.VISIBLE);
+            }
             if (mListFragment != null) {
                 mListFragment.setEnabled(true);
             }
-            if (mHasActionBar) {
-                mActionBarAdapter.setEnabled(true);
-            }
         } else {
-            if (mHasActionBar) {
-                mActionBarAdapter.setEnabled(false);
-            }
             if (mListFragment != null) {
                 mListFragment.setEnabled(false);
             }
@@ -429,7 +509,9 @@
                 mContactsUnavailableFragment.update();
             }
             contactsUnavailableView.setVisibility(View.VISIBLE);
-            mainView.setVisibility(View.INVISIBLE);
+            if (mainView != null) {
+                mainView.setVisibility(View.INVISIBLE);
+            }
         }
 
         invalidateOptionsMenu();
@@ -625,27 +707,28 @@
         if (!areContactsAvailable()) {
             return false;
         }
-
         super.onCreateOptionsMenu(menu);
 
         MenuInflater inflater = getMenuInflater();
-        if (mHasActionBar) {
-            inflater.inflate(R.menu.actions, menu);
+        inflater.inflate(R.menu.actions, menu);
+        // TODO: Figure out if R.menu.list or R.menu.search are necessary according to the overflow
+        // menus on the UX mocks.
+        MenuItem searchMenuItem = menu.findItem(R.id.menu_search);
+        if (searchMenuItem != null && searchMenuItem.getActionView() instanceof SearchView) {
+            SearchView searchView = (SearchView) searchMenuItem.getActionView();
+            searchView.setQueryHint(getString(R.string.hint_findContacts));
+            searchView.setIconifiedByDefault(false);
 
-            // Change add contact button to button with a custom view
-            final MenuItem addContact = menu.findItem(R.id.menu_add);
-            addContact.setActionView(mAddContactImageView);
-            return true;
-        } else if (mRequest.getActionCode() == ContactsRequest.ACTION_ALL_CONTACTS ||
-                mRequest.getActionCode() == ContactsRequest.ACTION_STREQUENT) {
-            inflater.inflate(R.menu.list, menu);
-            return true;
-        } else if (!mListFragment.isSearchMode()) {
-            inflater.inflate(R.menu.search, menu);
-            return true;
-        } else {
-            return false;
+            if (mActionBarAdapter != null) {
+                mActionBarAdapter.setSearchView(searchView);
+            }
         }
+
+        // TODO: Can remove this as a custom view because the account selector is in the editor now.
+        // Change add contact button to button with a custom view
+        final MenuItem addContact = menu.findItem(R.id.menu_add);
+        addContact.setActionView(mAddContactImageView);
+        return true;
     }
 
     @Override
@@ -723,6 +806,11 @@
                 startActivity(intent);
                 return true;
             }
+            case R.id.menu_contacts_filter: {
+                final Intent intent = new Intent(this, CustomContactListFilterActivity.class);
+                startActivityForResult(intent, SUBACTIVITY_CUSTOMIZE_FILTER);
+                return true;
+            }
             case R.id.menu_search: {
                 onSearchRequested();
                 return true;
@@ -865,12 +953,10 @@
                 final int unicodeChar = event.getUnicodeChar();
                 if (unicodeChar != 0 && !Character.isWhitespace(unicodeChar)) {
                     String query = new String(new int[]{ unicodeChar }, 0, 1);
-                    if (mHasActionBar) {
-                        if (!mActionBarAdapter.isSearchMode()) {
-                            mActionBarAdapter.setQueryString(query);
-                            mActionBarAdapter.setSearchMode(true);
-                            return true;
-                        }
+                    if (!mActionBarAdapter.isSearchMode()) {
+                        mActionBarAdapter.setQueryString(query);
+                        mActionBarAdapter.setSearchMode(true);
+                        return true;
                     } else if (!mRequest.isSearchMode()) {
                         if (!mSearchInitiated) {
                             mSearchInitiated = true;
diff --git a/src/com/android/contacts/list/ContactListFilterController.java b/src/com/android/contacts/list/ContactListFilterController.java
index c9f5530..4da5baa 100644
--- a/src/com/android/contacts/list/ContactListFilterController.java
+++ b/src/com/android/contacts/list/ContactListFilterController.java
@@ -43,6 +43,8 @@
 /**
  * Controls a list of {@link ContactListFilter}'s.
  */
+// TODO: Remove the extra functionality dealing with loading and displaying a list of filters in
+// the action bar.
 public class ContactListFilterController
         implements LoaderCallbacks<List<ContactListFilter>>, OnClickListener, OnItemClickListener {
 
@@ -84,11 +86,6 @@
         mListeners.remove(listener);
     }
 
-    public void setAnchor(View anchor) {
-        mAnchor = anchor;
-        mAnchor.setOnClickListener(this);
-    }
-
     public ContactListFilter getFilter() {
         return mFilter;
     }
@@ -105,11 +102,6 @@
         if (mFilter == null) {
             mFilter = ContactListFilter.restoreFromPreferences(getSharedPreferences());
         }
-        mLoaderManager.initLoader(R.id.contact_list_filter_loader, null, this);
-    }
-
-    public void onStop() {
-        mLoaderManager.destroyLoader(R.id.contact_list_filter_loader);
     }
 
     private SharedPreferences getSharedPreferences() {