Merge "Make toolbar title larger in landscape"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 27c9f96..72c6481 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -16,8 +16,8 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.contacts"
-    android:versionCode="10502"
-    android:versionName="1.5.2">
+    android:versionCode="10503"
+    android:versionName="1.5.3">
 
     <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="23" />
     <original-package android:name="com.android.contacts" />
@@ -508,5 +508,11 @@
         </provider>
 
         <meta-data android:name="android.nfc.disable_beam_default" android:value="true" />
+
+        <receiver android:name="com.android.contacts.editor.AccountsChangedBroadcastReceiver">
+            <intent-filter>
+                <action android:name="android.accounts.LOGIN_ACCOUNTS_CHANGED"/>
+            </intent-filter>
+        </receiver>
     </application>
 </manifest>
diff --git a/res/drawable/ic_menu_group_add.xml b/res/drawable/ic_add.xml
similarity index 100%
rename from res/drawable/ic_menu_group_add.xml
rename to res/drawable/ic_add.xml
diff --git a/res/layout/contacts_drawer_activity.xml b/res/layout/contacts_drawer_activity.xml
new file mode 100644
index 0000000..008d4f5
--- /dev/null
+++ b/res/layout/contacts_drawer_activity.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+
+<android.support.v4.widget.DrawerLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/drawer_layout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
+    tools:openDrawer="start">
+
+    <!-- To prevent hamburger menu from getting the initial focus. -->
+    <View
+        android:focusable="true"
+        android:focusableInTouchMode="true"
+        android:layout_width="1px"
+        android:layout_height="1px" >
+        <requestFocus/>
+    </View>
+
+    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/fragment_container"
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <include
+            layout="@layout/people_activity_toolbar"
+            android:id="@+id/toolbar_parent" />
+
+        <FrameLayout
+            android:id="@+id/content_frame"
+            android:layout_width="match_parent"
+            android:layout_height="fill_parent"
+            android:background="?android:attr/windowBackground" />
+    </LinearLayout>
+
+    <android.support.design.widget.NavigationView
+        android:id="@+id/nav_view"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_gravity="start"
+        android:fitsSystemWindows="true"
+        app:headerLayout="@layout/nav_header_main"
+        app:menu="@menu/activity_main_drawer"/>
+
+</android.support.v4.widget.DrawerLayout>
\ No newline at end of file
diff --git a/res/layout/floating_action_button.xml b/res/layout/floating_action_button.xml
index 294d88b..95c76ae 100644
--- a/res/layout/floating_action_button.xml
+++ b/res/layout/floating_action_button.xml
@@ -33,5 +33,5 @@
         android:background="@drawable/floating_action_button"
         android:tint="@color/floating_action_button_icon_color"
         android:contentDescription="@string/action_menu_add_new_contact_button"
-        android:src="@drawable/ic_person_add_24dp"/>
+        android:src="@drawable/ic_add"/>
 </FrameLayout>
\ No newline at end of file
diff --git a/res/layout/group_member_suggestion.xml b/res/layout/group_member_suggestion.xml
deleted file mode 100644
index 4fe8d20..0000000
--- a/res/layout/group_member_suggestion.xml
+++ /dev/null
@@ -1,64 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2011, 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.
-*/
--->
-
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="48dip"
-    android:orientation="horizontal"
-    android:gravity="center_vertical"
-    android:background="?android:attr/selectableItemBackground">
-
-    <LinearLayout
-        android:layout_width="0dip"
-        android:layout_height="match_parent"
-        android:layout_weight="1"
-        android:gravity="center_vertical"
-        android:orientation="vertical">
-
-        <TextView
-            android:id="@+id/text1"
-            android:textAppearance="?android:attr/textAppearanceMedium"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:paddingLeft="8dip"
-            android:paddingStart="8dip"
-            android:singleLine="true"
-            android:ellipsize="end"/>
-
-        <TextView android:id="@+id/text2"
-            android:textAppearance="?android:attr/textAppearanceSmall"
-            android:textColor="?android:attr/textColorSecondary"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:paddingLeft="8dip"
-            android:paddingStart="8dip"
-            android:singleLine="true"
-            android:ellipsize="end" />
-
-    </LinearLayout>
-
-    <ImageView
-        android:id="@+id/icon"
-        android:layout_width="48dip"
-        android:layout_height="48dip"
-        android:cropToPadding="true"
-        android:scaleType="centerCrop" />
-
-</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/group_members_activity.xml b/res/layout/group_members_activity.xml
index 387fdd2..5466d2f 100644
--- a/res/layout/group_members_activity.xml
+++ b/res/layout/group_members_activity.xml
@@ -16,13 +16,8 @@
 -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/fragment_container"
+    android:id="@+id/fragment_container_inner"
     android:orientation="vertical"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
-
-    <include
-        layout="@layout/people_activity_toolbar"
-        android:id="@+id/toolbar_parent" />
-
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/res/layout/people_activity.xml b/res/layout/people_activity.xml
index fe51c6f..d8b900d 100644
--- a/res/layout/people_activity.xml
+++ b/res/layout/people_activity.xml
@@ -14,69 +14,35 @@
      limitations under the License.
 -->
 
-<android.support.v4.widget.DrawerLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:id="@+id/drawer_layout"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/list_container"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:fitsSystemWindows="true"
-    tools:openDrawer="start">
+    android:layout_height="match_parent">
 
-    <!-- To prevent hamburger menu from getting the initial focus. -->
-    <View
-        android:focusable="true"
-        android:focusableInTouchMode="true"
-        android:layout_width="1px"
-        android:layout_height="1px" >
-        <requestFocus/>
-    </View>
+    <!--
+        ViewPager for swiping between tabs.  We put fragments at runtime.
 
-    <RelativeLayout
-        android:id="@+id/list_container"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent">
-
-        <include
-            layout="@layout/people_activity_toolbar"
-            android:id="@+id/toolbar_parent" />
-
-        <!--
-            ViewPager for swiping between tabs.  We put StrequentContactListFragment,
-            DefaultContactBrowseListFragment and GroupBrowseListFragment at runtime.
-
-            (Adding them directly as the children of this view is not recommended.  ViewPager should
-            be treated like a ListView, which doesn't expect children to be added from the layout.)
-        -->
-        <android.support.v4.view.ViewPager
-            android:id="@+id/tab_pager"
-            android:layout_height="match_parent"
-            android:layout_width="match_parent"
-            android:layout_below="@id/toolbar_parent"
-            />
-
-        <FrameLayout
-            android:id="@+id/contacts_unavailable_view"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_below="@id/toolbar_parent"
-            android:visibility="gone">
-            <FrameLayout
-                android:id="@+id/contacts_unavailable_container"
-                android:layout_height="match_parent"
-                android:layout_width="match_parent" />
-        </FrameLayout>
-
-        <include layout="@layout/floating_action_button" />
-    </RelativeLayout>
-
-    <android.support.design.widget.NavigationView
-        android:id="@+id/nav_view"
-        android:layout_width="wrap_content"
+        (Adding them directly as the children of this view is not recommended.  ViewPager should
+        be treated like a ListView, which doesn't expect children to be added from the layout.)
+    -->
+    <android.support.v4.view.ViewPager
+        android:id="@+id/tab_pager"
         android:layout_height="match_parent"
-        android:layout_gravity="start"
-        app:headerLayout="@layout/nav_header_main"
-        app:menu="@menu/activity_main_drawer"/>
+        android:layout_width="match_parent"
+        android:layout_below="@id/toolbar_parent"
+        />
 
-</android.support.v4.widget.DrawerLayout>
\ No newline at end of file
+    <FrameLayout
+        android:id="@+id/contacts_unavailable_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_below="@id/toolbar_parent"
+        android:visibility="gone">
+        <FrameLayout
+            android:id="@+id/contacts_unavailable_container"
+            android:layout_height="match_parent"
+            android:layout_width="match_parent" />
+    </FrameLayout>
+
+    <include layout="@layout/floating_action_button" />
+</RelativeLayout>
diff --git a/res/menu/view_group.xml b/res/menu/view_group.xml
index 2fc36be..cf945fd 100644
--- a/res/menu/view_group.xml
+++ b/res/menu/view_group.xml
@@ -24,11 +24,6 @@
         contacts:showAsAction="ifRoom" />
 
     <item
-        android:id="@+id/menu_search"
-        android:icon="@drawable/ic_ab_search"
-        android:title="@string/menu_search" />
-
-    <item
         android:id="@+id/menu_rename_group"
         android:title="@string/menu_renameGroup"/>
 
diff --git a/res/values/styles.xml b/res/values/styles.xml
index fd6f56d..0358caa 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -134,8 +134,8 @@
         <item name="colorPrimary">@color/primary_color</item>
         <item name="android:colorAccent">@color/primary_color</item>
         <item name="colorAccent">@color/primary_color</item>
-        <item name="android:alertDialogTheme">@style/ContactsAlertDialogTheme</item>
-        <item name="alertDialogTheme">@style/ContactsAlertDialogTheme</item>
+        <item name="android:alertDialogTheme">@style/ContactsAlertDialogThemeAppCompat</item>
+        <item name="alertDialogTheme">@style/ContactsAlertDialogThemeAppCompat</item>
         <item name="list_item_height">?android:attr/listPreferredItemHeight</item>
         <item name="activated_background">@drawable/list_item_activated_background</item>
         <item name="section_header_background">@drawable/list_title_holo</item>
@@ -173,6 +173,13 @@
         <item name="list_item_text_indent">@dimen/contact_browser_list_item_text_indent</item>
         <!-- Favorites -->
         <item name="favorites_padding_bottom">0dip</item>
+        <item name="drawerArrowStyle">@style/DrawerArrowStyle</item>
+    </style>
+
+    <style name="DrawerArrowStyle" parent="Widget.AppCompat.DrawerArrowToggle">
+        <item name="spinBars">true</item>
+        <item name="color">@android:color/white</item>
+        <item name="android:color">@android:color/white</item>
     </style>
 
     <style name="ContactsUnavailableButtonStyle" parent="@style/Widget.AppCompat.Button.Colored">
@@ -377,7 +384,13 @@
         <item name="android:fontFamily">sans-serif</item>
     </style>
 
-    <style name="ContactsAlertDialogTheme" parent="Theme.AppCompat.Light.Dialog.MinWidth">
+    <!-- Inherit from Theme.Material.Light.Dialog instead of Theme.Material.Light.Dialog.Alert
+        since the Alert dialog is private. They are identical anyway. -->
+    <style name="ContactsAlertDialogTheme" parent="@android:style/Theme.Material.Light.Dialog">
+        <item name="android:colorAccent">@color/primary_color</item>
+    </style>
+
+    <style name="ContactsAlertDialogThemeAppCompat" parent="Theme.AppCompat.Light.Dialog.MinWidth">
         <item name="android:colorAccent">@color/primary_color</item>
         <item name="colorAccent">@color/primary_color</item>
     </style>
diff --git a/src/com/android/contacts/ContactsDrawerActivity.java b/src/com/android/contacts/ContactsDrawerActivity.java
new file mode 100644
index 0000000..62a9258
--- /dev/null
+++ b/src/com/android/contacts/ContactsDrawerActivity.java
@@ -0,0 +1,312 @@
+/*
+ * 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;
+
+import android.app.FragmentManager;
+import android.app.FragmentTransaction;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Color;
+import android.graphics.PorterDuff;
+import android.os.Bundle;
+import android.support.annotation.LayoutRes;
+import android.support.design.widget.NavigationView;
+import android.support.v4.view.GravityCompat;
+import android.support.v4.widget.DrawerLayout;
+import android.support.v7.app.ActionBarDrawerToggle;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.Toolbar;
+import android.telecom.TelecomManager;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.SubMenu;
+import android.view.ViewGroup;
+
+import com.android.contacts.common.ContactsUtils;
+import com.android.contacts.common.compat.BlockedNumberContractCompat;
+import com.android.contacts.common.compat.TelecomManagerUtil;
+import com.android.contacts.common.list.ContactListFilter;
+import com.android.contacts.common.list.ContactListFilterController;
+import com.android.contacts.common.preference.ContactsPreferenceActivity;
+import com.android.contacts.common.util.AccountFilterUtil;
+import com.android.contacts.common.util.ImplicitIntentsUtil;
+import com.android.contacts.common.util.ViewUtil;
+import com.android.contacts.editor.ContactEditorFragment;
+import com.android.contacts.group.GroupListItem;
+import com.android.contacts.group.GroupUtil;
+import com.android.contacts.group.GroupsFragment;
+import com.android.contacts.group.GroupsFragment.GroupsListener;
+import com.android.contacts.interactions.AccountFiltersFragment;
+import com.android.contacts.interactions.AccountFiltersFragment.AccountFiltersListener;
+import com.android.contacts.quickcontact.QuickContactActivity;
+import com.android.contacts.util.PhoneCapabilityTester;
+import com.android.contactsbind.Assistants;
+import com.android.contactsbind.HelpUtils;
+
+import java.util.List;
+
+/**
+ * A common superclass for Contacts activities with a navigation drawer.
+ */
+public abstract class ContactsDrawerActivity extends AppCompatContactsActivity implements
+        AccountFiltersListener,
+        GroupsListener,
+        NavigationView.OnNavigationItemSelectedListener {
+
+    protected static String TAG = "ContactsDrawerActivity";
+
+    protected static final String GROUPS_TAG = "groups";
+    protected static final String FILTERS_TAG = "filters";
+
+    protected ContactListFilterController mContactListFilterController;
+    protected DrawerLayout mDrawer;
+    protected Toolbar mToolbar;
+    protected NavigationView mNavigationView;
+    protected GroupsFragment mGroupsFragment;
+    protected AccountFiltersFragment mAccountFiltersFragment;
+
+    @Override
+    protected void onCreate(Bundle savedState) {
+        super.onCreate(savedState);
+
+        mContactListFilterController = ContactListFilterController.getInstance(this);
+        mContactListFilterController.checkFilterValidity(false);
+
+        super.setContentView(R.layout.contacts_drawer_activity);
+
+        // Set up the action bar.
+        mToolbar = getView(R.id.toolbar);
+        setSupportActionBar(mToolbar);
+
+        // Add shadow under toolbar.
+        ViewUtil.addRectangularOutlineProvider(findViewById(R.id.toolbar_parent), getResources());
+
+        // Set up hamburger button.
+        mDrawer = (DrawerLayout) findViewById(R.id.drawer_layout);
+        final ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, mDrawer, mToolbar,
+                R.string.navigation_drawer_open, R.string.navigation_drawer_close);
+        mDrawer.setDrawerListener(toggle);
+        toggle.syncState();
+
+        // Set up hamburger menu items.
+        mNavigationView = (NavigationView) findViewById(R.id.nav_view);
+        mNavigationView.setNavigationItemSelectedListener(this);
+
+        final Menu menu = mNavigationView.getMenu();
+        final boolean showBlockedNumbers = PhoneCapabilityTester.isPhone(this)
+                && ContactsUtils.FLAG_N_FEATURE
+                && BlockedNumberContractCompat.canCurrentUserBlockNumbers(this);
+
+        if (!showBlockedNumbers) {
+            menu.removeItem(R.id.nav_blocked_numbers);
+        }
+
+        if (Assistants.getDuplicatesActivityIntent(this) == null) {
+            menu.removeItem(R.id.nav_find_duplicates);
+        }
+
+        if (!HelpUtils.isHelpAndFeedbackAvailable()) {
+            menu.removeItem(R.id.nav_help);
+        }
+
+        // Set up fragment manager to load groups and filters.
+        final FragmentManager fragmentManager = getFragmentManager();
+        final FragmentTransaction transaction = fragmentManager.beginTransaction();
+        addGroupsAndFiltersFragments(transaction);
+        transaction.commitAllowingStateLoss();
+        fragmentManager.executePendingTransactions();
+    }
+
+    @Override
+    public void setContentView(@LayoutRes int layoutResID) {
+        final ViewGroup parent = (ViewGroup) findViewById(R.id.content_frame);
+        if (parent != null) {
+            parent.removeAllViews();
+        }
+        LayoutInflater.from(this).inflate(layoutResID, parent);
+    }
+
+    protected void addGroupsAndFiltersFragments(FragmentTransaction transaction) {
+        final FragmentManager fragmentManager = getFragmentManager();
+        mGroupsFragment = (GroupsFragment) fragmentManager.findFragmentByTag(GROUPS_TAG);
+        mAccountFiltersFragment = (AccountFiltersFragment)
+                fragmentManager.findFragmentByTag(FILTERS_TAG);
+
+        if (mGroupsFragment == null && ContactsUtils.areGroupWritableAccountsAvailable(this)) {
+            mGroupsFragment = new GroupsFragment();
+            transaction.add(mGroupsFragment, GROUPS_TAG);
+        }
+
+        if (mAccountFiltersFragment == null) {
+            mAccountFiltersFragment = new AccountFiltersFragment();
+            transaction.add(mAccountFiltersFragment, FILTERS_TAG);
+        }
+
+        if (ContactsUtils.areGroupWritableAccountsAvailable(this) && mGroupsFragment != null) {
+            mGroupsFragment.setListener(this);
+        }
+        mAccountFiltersFragment.setListener(this);
+    }
+
+    @Override
+    public void onGroupsLoaded(List<GroupListItem> groupListItems) {
+        final Menu menu = mNavigationView.getMenu();
+        final MenuItem groupsMenuItem = menu.findItem(R.id.nav_groups);
+        final SubMenu subMenu = groupsMenuItem.getSubMenu();
+        subMenu.removeGroup(R.id.nav_groups_items);
+
+        if (groupListItems != null) {
+            // Add each group
+            for (final GroupListItem groupListItem : groupListItems) {
+                if (GroupUtil.isEmptyFFCGroup(groupListItem)) {
+                    continue;
+                }
+                final String title = groupListItem.getTitle();
+                final MenuItem menuItem =
+                        subMenu.add(R.id.nav_groups_items, Menu.NONE, Menu.NONE, title);
+                menuItem.setIcon(R.drawable.ic_menu_label);
+                menuItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+                    @Override
+                    public boolean onMenuItemClick(MenuItem item) {
+                        onGroupMenuItemClicked(groupListItem.getGroupId());
+                        return true;
+                    }
+                });
+            }
+        }
+
+        // Create a menu item in the sub menu to add new groups
+        final MenuItem menuItem = subMenu.add(R.id.nav_groups_items, Menu.NONE, Menu.NONE,
+                getString(R.string.menu_new_group_action_bar));
+        menuItem.setIcon(R.drawable.ic_add);
+        menuItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+            @Override
+            public boolean onMenuItemClick(MenuItem item) {
+                onCreateGroupMenuItemClicked();
+                return true;
+            }
+        });
+    }
+
+    protected void onGroupMenuItemClicked(long groupId) {
+        final Intent intent = GroupUtil.createViewGroupIntent(this, groupId);
+        startActivity(intent);
+    }
+
+    protected void onCreateGroupMenuItemClicked() {
+        startActivity(GroupUtil.createAddGroupIntent(this));
+        mDrawer.closeDrawer(GravityCompat.START);
+    }
+
+    @Override
+    public void onFiltersLoaded(List<ContactListFilter> accountFilterItems) {
+        final Menu menu = mNavigationView.getMenu();
+        final MenuItem filtersMenuItem = menu.findItem(R.id.nav_filters);
+        final SubMenu subMenu = filtersMenuItem.getSubMenu();
+        subMenu.removeGroup(R.id.nav_filters_items);
+
+        if (accountFilterItems == null || accountFilterItems.size() < 2) {
+            return;
+        }
+
+        for (int i = 0; i < accountFilterItems.size(); i++) {
+            final ContactListFilter filter = accountFilterItems.get(i);
+            final String accountName = filter.accountName;
+            final MenuItem menuItem = subMenu.add(R.id.nav_filters_items, Menu.NONE, Menu.NONE,
+                    accountName);
+            final Intent intent = new Intent();
+            intent.putExtra(AccountFilterUtil.EXTRA_CONTACT_LIST_FILTER, filter);
+            menuItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+                @Override
+                public boolean onMenuItemClick(MenuItem item) {
+                    mDrawer.closeDrawer(GravityCompat.START);
+                    AccountFilterUtil.handleAccountFilterResult(mContactListFilterController,
+                            AppCompatActivity.RESULT_OK, intent);
+                    if (shouldFinish()) {
+                        finish();
+                    }
+                    return true;
+                }
+            });
+            menuItem.setIcon(filter.icon);
+            // Get rid of the default memu item overlay and show original account icons.
+            menuItem.getIcon().setColorFilter(Color.TRANSPARENT, PorterDuff.Mode.SRC_ATOP);
+        }
+    }
+
+    /**
+     * @return true if the child activity should finish after launching another activity.
+     */
+    protected abstract boolean shouldFinish();
+
+    @Override
+    public boolean onNavigationItemSelected(MenuItem item) {
+        final int id = item.getItemId();
+
+        if (id == R.id.nav_settings) {
+            startActivity(createPreferenceIntent());
+        } else if (id == R.id.nav_help) {
+            HelpUtils.launchHelpAndFeedbackForMainScreen(this);
+        } else if (id == R.id.nav_all_contacts) {
+            switchToAllContacts();
+        } else if (id == R.id.nav_blocked_numbers) {
+            final Intent intent = TelecomManagerUtil.createManageBlockedNumbersIntent(
+                    (TelecomManager) getSystemService(Context.TELECOM_SERVICE));
+            ImplicitIntentsUtil.startActivityInApp(this, intent);
+        } else if (id == R.id.nav_find_duplicates) {
+            launchFindDuplicates();
+        } else if (item.getIntent() != null) {
+            ImplicitIntentsUtil.startActivityInApp(this, item.getIntent());
+        } else {
+            Log.w(TAG, "Unhandled navigation view item selection");
+        }
+
+        mDrawer.closeDrawer(GravityCompat.START);
+        return true;
+    }
+
+    private Intent createPreferenceIntent() {
+        final Intent intent = new Intent(this, ContactsPreferenceActivity.class);
+        intent.putExtra(ContactsPreferenceActivity.EXTRA_NEW_LOCAL_PROFILE,
+                ContactEditorFragment.INTENT_EXTRA_NEW_LOCAL_PROFILE);
+        intent.putExtra(ContactsPreferenceActivity.EXTRA_MODE_FULLY_EXPANDED,
+                QuickContactActivity.MODE_FULLY_EXPANDED);
+        intent.putExtra(ContactsPreferenceActivity.EXTRA_PREVIOUS_SCREEN_TYPE,
+                QuickContactActivity.EXTRA_PREVIOUS_SCREEN_TYPE);
+        return intent;
+    }
+
+    protected void switchToAllContacts() {
+        final Intent intent = new Intent();
+        final ContactListFilter filter = createAllAccountsFilter();
+        intent.putExtra(AccountFilterUtil.EXTRA_CONTACT_LIST_FILTER, filter);
+        AccountFilterUtil.handleAccountFilterResult(
+                mContactListFilterController, AppCompatActivity.RESULT_OK, intent);
+    }
+
+    protected void launchFindDuplicates() {
+        ImplicitIntentsUtil.startActivityInAppIfPossible(this,
+                Assistants.getDuplicatesActivityIntent(this));
+    }
+
+    protected ContactListFilter createAllAccountsFilter() {
+        return ContactListFilter.createFilterWithType(ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS);
+    }
+
+}
diff --git a/src/com/android/contacts/GroupListLoader.java b/src/com/android/contacts/GroupListLoader.java
index 5bb240f..4816a5e 100644
--- a/src/com/android/contacts/GroupListLoader.java
+++ b/src/com/android/contacts/GroupListLoader.java
@@ -20,6 +20,8 @@
 import android.net.Uri;
 import android.provider.ContactsContract.Groups;
 
+import com.android.contacts.group.GroupUtil;
+
 /**
  * Group loader for the group list that includes details such as the number of contacts per group
  * and number of groups per account. This list is sorted by account type, account name, where the
@@ -56,12 +58,11 @@
     private static final Uri GROUP_LIST_URI = Groups.CONTENT_SUMMARY_URI;
 
     public GroupListLoader(Context context) {
-        // Sort groups from all accounts alphabettically and in a localized way.
         super(context,
                 GROUP_LIST_URI,
                 COLUMNS,
                 DEFAULT_SELECTION,
                 null,
-                Groups.TITLE + " COLLATE LOCALIZED ASC");
+                GroupUtil.getGroupsSortOrder());
     }
 }
diff --git a/src/com/android/contacts/GroupMemberLoader.java b/src/com/android/contacts/GroupMemberLoader.java
index 9f55848..8bc7d04 100644
--- a/src/com/android/contacts/GroupMemberLoader.java
+++ b/src/com/android/contacts/GroupMemberLoader.java
@@ -52,34 +52,8 @@
         public static final int CONTACT_PHOTO_ID             = 5;
     }
 
-    public static class GroupDetailQuery {
-        private static final String[] PROJECTION = new String[] {
-            Data.CONTACT_ID,                        // 0
-            Data.PHOTO_URI,                         // 1
-            Data.LOOKUP_KEY,                        // 2
-            Data.DISPLAY_NAME_PRIMARY,              // 3
-            Data.CONTACT_PRESENCE,                  // 4
-            Data.CONTACT_STATUS,                    // 5
-        };
-
-        public static final int CONTACT_ID                   = 0;
-        public static final int CONTACT_PHOTO_URI            = 1;
-        public static final int CONTACT_LOOKUP_KEY           = 2;
-        public static final int CONTACT_DISPLAY_NAME_PRIMARY = 3;
-        public static final int CONTACT_PRESENCE_STATUS      = 4;
-        public static final int CONTACT_STATUS               = 5;
-    }
-
     private final long mGroupId;
 
-    /**
-     * @return GroupMemberLoader object which can be used in group editor.
-     */
-    public static GroupMemberLoader constructLoaderForGroupEditorQuery(
-            Context context, long groupId) {
-        return new GroupMemberLoader(context, groupId, GroupEditorQuery.PROJECTION);
-    }
-
     private GroupMemberLoader(Context context, long groupId, String[] projection) {
         super(context);
         mGroupId = groupId;
diff --git a/src/com/android/contacts/GroupMetaDataLoader.java b/src/com/android/contacts/GroupMetaDataLoader.java
index ad9b0f9..8cdca2e 100644
--- a/src/com/android/contacts/GroupMetaDataLoader.java
+++ b/src/com/android/contacts/GroupMetaDataLoader.java
@@ -20,6 +20,8 @@
 import android.net.Uri;
 import android.provider.ContactsContract.Groups;
 
+import com.android.contacts.group.GroupUtil;
+
 /**
  * Group meta-data loader. Loads all groups or just a single group from the
  * database (if given a {@link Uri}).
@@ -52,7 +54,7 @@
         super(context, ensureIsGroupUri(groupUri), COLUMNS,
                 Groups.ACCOUNT_TYPE + " NOT NULL AND " + Groups.ACCOUNT_NAME + " NOT NULL AND "
                         + Groups.DELETED + "=0",
-                null, Groups.TITLE + " COLLATE NOCASE ASC");
+                null, GroupUtil.getGroupsSortOrder());
     }
 
     /**
diff --git a/src/com/android/contacts/activities/ActionBarAdapter.java b/src/com/android/contacts/activities/ActionBarAdapter.java
index 7042121..3af9c4b 100644
--- a/src/com/android/contacts/activities/ActionBarAdapter.java
+++ b/src/com/android/contacts/activities/ActionBarAdapter.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.content.res.TypedArray;
+import android.graphics.Color;
 import android.os.Bundle;
 import android.preference.PreferenceManager;
 import android.support.v4.content.ContextCompat;
@@ -517,9 +518,7 @@
                     R.color.contextual_selection_bar_status_bar_color);
             mActivity.getWindow().setStatusBarColor(cabStatusBarColor);
         } else {
-            final int normalStatusBarColor = ContextCompat.getColor(
-                    mActivity, R.color.primary_color_dark);
-            mActivity.getWindow().setStatusBarColor(normalStatusBarColor);
+            mActivity.getWindow().setStatusBarColor(Color.TRANSPARENT);
         }
     }
 
diff --git a/src/com/android/contacts/activities/ContactEditorBaseActivity.java b/src/com/android/contacts/activities/ContactEditorBaseActivity.java
index ffbeb49..97095f0 100644
--- a/src/com/android/contacts/activities/ContactEditorBaseActivity.java
+++ b/src/com/android/contacts/activities/ContactEditorBaseActivity.java
@@ -16,6 +16,18 @@
 
 package com.android.contacts.activities;
 
+import android.app.ActionBar;
+import android.app.Dialog;
+import android.content.ContentValues;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.RawContacts;
+import android.util.Log;
+import android.view.View;
+import android.view.inputmethod.InputMethodManager;
+
 import com.android.contacts.ContactSaveService;
 import com.android.contacts.ContactsActivity;
 import com.android.contacts.R;
@@ -29,18 +41,6 @@
 import com.android.contacts.interactions.ContactDeletionInteraction;
 import com.android.contacts.util.DialogManager;
 
-import android.app.ActionBar;
-import android.app.Dialog;
-import android.content.ContentValues;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.provider.ContactsContract.Contacts;
-import android.provider.ContactsContract.RawContacts;
-import android.util.Log;
-import android.view.View;
-import android.view.inputmethod.InputMethodManager;
-
 import java.util.ArrayList;
 
 /**
@@ -68,6 +68,8 @@
     public static final String ACTION_SAVE_COMPLETED = "saveCompleted";
 
     public static final int RESULT_CODE_SPLIT = 2;
+    // 3 used for ContactDeletionInteraction.RESULT_CODE_DELETED
+    public static final int RESULT_CODE_EDITED = 4;
 
     protected int mActionBarTitleResId;
 
diff --git a/src/com/android/contacts/activities/ContactSelectionActivity.java b/src/com/android/contacts/activities/ContactSelectionActivity.java
index 80a4acb..17ba765 100644
--- a/src/com/android/contacts/activities/ContactSelectionActivity.java
+++ b/src/com/android/contacts/activities/ContactSelectionActivity.java
@@ -139,10 +139,9 @@
                 .inflate(R.layout.custom_action_bar, null);
         mSearchView = (SearchView) mSearchViewContainer.findViewById(R.id.search_view);
 
-        // Postal address  group member,and legacy pickers don't support search, so just show
+        // Postal address pickers (and legacy pickers) don't support search, so just show
         // "HomeAsUp" button and title.
         if (mRequest.getActionCode() == ContactsRequest.ACTION_PICK_POSTAL ||
-                mRequest.getActionCode() == ContactsRequest.ACTION_PICK_GROUP_MEMBERS ||
                 mRequest.isLegacyCompatibilityMode()) {
             mSearchView.setVisibility(View.GONE);
             if (actionBar != null) {
@@ -357,11 +356,16 @@
             }
 
             case ContactsRequest.ACTION_PICK_GROUP_MEMBERS: {
-                final AccountWithDataSet account = getIntent().getParcelableExtra(
-                        UiIntentActions.GROUP_ACCOUNT_WITH_DATA_SET);
-                final ArrayList<String> rawContactIds = getIntent().getStringArrayListExtra(
-                        UiIntentActions.GROUP_RAW_CONTACT_IDS);
-                mListFragment = GroupMemberPickerFragment.newInstance(account, rawContactIds);
+                final String accountName = getIntent().getStringExtra(
+                        UiIntentActions.GROUP_ACCOUNT_NAME);
+                final String accountType = getIntent().getStringExtra(
+                        UiIntentActions.GROUP_ACCOUNT_TYPE);
+                final String accountDataSet = getIntent().getStringExtra(
+                        UiIntentActions.GROUP_ACCOUNT_DATA_SET);
+                final ArrayList<String> contactIds = getIntent().getStringArrayListExtra(
+                        UiIntentActions.GROUP_CONTACT_IDS);
+                mListFragment = GroupMemberPickerFragment.newInstance(
+                        accountName, accountType, accountDataSet, contactIds);
                 break;
             }
 
@@ -483,8 +487,10 @@
     private final class GroupMemberPickerListener implements GroupMemberPickerFragment.Listener {
 
         @Override
-        public void onGroupMemberClicked(Uri uri) {
-            returnPickerResult(uri);
+        public void onGroupMemberClicked(long contactId) {
+            final Intent intent = new Intent();
+            intent.putExtra(UiIntentActions.TARGET_CONTACT_ID_EXTRA_KEY, contactId);
+            returnPickerResult(intent);
         }
     }
 
diff --git a/src/com/android/contacts/activities/GroupMembersActivity.java b/src/com/android/contacts/activities/GroupMembersActivity.java
index f41972e..01999bb 100644
--- a/src/com/android/contacts/activities/GroupMembersActivity.java
+++ b/src/com/android/contacts/activities/GroupMembersActivity.java
@@ -17,27 +17,27 @@
 
 import android.accounts.Account;
 import android.app.FragmentManager;
+import android.content.Context;
+import android.app.FragmentTransaction;
 import android.app.LoaderManager.LoaderCallbacks;
 import android.content.CursorLoader;
 import android.content.Intent;
-import android.content.Loader;
 import android.database.Cursor;
 import android.net.Uri;
+import android.os.AsyncTask;
 import android.os.Bundle;
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.Intents;
+import android.provider.ContactsContract.RawContacts;
+import android.support.v4.view.GravityCompat;
 import android.support.v7.widget.Toolbar;
 import android.util.Log;
 import android.view.Menu;
 import android.view.MenuItem;
-import android.view.View;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.AutoCompleteTextView;
 import android.widget.Toast;
 
-import com.android.contacts.AppCompatContactsActivity;
 import com.android.contacts.ContactSaveService;
+import com.android.contacts.ContactsDrawerActivity;
 import com.android.contacts.GroupMemberLoader;
 import com.android.contacts.GroupMemberLoader.GroupEditorQuery;
 import com.android.contacts.R;
@@ -53,9 +53,6 @@
 import com.android.contacts.group.GroupMembersListFragment;
 import com.android.contacts.group.GroupMetadata;
 import com.android.contacts.group.GroupNameEditDialogFragment;
-import com.android.contacts.group.Member;
-import com.android.contacts.group.SuggestedMemberListAdapter;
-import com.android.contacts.group.SuggestedMemberListAdapter.SuggestedMember;
 import com.android.contacts.interactions.GroupDeletionDialogFragment;
 import com.android.contacts.list.ContactsRequest;
 import com.android.contacts.list.MultiSelectContactsListFragment;
@@ -68,7 +65,7 @@
 /**
  * Displays the members of a group and allows the user to edit it.
  */
-public class GroupMembersActivity extends AppCompatContactsActivity implements
+public class GroupMembersActivity extends ContactsDrawerActivity implements
         ActionBarAdapter.Listener,
         MultiSelectContactsListFragment.OnCheckBoxListActionListener,
         SelectAccountDialogFragment.Listener,
@@ -85,8 +82,6 @@
     private static final String TAG_SELECT_ACCOUNT_DIALOG = "selectAccountDialog";
     private static final String TAG_GROUP_NAME_EDIT_DIALOG = "groupNameEditDialog";
 
-    private static final int LOADER_GROUP_MEMBERS = 0;
-
     private static final String ACTION_DELETE_GROUP = "deleteGroup";
     private static final String ACTION_CREATE_GROUP = "createGroup";
     private static final String ACTION_UPDATE_GROUP = "updateGroup";
@@ -95,35 +90,74 @@
 
     private static final int RESULT_GROUP_ADD_MEMBER = 100;
 
-    /** Loader callbacks for existing group members for the autocomplete text view. */
-    private final LoaderCallbacks<Cursor> mGroupMemberCallbacks = new LoaderCallbacks<Cursor>() {
+    /**
+     * Starts an Intent to add the raw contacts for a given contact ID to a group.
+     * Only the raw contacts that belong to the specified account are added.
+     */
+    private static class AddGroupMembersAsyncTask extends AsyncTask<Void, Void, Intent> {
 
-        @Override
-        public CursorLoader onCreateLoader(int id, Bundle args) {
-            return GroupMemberLoader.constructLoaderForGroupEditorQuery(
-                    GroupMembersActivity.this, mGroupMetadata.groupId);
+        private final Context mContext;
+        private final long mContactId;
+        private final long mGroupId;
+        private final String mAccountName;
+        private final String mAccountType;
+
+        AddGroupMembersAsyncTask(Context context, long contactId, long groupId, String accountName,
+                String accountType) {
+            mContext = context;
+            mContactId = contactId;
+            mGroupId = groupId;
+            mAccountName = accountName;
+            mAccountType = accountType;
         }
 
         @Override
-        public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
-            final List<Member> members = new ArrayList<>();
-            data.moveToPosition(-1);
-            while (data.moveToNext()) {
-                members.add(new Member(
-                        data.getLong(GroupEditorQuery.RAW_CONTACT_ID),
-                        data.getString(GroupEditorQuery.CONTACT_LOOKUP_KEY),
-                        data.getLong(GroupEditorQuery.CONTACT_ID),
-                        data.getString(GroupEditorQuery.CONTACT_DISPLAY_NAME_PRIMARY),
-                        data.getString(GroupEditorQuery.CONTACT_PHOTO_URI),
-                        data.getLong(GroupEditorQuery.CONTACT_PHOTO_ID)));
+        protected Intent doInBackground(Void... params) {
+            final long[] rawContactIdsToAdd = getRawContactIdsToAdd();
+            if (rawContactIdsToAdd.length == 0) {
+                return null;
             }
+            return ContactSaveService.createGroupUpdateIntent(
+                    mContext, mGroupId, /* newLabel */ null,
+                    rawContactIdsToAdd, /* rawContactIdsToRemove */ null,
+                    GroupMembersActivity.class, GroupMembersActivity.ACTION_ADD_TO_GROUP);
+        }
 
-            bindAutocompleteGroupMembers(members);
+        // TODO(wjang): prune raw contacts that are already in the group; ContactSaveService will
+        // log a warning if the raw contact is already a member and keep going but it is not ideal.
+        private long[] getRawContactIdsToAdd() {
+            final Uri rawContactUri = RawContacts.CONTENT_URI.buildUpon()
+                    .appendQueryParameter(RawContacts.ACCOUNT_NAME, mAccountName)
+                    .appendQueryParameter(RawContacts.ACCOUNT_TYPE, mAccountType)
+                    .build();
+            final String[] projection = new String[]{RawContacts._ID};
+            final String selection = RawContacts.CONTACT_ID + "=?";
+            final String[] selectionArgs = new String[1];
+            selectionArgs[0] = Long.toString(mContactId);
+            final Cursor cursor = mContext.getContentResolver().query(
+                    rawContactUri, projection, selection, selectionArgs, null, null);
+            final long[] rawContactIds = new long[cursor.getCount()];
+            try {
+                int i = 0;
+                while (cursor.moveToNext()) {
+                    rawContactIds[i] = cursor.getLong(0);
+                    i++;
+                }
+            } finally {
+                cursor.close();
+            }
+            return rawContactIds;
         }
 
         @Override
-        public void onLoaderReset(Loader<Cursor> loader) {}
-    };
+        protected void onPostExecute(Intent intent) {
+            if (intent == null) {
+                Toast.makeText(mContext, R.string.groupSavedErrorToast, Toast.LENGTH_SHORT).show();
+            } else {
+                mContext.startService(intent);
+            }
+        }
+    }
 
     private ActionBarAdapter mActionBarAdapter;
 
@@ -131,8 +165,6 @@
 
     private GroupMembersListFragment mMembersListFragment;
 
-    private SuggestedMemberListAdapter mAutoCompleteAdapter;
-
     private Uri mGroupUri;
     private boolean mIsInsertAction;
 
@@ -158,13 +190,10 @@
         setContentView(R.layout.group_members_activity);
 
         // Set up the action bar
-        final Toolbar toolbar = getView(R.id.toolbar);
-        setSupportActionBar(toolbar);
         mActionBarAdapter = new ActionBarAdapter(this, this, getSupportActionBar(),
-                /* portraitTabs */ null, /* landscapeTabs */ null, toolbar,
+                /* portraitTabs */ null, /* landscapeTabs */ null, mToolbar,
                 R.string.enter_contact_name);
         mActionBarAdapter.setShowHomeIcon(true);
-        mActionBarAdapter.setShowHomeAsUp(true);
 
         // Decide whether to prompt for the account and group name or start loading existing members
         if (mIsInsertAction) {
@@ -189,17 +218,14 @@
                 }
             }
         } else {
-            // Add the members list fragment
             final FragmentManager fragmentManager = getFragmentManager();
+            // Add the members list fragment
             mMembersListFragment = (GroupMembersListFragment)
                     fragmentManager.findFragmentByTag(TAG_GROUP_MEMBERS);
             if (mMembersListFragment == null) {
                 mMembersListFragment = GroupMembersListFragment.newInstance(getIntent().getData());
-                fragmentManager.beginTransaction()
-                        .replace(R.id.fragment_container, mMembersListFragment, TAG_GROUP_MEMBERS)
-                        .commit();
-            } else {
-                getLoaderManager().initLoader(LOADER_GROUP_MEMBERS, null, mGroupMemberCallbacks);
+                fragmentManager.beginTransaction().replace(R.id.fragment_container_inner,
+                        mMembersListFragment, TAG_GROUP_MEMBERS).commitAllowingStateLoss();
             }
             mMembersListFragment.setListener(this);
             if (mGroupMetadata != null && mGroupMetadata.editable) {
@@ -267,9 +293,13 @@
 
             mMembersListFragment = GroupMembersListFragment.newInstance(groupUri);
             mMembersListFragment.setListener(this);
-            getFragmentManager().beginTransaction()
-                    .replace(R.id.fragment_container, mMembersListFragment, TAG_GROUP_MEMBERS)
-                    .commit();
+
+            final FragmentTransaction transaction = getFragmentManager().beginTransaction();
+            addGroupsAndFiltersFragments(transaction);
+            transaction.replace(
+                    R.id.fragment_container_inner, mMembersListFragment, TAG_GROUP_MEMBERS)
+                    .commitAllowingStateLoss();
+
             if (mGroupMetadata != null && mGroupMetadata.editable) {
                 mMembersListFragment.setCheckBoxListListener(this);
             }
@@ -298,6 +328,32 @@
     }
 
     @Override
+    protected void onGroupMenuItemClicked(long groupId) {
+        if (mGroupMetadata.groupId != groupId) {
+            super.onGroupMenuItemClicked(groupId);
+            finish();
+        }
+        mDrawer.closeDrawer(GravityCompat.START);
+    }
+
+    @Override
+    protected boolean shouldFinish() {
+        return true;
+    }
+
+    @Override
+    protected void switchToAllContacts() {
+        super.switchToAllContacts();
+        finish();
+    }
+
+    @Override
+    protected void launchFindDuplicates() {
+        super.launchFindDuplicates();
+        finish();
+    }
+
+    @Override
     public boolean onCreateOptionsMenu(Menu menu) {
         if (mGroupMetadata == null || mGroupMetadata.memberCount < 0) {
             // Hide menu options until metadata is fully loaded
@@ -311,25 +367,13 @@
     @Override
     public boolean onPrepareOptionsMenu(Menu menu) {
         final boolean isSelectionMode = mActionBarAdapter.isSelectionMode();
-        final boolean isSearchMode = mActionBarAdapter.isSearchMode();
-
         final boolean isGroupEditable = mGroupMetadata != null && mGroupMetadata.editable;
         final boolean isGroupReadOnly = mGroupMetadata != null && mGroupMetadata.readOnly;
 
-        setVisible(menu, R.id.menu_add,
-                isGroupEditable && !isSelectionMode && !isSearchMode);
-
-        setVisible(menu, R.id.menu_search,
-                isGroupEditable && !isSelectionMode && !isSearchMode);
-
-        setVisible(menu, R.id.menu_rename_group,
-                isGroupEditable && !isSelectionMode && !isSearchMode);
-
-        setVisible(menu, R.id.menu_delete_group,
-                !isGroupReadOnly && !isSelectionMode && !isSearchMode);
-
-        setVisible(menu, R.id.menu_remove_from_group,
-                isGroupEditable && isSelectionMode);
+        setVisible(menu, R.id.menu_add, isGroupEditable && !isSelectionMode);
+        setVisible(menu, R.id.menu_rename_group, isGroupEditable && !isSelectionMode);
+        setVisible(menu, R.id.menu_delete_group, !isGroupReadOnly && !isSelectionMode);
+        setVisible(menu, R.id.menu_remove_from_group, isGroupEditable && isSelectionMode);
 
         return true;
     }
@@ -351,19 +395,14 @@
             case R.id.menu_add: {
                 final Intent intent = new Intent(Intent.ACTION_PICK);
                 intent.setType(ContactsContract.Groups.CONTENT_ITEM_TYPE);
-                intent.putExtra(UiIntentActions.GROUP_ACCOUNT_WITH_DATA_SET,
-                        mGroupMetadata.createAccountWithDataSet());
-                intent.putExtra(UiIntentActions.GROUP_RAW_CONTACT_IDS,
-                        getExistingGroupMemberRawContactIds());
+                intent.putExtra(UiIntentActions.GROUP_ACCOUNT_NAME, mGroupMetadata.accountName);
+                intent.putExtra(UiIntentActions.GROUP_ACCOUNT_TYPE, mGroupMetadata.accountType);
+                intent.putExtra(UiIntentActions.GROUP_ACCOUNT_DATA_SET, mGroupMetadata.dataSet);
+                intent.putExtra(UiIntentActions.GROUP_CONTACT_IDS,
+                        getExistingGroupMemberContactIds());
                 startActivityForResult(intent, RESULT_GROUP_ADD_MEMBER);
                 return true;
             }
-            case R.id.menu_search: {
-                if (mActionBarAdapter != null) {
-                    mActionBarAdapter.setSearchMode(true);
-                }
-                return true;
-            }
             case R.id.menu_rename_group: {
                 GroupNameEditDialogFragment.showUpdateDialog(
                         getFragmentManager(), TAG_GROUP_NAME_EDIT_DIALOG, mGroupMetadata.groupName);
@@ -385,15 +424,15 @@
         return super.onOptionsItemSelected(item);
     }
 
-    private ArrayList<String> getExistingGroupMemberRawContactIds() {
-        final ArrayList<String> rawContactIds = new ArrayList<>();
+    private ArrayList<String> getExistingGroupMemberContactIds() {
+        final ArrayList<String> contactIds = new ArrayList<>();
         final Cursor cursor = mMembersListFragment.getAdapter().getCursor(/* partition */ 0);
         if (cursor != null && cursor.moveToFirst()) {
             do {
-                rawContactIds.add(cursor.getString(GroupMembersQuery.RAW_CONTACT_ID));
+                contactIds.add(cursor.getString(GroupMembersQuery.CONTACT_ID));
             } while (cursor.moveToNext());
         }
-        return rawContactIds;
+        return contactIds;
     }
 
     private void deleteGroup() {
@@ -408,7 +447,6 @@
         }
     }
 
-    // TODO(wjang): replace this with group events
     private void logListEvent() {
         Logger.logListEvent(
                 ListEvent.ActionType.REMOVE_LABEL,
@@ -432,7 +470,12 @@
 
     @Override
     public void onBackPressed() {
-        if (mIsInsertAction) {
+        if (!isSafeToCommitTransactions()) {
+            return;
+        }
+        if (mDrawer.isDrawerOpen(GravityCompat.START)) {
+            mDrawer.closeDrawer(GravityCompat.START);
+        } else if (mIsInsertAction) {
             finish();
         } else if (mActionBarAdapter.isSelectionMode()) {
             mActionBarAdapter.setSelectionMode(false);
@@ -446,30 +489,14 @@
         }
     }
 
-
     @Override
     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
         if (requestCode == RESULT_GROUP_ADD_MEMBER && resultCode == RESULT_OK && data != null) {
-            final Uri rawContactUri = data.getData();
-            if (rawContactUri != null) {
-                long rawContactId = -1;
-                try {
-                    rawContactId = Long.parseLong(rawContactUri.getLastPathSegment());
-                } catch (NumberFormatException ignored) {}
-                if (rawContactId < 0) {
-                    Toast.makeText(this, R.string.groupSavedErrorToast, Toast.LENGTH_SHORT).show();
-                    Log.w(TAG, "Failed to parse ID from pick group member result uri " +
-                            rawContactUri);
-                    return;
-                }
-                final long[] rawContactIdsToAdd = new long[1];
-                rawContactIdsToAdd[0] = rawContactId;
-                final Intent intent = ContactSaveService.createGroupUpdateIntent(
-                        GroupMembersActivity.this, mGroupMetadata.groupId, /* newLabel */ null,
-                        rawContactIdsToAdd, /* rawContactIdsToRemove */ null,
-                        GroupMembersActivity.class, GroupMembersActivity.ACTION_ADD_TO_GROUP);
-                startService(intent);
-            }
+            final long contactId = data.getLongExtra(
+                    UiIntentActions.TARGET_CONTACT_ID_EXTRA_KEY, -1);
+            new AddGroupMembersAsyncTask(this, contactId, mGroupMetadata.groupId,
+                    mGroupMetadata.accountName, mGroupMetadata.accountType)
+                    .execute();
         }
     }
 
@@ -512,11 +539,6 @@
     @Override
     public void onAction(int action) {
         switch (action) {
-            case ActionBarAdapter.Listener.Action.START_SEARCH_MODE:
-                mActionBarAdapter.setSearchMode(true);
-                invalidateOptionsMenu();
-                showFabWithAnimation(/* showFabWithAnimation = */ false);
-                break;
             case ActionBarAdapter.Listener.Action.START_SELECTION_MODE:
                 if (mMembersListFragment != null) {
                     mMembersListFragment.displayCheckBoxes(true);
@@ -539,7 +561,7 @@
     }
 
     private void showFabWithAnimation(boolean showFab) {
-        // TODO(wjang): b/28497108
+        // TODO: b/28497108
     }
 
     @Override
@@ -598,63 +620,12 @@
     @Override
     public void onGroupMetadataLoaded(GroupMetadata groupMetadata) {
         mGroupMetadata = groupMetadata;
-
         if (!mIsInsertAction) {
             getSupportActionBar().setTitle(mGroupMetadata.groupName);
         }
-
-        bindAutocompleteTextView();
-        getLoaderManager().initLoader(LOADER_GROUP_MEMBERS, null, mGroupMemberCallbacks);
-
         invalidateOptionsMenu();
     }
 
-    private void bindAutocompleteTextView() {
-        final AutoCompleteTextView autoCompleteTextView =
-                (AutoCompleteTextView) mActionBarAdapter.getSearchView();
-        if (autoCompleteTextView == null) return;
-        mAutoCompleteAdapter = createAutocompleteAdapter();
-        autoCompleteTextView.setAdapter(mAutoCompleteAdapter);
-        autoCompleteTextView.setOnItemClickListener(new OnItemClickListener() {
-            @Override
-            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-                final SuggestedMember member = (SuggestedMember) view.getTag();
-                if (member == null) {
-                    return;
-                }
-                final long[] rawContactIdsToAdd = new long[1];
-                rawContactIdsToAdd[0] = member.getRawContactId();
-                final Intent intent = ContactSaveService.createGroupUpdateIntent(
-                        GroupMembersActivity.this, mGroupMetadata.groupId, /* newLabel */ null,
-                        rawContactIdsToAdd, /* rawContactIdsToRemove */ null,
-                        GroupMembersActivity.class, ACTION_ADD_TO_GROUP);
-                startService(intent);
-
-                // Update the autocomplete adapter so the contact doesn't get suggested again
-                mAutoCompleteAdapter.addNewMember(member.getContactId());
-
-                // Clear out the text field
-                autoCompleteTextView.setText("");
-            }
-        });
-    }
-
-    private SuggestedMemberListAdapter createAutocompleteAdapter() {
-        final SuggestedMemberListAdapter adapter = new SuggestedMemberListAdapter(
-                this, android.R.layout.simple_dropdown_item_1line);
-        adapter.setContentResolver(this.getContentResolver());
-        adapter.setAccountType(mGroupMetadata.accountType);
-        adapter.setAccountName(mGroupMetadata.accountName);
-        adapter.setDataSet(mGroupMetadata.dataSet);
-        return adapter;
-    }
-
-    private void bindAutocompleteGroupMembers(List<Member> members) {
-        if (mAutoCompleteAdapter != null) {
-            mAutoCompleteAdapter.updateExistingMembersList(members);
-        }
-    }
-
     @Override
     public void onGroupMetadataLoadFailed() {
         setResultCanceledAndFinish(R.string.groupLoadErrorToast);
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index 892e831..d5c5b9b 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -40,7 +40,6 @@
 import android.support.v4.view.PagerAdapter;
 import android.support.v4.view.ViewPager;
 import android.support.v4.widget.DrawerLayout;
-import android.support.v7.app.ActionBarDrawerToggle;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.widget.Toolbar;
 import android.telecom.TelecomManager;
@@ -57,8 +56,8 @@
 import android.widget.ImageButton;
 import android.widget.Toast;
 
-import com.android.contacts.AppCompatContactsActivity;
 import com.android.contacts.ContactSaveService;
+import com.android.contacts.ContactsDrawerActivity;
 import com.android.contacts.R;
 import com.android.contacts.activities.ActionBarAdapter.TabState;
 import com.android.contacts.common.ContactsUtils;
@@ -71,24 +70,24 @@
 import com.android.contacts.common.list.ContactListFilter;
 import com.android.contacts.common.list.ContactListFilterController;
 import com.android.contacts.common.list.DirectoryListLoader;
+import com.android.contacts.common.list.ProviderStatusWatcher;
+import com.android.contacts.common.list.ProviderStatusWatcher.ProviderStatusListener;
 import com.android.contacts.common.list.ViewPagerTabs;
 import com.android.contacts.common.logging.ListEvent;
 import com.android.contacts.common.logging.Logger;
 import com.android.contacts.common.logging.ScreenEvent.ScreenType;
-import com.android.contacts.common.preference.ContactsPreferenceActivity;
+import com.android.contacts.common.model.AccountTypeManager;
+import com.android.contacts.common.model.account.AccountWithDataSet;
 import com.android.contacts.common.util.AccountFilterUtil;
 import com.android.contacts.common.util.Constants;
 import com.android.contacts.common.util.ImplicitIntentsUtil;
-import com.android.contacts.common.util.ViewUtil;
 import com.android.contacts.common.widget.FloatingActionButtonController;
 import com.android.contacts.editor.ContactEditorFragment;
 import com.android.contacts.editor.EditorIntents;
 import com.android.contacts.group.GroupListItem;
 import com.android.contacts.group.GroupUtil;
 import com.android.contacts.group.GroupsFragment;
-import com.android.contacts.group.GroupsFragment.GroupsListener;
 import com.android.contacts.interactions.AccountFiltersFragment;
-import com.android.contacts.interactions.AccountFiltersFragment.AccountFiltersListener;
 import com.android.contacts.interactions.ContactDeletionInteraction;
 import com.android.contacts.interactions.ContactMultiDeletionInteraction;
 import com.android.contacts.interactions.ContactMultiDeletionInteraction.MultiContactDeleteListener;
@@ -99,8 +98,6 @@
 import com.android.contacts.list.MultiSelectContactsListFragment.OnCheckBoxListActionListener;
 import com.android.contacts.list.OnContactBrowserActionListener;
 import com.android.contacts.list.OnContactsUnavailableActionListener;
-import com.android.contacts.list.ProviderStatusWatcher;
-import com.android.contacts.list.ProviderStatusWatcher.ProviderStatusListener;
 import com.android.contacts.quickcontact.QuickContactActivity;
 import com.android.contacts.util.DialogManager;
 import com.android.contacts.util.PhoneCapabilityTester;
@@ -114,17 +111,14 @@
 /**
  * Displays a list to browse contacts.
  */
-public class PeopleActivity extends AppCompatContactsActivity implements
+public class PeopleActivity extends ContactsDrawerActivity implements
         View.OnCreateContextMenuListener,
         View.OnClickListener,
-        AccountFiltersListener,
         ActionBarAdapter.Listener,
         DialogManager.DialogShowingViewActivity,
         ContactListFilterController.ContactListFilterListener,
-        GroupsListener,
         ProviderStatusListener,
-        MultiContactDeleteListener,
-        NavigationView.OnNavigationItemSelectedListener {
+        MultiContactDeleteListener {
 
     private static final String TAG = "PeopleActivity";
 
@@ -138,12 +132,11 @@
     private ContactsRequest mRequest;
 
     private ActionBarAdapter mActionBarAdapter;
+    private List<AccountWithDataSet> mWritableAccounts;
     private FloatingActionButtonController mFloatingActionButtonController;
     private View mFloatingActionButtonContainer;
     private boolean wasLastFabAnimationScaleIn = false;
 
-    private ContactListFilterController mContactListFilterController;
-
     private ContactsUnavailableFragment mContactsUnavailableFragment;
     private ProviderStatusWatcher mProviderStatusWatcher;
     private Integer mProviderStatus;
@@ -154,8 +147,6 @@
      * Showing a list of Contacts. Also used for showing search results in search mode.
      */
     private DefaultContactBrowseListFragment mAllFragment;
-    private GroupsFragment mGroupsFragment;
-    private AccountFiltersFragment mAccountFiltersFragment;
 
     /** ViewPager for swipe */
     private ViewPager mTabPager;
@@ -164,8 +155,6 @@
     private String[] mTabTitles;
     private final TabPagerListener mTabPagerListener = new TabPagerListener();
 
-    private NavigationView mNavigationView;
-
     private boolean mEnableDebugMenuOptions;
 
     /**
@@ -207,10 +196,6 @@
         return (mProviderStatus != null) && mProviderStatus.equals(ProviderStatus.STATUS_NORMAL);
     }
 
-    private boolean areGroupWritableAccountsAvailable() {
-        return ContactsUtils.areGroupWritableAccountsAvailable(this);
-    }
-
     /**
      * Initialize fragments that are (or may not be) in the layout.
      *
@@ -267,9 +252,6 @@
             Log.d(Constants.PERFORMANCE_TAG, "PeopleActivity.onCreate finish");
         }
         getWindow().setBackgroundDrawable(null);
-        if (CompatUtils.isLollipopCompatible()) {
-            getWindow().setStatusBarColor(Color.TRANSPARENT);
-        }
     }
 
     @Override
@@ -336,50 +318,19 @@
         mTabPager.setOnPageChangeListener(mTabPagerListener);
 
         // Configure toolbar and toolbar tabs. If in landscape mode, we configure tabs differently.
-        final Toolbar toolbar = getView(R.id.toolbar);
-        setSupportActionBar(toolbar);
         final ViewPagerTabs portraitViewPagerTabs
                 = (ViewPagerTabs) findViewById(R.id.lists_pager_header);
         ViewPagerTabs landscapeViewPagerTabs = null;
         if (portraitViewPagerTabs ==  null) {
             landscapeViewPagerTabs = (ViewPagerTabs) getLayoutInflater().inflate(
-                    R.layout.people_activity_tabs_lands, toolbar, /* attachToRoot = */ false);
+                    R.layout.people_activity_tabs_lands, mToolbar, /* attachToRoot = */ false);
             mViewPagerTabs = landscapeViewPagerTabs;
         } else {
             mViewPagerTabs = portraitViewPagerTabs;
         }
         mViewPagerTabs.setViewPager(mTabPager);
 
-        final DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
-        final ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar,
-                R.string.navigation_drawer_open, R.string.navigation_drawer_close);
-        drawer.setDrawerListener(toggle);
-        toggle.syncState();
-
-        mNavigationView = (NavigationView) findViewById(R.id.nav_view);
-        mNavigationView.setNavigationItemSelectedListener(this);
-
-        final Menu menu = mNavigationView.getMenu();
-
-        final boolean showBlockedNumbers = PhoneCapabilityTester.isPhone(this)
-                && ContactsUtils.FLAG_N_FEATURE
-                && BlockedNumberContractCompat.canCurrentUserBlockNumbers(this);
-
-        if (!showBlockedNumbers) {
-            menu.removeItem(R.id.nav_blocked_numbers);
-        }
-
-        if (Assistants.getDuplicatesActivityIntent(this) == null) {
-            menu.removeItem(R.id.nav_find_duplicates);
-        }
-
-        if (!HelpUtils.isHelpAndFeedbackAvailable()) {
-            menu.removeItem(R.id.nav_help);
-        }
-
         final String ALL_TAG = "tab-pager-all";
-        final String GROUPS_TAG = "groups";
-        final String FILTERS_TAG = "filters";
 
         // Create the fragments and add as children of the view pager.
         // The pager adapter will only change the visibility; it'll never create/destroy
@@ -389,49 +340,27 @@
         // existing.
         mAllFragment = (DefaultContactBrowseListFragment)
                 fragmentManager.findFragmentByTag(ALL_TAG);
-        mGroupsFragment = (GroupsFragment)
-                fragmentManager.findFragmentByTag(GROUPS_TAG);
-        mAccountFiltersFragment = (AccountFiltersFragment)
-                fragmentManager.findFragmentByTag(FILTERS_TAG);
 
         if (mAllFragment == null) {
             mAllFragment = new DefaultContactBrowseListFragment();
             transaction.add(R.id.tab_pager, mAllFragment, ALL_TAG);
-
-            if (areGroupWritableAccountsAvailable()) {
-                mGroupsFragment = new GroupsFragment();
-                transaction.add(mGroupsFragment, GROUPS_TAG);
-            }
-
-            mAccountFiltersFragment = new AccountFiltersFragment();
-            transaction.add(mAccountFiltersFragment, FILTERS_TAG);
         }
 
         mAllFragment.setOnContactListActionListener(new ContactBrowserActionListener());
         mAllFragment.setCheckBoxListListener(new CheckBoxListListener());
         mAllFragment.setListType(ListEvent.ListType.ALL_CONTACTS);
 
-        if (areGroupWritableAccountsAvailable() && mGroupsFragment != null) {
-            mGroupsFragment.setListener(this);
-        }
-
-        mAccountFiltersFragment.setListener(this);
-
         // Hide all fragments for now.  We adjust visibility when we get onSelectedTabChanged()
         // from ActionBarAdapter.
         transaction.hide(mAllFragment);
-        // Groups fragment has no UI, no need to hide it
 
         transaction.commitAllowingStateLoss();
         fragmentManager.executePendingTransactions();
 
         mActionBarAdapter = new ActionBarAdapter(this, this, getSupportActionBar(),
-                portraitViewPagerTabs, landscapeViewPagerTabs, toolbar);
+                portraitViewPagerTabs, landscapeViewPagerTabs, mToolbar);
         mActionBarAdapter.initialize(savedState, mRequest);
 
-        // Add shadow under toolbar
-        ViewUtil.addRectangularOutlineProvider(findViewById(R.id.toolbar_parent), getResources());
-
         // Configure floating action button
         mFloatingActionButtonContainer = findViewById(R.id.floating_action_button_container);
         final ImageButton floatingActionButton
@@ -563,12 +492,25 @@
 
     private void initializeFabVisibility() {
         final boolean hideFab = mActionBarAdapter.isSearchMode()
-                || mActionBarAdapter.isSelectionMode();
+                || mActionBarAdapter.isSelectionMode()
+                || !shouldShowFabForAccount();
         mFloatingActionButtonContainer.setVisibility(hideFab ? View.GONE : View.VISIBLE);
         mFloatingActionButtonController.resetIn();
         wasLastFabAnimationScaleIn = !hideFab;
     }
 
+    private boolean shouldShowFabForAccount() {
+        return isCurrentAccountFilterWritable()
+                || isAllContactsFilter(mContactListFilterController.getFilter());
+    }
+
+    private boolean isCurrentAccountFilterWritable() {
+        final ContactListFilter currentFilter = mContactListFilterController.getFilter();
+        final AccountWithDataSet accountOfCurrentFilter = new AccountWithDataSet(
+                currentFilter.accountName, currentFilter.accountType, currentFilter.dataSet);
+        return mWritableAccounts != null && mWritableAccounts.contains(accountOfCurrentFilter);
+    }
+
     private void showFabWithAnimation(boolean showFab) {
         if (mFloatingActionButtonContainer == null) {
             return;
@@ -596,6 +538,7 @@
         }
 
         setFilterAndUpdateTitle(mContactListFilterController.getFilter());
+        showFabWithAnimation(shouldShowFabForAccount());
 
         invalidateOptionsMenuIfNeeded();
     }
@@ -920,67 +863,18 @@
     }
 
     @Override
-    public void onGroupsLoaded(List<GroupListItem> groupListItems) {
-        final Menu menu = mNavigationView.getMenu();
-        final MenuItem groupsMenuItem = menu.findItem(R.id.nav_groups);
-        final SubMenu subMenu = groupsMenuItem.getSubMenu();
-        subMenu.removeGroup(R.id.nav_groups_items);
-
-        if (groupListItems != null) {
-            // Add each group
-            for (GroupListItem groupListItem : groupListItems) {
-                if (GroupUtil.isEmptyFFCGroup(groupListItem)) {
-                    continue;
-                }
-                final String title = groupListItem.getTitle();
-                final MenuItem menuItem =
-                        subMenu.add(R.id.nav_groups_items, Menu.NONE, Menu.NONE, title);
-                menuItem.setIntent(GroupUtil.createViewGroupIntent(
-                        this, groupListItem.getGroupId()));
-                menuItem.setIcon(R.drawable.ic_menu_label);
-            }
-        }
-
-        // Create a menu item in the sub menu to add new groups
-        final MenuItem menuItem = subMenu.add(R.id.nav_groups_items, Menu.NONE, Menu.NONE,
-                getString(R.string.menu_new_group_action_bar));
-        menuItem.setIntent(GroupUtil.createAddGroupIntent(this));
-        menuItem.setIcon(R.drawable.ic_menu_group_add);
+    public void onFiltersLoaded(List<ContactListFilter> accountFilterItems) {
+        super.onFiltersLoaded(accountFilterItems);
+        mWritableAccounts =
+                AccountTypeManager.getInstance(this).getAccounts(/* contactWritableOnly */ true);
+        initializeFabVisibility();
     }
 
     @Override
-    public void onFiltersLoaded(List<ContactListFilter> accountFilterItems) {
-        final Menu menu = mNavigationView.getMenu();
-        final MenuItem filtersMenuItem = menu.findItem(R.id.nav_filters);
-        final SubMenu subMenu = filtersMenuItem.getSubMenu();
-        subMenu.removeGroup(R.id.nav_filters_items);
-
-        if (accountFilterItems == null || accountFilterItems.size() < 2) {
-            return;
-        }
-
-        for (int i = 0; i < accountFilterItems.size(); i++) {
-            final ContactListFilter filter = accountFilterItems.get(i);
-            final String accountName = filter.accountName;
-            final MenuItem menuItem = subMenu.add(R.id.nav_filters_items, Menu.NONE, Menu.NONE,
-                    accountName);
-            final Intent intent = new Intent();
-            intent.putExtra(AccountFilterUtil.EXTRA_CONTACT_LIST_FILTER, filter);
-            menuItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
-                @Override
-                public boolean onMenuItemClick(MenuItem item) {
-                    final DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
-                    drawer.closeDrawer(GravityCompat.START);
-                    mAllFragment.setListType(ListEvent.ListType.ACCOUNT);
-                    AccountFilterUtil.handleAccountFilterResult(
-                            mContactListFilterController, AppCompatActivity.RESULT_OK, intent);
-                    return true;
-                }
-            });
-            menuItem.setIcon(filter.icon);
-            // Get rid of the default memu item overlay and show original account icons.
-            menuItem.getIcon().setColorFilter(Color.TRANSPARENT, PorterDuff.Mode.SRC_ATOP);
-        }
+    protected void onGroupMenuItemClicked(long groupId) {
+        switchToAllContacts();
+        super.onGroupMenuItemClicked(groupId);
+        mDrawer.closeDrawer(GravityCompat.START);
     }
 
     @Override
@@ -1057,8 +951,7 @@
                 if (mAllFragment.isSearchMode()) {
                     previousScreen = ScreenType.SEARCH;
                 } else {
-                    if (mAllFragment.getFilter().filterType ==
-                            ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS) {
+                    if (isAllContactsFilter(mContactListFilterController.getFilter())) {
                         if (position < mAllFragment.getAdapter().getNumberOfFavorites()) {
                             previousScreen = ScreenType.FAVORITES;
                         } else {
@@ -1263,50 +1156,6 @@
         return super.onOptionsItemSelected(item);
     }
 
-    @SuppressWarnings("StatementWithEmptyBody")
-    @Override
-    public boolean onNavigationItemSelected(MenuItem item) {
-        final int id = item.getItemId();
-
-        if (id == R.id.nav_settings) {
-            startActivity(createPreferenceIntent());
-        } else if (id == R.id.nav_help) {
-            HelpUtils.launchHelpAndFeedbackForMainScreen(this);
-        } else if (id == R.id.nav_all_contacts) {
-            switchToAllContacts();
-        } else if (id == R.id.nav_blocked_numbers) {
-            final Intent intent = TelecomManagerUtil.createManageBlockedNumbersIntent(
-                    (TelecomManager) getSystemService(Context.TELECOM_SERVICE));
-            if (intent != null) {
-                startActivity(intent);
-            }
-        } else if (id == R.id.nav_find_duplicates) {
-            ImplicitIntentsUtil.startActivityInAppIfPossible(this,
-                    Assistants.getDuplicatesActivityIntent(this));
-        } else if (item.getIntent() != null) {
-            ImplicitIntentsUtil.startActivityInApp(this, item.getIntent());
-        } else {
-            Log.w(TAG, "Unhandled navigation view item selection");
-        }
-
-        final DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
-        drawer.closeDrawer(GravityCompat.START);
-        return true;
-    }
-
-    private Intent createPreferenceIntent() {
-        final Intent intent = new Intent(this, ContactsPreferenceActivity.class);
-        intent.putExtra(ContactsPreferenceActivity.EXTRA_NEW_LOCAL_PROFILE,
-                ContactEditorFragment.INTENT_EXTRA_NEW_LOCAL_PROFILE);
-        intent.putExtra(ContactsPreferenceActivity.EXTRA_MODE_FULLY_EXPANDED,
-                QuickContactActivity.MODE_FULLY_EXPANDED);
-        intent.putExtra(ContactsPreferenceActivity.EXTRA_PREVIOUS_SCREEN_TYPE,
-                QuickContactActivity.EXTRA_PREVIOUS_SCREEN_TYPE);
-        intent.putExtra(ContactsPreferenceActivity.EXTRA_ARE_CONTACTS_AVAILABLE,
-                areContactsAvailable());
-        return intent;
-    }
-
     private void showImportExportDialogFragment(){
         ImportExportDialogFragment.show(getFragmentManager(), areContactsAvailable(),
                 PeopleActivity.class, ImportExportDialogFragment.EXPORT_MODE_ALL_CONTACTS);
@@ -1404,7 +1253,6 @@
                     /* count */ mAllFragment.getAdapter().getCount(), /* clickedIndex */ -1,
                     /* numSelected */ mAllFragment.getAdapter().getSelectedContactIds().size());
 
-
 // TODO fix or remove multipicker code
 //                else if (resultCode == RESULT_CANCELED && mMode == MODE_PICK_MULTIPLE_PHONES) {
 //                    // Finish the activity if the sub activity was canceled as back key is used
@@ -1446,9 +1294,8 @@
             return;
         }
 
-        final DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
-        if (drawer.isDrawerOpen(GravityCompat.START)) {
-            drawer.closeDrawer(GravityCompat.START);
+        if (mDrawer.isDrawerOpen(GravityCompat.START)) {
+            mDrawer.closeDrawer(GravityCompat.START);
         } else if (mActionBarAdapter.isSelectionMode()) {
             mActionBarAdapter.setSelectionMode(false);
             mAllFragment.displayCheckBoxes(false);
@@ -1537,6 +1384,9 @@
 
     private void setFilterAndUpdateTitle(ContactListFilter filter, boolean restoreSelectedUri) {
         mAllFragment.setFilter(filter, restoreSelectedUri);
+        final int listType =  filter.filterType == ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS
+                ? ListEvent.ListType.ALL_CONTACTS : ListEvent.ListType.ACCOUNT;
+        mAllFragment.setListType(listType);
         if (getSupportActionBar() != null) {
             final String actionBarTitle = TextUtils.isEmpty(filter.accountName) ?
                     getString(R.string.contactsList) : filter.accountName;
@@ -1544,21 +1394,18 @@
         }
     }
 
-    private void switchToAllContacts() {
-        final Intent intent = new Intent();
-        final ContactListFilter filter = createAllAccountsFilter();
-        intent.putExtra(AccountFilterUtil.EXTRA_CONTACT_LIST_FILTER, filter);
-        AccountFilterUtil.handleAccountFilterResult(
-                mContactListFilterController, AppCompatActivity.RESULT_OK, intent);
-    }
-
-    private ContactListFilter createAllAccountsFilter() {
-        return ContactListFilter.createFilterWithType(ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS);
-    }
-
     // Persist filter only when it's of the type FILTER_TYPE_ALL_ACCOUNTS.
     private void persistFilterIfNeeded(ContactListFilter filter) {
-        mContactListFilterController.setContactListFilter(filter, /* persistent */
-                filter.filterType == ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS);
+        mContactListFilterController.setContactListFilter(filter,
+                /* persistent */ isAllContactsFilter(filter));
+    }
+
+    private boolean isAllContactsFilter(ContactListFilter filter) {
+        return filter.filterType == ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS;
+    }
+
+    @Override
+    protected boolean shouldFinish() {
+        return false;
     }
 }
diff --git a/src/com/android/contacts/compat/ProviderStatusCompat.java b/src/com/android/contacts/compat/ProviderStatusCompat.java
deleted file mode 100644
index 2b5c820..0000000
--- a/src/com/android/contacts/compat/ProviderStatusCompat.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2015 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.compat;
-
-import android.os.Build;
-import android.provider.ContactsContract.ProviderStatus;
-
-import com.android.contacts.common.compat.CompatUtils;
-import com.android.contacts.common.compat.SdkVersionOverride;
-
-/**
- * This class contains constants from the pre-M version of ContactsContract.ProviderStatus class
- * and also the mappings between pre-M constants and M constants for compatibility purpose,
- * because ProviderStatus class constant names and values changed and the class became visible in
- * API level 23.
- */
-public class ProviderStatusCompat {
-    /**
-     * Not instantiable.
-     */
-    private ProviderStatusCompat() {
-    }
-
-    public static final boolean USE_CURRENT_VERSION = CompatUtils.isMarshmallowCompatible();
-
-    public static final int STATUS_EMPTY = USE_CURRENT_VERSION ?
-            ProviderStatus.STATUS_EMPTY : ProviderStatusCompat.STATUS_NO_ACCOUNTS_NO_CONTACTS;
-
-    public static final int STATUS_BUSY = USE_CURRENT_VERSION ?
-            ProviderStatus.STATUS_BUSY : ProviderStatusCompat.STATUS_UPGRADING;
-
-    /**
-     * Default status of the provider, using the actual constant to guard against errors
-     */
-    public static final int STATUS_NORMAL = ProviderStatus.STATUS_NORMAL;
-
-    /**
-     * The following three constants are from pre-M.
-     *
-     * The status used when the provider is in the process of upgrading.  Contacts
-     * are temporarily unaccessible.
-     */
-    private static final int STATUS_UPGRADING = 1;
-
-    /**
-     * The status used during a locale change.
-     */
-    public static final int STATUS_CHANGING_LOCALE = 3;
-
-    /**
-     * The status that indicates that there are no accounts and no contacts
-     * on the device.
-     */
-    private static final int STATUS_NO_ACCOUNTS_NO_CONTACTS = 4;
-}
diff --git a/src/com/android/contacts/editor/AccountsChangedBroadcastReceiver.java b/src/com/android/contacts/editor/AccountsChangedBroadcastReceiver.java
new file mode 100644
index 0000000..55300d5
--- /dev/null
+++ b/src/com/android/contacts/editor/AccountsChangedBroadcastReceiver.java
@@ -0,0 +1,71 @@
+/*
+ * 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.editor;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.contacts.R;
+import com.android.contacts.common.model.AccountTypeManager;
+import com.android.contacts.common.model.account.AccountWithDataSet;
+
+import java.util.List;
+
+/**
+ * This class is to fix the bug that no prompt is seen for multiple accounts while creating new
+ * contacts. By registering a BroadcastReceiver statically, we detect the changes of accounts by
+ * receiving the message "android.accounts.LOGIN_ACCOUNTS_CHANGED". If the BroadcastReceiver gets
+ * this message, it will get the default account from the SharedPreference and compare current
+ * accounts with the default account. At last, it will renew the default account in the
+ * SharedPreference if necessary.
+ */
+public class AccountsChangedBroadcastReceiver extends BroadcastReceiver {
+    final String TAG = "AccountsChanged";
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        Context appContext = context.getApplicationContext();
+        final ContactEditorUtils contactEditorUtils = ContactEditorUtils.getInstance(appContext);
+        final String defaultAccountKey = appContext.getResources().getString(
+                R.string.contact_editor_default_account_key);
+        final SharedPreferences pref = appContext.getSharedPreferences(
+                appContext.getPackageName(), Context.MODE_PRIVATE);
+        final String defaultAccountString = pref.getString(defaultAccountKey, null);
+
+        if (!TextUtils.isEmpty(defaultAccountString)) {
+            AccountWithDataSet defaultAccount;
+            try {
+                defaultAccount = AccountWithDataSet.unstringify(defaultAccountString);
+            } catch (IllegalArgumentException e) {
+                Log.e(TAG, "Invalid string in SharedPreference", e);
+                contactEditorUtils.saveDefaultAndAllAccounts(null);
+                return;
+            }
+
+            final AccountTypeManager accountTypeManager = AccountTypeManager.getInstance(
+                    appContext);
+            final List<AccountWithDataSet> accounts = accountTypeManager.getAccounts(true);
+            // Delete default account pref if it has been deleted.
+            if (accounts == null || accounts.size() < 1 || !accounts.contains(defaultAccount)) {
+                contactEditorUtils.saveDefaultAndAllAccounts(null);
+            }
+        }
+    }
+}
diff --git a/src/com/android/contacts/editor/ContactEditorBaseFragment.java b/src/com/android/contacts/editor/ContactEditorBaseFragment.java
index 4182e1f..c1e5af8 100644
--- a/src/com/android/contacts/editor/ContactEditorBaseFragment.java
+++ b/src/com/android/contacts/editor/ContactEditorBaseFragment.java
@@ -16,35 +16,6 @@
 
 package com.android.contacts.editor;
 
-import com.android.contacts.common.logging.ScreenEvent.ScreenType;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-
-import com.android.contacts.ContactSaveService;
-import com.android.contacts.GroupMetaDataLoader;
-import com.android.contacts.R;
-import com.android.contacts.activities.ContactEditorAccountsChangedActivity;
-import com.android.contacts.activities.ContactEditorBaseActivity;
-import com.android.contacts.activities.ContactEditorBaseActivity.ContactEditor;
-import com.android.contacts.common.model.AccountTypeManager;
-import com.android.contacts.common.model.Contact;
-import com.android.contacts.common.model.ContactLoader;
-import com.android.contacts.common.model.RawContact;
-import com.android.contacts.common.model.RawContactDelta;
-import com.android.contacts.common.model.RawContactDeltaList;
-import com.android.contacts.common.model.RawContactModifier;
-import com.android.contacts.common.model.ValuesDelta;
-import com.android.contacts.common.model.account.AccountType;
-import com.android.contacts.common.model.account.AccountWithDataSet;
-import com.android.contacts.common.util.ImplicitIntentsUtil;
-import com.android.contacts.common.util.MaterialColorMapUtils;
-import com.android.contacts.editor.AggregationSuggestionEngine.Suggestion;
-import com.android.contacts.list.UiIntentActions;
-import com.android.contacts.quickcontact.QuickContactActivity;
-import com.android.contacts.util.HelpUtils;
-import com.android.contacts.util.PhoneCapabilityTester;
-import com.android.contacts.util.UiClosables;
-
 import android.accounts.Account;
 import android.app.Activity;
 import android.app.Fragment;
@@ -84,6 +55,34 @@
 import android.widget.ListPopupWindow;
 import android.widget.Toast;
 
+import com.android.contacts.ContactSaveService;
+import com.android.contacts.GroupMetaDataLoader;
+import com.android.contacts.R;
+import com.android.contacts.activities.ContactEditorAccountsChangedActivity;
+import com.android.contacts.activities.ContactEditorBaseActivity;
+import com.android.contacts.activities.ContactEditorBaseActivity.ContactEditor;
+import com.android.contacts.common.logging.ScreenEvent.ScreenType;
+import com.android.contacts.common.model.AccountTypeManager;
+import com.android.contacts.common.model.Contact;
+import com.android.contacts.common.model.ContactLoader;
+import com.android.contacts.common.model.RawContact;
+import com.android.contacts.common.model.RawContactDelta;
+import com.android.contacts.common.model.RawContactDeltaList;
+import com.android.contacts.common.model.RawContactModifier;
+import com.android.contacts.common.model.ValuesDelta;
+import com.android.contacts.common.model.account.AccountType;
+import com.android.contacts.common.model.account.AccountWithDataSet;
+import com.android.contacts.common.util.ImplicitIntentsUtil;
+import com.android.contacts.common.util.MaterialColorMapUtils;
+import com.android.contacts.editor.AggregationSuggestionEngine.Suggestion;
+import com.android.contacts.list.UiIntentActions;
+import com.android.contacts.quickcontact.QuickContactActivity;
+import com.android.contacts.util.HelpUtils;
+import com.android.contacts.util.PhoneCapabilityTester;
+import com.android.contacts.util.UiClosables;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -1472,6 +1471,7 @@
                             QuickContactActivity.MODE_FULLY_EXPANDED);
                     resultIntent.putExtra(QuickContactActivity.EXTRA_PREVIOUS_SCREEN_TYPE,
                             ScreenType.EDITOR);
+                    resultIntent.putExtra(QuickContactActivity.EXTRA_CONTACT_EDITED, true);
                 } else {
                     resultIntent = null;
                 }
diff --git a/src/com/android/contacts/group/GroupMembersListAdapter.java b/src/com/android/contacts/group/GroupMembersListAdapter.java
index 86e75b1..e84dde7 100644
--- a/src/com/android/contacts/group/GroupMembersListAdapter.java
+++ b/src/com/android/contacts/group/GroupMembersListAdapter.java
@@ -28,6 +28,7 @@
 import android.view.ViewGroup;
 
 import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
+import com.android.contacts.common.R;
 import com.android.contacts.common.list.ContactListItemView;
 import com.android.contacts.common.list.MultiSelectEntryContactListAdapter;
 import com.android.contacts.common.preference.ContactsPreferences;
@@ -71,7 +72,8 @@
 
     public GroupMembersListAdapter(Context context) {
         super(context, GroupMembersQuery.RAW_CONTACT_ID);
-        mUnknownNameText = context.getText(android.R.string.unknownName);
+        mUnknownNameText = context.getText(R.string.missing_name);
+        setSectionHeaderDisplayEnabled(true);
     }
 
     /** Sets the ID of the group whose members will be displayed. */
@@ -93,7 +95,6 @@
                 .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
                         String.valueOf(Directory.DEFAULT))
                 .appendQueryParameter(Contacts.EXTRA_ADDRESS_BOOK_INDEX, "true")
-                .appendQueryParameter(Contacts.EXTRA_ADDRESS_BOOK_INDEX_COUNTS, "true")
                 .build());
 
         loader.setSelection(Data.MIMETYPE + "=?" + " AND " + GroupMembership.GROUP_ROW_ID + "=?");
@@ -131,7 +132,6 @@
         final ContactListItemView view =
                 super.newView(context, partition, cursor, position, parent);
         view.setUnknownNameText(mUnknownNameText);
-        view.setQuickContactEnabled(isQuickContactEnabled());
         return view;
     }
 
@@ -140,10 +140,21 @@
         super.bindView(v, partition, cursor, position);
         final ContactListItemView view = (ContactListItemView) v;
         bindViewId(view, cursor, GroupMembersQuery.CONTACT_ID);
+        bindSectionHeaderAndDivider(view, position);
         bindName(view, cursor);
         bindPhoto(view, cursor);
     }
 
+    protected void bindSectionHeaderAndDivider(ContactListItemView view, int position) {
+        view.setIsSectionHeaderEnabled(isSectionHeaderDisplayEnabled());
+        if (isSectionHeaderDisplayEnabled()) {
+            final Placement placement = getItemPlacementInSection(position);
+            view.setSectionHeader(placement.sectionHeader);
+        } else {
+            view.setSectionHeader(null);
+        }
+    }
+
     private void bindName(ContactListItemView view, Cursor cursor) {
         view.showDisplayName(cursor, GroupMembersQuery.CONTACT_DISPLAY_NAME,
                 getContactNameDisplayOrder());
diff --git a/src/com/android/contacts/group/GroupUtil.java b/src/com/android/contacts/group/GroupUtil.java
index 2057a94..2eee35b 100644
--- a/src/com/android/contacts/group/GroupUtil.java
+++ b/src/com/android/contacts/group/GroupUtil.java
@@ -149,4 +149,11 @@
     private static boolean isSystemIdFFC(String systemId) {
         return !TextUtils.isEmpty(systemId) && FFC_GROUPS.contains(systemId);
     }
+
+    /**
+     * Sort groups alphabetically and in a localized way.
+     */
+    public static String getGroupsSortOrder() {
+        return Groups.TITLE + " COLLATE LOCALIZED ASC";
+    }
 }
\ No newline at end of file
diff --git a/src/com/android/contacts/group/Member.java b/src/com/android/contacts/group/Member.java
deleted file mode 100644
index ad6f9b2..0000000
--- a/src/com/android/contacts/group/Member.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2011 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.group;
-
-import android.net.Uri;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.provider.ContactsContract.Contacts;
-
-import com.google.common.base.Objects;
-
-/** A member of the group currently being displayed to the user. */
-public class Member implements Parcelable {
-
-    public static final Parcelable.Creator<Member> CREATOR = new Parcelable.Creator<Member>() {
-        @Override
-        public Member createFromParcel(Parcel in) {
-            return new Member(in);
-        }
-
-        @Override
-        public Member[] newArray(int size) {
-            return new Member[size];
-        }
-    };
-
-    private final long mRawContactId;
-    private final long mContactId;
-    private final Uri mLookupUri;
-    private final String mDisplayName;
-    private final Uri mPhotoUri;
-    private final String mLookupKey;
-    private final long mPhotoId;
-
-    public Member(long rawContactId, String lookupKey, long contactId, String displayName,
-            String photoUri, long photoId) {
-        mRawContactId = rawContactId;
-        mContactId = contactId;
-        mLookupKey = lookupKey;
-        mLookupUri = Contacts.getLookupUri(contactId, lookupKey);
-        mDisplayName = displayName;
-        mPhotoUri = (photoUri != null) ? Uri.parse(photoUri) : null;
-        mPhotoId = photoId;
-    }
-
-    public long getRawContactId() {
-        return mRawContactId;
-    }
-
-    public long getContactId() {
-        return mContactId;
-    }
-
-    public Uri getLookupUri() {
-        return mLookupUri;
-    }
-
-    public String getLookupKey() {
-        return mLookupKey;
-    }
-
-    public String getDisplayName() {
-        return mDisplayName;
-    }
-
-    public Uri getPhotoUri() {
-        return mPhotoUri;
-    }
-
-    public long getPhotoId() {
-        return mPhotoId;
-    }
-
-    @Override
-    public boolean equals(Object object) {
-        if (object instanceof Member) {
-            Member otherMember = (Member) object;
-            return Objects.equal(mLookupUri, otherMember.getLookupUri());
-        }
-        return false;
-    }
-
-    @Override
-    public int hashCode() {
-        return mLookupUri == null ? 0 : mLookupUri.hashCode();
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeLong(mRawContactId);
-        dest.writeLong(mContactId);
-        dest.writeParcelable(mLookupUri, flags);
-        dest.writeString(mLookupKey);
-        dest.writeString(mDisplayName);
-        dest.writeParcelable(mPhotoUri, flags);
-        dest.writeLong(mPhotoId);
-    }
-
-    private Member(Parcel in) {
-        mRawContactId = in.readLong();
-        mContactId = in.readLong();
-        mLookupUri = in.readParcelable(getClass().getClassLoader());
-        mLookupKey = in.readString();
-        mDisplayName = in.readString();
-        mPhotoUri = in.readParcelable(getClass().getClassLoader());
-        mPhotoId = in.readLong();
-    }
-}
\ No newline at end of file
diff --git a/src/com/android/contacts/group/SuggestedMemberListAdapter.java b/src/com/android/contacts/group/SuggestedMemberListAdapter.java
deleted file mode 100644
index e2756c6..0000000
--- a/src/com/android/contacts/group/SuggestedMemberListAdapter.java
+++ /dev/null
@@ -1,440 +0,0 @@
-/*
- * Copyright (C) 2011 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.group;
-
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.Context;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
-import android.net.Uri;
-import android.provider.ContactsContract.CommonDataKinds.Email;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.provider.ContactsContract.CommonDataKinds.Photo;
-import android.provider.ContactsContract.Contacts.Data;
-import android.provider.ContactsContract.RawContacts;
-import android.provider.ContactsContract.RawContactsEntity;
-import android.text.TextUtils;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.AutoCompleteTextView;
-import android.widget.Filter;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.android.contacts.R;
-import com.android.contacts.common.ContactPhotoManager;
-import com.android.contacts.group.SuggestedMemberListAdapter.SuggestedMember;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-
-/**
- * This adapter provides suggested contacts that can be added to a group for an
- * {@link AutoCompleteTextView} within the group editor.
- */
-public class SuggestedMemberListAdapter extends ArrayAdapter<SuggestedMember> {
-
-    private static final String[] PROJECTION_FILTERED_MEMBERS = new String[] {
-        RawContacts._ID,                        // 0
-        RawContacts.CONTACT_ID,                 // 1
-        RawContacts.DISPLAY_NAME_PRIMARY        // 2
-    };
-
-    private static final int RAW_CONTACT_ID_COLUMN_INDEX = 0;
-    private static final int CONTACT_ID_COLUMN_INDEX = 1;
-    private static final int DISPLAY_NAME_PRIMARY_COLUMN_INDEX = 2;
-
-    private static final String[] PROJECTION_MEMBER_DATA = new String[] {
-        RawContacts._ID,                        // 0
-        RawContacts.CONTACT_ID,                 // 1
-        Data.MIMETYPE,                          // 2
-        Data.DATA1,                             // 3
-        Photo.PHOTO,                            // 4
-    };
-
-    private static final int ID_INDEX = 0;
-    private static final int MIMETYPE_COLUMN_INDEX = 2;
-    private static final int DATA_COLUMN_INDEX = 3;
-    private static final int PHOTO_COLUMN_INDEX = 4;
-
-    private Filter mFilter;
-    private ContentResolver mContentResolver;
-    private LayoutInflater mInflater;
-    private ContactPhotoManager mPhotoManager;
-
-    private String mAccountType;
-    private String mAccountName;
-    private String mDataSet;
-
-    // TODO: Make this a Map for better performance when we check if a new contact is in the list
-    // or not
-    private final List<Long> mExistingMemberContactIds = new ArrayList<Long>();
-
-    private static final int SUGGESTIONS_LIMIT = 5;
-
-    public SuggestedMemberListAdapter(Context context, int textViewResourceId) {
-        super(context, textViewResourceId);
-        mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-        mPhotoManager = ContactPhotoManager.getInstance(context);
-    }
-
-    public void setAccountType(String accountType) {
-        mAccountType = accountType;
-    }
-
-    public void setAccountName(String accountName) {
-        mAccountName = accountName;
-    }
-
-    public void setDataSet(String dataSet) {
-        mDataSet = dataSet;
-    }
-
-    public void setContentResolver(ContentResolver resolver) {
-        mContentResolver = resolver;
-    }
-
-    public void updateExistingMembersList(List<Member> list) {
-        mExistingMemberContactIds.clear();
-        for (Member member : list) {
-            mExistingMemberContactIds.add(member.getContactId());
-        }
-    }
-
-    public void addNewMember(long contactId) {
-        mExistingMemberContactIds.add(contactId);
-    }
-
-    public void removeMember(long contactId) {
-        if (mExistingMemberContactIds.contains(contactId)) {
-            mExistingMemberContactIds.remove(contactId);
-        }
-    }
-
-    @Override
-    public View getView(int position, View convertView, ViewGroup parent) {
-        View result = convertView;
-        if (result == null) {
-            result = mInflater.inflate(R.layout.group_member_suggestion, parent, false);
-        }
-        // TODO: Use a viewholder
-        SuggestedMember member = getItem(position);
-        TextView text1 = (TextView) result.findViewById(R.id.text1);
-        TextView text2 = (TextView) result.findViewById(R.id.text2);
-        ImageView icon = (ImageView) result.findViewById(R.id.icon);
-        text1.setText(member.getDisplayName());
-        if (member.hasExtraInfo()) {
-            text2.setText(member.getExtraInfo());
-        } else {
-            text2.setVisibility(View.GONE);
-        }
-        byte[] byteArray = member.getPhotoByteArray();
-        if (byteArray == null) {
-            final Uri contactLookupUri = RawContacts.getContactLookupUri(mContentResolver,
-                    ContentUris.withAppendedId(RawContacts.CONTENT_URI, member.getContactId()));
-            final String imageRequestIdentifier = contactLookupUri == null
-                    ? null : contactLookupUri.toString();
-            GroupUtil.bindPhoto(mPhotoManager, icon, member.getPhotoId(),
-                /* photoUri */ null, member.getDisplayName(), imageRequestIdentifier);
-        } else {
-            Bitmap bitmap = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length);
-            icon.setImageBitmap(frameBitmapInCircle(bitmap));
-        }
-        result.setTag(member);
-        return result;
-    }
-
-    private static Bitmap frameBitmapInCircle(Bitmap input) {
-        // Crop the image if not squared.
-        final int targetDiameter = input.getWidth();
-        final Bitmap scaled = Bitmap.createScaledBitmap(
-                input, targetDiameter, targetDiameter, /* filter */ false);
-        int inputWidth = scaled.getWidth();
-        int inputHeight = scaled.getHeight();
-        int targetX, targetY, targetSize;
-        if (inputWidth >= inputHeight) {
-            targetX = inputWidth / 2 - inputHeight / 2;
-            targetY = 0;
-            targetSize = inputHeight;
-        } else {
-            targetX = 0;
-            targetY = inputHeight / 2 - inputWidth / 2;
-            targetSize = inputWidth;
-        }
-
-        // Create an output bitmap and a canvas to draw on it.
-        final Bitmap output = Bitmap.createBitmap(targetSize, targetSize, Bitmap.Config.ARGB_8888);
-        final Canvas canvas = new Canvas(output);
-
-        // Create a black paint to draw the mask.
-        final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
-        paint.setColor(Color.BLACK);
-
-        // Draw a circle.
-        canvas.drawCircle(targetDiameter / 2, targetDiameter / 2, targetDiameter / 2, paint);
-
-        // Replace the black parts of the mask with the input image.
-        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
-        canvas.drawBitmap(scaled, targetX /* left */, targetY /* top */, paint);
-
-        return output;
-    }
-
-    @Override
-    public Filter getFilter() {
-        if (mFilter == null) {
-            mFilter = new SuggestedMemberFilter();
-        }
-        return mFilter;
-    }
-
-    /**
-     * This filter queries for raw contacts that match the given account name and account type,
-     * as well as the search query.
-     */
-    public class SuggestedMemberFilter extends Filter {
-
-        @Override
-        protected FilterResults performFiltering(CharSequence prefix) {
-            FilterResults results = new FilterResults();
-            if (mContentResolver == null || TextUtils.isEmpty(prefix)) {
-                return results;
-            }
-
-            // Create a list to store the suggested contacts (which will be alphabetically ordered),
-            // but also keep a map of raw contact IDs to {@link SuggestedMember}s to make it easier
-            // to add supplementary data to the contact (photo, phone, email) to the members based
-            // on raw contact IDs after the second query is completed.
-            List<SuggestedMember> suggestionsList = new ArrayList<SuggestedMember>();
-            HashMap<Long, SuggestedMember> suggestionsMap = new HashMap<Long, SuggestedMember>();
-
-            // First query for all the raw contacts that match the given search query
-            // and have the same account name and type as specified in this adapter
-            String searchQuery = prefix.toString() + "%";
-            String accountClause = RawContacts.ACCOUNT_NAME + "=? AND " +
-                    RawContacts.ACCOUNT_TYPE + "=?";
-            String[] args;
-            if (mDataSet == null) {
-                accountClause += " AND " + RawContacts.DATA_SET + " IS NULL";
-                args = new String[] {mAccountName, mAccountType, searchQuery, searchQuery};
-            } else {
-                accountClause += " AND " + RawContacts.DATA_SET + "=?";
-                args = new String[] {
-                        mAccountName, mAccountType, mDataSet, searchQuery, searchQuery
-                };
-            }
-
-            Cursor cursor = mContentResolver.query(
-                    RawContacts.CONTENT_URI, PROJECTION_FILTERED_MEMBERS,
-                    accountClause + " AND (" +
-                    RawContacts.DISPLAY_NAME_PRIMARY + " LIKE ? OR " +
-                    RawContacts.DISPLAY_NAME_ALTERNATIVE + " LIKE ? )",
-                    args, RawContacts.DISPLAY_NAME_PRIMARY + " COLLATE LOCALIZED ASC");
-
-            if (cursor == null) {
-                return results;
-            }
-
-            // Read back the results from the cursor and filter out existing group members.
-            // For valid suggestions, add them to the hash map of suggested members.
-            try {
-                cursor.moveToPosition(-1);
-                while (cursor.moveToNext() && suggestionsMap.keySet().size() < SUGGESTIONS_LIMIT) {
-                    long rawContactId = cursor.getLong(RAW_CONTACT_ID_COLUMN_INDEX);
-                    long contactId = cursor.getLong(CONTACT_ID_COLUMN_INDEX);
-                    // Filter out contacts that have already been added to this group
-                    if (mExistingMemberContactIds.contains(contactId)) {
-                        continue;
-                    }
-                    // Otherwise, add the contact as a suggested new group member
-                    String displayName = cursor.getString(DISPLAY_NAME_PRIMARY_COLUMN_INDEX);
-                    SuggestedMember member = new SuggestedMember(rawContactId, displayName,
-                            contactId);
-                    // Store the member in the list of suggestions and add it to the hash map too.
-                    suggestionsList.add(member);
-                    suggestionsMap.put(rawContactId, member);
-                }
-            } finally {
-                cursor.close();
-            }
-
-            int numSuggestions = suggestionsMap.keySet().size();
-            if (numSuggestions == 0) {
-                return results;
-            }
-
-            // Create a part of the selection string for the next query with the pattern (?, ?, ?)
-            // where the number of comma-separated question marks represent the number of raw
-            // contact IDs found in the previous query (while respective the SUGGESTION_LIMIT)
-            final StringBuilder rawContactIdSelectionBuilder = new StringBuilder();
-            final String[] questionMarks = new String[numSuggestions];
-            Arrays.fill(questionMarks, "?");
-            rawContactIdSelectionBuilder.append(RawContacts._ID + " IN (")
-                    .append(TextUtils.join(",", questionMarks))
-                    .append(")");
-
-            // Construct the selection args based on the raw contact IDs we're interested in
-            // (as well as the photo, email, and phone mimetypes)
-            List<String> selectionArgs = new ArrayList<String>();
-            selectionArgs.add(Photo.CONTENT_ITEM_TYPE);
-            selectionArgs.add(Email.CONTENT_ITEM_TYPE);
-            selectionArgs.add(Phone.CONTENT_ITEM_TYPE);
-            for (Long rawContactId : suggestionsMap.keySet()) {
-                selectionArgs.add(String.valueOf(rawContactId));
-            }
-
-            // Perform a second query to retrieve a photo and possibly a phone number or email
-            // address for the suggested contact
-            Cursor memberDataCursor = mContentResolver.query(
-                    RawContactsEntity.CONTENT_URI, PROJECTION_MEMBER_DATA,
-                    "(" + Data.MIMETYPE + "=? OR " + Data.MIMETYPE + "=? OR " + Data.MIMETYPE +
-                    "=?) AND " + rawContactIdSelectionBuilder.toString(),
-                    selectionArgs.toArray(new String[0]), null);
-
-            if (memberDataCursor != null) {
-                try {
-                    memberDataCursor.moveToPosition(-1);
-                    while (memberDataCursor.moveToNext()) {
-                        long rawContactId = memberDataCursor.getLong(RAW_CONTACT_ID_COLUMN_INDEX);
-                        SuggestedMember member = suggestionsMap.get(rawContactId);
-                        if (member == null) {
-                            continue;
-                        }
-                        String mimetype = memberDataCursor.getString(MIMETYPE_COLUMN_INDEX);
-                        if (Photo.CONTENT_ITEM_TYPE.equals(mimetype)) {
-                            // Set photo
-                            member.setPhotoId(memberDataCursor.getLong(ID_INDEX));
-                            byte[] bitmapArray = memberDataCursor.getBlob(PHOTO_COLUMN_INDEX);
-                            member.setPhotoByteArray(bitmapArray);
-                        } else if (Email.CONTENT_ITEM_TYPE.equals(mimetype) ||
-                                Phone.CONTENT_ITEM_TYPE.equals(mimetype)) {
-                            // Set at most 1 extra piece of contact info that can be a phone number or
-                            // email
-                            if (!member.hasExtraInfo()) {
-                                String info = memberDataCursor.getString(DATA_COLUMN_INDEX);
-                                member.setExtraInfo(info);
-                            }
-                        }
-                    }
-                } finally {
-                    memberDataCursor.close();
-                }
-            }
-            results.values = suggestionsList;
-            return results;
-        }
-
-        @Override
-        protected void publishResults(CharSequence constraint, FilterResults results) {
-            @SuppressWarnings("unchecked")
-            List<SuggestedMember> suggestionsList = (List<SuggestedMember>) results.values;
-            if (suggestionsList == null) {
-                return;
-            }
-
-            // Clear out the existing suggestions in this adapter
-            clear();
-
-            // Add all the suggested members to this adapter
-            for (SuggestedMember member : suggestionsList) {
-                add(member);
-            }
-
-            notifyDataSetChanged();
-        }
-    }
-
-    /**
-     * This represents a single contact that is a suggestion for the user to add to a group.
-     */
-    // TODO: Merge this with the {@link GroupEditorFragment} Member class once we can find the
-    // lookup URI for this contact using the autocomplete filter queries
-    public class SuggestedMember {
-
-        private long mRawContactId;
-        private long mContactId;
-        private String mDisplayName;
-
-        private String mExtraInfo;
-        private byte[] mPhoto;
-        private long mPhotoId;
-
-        public SuggestedMember(long rawContactId, String displayName, long contactId) {
-            mRawContactId = rawContactId;
-            mDisplayName = displayName;
-            mContactId = contactId;
-        }
-
-        public String getDisplayName() {
-            return mDisplayName;
-        }
-
-        public String getExtraInfo() {
-            return mExtraInfo;
-        }
-
-        public long getRawContactId() {
-            return mRawContactId;
-        }
-
-        public long getContactId() {
-            return mContactId;
-        }
-
-        public byte[] getPhotoByteArray() {
-            return mPhoto;
-        }
-
-        public long getPhotoId() {
-            return mPhotoId;
-        }
-
-        public boolean hasExtraInfo() {
-            return mExtraInfo != null;
-        }
-
-        /**
-         * Set a phone number or email to distinguish this contact
-         */
-        public void setExtraInfo(String info) {
-            mExtraInfo = info;
-        }
-
-        public void setPhotoByteArray(byte[] photo) {
-            mPhoto = photo;
-        }
-
-        public void setPhotoId(long photoId) {
-            mPhotoId = photoId;
-        }
-
-        @Override
-        public String toString() {
-            return getDisplayName();
-        }
-    }
-}
diff --git a/src/com/android/contacts/interactions/AccountFiltersFragment.java b/src/com/android/contacts/interactions/AccountFiltersFragment.java
index 44a6edf..7836c19 100644
--- a/src/com/android/contacts/interactions/AccountFiltersFragment.java
+++ b/src/com/android/contacts/interactions/AccountFiltersFragment.java
@@ -41,7 +41,7 @@
         /**
          * Invoked after account filters have been loaded.
          */
-        void onFiltersLoaded(List<ContactListFilter> groupListItems);
+        void onFiltersLoaded(List<ContactListFilter> accountFilterItems);
     }
 
     private final LoaderManager.LoaderCallbacks<List<ContactListFilter>> mFiltersLoaderListener =
diff --git a/src/com/android/contacts/list/ContactsIntentResolver.java b/src/com/android/contacts/list/ContactsIntentResolver.java
index ded72c2..39eaeba 100644
--- a/src/com/android/contacts/list/ContactsIntentResolver.java
+++ b/src/com/android/contacts/list/ContactsIntentResolver.java
@@ -16,6 +16,7 @@
 
 package com.android.contacts.list;
 
+import android.accounts.Account;
 import android.app.Activity;
 import android.app.SearchManager;
 import android.content.Intent;
@@ -94,10 +95,12 @@
                 request.setActionCode(ContactsRequest.ACTION_PICK_EMAIL);
             } else if (Groups.CONTENT_ITEM_TYPE.equals(resolvedType)) {
                 request.setActionCode(ContactsRequest.ACTION_PICK_GROUP_MEMBERS);
-                request.setAccountWithDataSet(intent.<AccountWithDataSet> getParcelableExtra(
-                        UiIntentActions.GROUP_ACCOUNT_WITH_DATA_SET));
+                request.setAccountWithDataSet(new AccountWithDataSet(
+                        intent.getStringExtra(UiIntentActions.GROUP_ACCOUNT_NAME),
+                        intent.getStringExtra(UiIntentActions.GROUP_ACCOUNT_TYPE),
+                        intent.getStringExtra(UiIntentActions.GROUP_ACCOUNT_DATA_SET)));
                 request.setRawContactIds(intent.getStringArrayListExtra(
-                        UiIntentActions.GROUP_RAW_CONTACT_IDS));
+                        UiIntentActions.GROUP_CONTACT_IDS));
             }
         } else if (Intent.ACTION_CREATE_SHORTCUT.equals(action)) {
             String component = intent.getComponent().getClassName();
diff --git a/src/com/android/contacts/list/ContactsRequest.java b/src/com/android/contacts/list/ContactsRequest.java
index a686752..615fac6 100644
--- a/src/com/android/contacts/list/ContactsRequest.java
+++ b/src/com/android/contacts/list/ContactsRequest.java
@@ -16,10 +16,7 @@
 
 package com.android.contacts.list;
 
-import android.content.Intent;
 import android.net.Uri;
-import android.os.Parcel;
-import android.os.Parcelable;
 
 import com.android.contacts.common.model.account.AccountWithDataSet;
 
diff --git a/src/com/android/contacts/list/ContactsUnavailableFragment.java b/src/com/android/contacts/list/ContactsUnavailableFragment.java
index 5c62e5c..99a5b7e 100644
--- a/src/com/android/contacts/list/ContactsUnavailableFragment.java
+++ b/src/com/android/contacts/list/ContactsUnavailableFragment.java
@@ -33,7 +33,7 @@
 
 import com.android.contacts.R;
 import com.android.contacts.activities.ActionBarAdapter.TabState;
-import com.android.contacts.compat.ProviderStatusCompat;
+import com.android.contacts.common.compat.ProviderStatusCompat;
 
 /**
  * Fragment shown when contacts are unavailable. It contains provider status
diff --git a/src/com/android/contacts/list/GroupMemberPickListAdapter.java b/src/com/android/contacts/list/GroupMemberPickListAdapter.java
deleted file mode 100644
index d25aafd..0000000
--- a/src/com/android/contacts/list/GroupMemberPickListAdapter.java
+++ /dev/null
@@ -1,182 +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.list;
-
-import android.content.Context;
-import android.content.CursorLoader;
-import android.database.Cursor;
-import android.net.Uri;
-import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
-import android.provider.ContactsContract.Data;
-import android.provider.ContactsContract.RawContacts;
-import android.text.TextUtils;
-import android.view.View;
-import android.view.ViewGroup;
-
-import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
-import com.android.contacts.common.list.ContactEntryListAdapter;
-import com.android.contacts.common.list.ContactListItemView;
-import com.android.contacts.common.model.account.AccountWithDataSet;
-import com.android.contacts.common.preference.ContactsPreferences;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Adapter for raw contacts owned by an account that are not already members of a given group.
- */
-public class GroupMemberPickListAdapter extends ContactEntryListAdapter {
-
-    static class GroupMembersQuery {
-
-        private static final String[] PROJECTION_PRIMARY = new String[] {
-                Data.RAW_CONTACT_ID,             // 0
-                Data.CONTACT_ID,                 // 1
-                Data.DISPLAY_NAME_PRIMARY,       // 2
-                // Dummy columns overwritten by the cursor wrapper
-                Data.PHOTO_ID,                   // 3
-                Data.LOOKUP_KEY                  // 4
-        };
-
-        private static final String[] PROJECTION_ALTERNATIVE = new String[] {
-                Data.RAW_CONTACT_ID,             // 0
-                Data.CONTACT_ID,                 // 1
-                Data.DISPLAY_NAME_ALTERNATIVE,   // 2
-                // Dummy columns overwritten by the cursor wrapper
-                Data.PHOTO_ID,                   // 3
-                Data.LOOKUP_KEY                  // 4
-        };
-
-        static final int RAW_CONTACT_ID = 0;
-        static final int CONTACT_ID = 1;
-        static final int CONTACT_DISPLAY_NAME = 2;
-        // Provided by the cursor wrapper.
-        static final int CONTACT_PHOTO_ID = 3;
-        // Provided by the cursor wrapper.
-        static final int CONTACT_LOOKUP_KEY = 4;
-
-        private GroupMembersQuery() {
-        }
-    }
-
-    private AccountWithDataSet mAccount;
-    private final Set<String> mRawContactIds = new HashSet<>();
-
-    private final CharSequence mUnknownNameText;
-
-    public GroupMemberPickListAdapter(Context context) {
-        super(context);
-        mUnknownNameText = context.getText(android.R.string.unknownName);
-    }
-
-    public GroupMemberPickListAdapter setAccount(AccountWithDataSet account) {
-        mAccount = account;
-        return this;
-    }
-
-    public GroupMemberPickListAdapter setRawContactIds(ArrayList<String> rawContactIds) {
-        mRawContactIds.clear();
-        mRawContactIds.addAll(rawContactIds);
-        return this;
-    }
-
-    @Override
-    public String getContactDisplayName(int position) {
-        final Cursor cursor = (Cursor) getItem(position);
-        return cursor.getString(GroupMembersQuery.CONTACT_DISPLAY_NAME);
-    }
-
-    @Override
-    public void configureLoader(CursorLoader loader, long directoryId) {
-        final Uri uri = Data.CONTENT_URI.buildUpon()
-                .appendQueryParameter(Data.VISIBLE_CONTACTS_ONLY, "true")
-                .build();
-        loader.setUri(uri);
-        loader.setProjection(
-                getContactNameDisplayOrder() == ContactsPreferences.DISPLAY_ORDER_PRIMARY
-                        ? GroupMembersQuery.PROJECTION_PRIMARY
-                        : GroupMembersQuery.PROJECTION_ALTERNATIVE);
-        loader.setSelection(getSelection());
-        loader.setSelectionArgs(getSelectionArgs());
-        loader.setSortOrder(getSortOrder() == ContactsPreferences.SORT_ORDER_PRIMARY
-                ? Data.SORT_KEY_PRIMARY : Data.SORT_KEY_ALTERNATIVE
-                + " COLLATE LOCALIZED ASC");
-    }
-
-    private String getSelection() {
-        // Select raw contacts by account
-        String result = RawContacts.ACCOUNT_NAME + "=? AND " + RawContacts.ACCOUNT_TYPE + "=? AND "
-                + Data.MIMETYPE + "=? AND ";
-        if (TextUtils.isEmpty(mAccount.dataSet)) {
-            result += Data.DATA_SET + " IS NULL";
-        } else {
-            result += Data.DATA_SET + "=?";
-        }
-        return result;
-    }
-
-    private String[] getSelectionArgs() {
-        final ArrayList<String> result = new ArrayList<>();
-        result.add(mAccount.name);
-        result.add(mAccount.type);
-        result.add(GroupMembership.CONTENT_ITEM_TYPE);
-        if (!TextUtils.isEmpty(mAccount.dataSet)) result.add(mAccount.dataSet);
-        return result.toArray(new String[0]);
-    }
-
-    public Uri getRawContactUri(int position) {
-        final Cursor cursor = (Cursor) getItem(position);
-        final long rawContactId = cursor.getLong(GroupMembersQuery.RAW_CONTACT_ID);
-        return Data.CONTENT_URI.buildUpon()
-                .appendPath(Long.toString(rawContactId))
-                .build();
-    }
-
-    @Override
-    protected ContactListItemView newView(Context context, int partition, Cursor cursor,
-            int position, ViewGroup parent) {
-        final ContactListItemView view =
-                super.newView(context, partition, cursor, position, parent);
-        view.setUnknownNameText(mUnknownNameText);
-        return view;
-    }
-
-    @Override
-    protected void bindView(View v, int partition, Cursor cursor, int position) {
-        super.bindView(v, partition, cursor, position);
-        final ContactListItemView view = (ContactListItemView) v;
-        bindName(view, cursor);
-        bindViewId(view, cursor, GroupMembersQuery.RAW_CONTACT_ID);
-        bindPhoto(view, cursor);
-    }
-
-    private void bindName(ContactListItemView view, Cursor cursor) {
-        view.showDisplayName(cursor, GroupMembersQuery.CONTACT_DISPLAY_NAME,
-                getContactNameDisplayOrder());
-    }
-
-    private void bindPhoto(final ContactListItemView view, Cursor cursor) {
-        final long photoId = cursor.isNull(GroupMembersQuery.CONTACT_PHOTO_ID)
-                ? 0 : cursor.getLong(GroupMembersQuery.CONTACT_PHOTO_ID);
-        final DefaultImageRequest imageRequest = photoId == 0
-                ? getDefaultImageRequestFromCursor(cursor, GroupMembersQuery.CONTACT_DISPLAY_NAME,
-                GroupMembersQuery.CONTACT_LOOKUP_KEY)
-                : null;
-        getPhotoLoader().loadThumbnail(view.getPhotoView(), photoId, false, getCircularPhotos(),
-                imageRequest);
-    }
-}
diff --git a/src/com/android/contacts/list/GroupMemberPickerFragment.java b/src/com/android/contacts/list/GroupMemberPickerFragment.java
index edd5739..605758f 100644
--- a/src/com/android/contacts/list/GroupMemberPickerFragment.java
+++ b/src/com/android/contacts/list/GroupMemberPickerFragment.java
@@ -15,54 +15,46 @@
  */
 package com.android.contacts.list;
 
-import android.app.LoaderManager.LoaderCallbacks;
-import android.content.CursorLoader;
 import android.content.Loader;
 import android.database.Cursor;
 import android.database.CursorWrapper;
-import android.net.Uri;
 import android.os.Bundle;
-import android.provider.ContactsContract.Contacts;
-import android.provider.ContactsContract.Data;
 import android.util.Log;
-import android.util.Pair;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 
 import com.android.contacts.common.R;
 import com.android.contacts.common.list.ContactEntryListFragment;
-import com.android.contacts.common.model.account.AccountWithDataSet;
-import com.android.contacts.common.preference.ContactsPreferences;
-import com.android.contacts.list.GroupMemberPickListAdapter.GroupMembersQuery;
+import com.android.contacts.common.list.ContactListAdapter.ContactQuery;
+import com.android.contacts.common.list.ContactListFilter;
+import com.android.contacts.common.list.DefaultContactListAdapter;
 
 import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
 
 /**
  * Fragment containing raw contacts for a specified account that are not already in a group.
  */
 public class GroupMemberPickerFragment extends
-        ContactEntryListFragment<GroupMemberPickListAdapter> {
+        ContactEntryListFragment<DefaultContactListAdapter> {
 
     public static final String TAG = "GroupMemberPicker";
 
-    private static final String KEY_ACCOUNT = "account";
+    private static final String KEY_ACCOUNT_NAME = "accountName";
+    private static final String KEY_ACCOUNT_TYPE = "accountType";
+    private static final String KEY_ACCOUNT_DATA_SET = "accountDataSet";
     private static final String KEY_RAW_CONTACT_IDS = "rawContactIds";
 
-    private static final String ARG_ACCOUNT = "account";
+    private static final String ARG_ACCOUNT_NAME = "accountName";
+    private static final String ARG_ACCOUNT_TYPE = "accountType";
+    private static final String ARG_ACCOUNT_DATA_SET = "accountDataSet";
     private static final String ARG_RAW_CONTACT_IDS = "rawContactIds";
 
-    private static final int LOADER_CONTACT_ENTITY = 0;
-
     /** Callbacks for host of {@link GroupMemberPickerFragment}. */
     public interface Listener {
 
         /** Invoked when a potential group member is selected. */
-        void onGroupMemberClicked(Uri uri);
+        void onGroupMemberClicked(long contactId);
     }
 
     /**
@@ -82,23 +74,14 @@
             mIndex = new int[mCount];
 
             if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                Log.v(TAG, "FilterCursorWrapper starting size cursor=" + mCount + " photosMap="
-                        + (mContactPhotosMap == null ? 0 : mContactPhotosMap.size()));
+                Log.v(TAG, "FilterCursorWrapper starting cursor size is " + mCount);
             }
 
-            final Set<String> uniqueRawContactIds = new HashSet<String>();
-
             for (int i = 0; i < mCount; i++) {
                 super.moveToPosition(i);
-                final String rawContactId = getString(GroupMembersQuery.RAW_CONTACT_ID);
-                if (!mRawContactIds.contains(rawContactId)
-                        && !uniqueRawContactIds.contains(rawContactId)) {
+                final String contactId = getString(ContactQuery.CONTACT_ID);
+                if (!mRawContactIds.contains(contactId)) {
                     mIndex[mPos++] = i;
-                    uniqueRawContactIds.add(rawContactId);
-                }
-                if (mRawContactIds.contains(rawContactId) && mContactPhotosMap != null) {
-                    final long contactId = getLong(GroupMembersQuery.CONTACT_ID);
-                    mContactPhotosMap.remove(contactId);
                 }
             }
             mCount = mPos;
@@ -106,82 +89,11 @@
             super.moveToFirst();
 
             if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                Log.v(TAG, "FilterCursorWrapper ending  size cursor=" + mCount + " photosMap="
-                        + (mContactPhotosMap == null ? 0 : mContactPhotosMap.size()));
+                Log.v(TAG, "FilterCursorWrapper ending cursor size is" + mCount);
             }
         }
 
         @Override
-        public int getColumnIndex(String columnName) {
-            final int index = getColumnIndexForContactColumn(columnName);
-            return index < 0 ? super.getColumnIndex(columnName) : index;
-        }
-
-        @Override
-        public int getColumnIndexOrThrow(String columnName) {
-            final int index = getColumnIndexForContactColumn(columnName);
-            return index < 0 ? super.getColumnIndexOrThrow(columnName) : index;
-        }
-
-        private int getColumnIndexForContactColumn(String columnName) {
-            if (Data.PHOTO_ID.equals(columnName)) {
-                return GroupMembersQuery.CONTACT_PHOTO_ID;
-            }
-            if (Data.LOOKUP_KEY.equals(columnName)) {
-                return GroupMembersQuery.CONTACT_LOOKUP_KEY;
-            }
-            return -1;
-        }
-
-        @Override
-        public String[] getColumnNames() {
-            final String displayNameColumnName =
-                    getContactNameDisplayOrder() == ContactsPreferences.DISPLAY_ORDER_PRIMARY
-                            ? Data.DISPLAY_NAME_PRIMARY
-                            : Data.DISPLAY_NAME_ALTERNATIVE;
-            return new String[] {
-                    Data._ID,
-                    Data.CONTACT_ID,
-                    displayNameColumnName,
-                    Data.PHOTO_ID,
-                    Data.LOOKUP_KEY,
-            };
-        }
-
-        @Override
-        public String getString(int columnIndex) {
-            if (columnIndex == GroupMembersQuery.CONTACT_LOOKUP_KEY) {
-                if (columnIndex == GroupMembersQuery.CONTACT_PHOTO_ID) {
-                    final long contactId = getLong(GroupMembersQuery.CONTACT_ID);
-                    final Pair<Long,String> pair = getContactPhotoPair(contactId);
-                    if (pair != null) {
-                        return pair.second;
-                    }
-                }
-                return null;
-            }
-            return super.getString(columnIndex);
-        }
-
-        @Override
-        public long getLong(int columnIndex) {
-            if (columnIndex == GroupMembersQuery.CONTACT_PHOTO_ID) {
-                final long contactId = getLong(GroupMembersQuery.CONTACT_ID);
-                final Pair<Long,String> pair = getContactPhotoPair(contactId);
-                if (pair != null) {
-                    return pair.first;
-                }
-                return 0;
-            }
-            return super.getLong(columnIndex);
-        }
-
-        private Pair<Long,String> getContactPhotoPair(long contactId) {
-            return mContactPhotosMap != null && mContactPhotosMap.containsKey(contactId)
-                ? mContactPhotosMap.get(contactId) : null;
-        }
-
-        @Override
         public boolean move(int offset) {
             return moveToPosition(mPos + offset);
         }
@@ -223,49 +135,19 @@
         }
     }
 
-    private final LoaderCallbacks<Cursor> mContactsEntityCallbacks = new LoaderCallbacks<Cursor>() {
-
-        private final String[] PROJECTION = new String[] {
-                Data.CONTACT_ID,
-                Data.PHOTO_ID,
-                Data.LOOKUP_KEY
-        };
-
-        @Override
-        public CursorLoader onCreateLoader(int id, Bundle args) {
-            final CursorLoader loader = new CursorLoader(getActivity());
-            loader.setUri(Data.CONTENT_URI);
-            loader.setProjection(PROJECTION);
-            return loader;
-        }
-        @Override
-        public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
-            mContactPhotosMap = new HashMap<>();
-            while (cursor.moveToNext()) {
-                final long contactId = cursor.getLong(0);
-                final Pair<Long, String> pair =
-                        new Pair(cursor.getLong(1), cursor.getString(2));
-                mContactPhotosMap.put(contactId, pair);
-            }
-            GroupMemberPickerFragment.super.startLoading();
-        }
-
-        @Override
-        public void onLoaderReset(Loader<Cursor> loader) {}
-    };
-
-    private AccountWithDataSet mAccount;
+    private String mAccountName;
+    private String mAccountType;
+    private String mAccountDataSet;
     private ArrayList<String> mRawContactIds;
-    // Contact ID longs to Pairs of photo ID and contact lookup keys
-    private Map<Long, Pair<Long,String>> mContactPhotosMap;
-
     private Listener mListener;
 
-    public static GroupMemberPickerFragment newInstance(AccountWithDataSet account,
-            ArrayList<String> rawContactids) {
+    public static GroupMemberPickerFragment newInstance(String accountName, String accountType,
+            String accountDataSet, ArrayList<String> rawContactIds) {
         final Bundle args = new Bundle();
-        args.putParcelable(ARG_ACCOUNT, account);
-        args.putStringArrayList(ARG_RAW_CONTACT_IDS, rawContactids);
+        args.putString(ARG_ACCOUNT_NAME, accountName);
+        args.putString(ARG_ACCOUNT_TYPE, accountType);
+        args.putString(ARG_ACCOUNT_DATA_SET, accountDataSet);
+        args.putStringArrayList(ARG_RAW_CONTACT_IDS, rawContactIds);
 
         final GroupMemberPickerFragment fragment = new GroupMemberPickerFragment();
         fragment.setArguments(args);
@@ -273,40 +155,38 @@
     }
 
     public GroupMemberPickerFragment() {
-        setQuickContactEnabled(false);
         setPhotoLoaderEnabled(true);
+        setSectionHeaderDisplayEnabled(false);
         setVisibleScrollbarEnabled(true);
+
         setHasOptionsMenu(true);
     }
 
     @Override
     public void onCreate(Bundle savedState) {
-        super.onCreate(savedState);
         if (savedState == null) {
-            mAccount = getArguments().getParcelable(ARG_ACCOUNT);
+            mAccountName = getArguments().getString(ARG_ACCOUNT_NAME);
+            mAccountType = getArguments().getString(ARG_ACCOUNT_TYPE);
+            mAccountDataSet = getArguments().getString(ARG_ACCOUNT_DATA_SET);
             mRawContactIds = getArguments().getStringArrayList(ARG_RAW_CONTACT_IDS);
         } else {
-            mAccount = savedState.getParcelable(KEY_ACCOUNT);
+            mAccountName = savedState.getString(KEY_ACCOUNT_NAME);
+            mAccountType = savedState.getString(KEY_ACCOUNT_TYPE);
+            mAccountDataSet = savedState.getString(KEY_ACCOUNT_DATA_SET);
             mRawContactIds = savedState.getStringArrayList(KEY_RAW_CONTACT_IDS);
         }
+        super.onCreate(savedState);
     }
 
     @Override
     public void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
-        outState.putParcelable(KEY_ACCOUNT, mAccount);
+        outState.putString(KEY_ACCOUNT_NAME, mAccountName);
+        outState.putString(KEY_ACCOUNT_TYPE, mAccountType);
+        outState.putString(KEY_ACCOUNT_DATA_SET, mAccountDataSet);
         outState.putStringArrayList(KEY_RAW_CONTACT_IDS, mRawContactIds);
     }
 
-    @Override
-    protected void startLoading() {
-        if (mContactPhotosMap == null) {
-            getLoaderManager().restartLoader(LOADER_CONTACT_ENTITY, null, mContactsEntityCallbacks);
-        } else {
-            super.startLoading();
-        }
-    }
-
     public void setListener(Listener listener) {
         mListener = listener;
     }
@@ -324,24 +204,22 @@
     }
 
     @Override
-    protected GroupMemberPickListAdapter createListAdapter() {
-        final GroupMemberPickListAdapter adapter = new GroupMemberPickListAdapter(getActivity());
+    protected DefaultContactListAdapter createListAdapter() {
+        final DefaultContactListAdapter adapter = new DefaultContactListAdapter(getActivity());
+        adapter.setFilter(ContactListFilter.createGroupMembersFilter(
+                mAccountType, mAccountName, mAccountDataSet));
+        adapter.setSectionHeaderDisplayEnabled(true);
         adapter.setDisplayPhotos(true);
         return adapter;
     }
 
     @Override
-    protected void configureAdapter() {
-        super.configureAdapter();
-        getAdapter().setAccount(mAccount);
-        getAdapter().setRawContactIds(mRawContactIds);
-        getAdapter().setEmptyListEnabled(true);
-    }
-
-    @Override
     protected void onItemClick(int position, long id) {
         if (mListener != null) {
-            mListener.onGroupMemberClicked(getAdapter().getRawContactUri(position));
+            final long contactId = getAdapter().getContactId(position);
+            if (contactId > 0) {
+                mListener.onGroupMemberClicked(contactId);
+            }
         }
     }
 }
diff --git a/src/com/android/contacts/list/GroupMemberTileAdapter.java b/src/com/android/contacts/list/GroupMemberTileAdapter.java
deleted file mode 100644
index 15e67f1..0000000
--- a/src/com/android/contacts/list/GroupMemberTileAdapter.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2012 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.list;
-
-import android.content.Context;
-import android.database.Cursor;
-
-import com.android.contacts.GroupMemberLoader;
-import com.android.contacts.common.list.ContactEntry;
-import com.android.contacts.common.list.ContactTileAdapter;
-import com.android.contacts.common.list.ContactTileView;
-import com.google.common.collect.Lists;
-
-import java.util.ArrayList;
-
-/**
- * Tile adapter for groups.
- */
-public class GroupMemberTileAdapter extends ContactTileAdapter {
-
-    public GroupMemberTileAdapter(Context context, ContactTileView.Listener listener, int numCols) {
-        super(context, listener, numCols, DisplayType.GROUP_MEMBERS);
-    }
-
-    @Override
-    protected void bindColumnIndices() {
-        mIdIndex = GroupMemberLoader.GroupDetailQuery.CONTACT_ID;
-        mLookupIndex = GroupMemberLoader.GroupDetailQuery.CONTACT_LOOKUP_KEY;
-        mPhotoUriIndex = GroupMemberLoader.GroupDetailQuery.CONTACT_PHOTO_URI;
-        mNameIndex = GroupMemberLoader.GroupDetailQuery.CONTACT_DISPLAY_NAME_PRIMARY;
-        mPresenceIndex = GroupMemberLoader.GroupDetailQuery.CONTACT_PRESENCE_STATUS;
-        mStatusIndex = GroupMemberLoader.GroupDetailQuery.CONTACT_STATUS;
-    }
-
-    @Override
-    protected void saveNumFrequentsFromCursor(Cursor cursor) {
-        mNumFrequents = 0;
-    }
-
-    @Override
-    public int getItemViewType(int position) {
-        return ViewTypes.STARRED;
-    }
-
-    @Override
-    protected int getDividerPosition(Cursor cursor) {
-        // No divider
-        return -1;
-    }
-
-    @Override
-    public int getCount() {
-        if (mContactCursor == null || mContactCursor.isClosed()) {
-            return 0;
-        }
-
-        return getRowCount(mContactCursor.getCount());
-    }
-
-    @Override
-    public ArrayList<ContactEntry> getItem(int position) {
-        final ArrayList<ContactEntry> resultList = Lists.newArrayListWithCapacity(mColumnCount);
-        int contactIndex = position * mColumnCount;
-
-        for (int columnCounter = 0; columnCounter < mColumnCount; columnCounter++) {
-            resultList.add(createContactEntryFromCursor(mContactCursor, contactIndex));
-            contactIndex++;
-        }
-        return resultList;
-    }
-}
diff --git a/src/com/android/contacts/list/ProviderStatusWatcher.java b/src/com/android/contacts/list/ProviderStatusWatcher.java
deleted file mode 100644
index 51f776b..0000000
--- a/src/com/android/contacts/list/ProviderStatusWatcher.java
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * Copyright (C) 2012 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.list;
-
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.ContentObserver;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Handler;
-import android.provider.ContactsContract.ProviderStatus;
-import android.util.Log;
-
-import com.android.contacts.compat.ProviderStatusCompat;
-
-import com.google.common.collect.Lists;
-
-import java.util.ArrayList;
-
-/**
- * A singleton that keeps track of the last known provider status.
- *
- * All methods must be called on the UI thread unless noted otherwise.
- *
- * All members must be set on the UI thread unless noted otherwise.
- */
-public class ProviderStatusWatcher extends ContentObserver {
-    private static final String TAG = "ProviderStatusWatcher";
-    private static final boolean DEBUG = false;
-
-    /**
-     * Callback interface invoked when the provider status changes.
-     */
-    public interface ProviderStatusListener {
-        public void onProviderStatusChange();
-    }
-
-    private static final String[] PROJECTION = new String[] {
-        ProviderStatus.STATUS
-    };
-
-    /**
-     * We'll wait for this amount of time on the UI thread if the load hasn't finished.
-     */
-    private static final int LOAD_WAIT_TIMEOUT_MS = 1000;
-
-    private static ProviderStatusWatcher sInstance;
-
-    private final Context mContext;
-    private final Handler mHandler = new Handler();
-
-    private final Object mSignal = new Object();
-
-    private int mStartRequestedCount;
-
-    private LoaderTask mLoaderTask;
-
-    /** Last known provider status.  This can be changed on a worker thread.
-     *  See {@link ProviderStatus#STATUS} */
-    private Integer mProviderStatus;
-
-    private final ArrayList<ProviderStatusListener> mListeners = Lists.newArrayList();
-
-    private final Runnable mStartLoadingRunnable = new Runnable() {
-        @Override
-        public void run() {
-            startLoading();
-        }
-    };
-
-    /**
-     * Returns the singleton instance.
-     */
-    public synchronized static ProviderStatusWatcher getInstance(Context context) {
-        if (sInstance == null) {
-            sInstance = new ProviderStatusWatcher(context);
-        }
-        return sInstance;
-    }
-
-    private ProviderStatusWatcher(Context context) {
-        super(null);
-        mContext = context;
-    }
-
-    /** Add a listener. */
-    public void addListener(ProviderStatusListener listener) {
-        mListeners.add(listener);
-    }
-
-    /** Remove a listener */
-    public void removeListener(ProviderStatusListener listener) {
-        mListeners.remove(listener);
-    }
-
-    private void notifyListeners() {
-        if (DEBUG) {
-            Log.d(TAG, "notifyListeners: " + mListeners.size());
-        }
-        if (isStarted()) {
-            for (ProviderStatusListener listener : mListeners) {
-                listener.onProviderStatusChange();
-            }
-        }
-    }
-
-    private boolean isStarted() {
-        return mStartRequestedCount > 0;
-    }
-
-    /**
-     * Starts watching the provider status.  {@link #start()} and {@link #stop()} calls can be
-     * nested.
-     */
-    public void start() {
-        if (++mStartRequestedCount == 1) {
-            mContext.getContentResolver()
-                .registerContentObserver(ProviderStatus.CONTENT_URI, false, this);
-            startLoading();
-
-            if (DEBUG) {
-                Log.d(TAG, "Start observing");
-            }
-        }
-    }
-
-    /**
-     * Stops watching the provider status.
-     */
-    public void stop() {
-        if (!isStarted()) {
-            Log.e(TAG, "Already stopped");
-            return;
-        }
-        if (--mStartRequestedCount == 0) {
-
-            mHandler.removeCallbacks(mStartLoadingRunnable);
-
-            mContext.getContentResolver().unregisterContentObserver(this);
-            if (DEBUG) {
-                Log.d(TAG, "Stop observing");
-            }
-        }
-    }
-
-    /**
-     * @return last known provider status.
-     *
-     * If this method is called when we haven't started the status query or the query is still in
-     * progress, it will start a query in a worker thread if necessary, and *wait for the result*.
-     *
-     * This means this method is essentially a blocking {@link ProviderStatus#CONTENT_URI} query.
-     * This URI is not backed by the file system, so is usually fast enough to perform on the main
-     * thread, but in extreme cases (when the system takes a while to bring up the contacts
-     * provider?) this may still cause ANRs.
-     *
-     * In order to avoid that, if we can't load the status within {@link #LOAD_WAIT_TIMEOUT_MS},
-     * we'll give up and just returns {@link ProviderStatusCompat#STATUS_BUSY} in order to unblock
-     * the UI thread.  The actual result will be delivered later via {@link ProviderStatusListener}.
-     * (If {@link ProviderStatusCompat#STATUS_BUSY} is returned, the app (should) shows an according
-     * message, like "contacts are being updated".)
-     */
-    public int getProviderStatus() {
-        waitForLoaded();
-
-        if (mProviderStatus == null) {
-            return ProviderStatusCompat.STATUS_BUSY;
-        }
-
-        return mProviderStatus;
-    }
-
-    private void waitForLoaded() {
-        if (mProviderStatus == null) {
-            if (mLoaderTask == null) {
-                // For some reason the loader couldn't load the status.  Let's start it again.
-                startLoading();
-            }
-            synchronized (mSignal) {
-                try {
-                    mSignal.wait(LOAD_WAIT_TIMEOUT_MS);
-                } catch (InterruptedException ignore) {
-                }
-            }
-        }
-    }
-
-    private void startLoading() {
-        if (mLoaderTask != null) {
-            return; // Task already running.
-        }
-
-        if (DEBUG) {
-            Log.d(TAG, "Start loading");
-        }
-
-        mLoaderTask = new LoaderTask();
-        mLoaderTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
-    }
-
-    private class LoaderTask extends AsyncTask<Void, Void, Boolean> {
-        @Override
-        protected Boolean doInBackground(Void... params) {
-            try {
-                Cursor cursor = mContext.getContentResolver().query(ProviderStatus.CONTENT_URI,
-                        PROJECTION, null, null, null);
-                if (cursor != null) {
-                    try {
-                        if (cursor.moveToFirst()) {
-                            // Note here we can't just say "Status", as AsyncTask has the "Status"
-                            // enum too.
-                            mProviderStatus = cursor.getInt(0);
-                            return true;
-                        }
-                    } finally {
-                        cursor.close();
-                    }
-                }
-                return false;
-            } finally {
-                synchronized (mSignal) {
-                    mSignal.notifyAll();
-                }
-            }
-        }
-
-        @Override
-        protected void onCancelled(Boolean result) {
-            cleanUp();
-        }
-
-        @Override
-        protected void onPostExecute(Boolean loaded) {
-            cleanUp();
-            if (loaded != null && loaded) {
-                notifyListeners();
-            }
-        }
-
-        private void cleanUp() {
-            mLoaderTask = null;
-        }
-    }
-
-    /**
-     * Called when provider status may has changed.
-     *
-     * This method will be called on a worker thread by the framework.
-     */
-    @Override
-    public void onChange(boolean selfChange, Uri uri) {
-        if (!ProviderStatus.CONTENT_URI.equals(uri)) return;
-
-        // Provider status change is rare, so okay to log.
-        Log.i(TAG, "Provider status changed.");
-
-        mHandler.removeCallbacks(mStartLoadingRunnable); // Remove one in the queue, if any.
-        mHandler.post(mStartLoadingRunnable);
-    }
-}
diff --git a/src/com/android/contacts/list/UiIntentActions.java b/src/com/android/contacts/list/UiIntentActions.java
index 31e5ade..9552942 100644
--- a/src/com/android/contacts/list/UiIntentActions.java
+++ b/src/com/android/contacts/list/UiIntentActions.java
@@ -40,16 +40,28 @@
     public static final String GROUP_NAME_EXTRA_KEY = "com.android.contacts.extra.GROUP";
 
     /**
-     * The account used to filter potential raw contact groups members.
+     * The account name used to filter potential new group members.
      */
-    public static final String GROUP_ACCOUNT_WITH_DATA_SET =
-            "com.android.contacts.extra.GROUP_ACCOUNT_WITH_DATA_SET";
+    public static final String GROUP_ACCOUNT_NAME =
+            "com.android.contacts.extra.GROUP_ACCOUNT_NAME";
 
     /**
-     * The raw contact IDs for existing group members.
+     * The account type used to filter potential new group members.
      */
-    public static final String GROUP_RAW_CONTACT_IDS =
-            "com.android.contacts.extra.GROUP_RAW_CONTACT_IDS";
+    public static final String GROUP_ACCOUNT_TYPE =
+            "com.android.contacts.extra.GROUP_ACCOUNT_TYPE";
+
+    /**
+     * The account data set used to filter potential new group members.
+     */
+    public static final String GROUP_ACCOUNT_DATA_SET =
+            "com.android.contacts.extra.GROUP_ACCOUNT_DATA_SET";
+
+    /**
+     * The contact IDs for existing group members.
+     */
+    public static final String GROUP_CONTACT_IDS =
+            "com.android.contacts.extra.GROUP_CONTACT_IDS";
 
     /**
      * The action for the all contacts list tab.
diff --git a/src/com/android/contacts/quickcontact/QuickContactActivity.java b/src/com/android/contacts/quickcontact/QuickContactActivity.java
index 76e8605..64db298 100644
--- a/src/com/android/contacts/quickcontact/QuickContactActivity.java
+++ b/src/com/android/contacts/quickcontact/QuickContactActivity.java
@@ -209,6 +209,9 @@
 
     /** Used to pass the screen where the user came before launching this Activity. */
     public static final String EXTRA_PREVIOUS_SCREEN_TYPE = "previous_screen_type";
+    /** Used to tell the QuickContact that the previous contact was edited, so it can return an
+     * activity result back to the original Activity that launched it. */
+    public static final String EXTRA_CONTACT_EDITED = "contact_edited";
 
     private static final String TAG = "QuickContact";
 
@@ -1209,6 +1212,9 @@
             return;
         }
         Uri lookupUri = intent.getData();
+        if (intent.getBooleanExtra(EXTRA_CONTACT_EDITED, false)) {
+            setResult(ContactEditorBaseActivity.RESULT_CODE_EDITED);
+        }
 
         // Check to see whether it comes from the old version.
         if (lookupUri != null && LEGACY_AUTHORITY.equals(lookupUri.getAuthority())) {