Add hamburger menu to groups

Bug 28427279
Bug 28891044

Change-Id: Ib5c261ccac48342e5f5447b3042931bb778d62b5
diff --git a/src/com/android/contacts/ContactsDrawerActivity.java b/src/com/android/contacts/ContactsDrawerActivity.java
new file mode 100644
index 0000000..4c45606
--- /dev/null
+++ b/src/com/android/contacts/ContactsDrawerActivity.java
@@ -0,0 +1,313 @@
+/*
+ * 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.CompatUtils;
+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_menu_group_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/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/GroupMembersActivity.java b/src/com/android/contacts/activities/GroupMembersActivity.java
index f1242d6..fd65090 100644
--- a/src/com/android/contacts/activities/GroupMembersActivity.java
+++ b/src/com/android/contacts/activities/GroupMembersActivity.java
@@ -18,6 +18,9 @@
 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.database.Cursor;
 import android.net.Uri;
@@ -26,14 +29,17 @@
 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.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;
 import com.android.contacts.common.editor.SelectAccountDialogFragment;
 import com.android.contacts.common.logging.ListEvent;
@@ -59,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,
@@ -184,14 +190,13 @@
         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);
 
+        final FragmentManager fragmentManager = getFragmentManager();
+        final FragmentTransaction transaction = fragmentManager.beginTransaction();
         // Decide whether to prompt for the account and group name or start loading existing members
         if (mIsInsertAction) {
             // Check if we are in the middle of the insert flow.
@@ -216,7 +221,6 @@
             }
         } else {
             // Add the members list fragment
-            final FragmentManager fragmentManager = getFragmentManager();
             mMembersListFragment = (GroupMembersListFragment)
                     fragmentManager.findFragmentByTag(TAG_GROUP_MEMBERS);
             if (mMembersListFragment == null) {
@@ -291,9 +295,13 @@
 
             mMembersListFragment = GroupMembersListFragment.newInstance(groupUri);
             mMembersListFragment.setListener(this);
-            getFragmentManager().beginTransaction()
-                    .replace(R.id.fragment_container, mMembersListFragment, TAG_GROUP_MEMBERS)
-                    .commit();
+
+            final FragmentManager fragmentManager = getFragmentManager();
+            final FragmentTransaction transaction = fragmentManager.beginTransaction();
+            addGroupsAndFiltersFragments(transaction);
+            transaction.replace(R.id.fragment_container_inner, mMembersListFragment,
+                    TAG_GROUP_MEMBERS).commit();
+
             if (mGroupMetadata != null && mGroupMetadata.editable) {
                 mMembersListFragment.setCheckBoxListListener(this);
             }
@@ -322,6 +330,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
@@ -437,7 +471,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);
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index 6642749..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,26 +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.model.AccountTypeManager;
 import com.android.contacts.common.model.account.AccountWithDataSet;
-import com.android.contacts.common.preference.ContactsPreferenceActivity;
 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;
@@ -101,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;
@@ -116,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";
 
@@ -145,8 +137,6 @@
     private View mFloatingActionButtonContainer;
     private boolean wasLastFabAnimationScaleIn = false;
 
-    private ContactListFilterController mContactListFilterController;
-
     private ContactsUnavailableFragment mContactsUnavailableFragment;
     private ProviderStatusWatcher mProviderStatusWatcher;
     private Integer mProviderStatus;
@@ -157,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;
@@ -167,8 +155,6 @@
     private String[] mTabTitles;
     private final TabPagerListener mTabPagerListener = new TabPagerListener();
 
-    private NavigationView mNavigationView;
-
     private boolean mEnableDebugMenuOptions;
 
     /**
@@ -210,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.
      *
@@ -270,9 +252,6 @@
             Log.d(Constants.PERFORMANCE_TAG, "PeopleActivity.onCreate finish");
         }
         getWindow().setBackgroundDrawable(null);
-        if (CompatUtils.isLollipopCompatible()) {
-            getWindow().setStatusBarColor(Color.TRANSPARENT);
-        }
     }
 
     @Override
@@ -339,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
@@ -392,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
@@ -937,70 +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);
-        }
-
-        mWritableAccounts = AccountTypeManager.getInstance(this).getAccounts(true);
-        initializeFabVisibility();
+    protected void onGroupMenuItemClicked(long groupId) {
+        switchToAllContacts();
+        super.onGroupMenuItemClicked(groupId);
+        mDrawer.closeDrawer(GravityCompat.START);
     }
 
     @Override
@@ -1282,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);
@@ -1423,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
@@ -1465,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);
@@ -1556,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;
@@ -1563,18 +1394,6 @@
         }
     }
 
-    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,
@@ -1584,4 +1403,9 @@
     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/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/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/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);
-    }
-}