Open group fragment and duplicates fragment from PeopleActivity

* Also handle some side nav menu logic

Bug: 30944495

Test: manual - navigate between fragments, rotation, press Back/Home/Recent
               button, search, multi-select, modify group members,
               add/delete groups.

Change-Id: I4feeed89557a5c07852a1e2d2a39306cfa59c918
diff --git a/src/com/android/contacts/ContactsDrawerActivity.java b/src/com/android/contacts/ContactsDrawerActivity.java
index 047046b..2fd5089 100644
--- a/src/com/android/contacts/ContactsDrawerActivity.java
+++ b/src/com/android/contacts/ContactsDrawerActivity.java
@@ -22,7 +22,6 @@
 import android.content.Intent;
 import android.graphics.Color;
 import android.graphics.PorterDuff;
-import android.net.Uri;
 import android.os.Bundle;
 import android.provider.ContactsContract.Intents;
 import android.support.annotation.LayoutRes;
@@ -32,10 +31,7 @@
 import android.support.v4.widget.DrawerLayout;
 import android.support.v7.app.ActionBarDrawerToggle;
 import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
 import android.support.v7.widget.Toolbar;
-import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.Menu;
@@ -46,7 +42,7 @@
 import android.widget.LinearLayout;
 import android.widget.Toast;
 
-import com.android.contacts.activities.GroupMembersActivity;
+import com.android.contacts.activities.ActionBarAdapter;
 import com.android.contacts.common.ContactsUtils;
 import com.android.contacts.common.compat.CompatUtils;
 import com.android.contacts.common.editor.SelectAccountDialogFragment;
@@ -64,6 +60,7 @@
 import com.android.contacts.common.util.ViewUtil;
 import com.android.contacts.editor.ContactEditorFragment;
 import com.android.contacts.group.GroupListItem;
+import com.android.contacts.group.GroupMembersFragment;
 import com.android.contacts.group.GroupMetadata;
 import com.android.contacts.group.GroupNameEditDialogFragment;
 import com.android.contacts.group.GroupUtil;
@@ -71,9 +68,10 @@
 import com.android.contacts.group.GroupsFragment.GroupsListener;
 import com.android.contacts.interactions.AccountFiltersFragment;
 import com.android.contacts.interactions.AccountFiltersFragment.AccountFiltersListener;
+import com.android.contacts.list.DefaultContactBrowseListFragment;
+import com.android.contacts.list.MultiSelectContactsListFragment;
 import com.android.contacts.quickcontact.QuickContactActivity;
 import com.android.contacts.util.SharedPreferenceUtil;
-import com.android.contactsbind.Assistants;
 import com.android.contactsbind.HelpUtils;
 import com.android.contactsbind.ObjectFactory;
 
@@ -92,6 +90,15 @@
         NavigationView.OnNavigationItemSelectedListener,
         SelectAccountDialogFragment.Listener {
 
+    /** Possible views of Contacts app. */
+    public enum ContactsView {
+        NONE,
+        ALL_CONTACTS,
+        DUPLICATES,
+        GROUP_VIEW,
+        ACCOUNT_VIEW,
+    }
+
     protected static String TAG = "ContactsDrawerActivity";
 
     private static final String TAG_GROUPS = "groups";
@@ -100,15 +107,11 @@
     private static final String TAG_GROUP_NAME_EDIT_DIALOG = "groupNameEditDialog";
 
     private static final String KEY_NEW_GROUP_ACCOUNT = "newGroupAccount";
+    private static final String KEY_CONTACTS_VIEW = "contactsView";
 
     protected static final String ACTION_CREATE_GROUP = "createGroup";
 
-    // TODO(wenyiw): remove all the code related to these constants after switching to fragments.
-    // Positions of "all contacts" and "duplicates" in navigation drawer.
-    private static final int ALL_CONTACTS_POSITION = 1;
-    private static final int DUPLICATES_POSITION = 2;
-    // Gap between two menu groups, including a separator, a menu group header.
-    private static final int GAP_BETWEEN_TWO_MENU_GROUPS = 2;
+    protected ContactsView mCurrentView;
 
     private class ContactsActionBarDrawerToggle extends ActionBarDrawerToggle {
 
@@ -130,6 +133,33 @@
                 mMenuClickedBefore = true;
             }
             invalidateOptionsMenu();
+            // Stop search and selection mode like Gmail and Keep. Otherwise, if user switches to
+            // another fragment in navigation drawer, the current search/selection mode will be
+            // overlaid by the action bar of the newly-created fragment.
+            stopSearchAndSelection();
+        }
+
+        private void stopSearchAndSelection() {
+            final MultiSelectContactsListFragment listFragment;
+            if (isAllContactsView() || isAccountView()) {
+                listFragment = getAllFragment();
+            } else if (isGroupView()) {
+                listFragment = getGroupFragment();
+            } else {
+                listFragment = null;
+            }
+            if (listFragment == null) {
+                return;
+            }
+            final ActionBarAdapter actionBarAdapter = listFragment.getActionBarAdapter();
+            if (actionBarAdapter == null) {
+                return;
+            }
+            if (actionBarAdapter.isSearchMode()) {
+                actionBarAdapter.setSearchMode(false);
+            } else if (actionBarAdapter.isSelectionMode()) {
+                actionBarAdapter.setSelectionMode(false);
+            }
         }
 
         @Override
@@ -164,18 +194,16 @@
     protected GroupsFragment mGroupsFragment;
     protected AccountFiltersFragment mAccountFiltersFragment;
 
-    // Checkable menu item lookup maps. Every map declared here should be added to
-    // clearCheckedMenus() so that they can be cleared.
-    // TODO find a better way to handle selected menu item state, when swicthing to fragments.
-    protected Map<Long, MenuItem> mGroupMenuMap = new HashMap<>();
-    protected Map<ContactListFilter, MenuItem> mFilterMenuMap = new HashMap<>();
-    protected Map<Integer, MenuItem> mIdMenuMap = new HashMap<>();
-
     // The account the new group will be created under.
     private AccountWithDataSet mNewGroupAccount;
     private DeviceAccountPresentationValues mDeviceAccountPresentationValues;
 
-    private int mPositionOfLastGroup;
+    // Checkable menu item lookup maps. Every map declared here should be added to
+    // clearCheckedMenus() so that they can be cleared.
+    // TODO find a better way to handle selected menu item state, when switching to fragments.
+    protected Map<Long, MenuItem> mGroupMenuMap = new HashMap<>();
+    protected Map<ContactListFilter, MenuItem> mFilterMenuMap = new HashMap<>();
+    protected Map<Integer, MenuItem> mIdMenuMap = new HashMap<>();
 
     @Override
     protected void onCreate(Bundle savedState) {
@@ -202,61 +230,52 @@
         mDrawer.setDrawerListener(mToggle);
         mToggle.syncState();
 
+        // Set up navigation mode.
+        if (savedState != null) {
+            mCurrentView = ContactsView.values()[savedState.getInt(KEY_CONTACTS_VIEW)];
+        } else {
+            mCurrentView = ContactsView.ALL_CONTACTS;
+        }
+
         // Set up hamburger menu items.
         mNavigationView = (NavigationView) findViewById(R.id.nav_view);
         mNavigationView.setNavigationItemSelectedListener(this);
-
-        final Menu menu = mNavigationView.getMenu();
-
-        final MenuItem allContacts = menu.findItem(R.id.nav_all_contacts);
-        mIdMenuMap.put(R.id.nav_all_contacts, allContacts);
-
-        if (Assistants.getDuplicatesActivityIntent(this) == null) {
-            menu.removeItem(R.id.nav_find_duplicates);
-        } else {
-            final MenuItem findDup = menu.findItem(R.id.nav_find_duplicates);
-            mIdMenuMap.put(R.id.nav_find_duplicates, findDup);
-        }
-
-        if (!HelpUtils.isHelpAndFeedbackAvailable()) {
-            menu.removeItem(R.id.nav_help);
-        }
+        setUpMenu();
 
         loadGroupsAndFilters();
 
-        if (isDuplicatesActivity()) {
-            clearCheckedMenus();
-            mIdMenuMap.get(R.id.nav_find_duplicates).setCheckable(true);
-            mIdMenuMap.get(R.id.nav_find_duplicates).setChecked(true);
-            maybeUpdateScrollPosition(DUPLICATES_POSITION);
-        }
-
         if (savedState != null && savedState.containsKey(KEY_NEW_GROUP_ACCOUNT)) {
             mNewGroupAccount = AccountWithDataSet.unstringify(
                     savedState.getString(KEY_NEW_GROUP_ACCOUNT));
         }
     }
 
-    public Toolbar getToolbar() {
-        return mToolbar;
+    private void setUpMenu() {
+        final Menu menu = mNavigationView.getMenu();
+
+        if (ObjectFactory.getDuplicatesFragment() == null) {
+            menu.removeItem(R.id.nav_find_duplicates);
+        } else {
+            final MenuItem findDupMenu = menu.findItem(R.id.nav_find_duplicates);
+            mIdMenuMap.put(R.id.nav_find_duplicates, findDupMenu);
+            if (isDuplicatesView()) {
+                updateMenuSelection(findDupMenu);
+            }
+        }
+
+        if (!HelpUtils.isHelpAndFeedbackAvailable()) {
+            menu.removeItem(R.id.nav_help);
+        }
+
+        final MenuItem allContactsMenu = menu.findItem(R.id.nav_all_contacts);
+        mIdMenuMap.put(R.id.nav_all_contacts, allContactsMenu);
+        if (isAllContactsView()) {
+            updateMenuSelection(allContactsMenu);
+        }
     }
 
-    private void maybeUpdateScrollPosition(int position) {
-        if (mDrawer.isDrawerOpen(GravityCompat.START)) {
-            if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "Don't scroll menu when drawer open");
-            return;
-        }
-        final RecyclerView recyclerView = (RecyclerView) mNavigationView.getChildAt(0);
-        final LinearLayoutManager layoutManager =
-                (LinearLayoutManager) recyclerView.getLayoutManager();
-
-        // Get screen height
-        final DisplayMetrics metrics = getResources().getDisplayMetrics();
-        final int height = metrics.heightPixels;
-
-        // Set 1/3 screen height as offset if possible.
-        layoutManager.scrollToPositionWithOffset(position, height / 3);
-        recyclerView.requestLayout();
+    public Toolbar getToolbar() {
+        return mToolbar;
     }
 
     @Override
@@ -265,6 +284,7 @@
         if (mNewGroupAccount != null) {
             outState.putString(KEY_NEW_GROUP_ACCOUNT, mNewGroupAccount.stringify());
         }
+        outState.putInt(KEY_CONTACTS_VIEW, mCurrentView.ordinal());
     }
 
     @Override
@@ -284,37 +304,6 @@
         }
     }
 
-    @Override
-    protected void onNewIntent(Intent newIntent) {
-        mContactListFilterController.checkFilterValidity(false);
-        if (ACTION_CREATE_GROUP.equals(newIntent.getAction())) {
-            final Uri groupUri = newIntent.getData();
-            if (groupUri == null) {
-                Toast.makeText(this, R.string.groupSavedErrorToast, Toast.LENGTH_SHORT).show();
-                return;
-            }
-            if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "Received group URI " + groupUri);
-            Toast.makeText(this, R.string.groupCreatedToast, Toast.LENGTH_SHORT).show();
-            startActivity(GroupUtil.createViewGroupIntent(this, groupUri, /* title */ null));
-            if (shouldFinish()) {
-                // If we created a group while viewing the members of an existing group (i.e.
-                // while on GroupMembersActivity), finish the current GroupMembersActivity so that
-                // hitting back from the new GroupMembersActivity that was just stared will open
-                // the all contacts list. See b/30047708.
-                finish();
-            }
-        } else {
-            super.onNewIntent(newIntent);
-        }
-    }
-
-    /**
-     * Returns true if child class is DuplicatesActivity
-     */
-    protected boolean isDuplicatesActivity() {
-        return false;
-    }
-
     // Set up fragment manager to load groups and filters.
     protected void loadGroupsAndFilters() {
         final FragmentManager fragmentManager = getFragmentManager();
@@ -363,7 +352,7 @@
         subMenu.removeGroup(R.id.nav_groups_items);
         mGroupMenuMap = new HashMap<>();
 
-        mPositionOfLastGroup = DUPLICATES_POSITION + GAP_BETWEEN_TWO_MENU_GROUPS;
+        final GroupMetadata groupMetaData = getGroupMetadata();
 
         if (groupListItems != null) {
             // Add each group
@@ -371,11 +360,14 @@
                 if (GroupUtil.isEmptyFFCGroup(groupListItem)) {
                     continue;
                 }
-                mPositionOfLastGroup++;
                 final String title = groupListItem.getTitle();
                 final MenuItem menuItem =
-                        subMenu.add(R.id.nav_groups_items, Menu.NONE, mPositionOfLastGroup, title);
+                        subMenu.add(R.id.nav_groups_items, Menu.NONE, Menu.NONE, title);
                 mGroupMenuMap.put(groupListItem.getGroupId(), menuItem);
+                if (isGroupView() && groupMetaData != null
+                        && groupMetaData.groupId == groupListItem.getGroupId()) {
+                    updateMenuSelection(menuItem);
+                }
                 menuItem.setIcon(R.drawable.ic_menu_label);
                 menuItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
                     @Override
@@ -385,6 +377,7 @@
                             public void run() {
                                 onGroupMenuItemClicked(groupListItem.getGroupId(),
                                         groupListItem.getTitle());
+                                updateMenuSelection(menuItem);
                             }
                         });
                         mDrawer.closeDrawer(GravityCompat.START);
@@ -399,10 +392,9 @@
             return;
         }
 
-        mPositionOfLastGroup++;
         // Create a menu item in the sub menu to add new groups
         final MenuItem menuItem = subMenu.add(R.id.nav_groups_items, Menu.NONE,
-                mPositionOfLastGroup, getString(R.string.menu_new_group_action_bar));
+                Menu.NONE, getString(R.string.menu_new_group_action_bar));
         menuItem.setIcon(R.drawable.ic_add);
         menuItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
             @Override
@@ -418,37 +410,45 @@
             }
         });
 
-        if (getGroupMetadata() != null) {
-            updateGroupMenu(getGroupMetadata());
+        if (isGroupView() && groupMetaData != null) {
+            updateGroupMenu(groupMetaData);
         }
     }
 
-    // TODO(wenyiw) the method is public for now; we should remove it after b/30944495 is fixed.
     public void updateGroupMenu(GroupMetadata groupMetadata) {
         clearCheckedMenus();
         if (groupMetadata != null && mGroupMenuMap != null
                 && mGroupMenuMap.get(groupMetadata.groupId) != null) {
-            mGroupMenuMap.get(groupMetadata.groupId).setCheckable(true);
-            mGroupMenuMap.get(groupMetadata.groupId).setChecked(true);
-            maybeUpdateScrollPosition(mGroupMenuMap.get(groupMetadata.groupId).getOrder());
+            setMenuChecked(mGroupMenuMap.get(groupMetadata.groupId), true);
         }
     }
 
-    /**
-     * Returns group metadata if the child class is {@link GroupMembersActivity}, and null
-     * otherwise.
-     */
     protected GroupMetadata getGroupMetadata() {
         return null;
     }
 
-    protected void onGroupMenuItemClicked(long groupId, String title) {
-        startActivity(GroupUtil.createViewGroupIntent(this, groupId, title));
-        if (shouldFinish()) {
-            finish();
-        }
+    protected boolean isGroupView() {
+        return mCurrentView == ContactsView.GROUP_VIEW;
     }
 
+    protected boolean isDuplicatesView() {
+        return mCurrentView == ContactsView.DUPLICATES;
+    }
+
+    protected boolean isAllContactsView() {
+        return mCurrentView == ContactsView.ALL_CONTACTS;
+    }
+
+    protected boolean isAccountView() {
+        return mCurrentView == ContactsView.ACCOUNT_VIEW;
+    }
+
+    public boolean isInSecondLevel() {
+        return isGroupView() || isDuplicatesView();
+    }
+
+    protected abstract void onGroupMenuItemClicked(long groupId, String title);
+
     protected void onCreateGroupMenuItemClicked() {
         // Select the account to create the group
         final Bundle extras = getIntent().getExtras();
@@ -477,16 +477,16 @@
             return;
         }
 
-        int positionOfLastFilter = mPositionOfLastGroup + GAP_BETWEEN_TWO_MENU_GROUPS;
-
         mDeviceAccountPresentationValues.setFilters(accountFilterItems);
 
         for (int i = 0; i < accountFilterItems.size(); i++) {
-            positionOfLastFilter++;
             final ContactListFilter filter = accountFilterItems.get(i);
             final CharSequence menuName = mDeviceAccountPresentationValues.getLabel(i);
             final MenuItem menuItem = subMenu.add(R.id.nav_filters_items, Menu.NONE,
-                    positionOfLastFilter, menuName);
+                    Menu.NONE, menuName);
+            if (isAccountView() && filter == mContactListFilterController.getFilter()) {
+                updateMenuSelection(menuItem);
+            }
             mFilterMenuMap.put(filter, menuItem);
             final Intent intent = new Intent();
             intent.putExtra(AccountFilterActivity.EXTRA_CONTACT_LIST_FILTER, filter);
@@ -496,12 +496,8 @@
                     mToggle.runWhenIdle(new Runnable() {
                         @Override
                         public void run() {
-                            AccountFilterUtil.handleAccountFilterResult(
-                                    mContactListFilterController, AppCompatActivity.RESULT_OK,
-                                    intent);
-                            if (shouldFinish()) {
-                                finish();
-                            }
+                            onFilterMenuItemClicked(intent);
+                            updateMenuSelection(menuItem);
                         }
                     });
                     mDrawer.closeDrawer(GravityCompat.START);
@@ -523,40 +519,29 @@
             menuItem.setActionView(view);
         }
 
-        if (getContactListFilter() != null) {
-            updateFilterMenu(getContactListFilter());
+        if (isAccountView()) {
+            updateFilterMenu(mContactListFilterController.getFilter());
         }
     }
 
     public void updateFilterMenu(ContactListFilter filter) {
         clearCheckedMenus();
-        if (filter != null && filter.isContactsFilterType()) {
+        if (filter.filterType == ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS) {
             if (mIdMenuMap != null && mIdMenuMap.get(R.id.nav_all_contacts) != null) {
-                mIdMenuMap.get(R.id.nav_all_contacts).setCheckable(true);
-                mIdMenuMap.get(R.id.nav_all_contacts).setChecked(true);
-                maybeUpdateScrollPosition(ALL_CONTACTS_POSITION);
+                setMenuChecked(mIdMenuMap.get(R.id.nav_all_contacts), true);
             }
         } else {
             if (mFilterMenuMap != null && mFilterMenuMap.get(filter) != null) {
-                mFilterMenuMap.get(filter).setCheckable(true);
-                mFilterMenuMap.get(filter).setChecked(true);
-                maybeUpdateScrollPosition(mFilterMenuMap.get(filter).getOrder());
+                setMenuChecked(mFilterMenuMap.get(filter), true);
             }
         }
     }
 
-    /**
-     * Returns the current filter if the child class is PeopleActivity, and null otherwise.
-     */
-    protected ContactListFilter getContactListFilter() {
-        return null;
+    protected void onFilterMenuItemClicked(Intent intent) {
+        AccountFilterUtil.handleAccountFilterResult(mContactListFilterController,
+                AppCompatActivity.RESULT_OK, intent);
     }
 
-    /**
-     * Returns true if the child activity should finish after launching another activity.
-     */
-    protected abstract boolean shouldFinish();
-
     @Override
     public boolean onNavigationItemSelected(final MenuItem item) {
         final int id = item.getItemId();
@@ -570,7 +555,10 @@
                 } else if (id == R.id.nav_all_contacts) {
                     switchToAllContacts();
                 } else if (id == R.id.nav_find_duplicates) {
-                    launchFindDuplicates();
+                    if (!isDuplicatesView()) {
+                        launchFindDuplicates();
+                        updateMenuSelection(item);
+                    }
                 } else if (item.getIntent() != null) {
                     ImplicitIntentsUtil.startActivityInApp(ContactsDrawerActivity.this,
                             item.getIntent());
@@ -595,36 +583,47 @@
         return intent;
     }
 
-    protected void switchToAllContacts() {
+    public void switchToAllContacts() {
         final Intent intent = new Intent();
         final ContactListFilter filter = AccountFilterUtil.createContactsFilter(this);
         intent.putExtra(AccountFilterActivity.EXTRA_CONTACT_LIST_FILTER, filter);
         AccountFilterUtil.handleAccountFilterResult(
                 mContactListFilterController, AppCompatActivity.RESULT_OK, intent);
-        if (shouldFinish()) {
-            finish();
-        }
+
+        final Menu menu = mNavigationView.getMenu();
+        final MenuItem allContacts = menu.findItem(R.id.nav_all_contacts);
+        updateMenuSelection(allContacts);
+
+        setTitle(getString(R.string.contactsList));
     }
 
-    protected void launchFindDuplicates() {
-        ImplicitIntentsUtil.startActivityInAppIfPossible(this,
-                Assistants.getDuplicatesActivityIntent(this));
-    }
+    protected abstract void launchFindDuplicates();
+
+    protected abstract DefaultContactBrowseListFragment getAllFragment();
+
+    protected abstract GroupMembersFragment getGroupFragment();
+
+    public abstract void showFabWithAnimation(boolean showFab);
 
     private void clearCheckedMenus() {
         clearCheckedMenu(mFilterMenuMap);
         clearCheckedMenu(mGroupMenuMap);
         clearCheckedMenu(mIdMenuMap);
     }
+
     private void clearCheckedMenu(Map<?, MenuItem> map) {
         final Iterator it = map.entrySet().iterator();
         while (it.hasNext()) {
-            Entry pair = (Entry)it.next();
-            map.get(pair.getKey()).setCheckable(false);
-            map.get(pair.getKey()).setChecked(false);
+            Entry pair = (Entry) it.next();
+            setMenuChecked(map.get(pair.getKey()), false);
         }
     }
 
+    private void setMenuChecked(MenuItem menuItem, boolean checked) {
+        menuItem.setCheckable(checked);
+        menuItem.setChecked(checked);
+    }
+
     private void selectAccount() {
         final List<AccountWithDataSet> accounts = AccountTypeManager.getInstance(this)
                 .getAccounts(/* writable */ true);
@@ -654,4 +653,9 @@
     @Override
     public void onAccountSelectorCancelled() {
     }
+
+    private void updateMenuSelection(MenuItem menuItem) {
+        clearCheckedMenus();
+        setMenuChecked(menuItem, true);
+    }
 }