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);
+    }
 }
diff --git a/src/com/android/contacts/GroupMetaDataLoader.java b/src/com/android/contacts/GroupMetaDataLoader.java
index 8cdca2e..cc88605 100644
--- a/src/com/android/contacts/GroupMetaDataLoader.java
+++ b/src/com/android/contacts/GroupMetaDataLoader.java
@@ -66,7 +66,7 @@
         if (groupUri == null) {
             throw new IllegalArgumentException("Uri must not be null");
         }
-        if (!groupUri.toString().startsWith(Groups.CONTENT_URI.toString())) {
+        if (!GroupUtil.isGroupUri(groupUri)) {
             throw new IllegalArgumentException("Invalid group Uri: " + groupUri);
         }
         return groupUri;
diff --git a/src/com/android/contacts/activities/GroupMembersActivity.java b/src/com/android/contacts/activities/GroupMembersActivity.java
deleted file mode 100644
index e4b052c..0000000
--- a/src/com/android/contacts/activities/GroupMembersActivity.java
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Copyright (C) 2016 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.contacts.activities;
-
-import android.app.FragmentManager;
-import android.app.FragmentTransaction;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.support.v4.view.GravityCompat;
-import android.util.Log;
-import android.widget.Toast;
-
-import com.android.contacts.ContactsDrawerActivity;
-import com.android.contacts.R;
-import com.android.contacts.group.GroupMembersFragment;
-import com.android.contacts.group.GroupMetadata;
-import com.android.contacts.group.GroupUtil;
-
-/**
- * Displays the members of a group and allows the user to edit it.
- */
-public class GroupMembersActivity extends ContactsDrawerActivity {
-
-    private static final String TAG = "GroupMembers";
-
-    private static final String KEY_GROUP_URI = "groupUri";
-
-    private static final String TAG_GROUP_MEMBERS = "groupMembers";
-
-    private GroupMembersFragment mMembersFragment;
-
-    private Uri mGroupUri;
-
-    @Override
-    public void onCreate(Bundle savedState) {
-        super.onCreate(savedState);
-
-        // Parse the Intent
-        if (savedState != null) {
-            mGroupUri = savedState.getParcelable(KEY_GROUP_URI);
-        } else {
-            mGroupUri = getIntent().getData();
-            setTitle(getIntent().getStringExtra(GroupUtil.EXTRA_GROUP_NAME));
-        }
-        if (mGroupUri == null) {
-            setResultCanceledAndFinish(R.string.groupLoadErrorToast);
-            return;
-        }
-
-        // Set up the view
-        setContentView(R.layout.group_members_activity);
-
-        // Add the members list fragment
-        final FragmentManager fragmentManager = getFragmentManager();
-        mMembersFragment = (GroupMembersFragment)
-                fragmentManager.findFragmentByTag(TAG_GROUP_MEMBERS);
-        if (mMembersFragment == null) {
-            mMembersFragment = GroupMembersFragment.newInstance(getIntent().getData());
-            fragmentManager.beginTransaction().replace(R.id.fragment_container_inner,
-                    mMembersFragment, TAG_GROUP_MEMBERS).commitAllowingStateLoss();
-        }
-    }
-
-    @Override
-    public void onSaveInstanceState(Bundle outState) {
-        super.onSaveInstanceState(outState);
-        outState.putParcelable(KEY_GROUP_URI, mGroupUri);
-    }
-
-    // Invoked with results from the ContactSaveService
-    @Override
-    protected void onNewIntent(Intent newIntent) {
-        if (ContactsDrawerActivity.ACTION_CREATE_GROUP.equals(newIntent.getAction())) {
-            super.onNewIntent(newIntent);
-            return;
-        }
-        if (isDeleteAction(newIntent.getAction())) {
-            toast(R.string.groupDeletedToast);
-            setResult(RESULT_OK);
-            finish();
-        } else if (isSaveAction(newIntent.getAction())) {
-            final Uri groupUri = newIntent.getData();
-            if (groupUri == null) {
-                setResultCanceledAndFinish(R.string.groupSavedErrorToast);
-                return;
-            }
-            if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "Received group URI " + groupUri);
-
-            mGroupUri = groupUri;
-
-            toast(getToastMessageForSaveAction(newIntent.getAction()));
-
-            if (mMembersFragment.isEditMode()) {
-                // If we're removing group members one at a time, don't reload the fragment so
-                // the user can continue to remove group members one by one
-                if (getGroupCount() == 1) {
-                    // If we're deleting the last group member, exit edit mode
-                    onBackPressed();
-                }
-            } else if (!GroupUtil.ACTION_REMOVE_FROM_GROUP.equals(newIntent.getAction())) {
-                replaceGroupMembersFragment();
-                invalidateOptionsMenu();
-            }
-        }
-    }
-
-    private static boolean isDeleteAction(String action) {
-        return GroupUtil.ACTION_DELETE_GROUP.equals(action);
-    }
-
-    private static boolean isSaveAction(String action) {
-        return GroupUtil.ACTION_UPDATE_GROUP.equals(action)
-                || GroupUtil.ACTION_ADD_TO_GROUP.equals(action)
-                || GroupUtil.ACTION_REMOVE_FROM_GROUP.equals(action);
-    }
-
-    private static int getToastMessageForSaveAction(String action) {
-        if (GroupUtil.ACTION_UPDATE_GROUP.equals(action)) return R.string.groupUpdatedToast;
-        if (GroupUtil.ACTION_ADD_TO_GROUP.equals(action)) return R.string.groupMembersAddedToast;
-        if (GroupUtil.ACTION_REMOVE_FROM_GROUP.equals(action))
-            return R.string.groupMembersRemovedToast;
-        throw new IllegalArgumentException("Unhanded contact save action " + action);
-    }
-
-    private int getGroupCount() {
-        return mMembersFragment != null && mMembersFragment.getAdapter() != null
-                ? mMembersFragment.getAdapter().getCount() : -1;
-    }
-
-    private void replaceGroupMembersFragment() {
-        mMembersFragment = GroupMembersFragment.newInstance(mGroupUri);
-        final FragmentTransaction transaction = getFragmentManager().beginTransaction();
-        addGroupsAndFiltersFragments(transaction);
-        transaction.replace(R.id.fragment_container_inner, mMembersFragment, TAG_GROUP_MEMBERS)
-                .commitAllowingStateLoss();
-    }
-
-    @Override
-    protected void onGroupMenuItemClicked(long groupId, String title) {
-        if (mMembersFragment.getGroupMetadata().groupId != groupId) {
-            super.onGroupMenuItemClicked(groupId, title);
-        }
-    }
-
-    @Override
-    protected boolean shouldFinish() {
-        return true;
-    }
-
-    @Override
-    protected void launchFindDuplicates() {
-        super.launchFindDuplicates();
-        finish();
-    }
-
-    @Override
-    public void onBackPressed() {
-        if (!isSafeToCommitTransactions()) {
-            return;
-        }
-        if (mDrawer.isDrawerOpen(GravityCompat.START)) {
-            mDrawer.closeDrawer(GravityCompat.START);
-        } else if (mMembersFragment.isEditMode()) {
-            mMembersFragment.setEditMode(false);
-            mMembersFragment.getActionBarAdapter().setSelectionMode(false);
-            mMembersFragment.displayDeleteButtons(false);
-        } else if (mMembersFragment.getActionBarAdapter().isSelectionMode()) {
-            mMembersFragment.getActionBarAdapter().setSelectionMode(false);
-            mMembersFragment.displayCheckBoxes(false);
-        } else if (mMembersFragment.getActionBarAdapter().isSearchMode()) {
-            mMembersFragment.getActionBarAdapter().setSearchMode(false);
-        } else {
-            switchToAllContacts();
-            super.onBackPressed();
-        }
-    }
-
-    private void setResultCanceledAndFinish(int resId) {
-        toast(resId);
-        setResult(RESULT_CANCELED);
-        finish();
-    }
-
-    private void toast(int resId) {
-        if (resId >= 0) {
-            Toast.makeText(this, resId, Toast.LENGTH_SHORT).show();
-        }
-    }
-
-    @Override
-    protected GroupMetadata getGroupMetadata() {
-        return mMembersFragment.getGroupMetadata();
-    }
-}
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index 406ef00..dfda7d1 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -20,9 +20,9 @@
 import android.app.Fragment;
 import android.app.FragmentManager;
 import android.app.FragmentTransaction;
-import android.content.ActivityNotFoundException;
 import android.content.ContentResolver;
 import android.content.BroadcastReceiver;
+import android.content.ContentUris;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SyncStatusObserver;
@@ -30,8 +30,7 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
-import android.provider.ContactsContract.Contacts;
-import android.provider.ContactsContract.Intents;
+import android.provider.ContactsContract;
 import android.provider.ContactsContract.ProviderStatus;
 import android.support.design.widget.CoordinatorLayout;
 import android.support.design.widget.Snackbar;
@@ -69,6 +68,9 @@
 import com.android.contacts.common.util.ImplicitIntentsUtil;
 import com.android.contacts.common.widget.FloatingActionButtonController;
 import com.android.contacts.editor.EditorIntents;
+import com.android.contacts.group.GroupMembersFragment;
+import com.android.contacts.group.GroupMetadata;
+import com.android.contacts.group.GroupUtil;
 import com.android.contacts.list.ContactsIntentResolver;
 import com.android.contacts.list.ContactsRequest;
 import com.android.contacts.list.ContactsUnavailableFragment;
@@ -76,9 +78,9 @@
 import com.android.contacts.list.OnContactsUnavailableActionListener;
 import com.android.contacts.quickcontact.QuickContactActivity;
 import com.android.contacts.util.SyncUtil;
+import com.android.contactsbind.ObjectFactory;
 import com.android.contactsbind.experiments.Flags;
 import com.android.contacts.widget.FloatingActionButtonBehavior;
-import com.android.contactsbind.FeatureHighlightHelper;
 
 import java.util.List;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -89,8 +91,13 @@
 public class PeopleActivity extends ContactsDrawerActivity implements ProviderStatusListener {
 
     private static final String TAG = "PeopleActivity";
-
     private static final String TAG_ALL = "contacts-all";
+    private static final String TAG_UNAVAILABLE = "contacts-unavailable";
+    private static final String TAG_DUPLICATES = "contacts-duplicates";
+    // Tag for DuplicatesUtilFragment.java
+    public static final String TAG_DUPLICATES_UTIL = "DuplicatesUtilFragment";
+
+    private static final String KEY_GROUP_URI = "groupUri";
 
     private ContactsIntentResolver mIntentResolver;
     private ContactsRequest mRequest;
@@ -105,6 +112,8 @@
 
     private BroadcastReceiver mSaveServiceListener;
 
+    private boolean mShouldSwitchToGroupView;
+
     private CoordinatorLayout mLayoutRoot;
 
     /**
@@ -112,7 +121,8 @@
      */
     private DefaultContactBrowseListFragment mAllFragment;
 
-    private View mContactsView;
+    private GroupMembersFragment mMembersFragment;
+    private Uri mGroupUri;
 
     /**
      * True if this activity instance is a re-created one.  i.e. set true after orientation change.
@@ -128,7 +138,6 @@
      */
     private boolean mFragmentInitialized;
 
-
     /** Sequential ID assigned to each instance; used for logging */
     private final int mInstanceId;
     private static final AtomicInteger sNextInstanceId = new AtomicInteger();
@@ -238,6 +247,10 @@
 
         mIsRecreatedInstance = (savedState != null);
 
+        if (mIsRecreatedInstance) {
+            mGroupUri = savedState.getParcelable(KEY_GROUP_URI);
+        }
+
         createViewsAndFragments();
 
         if (Log.isLoggable(Constants.PERFORMANCE_TAG, Log.DEBUG)) {
@@ -249,21 +262,67 @@
     @Override
     protected void onNewIntent(Intent intent) {
         if (ContactsDrawerActivity.ACTION_CREATE_GROUP.equals(intent.getAction())) {
-            super.onNewIntent(intent);
+            mGroupUri = intent.getData();
+            if (mGroupUri == null) {
+                toast(R.string.groupSavedErrorToast);
+                return;
+            }
+            if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "Received group URI " + mGroupUri);
+            toast(R.string.groupCreatedToast);
+            switchToGroupView();
             return;
         }
 
+        if (isDeleteAction(intent.getAction())) {
+            toast(R.string.groupDeletedToast);
+            getFragmentManager().popBackStackImmediate();
+            mCurrentView = ContactsView.ALL_CONTACTS;
+            showFabWithAnimation(/* showFab */ true);
+            return;
+        }
+
+        if (isSaveAction(intent.getAction())) {
+            final Uri groupUri = intent.getData();
+            if (groupUri == null) {
+                getFragmentManager().popBackStackImmediate();
+                toast(R.string.groupSavedErrorToast);
+                return;
+            }
+            if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "Received group URI " + groupUri);
+
+            mGroupUri = groupUri;
+
+            toast(getToastMessageForSaveAction(intent.getAction()));
+
+            if (mMembersFragment.isEditMode()) {
+                // If we're removing group members one at a time, don't reload the fragment so
+                // the user can continue to remove group members one by one
+                if (getGroupCount() == 1) {
+                    // If we're deleting the last group member, exit edit mode
+                    onBackPressed();
+                }
+            } else if (!GroupUtil.ACTION_REMOVE_FROM_GROUP.equals(intent.getAction())) {
+                switchToGroupView();
+                invalidateOptionsMenu();
+            }
+        }
+
         setIntent(intent);
+
         if (!processIntent(true)) {
             finish();
             return;
         }
 
-        // Re-initialize ActionBarAdapter because {@link #onNewIntent(Intent)} doesn't invoke
-        // {@link Fragment#onActivityCreated(Bundle)} where we initialize ActionBarAdapter
-        // initially.
-        mAllFragment.setContactsRequest(mRequest);
-        mAllFragment.initializeActionBarAdapter(null);
+        mContactListFilterController.checkFilterValidity(false);
+
+        if (!isInSecondLevel()) {
+            // Re-initialize ActionBarAdapter because {@link #onNewIntent(Intent)} doesn't invoke
+            // {@link Fragment#onActivityCreated(Bundle)} where we initialize ActionBarAdapter
+            // initially.
+            mAllFragment.setContactsRequest(mRequest);
+            mAllFragment.initializeActionBarAdapter(null);
+        }
 
         // Re-configure fragments.
         configureFragments(true /* from request */);
@@ -271,6 +330,35 @@
         invalidateOptionsMenuIfNeeded();
     }
 
+    private int getGroupCount() {
+        return mMembersFragment != null && mMembersFragment.getAdapter() != null
+                ? mMembersFragment.getAdapter().getCount() : -1;
+    }
+
+    private static boolean isDeleteAction(String action) {
+        return GroupUtil.ACTION_DELETE_GROUP.equals(action);
+    }
+
+    private static boolean isSaveAction(String action) {
+        return GroupUtil.ACTION_UPDATE_GROUP.equals(action)
+                || GroupUtil.ACTION_ADD_TO_GROUP.equals(action)
+                || GroupUtil.ACTION_REMOVE_FROM_GROUP.equals(action);
+    }
+
+    private static int getToastMessageForSaveAction(String action) {
+        if (GroupUtil.ACTION_UPDATE_GROUP.equals(action)) return R.string.groupUpdatedToast;
+        if (GroupUtil.ACTION_ADD_TO_GROUP.equals(action)) return R.string.groupMembersAddedToast;
+        if (GroupUtil.ACTION_REMOVE_FROM_GROUP.equals(action))
+            return R.string.groupMembersRemovedToast;
+        throw new IllegalArgumentException("Unhanded contact save action " + action);
+    }
+
+    private void toast(int resId) {
+        if (resId >= 0) {
+            Toast.makeText(this, resId, Toast.LENGTH_SHORT).show();
+        }
+    }
+
     /**
      * Resolve the intent and initialize {@link #mRequest}, and launch another activity if redirect
      * is needed.
@@ -305,6 +393,11 @@
                 onCreateGroupMenuItemClicked();
                 return true;
             }
+            case ContactsRequest.ACTION_VIEW_GROUP:
+            case ContactsRequest.ACTION_EDIT_GROUP: {
+                mShouldSwitchToGroupView = true;
+                return true;
+            }
         }
         return true;
     }
@@ -314,26 +407,13 @@
 
         final FragmentManager fragmentManager = getFragmentManager();
 
-        final FragmentTransaction transaction = fragmentManager.beginTransaction();
+        setUpAllFragment(fragmentManager);
 
-        mAllFragment = (DefaultContactBrowseListFragment)
-                fragmentManager.findFragmentByTag(TAG_ALL);
-
-        mContactsView = getView(R.id.contacts_view);
-
-        if (mAllFragment == null) {
-            mAllFragment = new DefaultContactBrowseListFragment();
-            mAllFragment.setAnimateOnLoad(true);
-            transaction.add(R.id.contacts_list_container, mAllFragment, TAG_ALL);
+        if (isGroupView() && mGroupUri != null) {
+            mMembersFragment = (GroupMembersFragment)
+                    fragmentManager.findFragmentByTag(mGroupUri.toString());
         }
 
-        mAllFragment.setContactsAvailable(areContactsAvailable());
-        mAllFragment.setListType();
-        mAllFragment.setContactsRequest(mRequest);
-
-        transaction.commitAllowingStateLoss();
-        fragmentManager.executePendingTransactions();
-
         // Configure floating action button
         mFloatingActionButtonContainer = findViewById(R.id.floating_action_button_container);
         final ImageButton floatingActionButton
@@ -341,7 +421,8 @@
         floatingActionButton.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
-                onFabClicked();
+                AccountFilterUtil.startEditorIntent(PeopleActivity.this, getIntent(),
+                        mContactListFilterController.getFilter());
             }
         });
         mFloatingActionButtonController = new FloatingActionButtonController(this,
@@ -359,11 +440,35 @@
         fabParams.setBehavior(new FloatingActionButtonBehavior());
         fabParams.gravity = Gravity.BOTTOM | Gravity.END;
         mFloatingActionButtonContainer.setLayoutParams(fabParams);
+
+        if (mShouldSwitchToGroupView && !mIsRecreatedInstance) {
+            mGroupUri = mRequest.getContactUri();
+            switchToGroupView();
+            mShouldSwitchToGroupView = false;
+        }
+    }
+
+    private void setUpAllFragment(FragmentManager fragmentManager) {
+        mAllFragment = (DefaultContactBrowseListFragment)
+                fragmentManager.findFragmentByTag(TAG_ALL);
+
+        if (mAllFragment == null) {
+            mAllFragment = new DefaultContactBrowseListFragment();
+            mAllFragment.setAnimateOnLoad(true);
+            fragmentManager.beginTransaction()
+                    .add(R.id.contacts_list_container, mAllFragment, TAG_ALL)
+                    .commit();
+            fragmentManager.executePendingTransactions();
+        }
+
+        mAllFragment.setContactsAvailable(areContactsAvailable());
+        mAllFragment.setListType();
+        mAllFragment.setContactsRequest(mRequest);
     }
 
     @Override
     protected void onStart() {
-        if (!mFragmentInitialized) {
+        if (!mFragmentInitialized && (!isInSecondLevel())) {
             mFragmentInitialized = true;
             /* Configure fragments if we haven't.
              *
@@ -414,7 +519,9 @@
                     mSyncStatusObserver);
             onSyncStateUpdated();
         }
-        mAllFragment.maybeShowHamburgerFeatureHighlight();
+        if (!isInSecondLevel()) {
+            mAllFragment.maybeShowHamburgerFeatureHighlight();
+        }
         initializeFabVisibility();
 
         mSaveServiceListener = new SaveServiceListener();
@@ -459,11 +566,15 @@
                 searchMode = false;
             }
 
-            mAllFragment.getActionBarAdapter().setSearchMode(searchMode);
-            configureContactListFragmentForRequest();
+            if (!isInSecondLevel()) {
+                mAllFragment.getActionBarAdapter().setSearchMode(searchMode);
+                configureContactListFragmentForRequest();
+            }
         }
 
-        mAllFragment.configureContactListFragment();
+        if (!isInSecondLevel()) {
+            mAllFragment.configureContactListFragment();
+        }
     }
 
     private void initializeFabVisibility() {
@@ -473,7 +584,10 @@
     }
 
     private boolean shouldHideFab() {
-        if (mAllFragment.getActionBarAdapter() == null) return false;
+        if (mAllFragment != null && mAllFragment.getActionBarAdapter() == null
+                || isInSecondLevel()) {
+            return true;
+        }
         return mAllFragment.getActionBarAdapter().isSearchMode()
                 || mAllFragment.getActionBarAdapter().isSelectionMode();
     }
@@ -519,12 +633,6 @@
     }
 
     @Override
-    public void onFiltersLoaded(List<ContactListFilter> accountFilterItems) {
-        super.onFiltersLoaded(accountFilterItems);
-        initializeFabVisibility();
-    }
-
-    @Override
     public void onProviderStatusChange() {
         reloadGroupsAndFiltersIfNeeded();
         updateViewConfiguration(false);
@@ -550,28 +658,22 @@
                 && (mProviderStatus.equals(providerStatus))) return;
         mProviderStatus = providerStatus;
 
-        View contactsUnavailableView = findViewById(R.id.contacts_unavailable_view);
+        final FragmentManager fragmentManager= getFragmentManager();
+        final FragmentTransaction transaction = fragmentManager.beginTransaction();
 
         // Change in CP2's provider status may not take effect immediately, see b/30566908.
         // So we need to handle the case where provider status is STATUS_EMPTY and there is
         // actually at least one real account (not "local" account) on device.
-        if ((mProviderStatus.equals(ProviderStatus.STATUS_EMPTY) && hasNonLocalAccount())
-                || mProviderStatus.equals(ProviderStatus.STATUS_NORMAL)) {
-            // Ensure that the mContactsView is visible; we may have made it invisible below.
-            contactsUnavailableView.setVisibility(View.GONE);
-            if (mContactsView != null) {
-                mContactsView.setVisibility(View.VISIBLE);
-            }
-
+        if (shouldShowList()) {
             if (mAllFragment != null) {
-                getFragmentManager().beginTransaction()
-                        .show(mAllFragment)
-                        .commitAllowingStateLoss();
+                transaction.show(mAllFragment);
                 mAllFragment.setContactsAvailable(areContactsAvailable());
                 mAllFragment.setEnabled(true);
             }
+            if (mContactsUnavailableFragment != null) {
+                transaction.hide(mContactsUnavailableFragment);
+            }
         } else {
-            final FragmentTransaction transaction = getFragmentManager().beginTransaction();
             // Setting up the page so that the user can still use the app
             // even without an account.
             if (mAllFragment != null) {
@@ -582,23 +684,26 @@
                 mContactsUnavailableFragment = new ContactsUnavailableFragment();
                 mContactsUnavailableFragment.setOnContactsUnavailableActionListener(
                         new ContactsUnavailableFragmentListener());
-                transaction.replace(
-                        R.id.contacts_unavailable_container, mContactsUnavailableFragment);
+                transaction.add(R.id.contacts_list_container, mContactsUnavailableFragment,
+                        TAG_UNAVAILABLE);
             }
-            transaction.commitAllowingStateLoss();
+            transaction.show(mContactsUnavailableFragment);
             mContactsUnavailableFragment.updateStatus(mProviderStatus);
-
-            // Show the contactsUnavailableView, and hide the mContactsView so that we don't
-            // see it sliding in underneath the contactsUnavailableView at the edges.
-            contactsUnavailableView.setVisibility(View.VISIBLE);
-            if (mContactsView != null) {
-                mContactsView.setVisibility(View.GONE);
-            }
+        }
+        if (!transaction.isEmpty()) {
+            transaction.commit();
+            fragmentManager.executePendingTransactions();
         }
 
         invalidateOptionsMenuIfNeeded();
     }
 
+    private boolean shouldShowList() {
+        return mProviderStatus != null
+                && ((mProviderStatus.equals(ProviderStatus.STATUS_EMPTY) && hasNonLocalAccount())
+                        || mProviderStatus.equals(ProviderStatus.STATUS_NORMAL));
+    }
+
     // Returns true if there are real accounts (not "local" account) in the list of accounts.
     private boolean hasNonLocalAccount() {
         final List<AccountWithDataSet> allAccounts =
@@ -679,6 +784,21 @@
 
         if (mDrawer.isDrawerOpen(GravityCompat.START)) {
             mDrawer.closeDrawer(GravityCompat.START);
+        } else if (isGroupView()) {
+            if (mMembersFragment.isEditMode()) {
+                mMembersFragment.setEditMode(false);
+                mMembersFragment.getActionBarAdapter().setSelectionMode(false);
+                mMembersFragment.displayDeleteButtons(false);
+            } else if (mMembersFragment.getActionBarAdapter().isSelectionMode()) {
+                mMembersFragment.getActionBarAdapter().setSelectionMode(false);
+                mMembersFragment.displayCheckBoxes(false);
+            } else if (mMembersFragment.getActionBarAdapter().isSearchMode()) {
+                mMembersFragment.getActionBarAdapter().setSearchMode(false);
+            } else {
+                switchToAllContacts();
+            }
+        } else if (isDuplicatesView()) {
+            switchToAllContacts();
         } else if (mAllFragment.getActionBarAdapter().isSelectionMode()) {
             mAllFragment.getActionBarAdapter().setSelectionMode(false);
             mAllFragment.displayCheckBoxes(false);
@@ -690,52 +810,26 @@
                 Logger.logScreenView(this, ScreenType.SEARCH_EXIT);
                 Logger.logSearchEvent(mAllFragment.createSearchState());
             }
-        } else if (!isAllContactsFilter(mAllFragment.getFilter())) {
+        } else if (!AccountFilterUtil.isAllContactsFilter(mAllFragment.getFilter())
+                && !mAllFragment.isHidden()) {
+            // If mAllFragment is hidden, then mContactsUnavailableFragment is visible so we
+            // don't need to switch to all contacts.
             switchToAllContacts();
         } else {
             super.onBackPressed();
         }
     }
 
-    public void onFabClicked() {
-        final Intent intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI);
-        Bundle extras = getIntent().getExtras();
-        if (extras == null) {
-            extras = new Bundle();
-        }
-        final ContactListFilter filter = mAllFragment.getFilter();
-        // If we are in account view, we pass the account explicitly in order to
-        // create contact in the account. This will prevent the default account dialog
-        // from being displayed.
-        if (!isAllContactsFilter(filter) && !isDeviceContactsFilter(filter)) {
-            final Account account = new Account(filter.accountName, filter.accountType);
-            extras.putParcelable(Intents.Insert.EXTRA_ACCOUNT, account);
-            extras.putString(Intents.Insert.EXTRA_DATA_SET, filter.dataSet);
-        }
-        intent.putExtras(extras);
-        try {
-            ImplicitIntentsUtil.startActivityInApp(PeopleActivity.this, intent);
-        } catch (ActivityNotFoundException ex) {
-            Toast.makeText(PeopleActivity.this, R.string.missing_app, Toast.LENGTH_SHORT).show();
-        }
-    }
-
-    private boolean isAllContactsFilter(ContactListFilter filter) {
-        return filter != null && filter.isContactsFilterType();
-    }
-
-    private boolean isDeviceContactsFilter(ContactListFilter filter) {
-        return filter.filterType == ContactListFilter.FILTER_TYPE_DEVICE_CONTACTS;
+    @Override
+    protected void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putParcelable(KEY_GROUP_URI, mGroupUri);
     }
 
     @Override
-    protected boolean shouldFinish() {
-        return false;
-    }
-
-    @Override
-    protected ContactListFilter getContactListFilter() {
-        return mAllFragment.getFilter();
+    protected void onRestoreInstanceState(Bundle savedInstanceState) {
+        super.onRestoreInstanceState(savedInstanceState);
+        mGroupUri = savedInstanceState.getParcelable(KEY_GROUP_URI);
     }
 
     private void onGroupDeleted(Intent intent) {
@@ -763,4 +857,97 @@
             }
         }
     }
+
+    @Override
+    protected void onGroupMenuItemClicked(long groupId, String title) {
+        if (isGroupView() && mMembersFragment != null
+                && mMembersFragment.isCurrentGroup(groupId)) {
+            return;
+        }
+        mGroupUri = ContentUris.withAppendedId(ContactsContract.Groups.CONTENT_URI, groupId);
+        switchToGroupView();
+    }
+
+    @Override
+    protected void onFilterMenuItemClicked(Intent intent) {
+        super.onFilterMenuItemClicked(intent);
+        if (isInSecondLevel()) {
+            getFragmentManager().popBackStackImmediate();
+            showFabWithAnimation(/* showFab */ true);
+        }
+        mCurrentView = ContactsView.ACCOUNT_VIEW;
+    }
+
+    private void switchToGroupView() {
+        switchView(ContactsView.GROUP_VIEW);
+    }
+
+    @Override
+    protected void launchFindDuplicates() {
+        switchView(ContactsView.DUPLICATES);
+    }
+
+    private void switchView(ContactsView contactsView) {
+        maybePopBackStack();
+        mCurrentView = contactsView;
+        setUpNewFragment();
+    }
+
+    private void maybePopBackStack() {
+        final FragmentManager fragmentManager =  getFragmentManager();
+        if (isInSecondLevel()) {
+            fragmentManager.popBackStackImmediate();
+        }
+    }
+
+    private void setUpNewFragment() {
+        final FragmentManager fragmentManager =  getFragmentManager();
+        final FragmentTransaction transaction = fragmentManager.beginTransaction();
+        if (isGroupView()) {
+            mMembersFragment = GroupMembersFragment.newInstance(mGroupUri);
+            transaction.add(R.id.contacts_list_container, mMembersFragment, mGroupUri.toString());
+        } else if (isDuplicatesView()) {
+            final Fragment duplicatesFragment = ObjectFactory.getDuplicatesFragment();
+            final Fragment duplicatesUtilFragment = ObjectFactory.getDuplicatesUtilFragment();
+            duplicatesUtilFragment.setTargetFragment(duplicatesFragment, /* requestCode */ 0);
+            transaction.add(R.id.contacts_list_container, duplicatesFragment, TAG_DUPLICATES);
+            transaction.add(duplicatesUtilFragment, TAG_DUPLICATES_UTIL);
+        }
+        transaction.hide(mAllFragment);
+        transaction.addToBackStack(null);
+        transaction.commit();
+        fragmentManager.executePendingTransactions();
+
+        showFabWithAnimation(/* showFab */ false);
+    }
+
+    @Override
+    public void switchToAllContacts() {
+        final FragmentManager fragmentManager = getFragmentManager();
+        if (isInSecondLevel()) {
+            fragmentManager.popBackStackImmediate();
+            if (isGroupView()) {
+                mMembersFragment = null;
+            }
+        }
+        mCurrentView = ContactsView.ALL_CONTACTS;
+        showFabWithAnimation(/* showFab */ true);
+
+        super.switchToAllContacts();
+    }
+
+    @Override
+    protected DefaultContactBrowseListFragment getAllFragment() {
+        return mAllFragment;
+    }
+
+    @Override
+    protected GroupMembersFragment getGroupFragment() {
+        return mMembersFragment;
+    }
+
+    @Override
+    protected GroupMetadata getGroupMetadata() {
+        return mMembersFragment == null ? null : mMembersFragment.getGroupMetadata();
+    }
 }
diff --git a/src/com/android/contacts/common/util/AccountFilterUtil.java b/src/com/android/contacts/common/util/AccountFilterUtil.java
index 3c0520c..c69cf2a 100644
--- a/src/com/android/contacts/common/util/AccountFilterUtil.java
+++ b/src/com/android/contacts/common/util/AccountFilterUtil.java
@@ -16,17 +16,22 @@
 
 package com.android.contacts.common.util;
 
+import android.accounts.Account;
 import android.app.Activity;
 import android.app.Fragment;
+import android.content.ActivityNotFoundException;
 import android.content.AsyncTaskLoader;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.graphics.drawable.Drawable;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Intents;
 import android.text.TextUtils;
 import android.util.Log;
+import android.widget.Toast;
 
-import com.android.contacts.common.R;
+import com.android.contacts.R;
 import com.android.contacts.common.list.AccountFilterActivity;
 import com.android.contacts.common.list.ContactListFilter;
 import com.android.contacts.common.list.ContactListFilterController;
@@ -174,4 +179,36 @@
                         : ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS;
         return ContactListFilter.createFilterWithType(filterType);
     }
+
+    /**
+     * Start editor intent; and if filter is an account filter, we pass account info to editor so
+     * as to create a contact in that account.
+     */
+    public static void startEditorIntent(Context context, Intent src, ContactListFilter filter) {
+        final Intent intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI);
+        intent.putExtras(src);
+
+        // If we are in account view, we pass the account explicitly in order to
+        // create contact in the account. This will prevent the default account dialog
+        // from being displayed.
+        if (!isAllContactsFilter(filter) && !isDeviceContactsFilter(filter)) {
+            final Account account = new Account(filter.accountName, filter.accountType);
+            intent.putExtra(Intents.Insert.EXTRA_ACCOUNT, account);
+            intent.putExtra(Intents.Insert.EXTRA_DATA_SET, filter.dataSet);
+        }
+
+        try {
+            ImplicitIntentsUtil.startActivityInApp(context, intent);
+        } catch (ActivityNotFoundException ex) {
+            Toast.makeText(context, R.string.missing_app, Toast.LENGTH_SHORT).show();
+        }
+    }
+
+    public static boolean isAllContactsFilter(ContactListFilter filter) {
+        return filter != null && filter.isContactsFilterType();
+    }
+
+    public static boolean isDeviceContactsFilter(ContactListFilter filter) {
+        return filter.filterType == ContactListFilter.FILTER_TYPE_DEVICE_CONTACTS;
+    }
 }
diff --git a/src/com/android/contacts/group/GroupMembersFragment.java b/src/com/android/contacts/group/GroupMembersFragment.java
index a68b6cf..062edda 100644
--- a/src/com/android/contacts/group/GroupMembersFragment.java
+++ b/src/com/android/contacts/group/GroupMembersFragment.java
@@ -41,10 +41,10 @@
 import android.widget.Toast;
 
 import com.android.contacts.ContactSaveService;
+import com.android.contacts.ContactsDrawerActivity;
 import com.android.contacts.GroupMetaDataLoader;
 import com.android.contacts.R;
 import com.android.contacts.activities.ActionBarAdapter;
-import com.android.contacts.activities.GroupMembersActivity;
 import com.android.contacts.common.list.ContactsSectionIndexer;
 import com.android.contacts.common.list.MultiSelectEntryContactListAdapter.DeleteContactListener;
 import com.android.contacts.common.logging.ListEvent;
@@ -187,18 +187,17 @@
 
         @Override
         public CursorLoader onCreateLoader(int id, Bundle args) {
-            return new GroupMetaDataLoader(getActivity(), mGroupUri);
+            return new GroupMetaDataLoader(mActivity, mGroupUri);
         }
 
         @Override
         public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
             if (cursor == null || cursor.isClosed() || !cursor.moveToNext()) {
                 Log.e(TAG, "Failed to load group metadata for " + mGroupUri);
-                final Activity activity = getActivity();
                 Toast.makeText(getContext(), R.string.groupLoadErrorToast, Toast.LENGTH_SHORT)
                         .show();
-                activity.setResult(AppCompatActivity.RESULT_CANCELED);
-                activity.finish();
+                mActivity.setResult(AppCompatActivity.RESULT_CANCELED);
+                mActivity.finish();
                 return;
             }
             mGroupMetadata = new GroupMetadata();
@@ -211,7 +210,7 @@
             mGroupMetadata.readOnly = cursor.getInt(GroupMetaDataLoader.IS_READ_ONLY) == 1;
 
             final AccountTypeManager accountTypeManager =
-                    AccountTypeManager.getInstance(getActivity());
+                    AccountTypeManager.getInstance(mActivity);
             final AccountType accountType = accountTypeManager.getAccountType(
                     mGroupMetadata.accountType, mGroupMetadata.dataSet);
             mGroupMetadata.editable = accountType.isGroupMembershipEditable();
@@ -225,6 +224,8 @@
 
     private ActionBarAdapter mActionBarAdapter;
 
+    private ContactsDrawerActivity mActivity;
+
     private Uri mGroupUri;
 
     private boolean mIsEditMode;
@@ -246,7 +247,6 @@
         setPhotoLoaderEnabled(true);
         setSectionHeaderDisplayEnabled(true);
         setHasOptionsMenu(true);
-
         setListType(ListType.GROUP);
     }
 
@@ -256,7 +256,6 @@
             // Hide menu options until metadata is fully loaded
             return;
         }
-        super.onCreateOptionsMenu(menu, inflater);
         inflater.inflate(R.menu.view_group, menu);
     }
 
@@ -295,7 +294,7 @@
     public boolean onOptionsItemSelected(MenuItem item) {
         switch (item.getItemId()) {
             case android.R.id.home: {
-                getActivity().onBackPressed();
+                mActivity.onBackPressed();
                 return true;
             }
             case R.id.menu_add: {
@@ -371,7 +370,7 @@
                     } else {
                         displayCheckBoxes(true);
                     }
-                    getActivity().invalidateOptionsMenu();
+                    mActivity.invalidateOptionsMenu();
                     break;
                 case ActionBarAdapter.Listener.Action.STOP_SEARCH_AND_SELECTION_MODE:
                     mActionBarAdapter.setSearchMode(false);
@@ -380,7 +379,7 @@
                     } else {
                         displayCheckBoxes(false);
                     }
-                    getActivity().invalidateOptionsMenu();
+                    mActivity.invalidateOptionsMenu();
                     break;
                 case ActionBarAdapter.Listener.Action.BEGIN_STOPPING_SEARCH_AND_SELECTION_MODE:
                     break;
@@ -389,7 +388,7 @@
 
         @Override
         public void onUpButtonPressed() {
-            getActivity().onBackPressed();
+            mActivity.onBackPressed();
         }
     };
 
@@ -432,7 +431,7 @@
             final Intent intent = ContactSaveService.createGroupDeletionIntent(
                     getContext(), mGroupMetadata.groupId);
             getContext().startService(intent);
-            getActivity().finish();
+            mActivity.switchToAllContacts();
         } else {
             GroupDeletionDialogFragment.show(getFragmentManager(), mGroupMetadata.groupId,
                     mGroupMetadata.groupName);
@@ -442,17 +441,22 @@
     @Override
     public void onActivityCreated(Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
-        // This is the first safe place in the fragment lifecycle to know getActivity() will not
-        // be null (i.e. it can be null in onCreateView() of this fragment)
-        final GroupMembersActivity activity = (GroupMembersActivity) getActivity();
-        mActionBarAdapter = new ActionBarAdapter(activity, mActionBarListener,
-                activity.getSupportActionBar(), activity.getToolbar(), R.string.enter_contact_name);
+        mActivity = (ContactsDrawerActivity) getActivity();
+        mActionBarAdapter = new ActionBarAdapter(mActivity, mActionBarListener,
+                mActivity.getSupportActionBar(), mActivity.getToolbar(), R.string.enter_contact_name);
         mActionBarAdapter.setShowHomeIcon(true);
         final ContactsRequest contactsRequest = new ContactsRequest();
         contactsRequest.setActionCode(ContactsRequest.ACTION_GROUP);
         mActionBarAdapter.initialize(savedInstanceState, contactsRequest);
+        if (mGroupMetadata != null) {
+            mActivity.setTitle(mGroupMetadata.groupName);
+            if (mGroupMetadata.editable) {
+                setCheckBoxListListener(mCheckBoxListener);
+            }
+        }
     }
 
+    @Override
     public ActionBarAdapter getActionBarAdapter() {
         return mActionBarAdapter;
     }
@@ -462,7 +466,7 @@
     }
 
     public ArrayList<String> getMemberContactIds() {
-        return  new ArrayList<>(mGroupMemberContactIds);
+        return new ArrayList<>(mGroupMemberContactIds);
     }
 
     public int getMemberCount() {
@@ -517,7 +521,7 @@
             bindMembersCount(cursorWrapper.getCount());
             super.onLoadFinished(loader, cursorWrapper);
             // Update state of menu items (e.g. "Remove contacts") based on number of group members.
-            getActivity().invalidateOptionsMenu();
+            mActivity.invalidateOptionsMenu();
         }
     }
 
@@ -554,10 +558,9 @@
 
         maybeAttachCheckBoxListener();
 
-        final GroupMembersActivity activity = (GroupMembersActivity) getActivity();
-        activity.updateGroupMenu(mGroupMetadata);
-        activity.setTitle(mGroupMetadata.groupName);
-        activity.invalidateOptionsMenu();
+        mActivity.setTitle(mGroupMetadata.groupName);
+        mActivity.updateGroupMenu(mGroupMetadata);
+        mActivity.invalidateOptionsMenu();
 
         // Start loading the group members
         super.startLoading();
@@ -638,11 +641,8 @@
 
     @Override
     protected boolean onItemLongClick(int position, long id) {
-        final Activity activity = getActivity();
-        if (activity != null && activity instanceof GroupMembersActivity) {
-            if (mIsEditMode) {
-                return true;
-            }
+        if (mActivity != null && mIsEditMode) {
+            return true;
         }
         return super.onItemLongClick(position, id);
     }
@@ -663,6 +663,10 @@
         return mGroupMetadata;
     }
 
+    public boolean isCurrentGroup(long groupId) {
+        return mGroupMetadata != null && mGroupMetadata.groupId == groupId;
+    }
+
     @Override
     public void onDestroy() {
         if (mActionBarAdapter != null) {
diff --git a/src/com/android/contacts/group/GroupUtil.java b/src/com/android/contacts/group/GroupUtil.java
index 63a4fa8..372eed5 100644
--- a/src/com/android/contacts/group/GroupUtil.java
+++ b/src/com/android/contacts/group/GroupUtil.java
@@ -16,7 +16,6 @@
 
 package com.android.contacts.group;
 
-import android.content.ContentUris;
 import android.content.Context;
 import android.content.Intent;
 import android.database.Cursor;
@@ -29,7 +28,6 @@
 
 import com.android.contacts.GroupListLoader;
 import com.android.contacts.activities.ContactSelectionActivity;
-import com.android.contacts.activities.GroupMembersActivity;
 import com.android.contacts.common.ContactPhotoManager;
 import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
 import com.android.contacts.common.list.ContactsSectionIndexer;
@@ -116,21 +114,6 @@
         }
     }
 
-    /** Returns an Intent to view the details of the group identified by the given URI. */
-    public static Intent createViewGroupIntent(Context context, Uri groupUri, String title) {
-        final Intent intent = new Intent(context, GroupMembersActivity.class);
-        intent.setAction(Intent.ACTION_VIEW);
-        intent.setData(groupUri);
-        intent.putExtra(EXTRA_GROUP_NAME, title);
-        return intent;
-    }
-
-    /** Returns an Intent to view the details of the group identified by the given ID. */
-    public static Intent createViewGroupIntent(Context context, long groupId, String title) {
-        return createViewGroupIntent(context,
-                ContentUris.withAppendedId(Groups.CONTENT_URI, groupId), title);
-    }
-
     /** Returns an Intent to pick contacts to add to a group. */
     public static Intent createPickMemberIntent(Context context,
             GroupMetadata groupMetadata, ArrayList<String> memberContactIds) {
@@ -160,6 +143,13 @@
     }
 
     /**
+     * Returns true the URI is a group URI.
+     */
+    public static boolean isGroupUri(Uri uri) {
+        return  uri != null && uri.toString().startsWith(Groups.CONTENT_URI.toString());
+    }
+
+    /**
      * Sort groups alphabetically and in a localized way.
      */
     public static String getGroupsSortOrder() {
diff --git a/src/com/android/contacts/group/UpdateGroupMembersAsyncTask.java b/src/com/android/contacts/group/UpdateGroupMembersAsyncTask.java
index a040ddc..46aa674 100644
--- a/src/com/android/contacts/group/UpdateGroupMembersAsyncTask.java
+++ b/src/com/android/contacts/group/UpdateGroupMembersAsyncTask.java
@@ -26,7 +26,7 @@
 
 import com.android.contacts.ContactSaveService;
 import com.android.contacts.R;
-import com.android.contacts.activities.GroupMembersActivity;
+import com.android.contacts.activities.PeopleActivity;
 
 /**
  * Starts an Intent to add/remove the raw contacts for the given contact IDs to/from a group.
@@ -75,7 +75,7 @@
         }
         return ContactSaveService.createGroupUpdateIntent(
                 mContext, mGroupId, /* newLabel */ null, rawContactIdsToAdd,
-                rawContactIdsToRemove, GroupMembersActivity.class, action);
+                rawContactIdsToRemove, PeopleActivity.class, action);
     }
 
     // TODO(wjang): prune raw contacts that are already in the group; ContactSaveService will
diff --git a/src/com/android/contacts/interactions/GroupDeletionDialogFragment.java b/src/com/android/contacts/interactions/GroupDeletionDialogFragment.java
index e247536..5c5609d 100644
--- a/src/com/android/contacts/interactions/GroupDeletionDialogFragment.java
+++ b/src/com/android/contacts/interactions/GroupDeletionDialogFragment.java
@@ -23,6 +23,7 @@
 import android.os.Bundle;
 
 import com.android.contacts.ContactSaveService;
+import com.android.contacts.ContactsDrawerActivity;
 import com.android.contacts.R;
 
 /**
@@ -64,8 +65,9 @@
 
     protected void deleteGroup() {
         final long groupId = getArguments().getLong(ARG_GROUP_ID);
-        getActivity().startService(ContactSaveService.createGroupDeletionIntent(
+        final ContactsDrawerActivity activity = ((ContactsDrawerActivity) getActivity());
+        activity.startService(ContactSaveService.createGroupDeletionIntent(
                 getActivity(), groupId));
-        getActivity().finish();
+        activity.switchToAllContacts();
     }
 }
diff --git a/src/com/android/contacts/list/ContactsIntentResolver.java b/src/com/android/contacts/list/ContactsIntentResolver.java
index 354ea3a..8e93baf 100644
--- a/src/com/android/contacts/list/ContactsIntentResolver.java
+++ b/src/com/android/contacts/list/ContactsIntentResolver.java
@@ -35,6 +35,7 @@
 import android.util.Log;
 
 import com.android.contacts.common.model.account.AccountWithDataSet;
+import com.android.contacts.group.GroupUtil;
 
 /**
  * Parses a Contacts intent, extracting all relevant parts and packaging them
@@ -150,11 +151,19 @@
             if (ContactsContract.Contacts.CONTENT_TYPE.equals(resolvedType)
                     || android.provider.Contacts.People.CONTENT_TYPE.equals(resolvedType)) {
                 request.setActionCode(ContactsRequest.ACTION_ALL_CONTACTS);
-            } else {
+            } else if (!GroupUtil.isGroupUri(intent.getData())){
                 request.setActionCode(ContactsRequest.ACTION_VIEW_CONTACT);
                 request.setContactUri(intent.getData());
                 intent.setAction(Intent.ACTION_DEFAULT);
                 intent.setData(null);
+            } else {
+                request.setActionCode(ContactsRequest.ACTION_VIEW_GROUP);
+                request.setContactUri(intent.getData());
+            }
+        } else if (Intent.ACTION_EDIT.equals(action)) {
+            if (GroupUtil.isGroupUri(intent.getData())){
+                request.setActionCode(ContactsRequest.ACTION_EDIT_GROUP);
+                request.setContactUri(intent.getData());
             }
         // Since this is the filter activity it receives all intents
         // dispatched from the SearchManager for security reasons
diff --git a/src/com/android/contacts/list/ContactsRequest.java b/src/com/android/contacts/list/ContactsRequest.java
index e9b3a86..de6a4ba 100644
--- a/src/com/android/contacts/list/ContactsRequest.java
+++ b/src/com/android/contacts/list/ContactsRequest.java
@@ -45,6 +45,12 @@
     /** Create a new group */
     public static final int ACTION_INSERT_GROUP = 22;
 
+    /** View a group */
+    public static final int ACTION_VIEW_GROUP = 23;
+
+    /** Edit a group */
+    public static final int ACTION_EDIT_GROUP = 24;
+
     /** Show all starred contacts */
     public static final int ACTION_STARRED = 30;
 
diff --git a/src/com/android/contacts/list/DefaultContactBrowseListFragment.java b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
index 2fcf5da..4169ae6 100644
--- a/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
+++ b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
@@ -32,7 +32,6 @@
 import android.os.Bundle;
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.Directory;
-import android.support.v4.app.FragmentActivity;
 import android.support.v4.widget.SwipeRefreshLayout;
 import android.text.TextUtils;
 import android.util.Log;
@@ -55,7 +54,6 @@
 import com.android.contacts.ContactsDrawerActivity;
 import com.android.contacts.R;
 import com.android.contacts.activities.ActionBarAdapter;
-import com.android.contacts.activities.PeopleActivity;
 import com.android.contacts.common.Experiments;
 import com.android.contacts.common.compat.CompatUtils;
 import com.android.contacts.common.list.ContactEntryListFragment;
@@ -125,6 +123,7 @@
 
     private ActionBarAdapter mActionBarAdapter;
     private ContactMultiDeletionInteraction mMultiDeletionInteraction;
+    private ContactsDrawerActivity mActivity;
     private ContactsRequest mContactsRequest;
     protected ContactListFilterController mContactListFilterController;
 
@@ -137,7 +136,7 @@
             // Scroll to top after filter is changed.
             getListView().setSelection(0);
 
-            getActivity().invalidateOptionsMenu();
+            mActivity.invalidateOptionsMenu();
         }
     };
 
@@ -151,12 +150,12 @@
                     break;
                 case ActionBarAdapter.Listener.Action.START_SEARCH_MODE:
                     if (!mIsRecreatedInstance) {
-                        Logger.logScreenView(getActivity(), ScreenEvent.ScreenType.SEARCH);
+                        Logger.logScreenView(mActivity, ScreenEvent.ScreenType.SEARCH);
                     }
                     startSearchOrSelectionMode();
                     break;
                 case ActionBarAdapter.Listener.Action.BEGIN_STOPPING_SEARCH_AND_SELECTION_MODE:
-                    ((PeopleActivity) getActivity()).showFabWithAnimation(/* showFab */ true);
+                    mActivity.showFabWithAnimation(/* showFab */ true);
                     break;
                 case ActionBarAdapter.Listener.Action.STOP_SEARCH_AND_SELECTION_MODE:
                     // If queryString is empty, fragment data will not be reloaded,
@@ -167,8 +166,8 @@
                     }
                     setQueryTextToFragment("");
                     maybeHideCheckBoxes();
-                    getActivity().invalidateOptionsMenu();
-                    ((PeopleActivity) getActivity()).showFabWithAnimation(/* showFab */ true);
+                    mActivity.invalidateOptionsMenu();
+                    mActivity.showFabWithAnimation(/* showFab */ true);
                     // Determine whether the account has pullToRefresh feature
                     if (Flags.getInstance(getContext()).getBoolean(Experiments.PULL_TO_REFRESH)) {
                         setSwipeRefreshLayoutEnabledOrNot(getFilter());
@@ -188,8 +187,9 @@
         private void startSearchOrSelectionMode() {
             configureContactListFragment();
             maybeHideCheckBoxes();
-            getActivity().invalidateOptionsMenu();
-            ((PeopleActivity) getActivity()).showFabWithAnimation(/* showFab */ false);
+            mActivity.invalidateOptionsMenu();
+            mActivity.showFabWithAnimation(/* showFab */ false);
+
             final Context context = getContext();
             if (!SharedPreferenceUtil.getHamburgerPromoTriggerActionHappenedBefore(context)) {
                 SharedPreferenceUtil.setHamburgerPromoTriggerActionHappenedBefore(context);
@@ -199,7 +199,7 @@
         private void updateDebugOptionsVisibility(boolean visible) {
             if (mEnableDebugMenuOptions != visible) {
                 mEnableDebugMenuOptions = visible;
-                getActivity().invalidateOptionsMenu();
+                mActivity.invalidateOptionsMenu();
             }
         }
 
@@ -210,7 +210,14 @@
 
         @Override
         public void onUpButtonPressed() {
-            getActivity().onBackPressed();
+            mActivity.onBackPressed();
+        }
+    };
+
+    private final View.OnClickListener mAddContactListener = new View.OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            AccountFilterUtil.startEditorIntent(getContext(), mActivity.getIntent(), getFilter());
         }
     };
 
@@ -245,8 +252,7 @@
         if (mActionBarAdapter!= null && !mActionBarAdapter.isSearchMode()
                 && !mActionBarAdapter.isSelectionMode()
                 && SharedPreferenceUtil.getShouldShowHamburgerPromo(getContext())) {
-            if (FeatureHighlightHelper.showHamburgerFeatureHighlight(
-                    (FragmentActivity) getActivity())) {
+            if (FeatureHighlightHelper.showHamburgerFeatureHighlight(mActivity)) {
                 SharedPreferenceUtil.setHamburgerPromoDisplayedBefore(getContext());
             }
         }
@@ -373,12 +379,7 @@
         // Set up add contact button.
         final Button addContactButton =
                 (Button) emptyHomeView.findViewById(R.id.add_contact_button);
-        addContactButton.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                ((PeopleActivity) getActivity()).onFabClicked();
-            }
-        });
+        addContactButton.setOnClickListener(mAddContactListener);
         return emptyHomeView;
     }
 
@@ -399,12 +400,7 @@
         // Set up add contact button.
         final Button addContactButton =
                 (Button) emptyAccountView.findViewById(R.id.add_contact_button);
-        addContactButton.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                ((PeopleActivity) getActivity()).onFabClicked();
-            }
-        });
+        addContactButton.setOnClickListener(mAddContactListener);
         return emptyAccountView;
     }
 
@@ -412,7 +408,7 @@
     protected void onCreateView(LayoutInflater inflater, ViewGroup container) {
         super.onCreateView(inflater, container);
 
-        if (Flags.getInstance(getActivity()).getBoolean(Experiments.PULL_TO_REFRESH)) {
+        if (Flags.getInstance(getContext()).getBoolean(Experiments.PULL_TO_REFRESH)) {
             initSwipeRefreshLayout();
         }
         // Putting the header view inside a container will allow us to make
@@ -463,7 +459,7 @@
         bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
 
         final List<AccountWithDataSet> accounts = AccountTypeManager.getInstance(
-                getActivity()).getAccounts(/* contactsWritableOnly */ true);
+                getContext()).getAccounts(/* contactsWritableOnly */ true);
         final List<Account> syncableAccounts = filter.getSyncableAccounts(accounts);
         if (syncableAccounts != null && syncableAccounts.size() > 0) {
             for (Account account : syncableAccounts) {
@@ -492,9 +488,9 @@
                 : AccountFilterUtil.createContactsFilter(getContext());
         setContactListFilter(filter);
 
-        final ContactsDrawerActivity activity = (ContactsDrawerActivity) getActivity();
-        mActionBarAdapter = new ActionBarAdapter(activity, mActionBarListener,
-                activity.getSupportActionBar(), activity.getToolbar(), R.string.enter_contact_name);
+        mActivity = (ContactsDrawerActivity) getActivity();
+        mActionBarAdapter = new ActionBarAdapter(mActivity, mActionBarListener,
+                mActivity.getSupportActionBar(), mActivity.getToolbar(), R.string.enter_contact_name);
         mActionBarAdapter.setShowHomeIcon(true);
         initializeActionBarAdapter(savedInstanceState);
         if (isSearchMode()) {
@@ -591,13 +587,13 @@
         @Override
         public void onStartDisplayingCheckBoxes() {
             mActionBarAdapter.setSelectionMode(true);
-            getActivity().invalidateOptionsMenu();
+            mActivity.invalidateOptionsMenu();
         }
 
         @Override
         public void onSelectedContactIdsChanged() {
             mActionBarAdapter.setSelectionCount(getSelectedContactIds().size());
-            getActivity().invalidateOptionsMenu();
+            mActivity.invalidateOptionsMenu();
         }
 
         @Override
@@ -614,8 +610,6 @@
         setFilter(filter, restoreSelectedUri);
         setListType(mContactListFilterController.getFilterListType());
 
-        ((ContactsDrawerActivity) getActivity()).updateFilterMenu(filter);
-
         final String actionBarTitle;
         if (filter.filterType == ContactListFilter.FILTER_TYPE_DEVICE_CONTACTS) {
             actionBarTitle = getString(R.string.account_phone);
@@ -624,11 +618,11 @@
         } else {
             actionBarTitle = getString(R.string.contactsList);
         }
-        getActivity().setTitle(actionBarTitle);
+        mActivity.setTitle(actionBarTitle);
+        mActivity.updateFilterMenu(filter);
 
         if (CompatUtils.isNCompatible()) {
-            getActivity().setTitle(actionBarTitle);
-            getActivity().getWindow().getDecorView()
+            mActivity.getWindow().getDecorView()
                     .sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
         }
         // Determine whether the account has pullToRefresh feature
@@ -671,7 +665,7 @@
         setFilterAndUpdateTitle(getFilter());
         setVerticalScrollbarPosition(getScrollBarPosition());
         setSelectionVisible(false);
-        getActivity().invalidateOptionsMenu();
+        mActivity.invalidateOptionsMenu();
     }
 
     private int getScrollBarPosition() {
@@ -724,12 +718,12 @@
 
         @Override
         public void onDeleteContactAction(Uri contactUri) {
-            ContactDeletionInteraction.start(getActivity(), contactUri, false);
+            ContactDeletionInteraction.start(mActivity, contactUri, false);
         }
 
         @Override
         public void onFinishAction() {
-            getActivity().onBackPressed();
+            mActivity.onBackPressed();
         }
 
         @Override
@@ -767,8 +761,8 @@
 
     @Override
     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
-        if (!mContactsAvailable) {
-            // If contacts aren't available, hide all menu items.
+        if (!mContactsAvailable || mActivity.isInSecondLevel()) {
+            // If contacts aren't available or this fragment is not visible, hide all menu items.
             return;
         }
         super.onCreateOptionsMenu(menu, inflater);
@@ -826,7 +820,7 @@
                 // The home icon on the action bar is pressed
                 if (mActionBarAdapter.isUpShowing()) {
                     // "UP" icon press -- should be treated as "back".
-                    getActivity().onBackPressed();
+                    mActivity.onBackPressed();
                 }
                 return true;
             }
diff --git a/src/com/android/contacts/list/MultiSelectContactsListFragment.java b/src/com/android/contacts/list/MultiSelectContactsListFragment.java
index ea74834..41fd11e 100644
--- a/src/com/android/contacts/list/MultiSelectContactsListFragment.java
+++ b/src/com/android/contacts/list/MultiSelectContactsListFragment.java
@@ -34,6 +34,7 @@
 import android.widget.TextView;
 
 import com.android.contacts.R;
+import com.android.contacts.activities.ActionBarAdapter;
 import com.android.contacts.common.list.ContactEntryListFragment;
 import com.android.contacts.common.list.MultiSelectEntryContactListAdapter;
 import com.android.contacts.common.list.MultiSelectEntryContactListAdapter.SelectedContactsListener;
@@ -458,4 +459,10 @@
                 listView.getPaddingBottom());
     }
 
+    /**
+     * Returns the {@link ActionBarAdapter} object associated with list fragment.
+     */
+    public ActionBarAdapter getActionBarAdapter() {
+        return null;
+    }
 }