Let DefaultContactBrowseListFragment control actionbar, menu and more.

Test: manual or use GoogleContactsTests.apk

Bug: 30944495

Change-Id: Ic31df5cfe946363ff78254b7c82b042c13b107f4
diff --git a/src/com/android/contacts/ContactsDrawerActivity.java b/src/com/android/contacts/ContactsDrawerActivity.java
index 54bc4ad..1cfab16 100644
--- a/src/com/android/contacts/ContactsDrawerActivity.java
+++ b/src/com/android/contacts/ContactsDrawerActivity.java
@@ -281,6 +281,7 @@
 
     @Override
     protected void onNewIntent(Intent newIntent) {
+        mContactListFilterController.checkFilterValidity(false);
         if (ACTION_CREATE_GROUP.equals(newIntent.getAction())) {
             final Uri groupUri = newIntent.getData();
             if (groupUri == null) {
@@ -522,7 +523,7 @@
         }
     }
 
-    protected void updateFilterMenu(ContactListFilter filter) {
+    public void updateFilterMenu(ContactListFilter filter) {
         clearCheckedMenus();
         if (filter != null && filter.isContactsFilterType()) {
             if (mIdMenuMap != null && mIdMenuMap.get(R.id.nav_all_contacts) != null) {
@@ -591,7 +592,7 @@
 
     protected void switchToAllContacts() {
         final Intent intent = new Intent();
-        final ContactListFilter filter = createContactsFilter();
+        final ContactListFilter filter = AccountFilterUtil.createContactsFilter(this);
         intent.putExtra(AccountFilterActivity.EXTRA_CONTACT_LIST_FILTER, filter);
         AccountFilterUtil.handleAccountFilterResult(
                 mContactListFilterController, AppCompatActivity.RESULT_OK, intent);
@@ -605,19 +606,6 @@
                 Assistants.getDuplicatesActivityIntent(this));
     }
 
-    /**
-     * Returns a {@link ContactListFilter} of type
-     * {@link ContactListFilter#FILTER_TYPE_ALL_ACCOUNTS}, or if a custom "Contacts to display"
-     * filter has been set, then one of type {@link ContactListFilter#FILTER_TYPE_CUSTOM}.
-     */
-    protected ContactListFilter createContactsFilter() {
-        final int filterType =
-                ContactListFilterController.getInstance(this).isCustomFilterPersisted()
-                        ? ContactListFilter.FILTER_TYPE_CUSTOM
-                        : ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS;
-        return ContactListFilter.createFilterWithType(filterType);
-    }
-
     private void clearCheckedMenus() {
         clearCheckedMenu(mFilterMenuMap);
         clearCheckedMenu(mGroupMenuMap);
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index 8cef3e3..d596398 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -23,39 +23,30 @@
 import android.content.ActivityNotFoundException;
 import android.content.ContentResolver;
 import android.content.BroadcastReceiver;
-import android.content.ContentUris;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SyncStatusObserver;
 import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.Intents;
 import android.provider.ContactsContract.ProviderStatus;
-import android.provider.ContactsContract.QuickContact;
 import android.support.design.widget.CoordinatorLayout;
-import android.support.design.widget.FloatingActionButton;
 import android.support.design.widget.Snackbar;
 import android.support.v4.content.LocalBroadcastManager;
 import android.support.v4.view.GravityCompat;
 import android.support.v4.widget.SwipeRefreshLayout;
-import android.text.TextUtils;
 import android.util.Log;
 import android.view.Gravity;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.Menu;
-import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.SubMenu;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityEvent;
 import android.widget.ImageButton;
 import android.widget.Toast;
 
@@ -64,74 +55,46 @@
 import com.android.contacts.R;
 import com.android.contacts.common.Experiments;
 import com.android.contacts.common.activity.RequestPermissionsActivity;
-import com.android.contacts.common.compat.CompatUtils;
 import com.android.contacts.common.interactions.ImportExportDialogFragment;
-import com.android.contacts.common.list.ContactEntryListFragment;
 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.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.model.account.GoogleAccountType;
+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.widget.FloatingActionButtonController;
 import com.android.contacts.editor.EditorIntents;
-import com.android.contacts.interactions.ContactDeletionInteraction;
-import com.android.contacts.interactions.ContactMultiDeletionInteraction;
-import com.android.contacts.interactions.ContactMultiDeletionInteraction.MultiContactDeleteListener;
 import com.android.contacts.list.ContactsIntentResolver;
 import com.android.contacts.list.ContactsRequest;
 import com.android.contacts.list.ContactsUnavailableFragment;
 import com.android.contacts.list.DefaultContactBrowseListFragment;
-import com.android.contacts.list.MultiSelectContactsListFragment.OnCheckBoxListActionListener;
-import com.android.contacts.list.OnContactBrowserActionListener;
 import com.android.contacts.list.OnContactsUnavailableActionListener;
 import com.android.contacts.quickcontact.QuickContactActivity;
-import com.android.contacts.util.DialogManager;
-import com.android.contacts.util.SharedPreferenceUtil;
 import com.android.contacts.util.SyncUtil;
 import com.android.contactsbind.experiments.Flags;
 import com.android.contacts.widget.FloatingActionButtonBehavior;
 import com.google.android.libraries.material.featurehighlight.FeatureHighlight;
 
 import java.util.List;
-import java.util.Locale;
 import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * Displays a list to browse contacts.
  */
-public class PeopleActivity extends ContactsDrawerActivity implements
-        View.OnCreateContextMenuListener,
-        View.OnClickListener,
-        ActionBarAdapter.Listener,
-        DialogManager.DialogShowingViewActivity,
-        ContactListFilterController.ContactListFilterListener,
-        ProviderStatusListener,
-        MultiContactDeleteListener,
-        DefaultContactBrowseListFragment.FeatureHighlightCallback {
+public class PeopleActivity extends ContactsDrawerActivity implements ProviderStatusListener {
 
     private static final String TAG = "PeopleActivity";
 
-    private static final String ENABLE_DEBUG_OPTIONS_HIDDEN_CODE = "debug debug!";
-
     private static final String TAG_ALL = "contacts-all";
 
-    private static final int ACTIVITY_REQUEST_CODE_SHARE = 0;
-
-    private final DialogManager mDialogManager = new DialogManager(this);
-
     private ContactsIntentResolver mIntentResolver;
     private ContactsRequest mRequest;
 
-    private ActionBarAdapter mActionBarAdapter;
-    private List<AccountWithDataSet> mWritableAccounts;
     private FloatingActionButtonController mFloatingActionButtonController;
     private View mFloatingActionButtonContainer;
     private boolean wasLastFabAnimationScaleIn = false;
@@ -142,8 +105,6 @@
 
     private BroadcastReceiver mSaveServiceListener;
 
-    private boolean mOptionsMenuContactsAvailable;
-
     private CoordinatorLayout mLayoutRoot;
 
     /**
@@ -153,8 +114,6 @@
 
     private View mContactsView;
 
-    private boolean mEnableDebugMenuOptions;
-
     /**
      * True if this activity instance is a re-created one.  i.e. set true after orientation change.
      * This is set in {@link #onCreate} for later use in {@link #onStart}.
@@ -169,10 +128,6 @@
      */
     private boolean mFragmentInitialized;
 
-    /**
-     * This is to disable {@link #onOptionsItemSelected} when we trying to stop the activity.
-     */
-    private boolean mDisableOptionItemSelected;
 
     /** Sequential ID assigned to each instance; used for logging */
     private final int mInstanceId;
@@ -194,11 +149,12 @@
 
     // Update sync status for accounts in current ContactListFilter
     private void onSyncStateUpdated() {
-        if (mActionBarAdapter.isSearchMode() || mActionBarAdapter.isSelectionMode()) {
+        if (mAllFragment.getActionBarAdapter().isSearchMode()
+                || mAllFragment.getActionBarAdapter().isSelectionMode()) {
             return;
         }
 
-        final ContactListFilter filter = mContactListFilterController.getFilter();
+        final ContactListFilter filter = mAllFragment.getFilter();
         if (filter != null) {
             final SwipeRefreshLayout swipeRefreshLayout = mAllFragment.getSwipeRefreshLayout();
             if (swipeRefreshLayout == null) {
@@ -277,22 +233,12 @@
             finish();
             return;
         }
-        mContactListFilterController = ContactListFilterController.getInstance(this);
-        mContactListFilterController.checkFilterValidity(false);
-        mContactListFilterController.addListener(this);
 
         mProviderStatusWatcher.addListener(this);
 
         mIsRecreatedInstance = (savedState != null);
 
-        // Use FILTER_TYPE_ALL_ACCOUNTS filter if the activity is not a re-created one.
-        // This is useful when user upgrades app while an account filter or a custom filter was
-        // stored in sharedPreference in a previous version of Contacts app.
-        final ContactListFilter filter = mIsRecreatedInstance
-                ? mContactListFilterController.getFilter() : createContactsFilter();
-        persistFilterIfNeeded(filter);
-
-        createViewsAndFragments(savedState);
+        createViewsAndFragments();
 
         if (Log.isLoggable(Constants.PERFORMANCE_TAG, Log.DEBUG)) {
             Log.d(Constants.PERFORMANCE_TAG, "PeopleActivity.onCreate finish");
@@ -300,18 +246,6 @@
         getWindow().setBackgroundDrawable(null);
     }
 
-    private void maybeShowHamburgerFeatureHighlight() {
-        if (!mActionBarAdapter.isSearchMode() && !mActionBarAdapter.isSelectionMode()
-                && SharedPreferenceUtil.getShouldShowHamburgerPromo(this)) {
-            final FeatureHighlight hamburgerFeatureHighlight =
-                    mActionBarAdapter.getHamburgerFeatureHighlight();
-            if (hamburgerFeatureHighlight != null) {
-                hamburgerFeatureHighlight.show(this);
-                SharedPreferenceUtil.setHamburgerPromoDisplayedBefore(this);
-            }
-        }
-    }
-
     @Override
     protected void onNewIntent(Intent intent) {
         if (ContactsDrawerActivity.ACTION_CREATE_GROUP.equals(intent.getAction())) {
@@ -324,9 +258,12 @@
             finish();
             return;
         }
-        mActionBarAdapter.initialize(null, mRequest);
 
-        mContactListFilterController.checkFilterValidity(false);
+        // Re-initialize ActionBarAdapter because {@link #onNewIntent(Intent)} doesn't invoke
+        // {@link Fragment#onActivityCreated(Bundle)} where we initialize ActionBarAdapter
+        // initially.
+        mAllFragment.setContactsRequest(mRequest);
+        mAllFragment.initializeActionBarAdapter(null);
 
         // Re-configure fragments.
         configureFragments(true /* from request */);
@@ -372,7 +309,7 @@
         return true;
     }
 
-    private void createViewsAndFragments(Bundle savedState) {
+    private void createViewsAndFragments() {
         setContentView(R.layout.people_activity);
 
         final FragmentManager fragmentManager = getFragmentManager();
@@ -390,29 +327,25 @@
             transaction.add(R.id.contacts_list_container, mAllFragment, TAG_ALL);
         }
 
-        mAllFragment.setFeatureHighlightCallback(this);
-        mAllFragment.setOnContactListActionListener(new ContactBrowserActionListener());
-        mAllFragment.setCheckBoxListListener(new CheckBoxListListener());
-        mAllFragment.setListType(mContactListFilterController.getFilterListType());
-
-        // Hide all fragments for now.  We adjust visibility when we get
-        // onAction(Action.STOP_SEARCH_AND_SELECTION_MODE) from ActionBarAdapter.
-        transaction.hide(mAllFragment);
+        mAllFragment.setContactsAvailable(areContactsAvailable());
+        mAllFragment.setListType();
+        mAllFragment.setContactsRequest(mRequest);
 
         transaction.commitAllowingStateLoss();
         fragmentManager.executePendingTransactions();
 
-        mActionBarAdapter = new ActionBarAdapter(this, this, getSupportActionBar(), mToolbar);
-        mActionBarAdapter.initialize(savedState, mRequest);
-
         // Configure floating action button
         mFloatingActionButtonContainer = findViewById(R.id.floating_action_button_container);
         final ImageButton floatingActionButton
                 = (ImageButton) findViewById(R.id.floating_action_button);
-        floatingActionButton.setOnClickListener(this);
+        floatingActionButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                onFabClicked();
+            }
+        });
         mFloatingActionButtonController = new FloatingActionButtonController(this,
                 mFloatingActionButtonContainer, floatingActionButton);
-        initializeFabVisibility();
 
         invalidateOptionsMenuIfNeeded();
 
@@ -454,7 +387,6 @@
 
     @Override
     protected void onPause() {
-        mOptionsMenuContactsAvailable = false;
         mProviderStatusWatcher.stop();
 
         LocalBroadcastManager.getInstance(this).unregisterReceiver(mSaveServiceListener);
@@ -474,12 +406,6 @@
         mProviderStatusWatcher.start();
         updateViewConfiguration(true);
 
-        // Re-register the listener, which may have been cleared when onSaveInstanceState was
-        // called.  See also: onSaveInstanceState
-        mActionBarAdapter.setListener(this);
-        mDisableOptionItemSelected = false;
-        updateFragmentsVisibility();
-
         if (Flags.getInstance(this).getBoolean(Experiments.PULL_TO_REFRESH)) {
             mStatusChangeListenerHandle = ContentResolver.addStatusChangeListener(
                     ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE
@@ -488,7 +414,8 @@
                     mSyncStatusObserver);
             onSyncStateUpdated();
         }
-        maybeShowHamburgerFeatureHighlight();
+        mAllFragment.maybeShowHamburgerFeatureHighlight();
+        initializeFabVisibility();
 
         mSaveServiceListener = new SaveServiceListener();
         LocalBroadcastManager.getInstance(this).registerReceiver(mSaveServiceListener,
@@ -498,16 +425,6 @@
     @Override
     protected void onDestroy() {
         mProviderStatusWatcher.removeListener(this);
-
-        // Some of variables will be null if this Activity redirects Intent.
-        // See also onCreate() or other methods called during the Activity's initialization.
-        if (mActionBarAdapter != null) {
-            mActionBarAdapter.setListener(null);
-        }
-        if (mContactListFilterController != null) {
-            mContactListFilterController.removeListener(this);
-        }
-
         super.onDestroy();
     }
 
@@ -518,7 +435,7 @@
             boolean searchMode = mRequest.isSearchMode();
             switch (actionCode) {
                 case ContactsRequest.ACTION_ALL_CONTACTS:
-                    filter = createContactsFilter();
+                    filter = AccountFilterUtil.createContactsFilter(this);
                     break;
                 case ContactsRequest.ACTION_CONTACTS_WITH_PHONES:
                     filter = ContactListFilter.createFilterWithType(
@@ -534,7 +451,7 @@
             }
 
             if (filter != null) {
-                mContactListFilterController.setContactListFilter(filter, /* persistent */ false);
+                mAllFragment.setContactListFilter(filter);
                 searchMode = false;
             }
 
@@ -542,39 +459,26 @@
                 searchMode = false;
             }
 
-            mActionBarAdapter.setSearchMode(searchMode);
+            mAllFragment.getActionBarAdapter().setSearchMode(searchMode);
             configureContactListFragmentForRequest();
         }
 
-        configureContactListFragment();
-
-        invalidateOptionsMenuIfNeeded();
+        mAllFragment.configureContactListFragment();
     }
 
     private void initializeFabVisibility() {
-        final boolean hideFab = mActionBarAdapter.isSearchMode()
-                || mActionBarAdapter.isSelectionMode()
-                || !shouldShowFabForAccount();
-        mFloatingActionButtonContainer.setVisibility(hideFab ? View.GONE : View.VISIBLE);
+        mFloatingActionButtonContainer.setVisibility(shouldHideFab() ? View.GONE : View.VISIBLE);
         mFloatingActionButtonController.resetIn();
-        wasLastFabAnimationScaleIn = !hideFab;
+        wasLastFabAnimationScaleIn = !shouldHideFab();
     }
 
-    private boolean shouldShowFabForAccount() {
-        return isCurrentAccountFilterWritable()
-                || isAllContactsFilter(mContactListFilterController.getFilter());
+    private boolean shouldHideFab() {
+        if (mAllFragment.getActionBarAdapter() == null) return false;
+        return mAllFragment.getActionBarAdapter().isSearchMode()
+                || mAllFragment.getActionBarAdapter().isSelectionMode();
     }
 
-    private boolean isCurrentAccountFilterWritable() {
-        final ContactListFilter currentFilter = mContactListFilterController.getFilter();
-        final AccountWithDataSet accountOfCurrentFilter = new AccountWithDataSet(
-                currentFilter.accountName, currentFilter.accountType, currentFilter.dataSet);
-        return accountOfCurrentFilter.isLocalAccount()
-                || (mWritableAccounts != null
-                && mWritableAccounts.contains(accountOfCurrentFilter));
-    }
-
-    private void showFabWithAnimation(boolean showFab) {
+    public void showFabWithAnimation(boolean showFab) {
         if (mFloatingActionButtonContainer == null) {
             return;
         }
@@ -594,99 +498,6 @@
         }
     }
 
-    @Override
-    public void onContactListFilterChanged() {
-        if (mAllFragment == null || !mAllFragment.isAdded()) {
-            return;
-        }
-
-        setFilterAndUpdateTitle(mContactListFilterController.getFilter());
-        // Scroll to top after filter is changed.
-        mAllFragment.getListView().setSelection(0);
-        showFabWithAnimation(shouldShowFabForAccount());
-
-        invalidateOptionsMenuIfNeeded();
-    }
-
-    /**
-     * Handler for action bar actions.
-     */
-    @Override
-    public void onAction(int action) {
-        switch (action) {
-            case ActionBarAdapter.Listener.Action.START_SELECTION_MODE:
-                mAllFragment.displayCheckBoxes(true);
-                startSearchOrSelectionMode();
-                break;
-            case ActionBarAdapter.Listener.Action.START_SEARCH_MODE:
-                if (!mIsRecreatedInstance) {
-                    Logger.logScreenView(this, ScreenType.SEARCH);
-                }
-                startSearchOrSelectionMode();
-                break;
-            case ActionBarAdapter.Listener.Action.BEGIN_STOPPING_SEARCH_AND_SELECTION_MODE:
-                showFabWithAnimation(shouldShowFabForAccount());
-                break;
-            case ActionBarAdapter.Listener.Action.STOP_SEARCH_AND_SELECTION_MODE:
-                // If queryString is empty, fragment data will not be reloaded,
-                // so hamburger promo should be checked now.
-                // If not empty, promo should be checked and displayed after reloading. (b/30706521)
-                if (TextUtils.isEmpty(mAllFragment.getQueryString())) {
-                    maybeShowHamburgerFeatureHighlight();
-                }
-                setQueryTextToFragment("");
-                updateFragmentsVisibility();
-                invalidateOptionsMenu();
-                showFabWithAnimation(shouldShowFabForAccount());
-                // Determine whether the account has pullToRefresh feature
-                if (Flags.getInstance(this).getBoolean(Experiments.PULL_TO_REFRESH)) {
-                    setSwipeRefreshLayoutEnabledOrNot(mContactListFilterController.getFilter());
-                }
-                break;
-            case ActionBarAdapter.Listener.Action.CHANGE_SEARCH_QUERY:
-                final String queryString = mActionBarAdapter.getQueryString();
-                setQueryTextToFragment(queryString);
-                updateDebugOptionsVisibility(
-                        ENABLE_DEBUG_OPTIONS_HIDDEN_CODE.equals(queryString));
-                break;
-            default:
-                throw new IllegalStateException("Unkonwn ActionBarAdapter action: " + action);
-        }
-    }
-
-    private void startSearchOrSelectionMode() {
-        configureFragments(false /* from request */);
-        updateFragmentsVisibility();
-        invalidateOptionsMenu();
-        showFabWithAnimation(/* showFab */ false);
-        if (!SharedPreferenceUtil.getHamburgerPromoTriggerActionHappenedBefore(this)) {
-            SharedPreferenceUtil.setHamburgerPromoTriggerActionHappenedBefore(this);
-        }
-    }
-
-    @Override
-    public void onUpButtonPressed() {
-        onBackPressed();
-    }
-
-    private void updateDebugOptionsVisibility(boolean visible) {
-        if (mEnableDebugMenuOptions != visible) {
-            mEnableDebugMenuOptions = visible;
-            invalidateOptionsMenu();
-        }
-    }
-
-    /**
-     * Updates the fragment/view visibility according to the current mode, such as
-     * {@link ActionBarAdapter#isSearchMode()}.
-     */
-    private void updateFragmentsVisibility() {
-        if (!mActionBarAdapter.isSelectionMode()) {
-            mAllFragment.displayCheckBoxes(false);
-        }
-        invalidateOptionsMenu();
-    }
-
     private void setQueryTextToFragment(String query) {
         mAllFragment.setQueryString(query, true);
         mAllFragment.setVisibleScrollbarEnabled(!mAllFragment.isSearchMode());
@@ -698,8 +509,7 @@
             mAllFragment.setSelectedContactUri(contactUri);
         }
 
-        setFilterAndUpdateTitle(mContactListFilterController.getFilter());
-        setQueryTextToFragment(mActionBarAdapter.getQueryString());
+        setQueryTextToFragment(mAllFragment.getActionBarAdapter().getQueryString());
 
         if (mRequest.isDirectorySearchEnabled()) {
             mAllFragment.setDirectorySearchMode(DirectoryListLoader.SEARCH_MODE_DEFAULT);
@@ -708,28 +518,9 @@
         }
     }
 
-    private void configureContactListFragment() {
-        // Filter may be changed when this Activity is in background.
-        setFilterAndUpdateTitle(mContactListFilterController.getFilter());
-
-        mAllFragment.setVerticalScrollbarPosition(getScrollBarPosition());
-        mAllFragment.setSelectionVisible(false);
-    }
-
-    private int getScrollBarPosition() {
-        return isRTL() ? View.SCROLLBAR_POSITION_LEFT : View.SCROLLBAR_POSITION_RIGHT;
-    }
-
-    private boolean isRTL() {
-        final Locale locale = Locale.getDefault();
-        return TextUtils.getLayoutDirectionFromLocale(locale) == View.LAYOUT_DIRECTION_RTL;
-    }
-
     @Override
     public void onFiltersLoaded(List<ContactListFilter> accountFilterItems) {
         super.onFiltersLoaded(accountFilterItems);
-        mWritableAccounts =
-                AccountTypeManager.getInstance(this).getAccounts(/* contactWritableOnly */ true);
         initializeFabVisibility();
     }
 
@@ -773,22 +564,28 @@
             }
 
             if (mAllFragment != null) {
+                getFragmentManager().beginTransaction()
+                        .show(mAllFragment)
+                        .commitAllowingStateLoss();
+                mAllFragment.setContactsAvailable(areContactsAvailable());
                 mAllFragment.setEnabled(true);
             }
         } else {
+            final FragmentTransaction transaction = getFragmentManager().beginTransaction();
             // Setting up the page so that the user can still use the app
             // even without an account.
             if (mAllFragment != null) {
                 mAllFragment.setEnabled(false);
+                transaction.hide(mAllFragment);
             }
             if (mContactsUnavailableFragment == null) {
                 mContactsUnavailableFragment = new ContactsUnavailableFragment();
                 mContactsUnavailableFragment.setOnContactsUnavailableActionListener(
                         new ContactsUnavailableFragmentListener());
-                getFragmentManager().beginTransaction()
-                        .replace(R.id.contacts_unavailable_container, mContactsUnavailableFragment)
-                        .commitAllowingStateLoss();
+                transaction.replace(
+                        R.id.contacts_unavailable_container, mContactsUnavailableFragment);
             }
+            transaction.commitAllowingStateLoss();
             mContactsUnavailableFragment.updateStatus(mProviderStatus);
 
             // Show the contactsUnavailableView, and hide the mContactsView so that we don't
@@ -815,94 +612,6 @@
         return !allAccounts.get(0).isLocalAccount();
     }
 
-    private final class ContactBrowserActionListener implements OnContactBrowserActionListener {
-        ContactBrowserActionListener() {}
-
-        @Override
-        public void onSelectionChange() {
-
-        }
-
-        @Override
-        public void onViewContactAction(int position, Uri contactLookupUri,
-                boolean isEnterpriseContact) {
-            if (isEnterpriseContact) {
-                // No implicit intent as user may have a different contacts app in work profile.
-                QuickContact.showQuickContact(PeopleActivity.this, new Rect(), contactLookupUri,
-                        QuickContactActivity.MODE_FULLY_EXPANDED, null);
-            } else {
-                final Intent intent = ImplicitIntentsUtil.composeQuickContactIntent(
-                        PeopleActivity.this, contactLookupUri,
-                        QuickContactActivity.MODE_FULLY_EXPANDED);
-                final int previousScreen;
-                if (mAllFragment.isSearchMode()) {
-                    previousScreen = ScreenType.SEARCH;
-                } else {
-                    if (isAllContactsFilter(mContactListFilterController.getFilter())) {
-                        if (position < mAllFragment.getAdapter().getNumberOfFavorites()) {
-                            previousScreen = ScreenType.FAVORITES;
-                        } else {
-                            previousScreen = ScreenType.ALL_CONTACTS;
-                        }
-                    } else {
-                        previousScreen = ScreenType.LIST_ACCOUNT;
-                    }
-                }
-                Logger.logListEvent(ListEvent.ActionType.CLICK,
-                        /* listType */ getListTypeIncludingSearch(),
-                        /* count */ mAllFragment.getAdapter().getCount(),
-                        /* clickedIndex */ position, /* numSelected */ 0);
-                intent.putExtra(QuickContactActivity.EXTRA_PREVIOUS_SCREEN_TYPE, previousScreen);
-                ImplicitIntentsUtil.startActivityInApp(PeopleActivity.this, intent);
-            }
-        }
-
-        @Override
-        public void onDeleteContactAction(Uri contactUri) {
-            ContactDeletionInteraction.start(PeopleActivity.this, contactUri, false);
-        }
-
-        @Override
-        public void onFinishAction() {
-            onBackPressed();
-        }
-
-        @Override
-        public void onInvalidSelection() {
-            ContactListFilter filter;
-            ContactListFilter currentFilter = mAllFragment.getFilter();
-            if (currentFilter != null
-                    && currentFilter.filterType == ContactListFilter.FILTER_TYPE_SINGLE_CONTACT) {
-                filter = createContactsFilter();
-                setFilterAndUpdateTitle(filter);
-            } else {
-                filter = ContactListFilter.createFilterWithType(
-                        ContactListFilter.FILTER_TYPE_SINGLE_CONTACT);
-                setFilterAndUpdateTitle(filter, /* restoreSelectedUri */ false);
-            }
-            persistFilterIfNeeded(filter);
-        }
-    }
-
-    private final class CheckBoxListListener implements OnCheckBoxListActionListener {
-        @Override
-        public void onStartDisplayingCheckBoxes() {
-            mActionBarAdapter.setSelectionMode(true);
-            invalidateOptionsMenu();
-        }
-
-        @Override
-        public void onSelectedContactIdsChanged() {
-            mActionBarAdapter.setSelectionCount(mAllFragment.getSelectedContactIds().size());
-            invalidateOptionsMenu();
-        }
-
-        @Override
-        public void onStopDisplayingCheckBoxes() {
-            mActionBarAdapter.setSelectionMode(false);
-        }
-    }
-
     private class ContactsUnavailableFragmentListener
             implements OnContactsUnavailableActionListener {
         ContactsUnavailableFragmentListener() {}
@@ -925,232 +634,19 @@
         }
     }
 
-    @Override
-    public boolean onCreateOptionsMenu(Menu menu) {
-        if (!areContactsAvailable()) {
-            // If contacts aren't available, hide all menu items.
-            return false;
-        }
-        super.onCreateOptionsMenu(menu);
-
-        MenuInflater inflater = getMenuInflater();
-        inflater.inflate(R.menu.people_options, menu);
-
-        return true;
-    }
-
     private void invalidateOptionsMenuIfNeeded() {
-        if (isOptionsMenuChanged()) {
+        if (mAllFragment != null
+                || mAllFragment.getOptionsMenuContactsAvailable() != areContactsAvailable()) {
             invalidateOptionsMenu();
         }
     }
 
-    public boolean isOptionsMenuChanged() {
-        if (mOptionsMenuContactsAvailable != areContactsAvailable()) {
-            return true;
-        }
-
-        if (mAllFragment != null && mAllFragment.isOptionsMenuChanged()) {
-            return true;
-        }
-
-        return false;
-    }
-
-    @Override
-    public boolean onPrepareOptionsMenu(Menu menu) {
-        mOptionsMenuContactsAvailable = areContactsAvailable();
-        if (!mOptionsMenuContactsAvailable) {
-            return false;
-        }
-
-        final boolean isSearchOrSelectionMode = mActionBarAdapter.isSearchMode()
-                || mActionBarAdapter.isSelectionMode();
-        makeMenuItemVisible(menu, R.id.menu_search, !isSearchOrSelectionMode);
-
-        final boolean showSelectedContactOptions = mActionBarAdapter.isSelectionMode()
-                && mAllFragment.getSelectedContactIds().size() != 0;
-        makeMenuItemVisible(menu, R.id.menu_share, showSelectedContactOptions);
-        makeMenuItemVisible(menu, R.id.menu_delete, showSelectedContactOptions);
-        final boolean showLinkContactsOptions = mActionBarAdapter.isSelectionMode()
-                && mAllFragment.getSelectedContactIds().size() > 1;
-        makeMenuItemVisible(menu, R.id.menu_join, showLinkContactsOptions);
-
-        // Debug options need to be visible even in search mode.
-        makeMenuItemVisible(menu, R.id.export_database, mEnableDebugMenuOptions &&
-                hasExportIntentHandler());
-
-        return true;
-    }
-
-    private boolean hasExportIntentHandler() {
-        final Intent intent = new Intent();
-        intent.setAction("com.android.providers.contacts.DUMP_DATABASE");
-        final List<ResolveInfo> receivers = getPackageManager().queryIntentActivities(intent,
-                PackageManager.MATCH_DEFAULT_ONLY);
-        return receivers != null && receivers.size() > 0;
-    }
-
-    private void makeMenuItemVisible(Menu menu, int itemId, boolean visible) {
-        final MenuItem item = menu.findItem(itemId);
-        if (item != null) {
-            item.setVisible(visible);
-        }
-    }
-
-    @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
-        if (mDisableOptionItemSelected) {
-            return false;
-        }
-
-        switch (item.getItemId()) {
-            case android.R.id.home: {
-                // The home icon on the action bar is pressed
-                if (mActionBarAdapter.isUpShowing()) {
-                    // "UP" icon press -- should be treated as "back".
-                    onBackPressed();
-                }
-                return true;
-            }
-            case R.id.menu_search: {
-                onSearchRequested();
-                return true;
-            }
-            case R.id.menu_share: {
-                shareSelectedContacts();
-                return true;
-            }
-            case R.id.menu_join: {
-                Logger.logListEvent(ListEvent.ActionType.LINK,
-                        /* listType */ getListTypeIncludingSearch(),
-                        /* count */ mAllFragment.getAdapter().getCount(), /* clickedIndex */ -1,
-                        /* numSelected */ mAllFragment.getAdapter().getSelectedContactIds().size());
-                joinSelectedContacts();
-                return true;
-            }
-            case R.id.menu_delete: {
-                deleteSelectedContacts();
-                return true;
-            }
-            case R.id.export_database: {
-                final Intent intent = new Intent("com.android.providers.contacts.DUMP_DATABASE");
-                intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
-                ImplicitIntentsUtil.startActivityOutsideApp(this, intent);
-                return true;
-            }
-        }
-        return super.onOptionsItemSelected(item);
-    }
-
     private void showImportExportDialogFragment(){
         ImportExportDialogFragment.show(getFragmentManager(), areContactsAvailable(),
                 PeopleActivity.class, ImportExportDialogFragment.EXPORT_MODE_ALL_CONTACTS);
     }
 
     @Override
-    public boolean onSearchRequested() { // Search key pressed.
-        if (!mActionBarAdapter.isSelectionMode()) {
-            mActionBarAdapter.setSearchMode(true);
-        }
-        return true;
-    }
-
-    /**
-     * Share all contacts that are currently selected in mAllFragment. This method is pretty
-     * inefficient for handling large numbers of contacts. I don't expect this to be a problem.
-     */
-    private void shareSelectedContacts() {
-        final StringBuilder uriListBuilder = new StringBuilder();
-        for (Long contactId : mAllFragment.getSelectedContactIds()) {
-            final Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
-            final Uri lookupUri = Contacts.getLookupUri(getContentResolver(), contactUri);
-            if (lookupUri == null) {
-                continue;
-            }
-            final List<String> pathSegments = lookupUri.getPathSegments();
-            if (pathSegments.size() < 2) {
-                continue;
-            }
-            final String lookupKey = pathSegments.get(pathSegments.size() - 2);
-            if (uriListBuilder.length() > 0) {
-                uriListBuilder.append(':');
-            }
-            uriListBuilder.append(Uri.encode(lookupKey));
-        }
-        if (uriListBuilder.length() == 0) {
-            return;
-        }
-        final Uri uri = Uri.withAppendedPath(
-                Contacts.CONTENT_MULTI_VCARD_URI,
-                Uri.encode(uriListBuilder.toString()));
-        final Intent intent = new Intent(Intent.ACTION_SEND);
-        intent.setType(Contacts.CONTENT_VCARD_TYPE);
-        intent.putExtra(Intent.EXTRA_STREAM, uri);
-        try {
-            startActivityForResult(Intent.createChooser(intent, getResources().getQuantityString(
-                    R.plurals.title_share_via,
-                    /* quantity */ mAllFragment.getSelectedContactIds().size()))
-                    , ACTIVITY_REQUEST_CODE_SHARE);
-        } catch (final ActivityNotFoundException ex) {
-            Toast.makeText(this, R.string.share_error, Toast.LENGTH_SHORT).show();
-        }
-    }
-
-    private void joinSelectedContacts() {
-        final Intent intent = ContactSaveService.createJoinSeveralContactsIntent(
-                this, mAllFragment.getSelectedContactIdsArray());
-        this.startService(intent);
-
-        mActionBarAdapter.setSelectionMode(false);
-    }
-
-    private void deleteSelectedContacts() {
-        ContactMultiDeletionInteraction.start(PeopleActivity.this,
-                mAllFragment.getSelectedContactIds());
-    }
-
-    @Override
-    public void onDeletionFinished() {
-        // The parameters count and numSelected are both the number of contacts before deletion.
-        Logger.logListEvent(ListEvent.ActionType.DELETE,
-                /* listType */ getListTypeIncludingSearch(),
-                /* count */ mAllFragment.getAdapter().getCount(), /* clickedIndex */ -1,
-                /* numSelected */ mAllFragment.getSelectedContactIds().size());
-        mActionBarAdapter.setSelectionMode(false);
-    }
-
-    private int getListTypeIncludingSearch() {
-        return mAllFragment.isSearchMode()
-                ? ListEvent.ListType.SEARCH_RESULT : mAllFragment.getListType();
-    }
-
-    @Override
-    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
-        switch (requestCode) {
-            // TODO: Using the new startActivityWithResultFromFragment API this should not be needed
-            // anymore
-            case ContactEntryListFragment.ACTIVITY_REQUEST_CODE_PICKER:
-                if (resultCode == RESULT_OK) {
-                    mAllFragment.onPickerResult(data);
-                }
-            case ACTIVITY_REQUEST_CODE_SHARE:
-                Logger.logListEvent(ListEvent.ActionType.SHARE,
-                    /* listType */ getListTypeIncludingSearch(),
-                    /* 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
-//                    // to confirm user selection in MODE_PICK_MULTIPLE_PHONES.
-//                    finish();
-//                }
-//                break;
-        }
-    }
-
-    @Override
     public boolean onKeyDown(int keyCode, KeyEvent event) {
         // TODO move to the fragment
 
@@ -1160,14 +656,14 @@
                 // If COMBINING_ACCENT is set, it's not a unicode character.
                 && ((unicodeChar & KeyCharacterMap.COMBINING_ACCENT) == 0)
                 && !Character.isWhitespace(unicodeChar)) {
-            if (mActionBarAdapter.isSelectionMode()) {
+            if (mAllFragment.getActionBarAdapter().isSelectionMode()) {
                 // Ignore keyboard input when in selection mode.
                 return true;
             }
             String query = new String(new int[]{unicodeChar}, 0, 1);
-            if (!mActionBarAdapter.isSearchMode()) {
-                mActionBarAdapter.setSearchMode(true);
-                mActionBarAdapter.setQueryString(query);
+            if (!mAllFragment.getActionBarAdapter().isSearchMode()) {
+                mAllFragment.getActionBarAdapter().setSearchMode(true);
+                mAllFragment.getActionBarAdapter().setQueryString(query);
                 return true;
             }
         }
@@ -1183,153 +679,47 @@
 
         if (mDrawer.isDrawerOpen(GravityCompat.START)) {
             mDrawer.closeDrawer(GravityCompat.START);
-        } else if (mActionBarAdapter.isSelectionMode()) {
-            mActionBarAdapter.setSelectionMode(false);
+        } else if (mAllFragment.getActionBarAdapter().isSelectionMode()) {
+            mAllFragment.getActionBarAdapter().setSelectionMode(false);
             mAllFragment.displayCheckBoxes(false);
-        } else if (mActionBarAdapter.isSearchMode()) {
-            mActionBarAdapter.setSearchMode(false);
-
+        } else if (mAllFragment.getActionBarAdapter().isSearchMode()) {
+            mAllFragment.getActionBarAdapter().setSearchMode(false);
             if (mAllFragment.wasSearchResultClicked()) {
                 mAllFragment.resetSearchResultClicked();
             } else {
                 Logger.logScreenView(this, ScreenType.SEARCH_EXIT);
                 Logger.logSearchEvent(mAllFragment.createSearchState());
             }
-        } else if (!isAllContactsFilter(mContactListFilterController.getFilter())) {
+        } else if (!isAllContactsFilter(mAllFragment.getFilter())) {
             switchToAllContacts();
         } else {
             super.onBackPressed();
         }
     }
 
-    @Override
-    protected void onSaveInstanceState(Bundle outState) {
-        super.onSaveInstanceState(outState);
-        mActionBarAdapter.onSaveInstanceState(outState);
-
-        // Clear the listener to make sure we don't get callbacks after onSaveInstanceState,
-        // in order to avoid doing fragment transactions after it.
-        // TODO Figure out a better way to deal with the issue.
-        mDisableOptionItemSelected = true;
-        mActionBarAdapter.setListener(null);
-    }
-
-    @Override
-    protected void onRestoreInstanceState(Bundle savedInstanceState) {
-        super.onRestoreInstanceState(savedInstanceState);
-        if (mActionBarAdapter.isSearchMode()) {
-            mActionBarAdapter.setFocusOnSearchView();
-        }
-    }
-
-    @Override
-    public DialogManager getDialogManager() {
-        return mDialogManager;
-    }
-
-    @Override
-    public void onClick(View view) {
-        switch (view.getId()) {
-            case R.id.floating_action_button:
-                onFabClicked();
-                break;
-            default:
-                Log.wtf(TAG, "Unexpected onClick event from " + view);
-        }
-    }
-
     public void onFabClicked() {
         final Intent intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI);
-        final Bundle extras = getIntent().getExtras();
-        if (extras != null) {
-            final ContactListFilter filter = mContactListFilterController.getFilter();
-            // If we are in account view, we pass the account explicitly in order to
-            // create contact in the account. This will prevent the default account dialog
-            // from being displayed.
-            if (!isAllContactsFilter(filter) && !isDeviceContactsFilter(filter)) {
-                final Account account = new Account(filter.accountName, filter.accountType);
-                extras.putParcelable(Intents.Insert.EXTRA_ACCOUNT, account);
-                extras.putString(Intents.Insert.EXTRA_DATA_SET, filter.dataSet);
-            }
-            intent.putExtras(extras);
+        Bundle extras = getIntent().getExtras();
+        if (extras == null) {
+            extras = new Bundle();
         }
+        final ContactListFilter filter = mAllFragment.getFilter();
+        // If we are in account view, we pass the account explicitly in order to
+        // create contact in the account. This will prevent the default account dialog
+        // from being displayed.
+        if (!isAllContactsFilter(filter) && !isDeviceContactsFilter(filter)) {
+            final Account account = new Account(filter.accountName, filter.accountType);
+            extras.putParcelable(Intents.Insert.EXTRA_ACCOUNT, account);
+            extras.putString(Intents.Insert.EXTRA_DATA_SET, filter.dataSet);
+        }
+        intent.putExtras(extras);
         try {
             ImplicitIntentsUtil.startActivityInApp(PeopleActivity.this, intent);
         } catch (ActivityNotFoundException ex) {
-            Toast.makeText(PeopleActivity.this, R.string.missing_app,
-                    Toast.LENGTH_SHORT).show();
+            Toast.makeText(PeopleActivity.this, R.string.missing_app, Toast.LENGTH_SHORT).show();
         }
     }
 
-    private void setFilterAndUpdateTitle(ContactListFilter filter) {
-        setFilterAndUpdateTitle(filter, true);
-    }
-
-    private void setFilterAndUpdateTitle(ContactListFilter filter, boolean restoreSelectedUri) {
-        mAllFragment.setFilter(filter, restoreSelectedUri);
-
-        mAllFragment.setListType(mContactListFilterController.getFilterListType());
-
-        updateFilterMenu(filter);
-
-        if (getSupportActionBar() != null) {
-            String actionBarTitle;
-            if (filter.filterType == ContactListFilter.FILTER_TYPE_DEVICE_CONTACTS) {
-                actionBarTitle = getString(R.string.account_phone);
-            } else if (!TextUtils.isEmpty(filter.accountName)) {
-                actionBarTitle = getActionBarTitleForAccount(filter);
-            } else {
-                actionBarTitle = getString(R.string.contactsList);
-            }
-            getSupportActionBar().setTitle(actionBarTitle);
-            if (CompatUtils.isNCompatible()) {
-                this.setTitle(actionBarTitle);
-                getWindow().getDecorView()
-                        .sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
-            }
-        }
-
-        // Determine whether the account has pullToRefresh feature
-        if (Flags.getInstance(this).getBoolean(Experiments.PULL_TO_REFRESH)) {
-            setSwipeRefreshLayoutEnabledOrNot(filter);
-        }
-    }
-
-    private void setSwipeRefreshLayoutEnabledOrNot(ContactListFilter filter) {
-        final SwipeRefreshLayout swipeRefreshLayout = mAllFragment.getSwipeRefreshLayout();
-        if (swipeRefreshLayout == null) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "Can not load swipeRefreshLayout, swipeRefreshLayout is null");
-            }
-            return;
-        }
-
-        swipeRefreshLayout.setRefreshing(false);
-        swipeRefreshLayout.setEnabled(false);
-
-        if (filter != null && !mActionBarAdapter.isSearchMode()
-                && !mActionBarAdapter.isSelectionMode()) {
-            final List<AccountWithDataSet> accounts = AccountTypeManager.getInstance(this)
-                    .getAccounts(/* contactsWritableOnly */ true);
-            if (filter.isSyncable(accounts)) {
-                swipeRefreshLayout.setEnabled(true);
-            }
-        }
-    }
-
-    private String getActionBarTitleForAccount(ContactListFilter filter) {
-        if (GoogleAccountType.ACCOUNT_TYPE.equals(filter.accountType)) {
-            return getString(R.string.title_from_google);
-        }
-        return getString(R.string.title_from_other_accounts, filter.accountName);
-    }
-
-    // Persist filter only when it's of the type FILTER_TYPE_ALL_ACCOUNTS.
-    private void persistFilterIfNeeded(ContactListFilter filter) {
-        mContactListFilterController.setContactListFilter(filter,
-                /* persistent */ isAllContactsFilter(filter));
-    }
-
     private boolean isAllContactsFilter(ContactListFilter filter) {
         return filter != null && filter.isContactsFilterType();
     }
@@ -1345,12 +735,7 @@
 
     @Override
     protected ContactListFilter getContactListFilter() {
-        return mContactListFilterController.getFilter();
-    }
-
-    @Override
-    public void onLoadFinishedCallback() {
-        maybeShowHamburgerFeatureHighlight();
+        return mAllFragment.getFilter();
     }
 
     private void onGroupDeleted(Intent intent) {
diff --git a/src/com/android/contacts/common/util/AccountFilterUtil.java b/src/com/android/contacts/common/util/AccountFilterUtil.java
index 76975a6..66bffdc 100644
--- a/src/com/android/contacts/common/util/AccountFilterUtil.java
+++ b/src/com/android/contacts/common/util/AccountFilterUtil.java
@@ -162,4 +162,17 @@
             return null;
         }
     }
+
+    /**
+     * Returns a {@link ContactListFilter} of type
+     * {@link ContactListFilter#FILTER_TYPE_ALL_ACCOUNTS}, or if a custom "Contacts to display"
+     * filter has been set, then one of type {@link ContactListFilter#FILTER_TYPE_CUSTOM}.
+     */
+    public static ContactListFilter createContactsFilter(Context context) {
+        final int filterType =
+                ContactListFilterController.getInstance(context).isCustomFilterPersisted()
+                        ? ContactListFilter.FILTER_TYPE_CUSTOM
+                        : ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS;
+        return ContactListFilter.createFilterWithType(filterType);
+    }
 }
diff --git a/src/com/android/contacts/interactions/ContactMultiDeletionInteraction.java b/src/com/android/contacts/interactions/ContactMultiDeletionInteraction.java
index 173f66e..ff0d978 100644
--- a/src/com/android/contacts/interactions/ContactMultiDeletionInteraction.java
+++ b/src/com/android/contacts/interactions/ContactMultiDeletionInteraction.java
@@ -75,21 +75,22 @@
     private TreeSet<Long> mContactIds;
     private Context mContext;
     private AlertDialog mDialog;
+    private MultiContactDeleteListener mListener;
 
     /**
      * Starts the interaction.
      *
-     * @param activity the activity within which to start the interaction
+     * @param hostFragment the fragment within which to start the interaction
      * @param contactIds the IDs of contacts to be deleted
      * @return the newly created interaction
      */
     public static ContactMultiDeletionInteraction start(
-            Activity activity, TreeSet<Long> contactIds) {
+            Fragment hostFragment, TreeSet<Long> contactIds) {
         if (contactIds == null) {
             return null;
         }
 
-        final FragmentManager fragmentManager = activity.getFragmentManager();
+        final FragmentManager fragmentManager = hostFragment.getFragmentManager();
         ContactMultiDeletionInteraction fragment =
                 (ContactMultiDeletionInteraction) fragmentManager.findFragmentByTag(FRAGMENT_TAG);
         if (fragment == null) {
@@ -291,13 +292,10 @@
     protected void doDeleteContact(long[] contactIds) {
         mContext.startService(ContactSaveService.createDeleteMultipleContactsIntent(mContext,
                 contactIds));
-        notifyListenerActivity();
+        mListener.onDeletionFinished();
     }
 
-    private void notifyListenerActivity() {
-        if (getActivity() instanceof MultiContactDeleteListener) {
-            final MultiContactDeleteListener listener = (MultiContactDeleteListener) getActivity();
-            listener.onDeletionFinished();
-        }
+    public void setListener(MultiContactDeleteListener listener) {
+        mListener = listener;
     }
 }
diff --git a/src/com/android/contacts/list/ContactBrowseListFragment.java b/src/com/android/contacts/list/ContactBrowseListFragment.java
index da33b55..262856c 100644
--- a/src/com/android/contacts/list/ContactBrowseListFragment.java
+++ b/src/com/android/contacts/list/ContactBrowseListFragment.java
@@ -680,9 +680,4 @@
             return mPersistentSelectionPrefix + "-" + mFilter.getId();
         }
     }
-
-    public boolean isOptionsMenuChanged() {
-        // This fragment does not have an option menu of its own
-        return false;
-    }
 }
diff --git a/src/com/android/contacts/list/DefaultContactBrowseListFragment.java b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
index a25e769..7428e7a 100644
--- a/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
+++ b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
@@ -16,19 +16,31 @@
 package com.android.contacts.list;
 
 import android.accounts.Account;
+import android.app.Activity;
+import android.content.ActivityNotFoundException;
 import android.content.ContentResolver;
+import android.content.ContentUris;
 import android.content.Context;
 import android.content.CursorLoader;
+import android.content.Intent;
 import android.content.Loader;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.database.Cursor;
+import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Bundle;
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.Directory;
+import android.support.v4.app.FragmentActivity;
 import android.support.v4.widget.SwipeRefreshLayout;
 import android.text.TextUtils;
+import android.util.Log;
 import android.view.Gravity;
 import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
@@ -37,27 +49,56 @@
 import android.widget.ImageView;
 import android.widget.LinearLayout.LayoutParams;
 import android.widget.TextView;
+import android.widget.Toast;
 
+import com.android.contacts.ContactSaveService;
+import com.android.contacts.ContactsDrawerActivity;
 import com.android.contacts.R;
+import com.android.contacts.activities.ActionBarAdapter;
 import com.android.contacts.activities.PeopleActivity;
 import com.android.contacts.common.Experiments;
+import com.android.contacts.common.compat.CompatUtils;
+import com.android.contacts.common.list.ContactEntryListFragment;
 import com.android.contacts.common.list.ContactListAdapter;
 import com.android.contacts.common.list.ContactListFilter;
+import com.android.contacts.common.list.ContactListFilterController;
+import com.android.contacts.common.list.ContactListFilterController.ContactListFilterListener;
 import com.android.contacts.common.list.ContactListItemView;
 import com.android.contacts.common.list.DefaultContactListAdapter;
 import com.android.contacts.common.list.FavoritesAndContactsLoader;
+import com.android.contacts.common.logging.ListEvent;
+import com.android.contacts.common.logging.Logger;
+import com.android.contacts.common.logging.ScreenEvent;
 import com.android.contacts.common.model.AccountTypeManager;
 import com.android.contacts.common.model.account.AccountWithDataSet;
+import com.android.contacts.common.model.account.GoogleAccountType;
+import com.android.contacts.common.util.AccountFilterUtil;
+import com.android.contacts.common.util.ImplicitIntentsUtil;
+import com.android.contacts.interactions.ContactDeletionInteraction;
+import com.android.contacts.interactions.ContactMultiDeletionInteraction;
+import com.android.contacts.interactions.ContactMultiDeletionInteraction.MultiContactDeleteListener;
+import com.android.contacts.quickcontact.QuickContactActivity;
+import com.android.contacts.util.SharedPreferenceUtil;
 import com.android.contacts.util.SyncUtil;
 import com.android.contactsbind.experiments.Flags;
 
+import com.google.android.libraries.material.featurehighlight.FeatureHighlight;
+
 import java.util.List;
+import java.util.Locale;
 
 /**
  * Fragment containing a contact list used for browsing (as compared to
  * picking a contact with one of the PICK intents).
  */
 public class DefaultContactBrowseListFragment extends ContactBrowseListFragment {
+
+    private static final String TAG = "DefaultListFragment";
+    private static final String ENABLE_DEBUG_OPTIONS_HIDDEN_CODE = "debug debug!";
+    private static final String KEY_DELETION_IN_PROGRESS = "deletionInProgress";
+
+    private static final int ACTIVITY_REQUEST_CODE_SHARE = 0;
+
     private View mSearchHeaderView;
     private View mSearchProgress;
     private View mEmptyAccountView;
@@ -65,11 +106,114 @@
     private View mAccountFilterContainer;
     private TextView mSearchProgressText;
     private SwipeRefreshLayout mSwipeRefreshLayout;
-    private FeatureHighlightCallback mCallback;
 
-    public interface FeatureHighlightCallback {
-        void onLoadFinishedCallback();
-    }
+    private boolean mContactsAvailable;
+    private boolean mEnableDebugMenuOptions;
+    private boolean mIsRecreatedInstance;
+    private boolean mOptionsMenuContactsAvailable;
+
+    /**
+     * This is to tell whether we need to restart ContactMultiDeletionInteraction and set listener.
+     * if screen is rotated while deletion dialog is shown.
+     */
+    private boolean mIsDeletionInProgress;
+
+    /**
+     * This is to disable {@link #onOptionsItemSelected} when we trying to stop the
+     * activity/fragment.
+     */
+    private boolean mDisableOptionItemSelected;
+
+    private ActionBarAdapter mActionBarAdapter;
+    private ContactMultiDeletionInteraction mMultiDeletionInteraction;
+    private ContactsRequest mContactsRequest;
+    protected ContactListFilterController mContactListFilterController;
+
+    private final ContactListFilterListener mFilterListener = new ContactListFilterListener() {
+        @Override
+        public void onContactListFilterChanged() {
+            final ContactListFilter filter = mContactListFilterController.getFilter();
+            setFilterAndUpdateTitle(filter);
+
+            // Scroll to top after filter is changed.
+            getListView().setSelection(0);
+
+            getActivity().invalidateOptionsMenu();
+        }
+    };
+
+    private final ActionBarAdapter.Listener mActionBarListener = new ActionBarAdapter.Listener() {
+        @Override
+        public void onAction(int action) {
+            switch (action) {
+                case ActionBarAdapter.Listener.Action.START_SELECTION_MODE:
+                    displayCheckBoxes(true);
+                    startSearchOrSelectionMode();
+                    break;
+                case ActionBarAdapter.Listener.Action.START_SEARCH_MODE:
+                    if (!mIsRecreatedInstance) {
+                        Logger.logScreenView(getActivity(), ScreenEvent.ScreenType.SEARCH);
+                    }
+                    startSearchOrSelectionMode();
+                    break;
+                case ActionBarAdapter.Listener.Action.BEGIN_STOPPING_SEARCH_AND_SELECTION_MODE:
+                    ((PeopleActivity) getActivity()).showFabWithAnimation(/* showFab */ true);
+                    break;
+                case ActionBarAdapter.Listener.Action.STOP_SEARCH_AND_SELECTION_MODE:
+                    // If queryString is empty, fragment data will not be reloaded,
+                    // so hamburger promo should be checked now.
+                    // Otherwise, promo should be checked and displayed after reloading, b/30706521.
+                    if (TextUtils.isEmpty(getQueryString())) {
+                        maybeShowHamburgerFeatureHighlight();
+                    }
+                    setQueryTextToFragment("");
+                    maybeHideCheckBoxes();
+                    getActivity().invalidateOptionsMenu();
+                    ((PeopleActivity) getActivity()).showFabWithAnimation(/* showFab */ true);
+                    // Determine whether the account has pullToRefresh feature
+                    if (Flags.getInstance(getContext()).getBoolean(Experiments.PULL_TO_REFRESH)) {
+                        setSwipeRefreshLayoutEnabledOrNot(getFilter());
+                    }
+                    break;
+                case ActionBarAdapter.Listener.Action.CHANGE_SEARCH_QUERY:
+                    final String queryString = mActionBarAdapter.getQueryString();
+                    setQueryTextToFragment(queryString);
+                    updateDebugOptionsVisibility(
+                            ENABLE_DEBUG_OPTIONS_HIDDEN_CODE.equals(queryString));
+                    break;
+                default:
+                    throw new IllegalStateException("Unknown ActionBarAdapter action: " + action);
+            }
+        }
+
+        private void startSearchOrSelectionMode() {
+            configureContactListFragment();
+            maybeHideCheckBoxes();
+            getActivity().invalidateOptionsMenu();
+            ((PeopleActivity) getActivity()).showFabWithAnimation(/* showFab */ false);
+            final Context context = getContext();
+            if (!SharedPreferenceUtil.getHamburgerPromoTriggerActionHappenedBefore(context)) {
+                SharedPreferenceUtil.setHamburgerPromoTriggerActionHappenedBefore(context);
+            }
+        }
+
+        private void updateDebugOptionsVisibility(boolean visible) {
+            if (mEnableDebugMenuOptions != visible) {
+                mEnableDebugMenuOptions = visible;
+                getActivity().invalidateOptionsMenu();
+            }
+        }
+
+        private void setQueryTextToFragment(String query) {
+            setQueryString(query, true);
+            setVisibleScrollbarEnabled(!isSearchMode());
+        }
+
+        @Override
+        public void onUpButtonPressed() {
+            getActivity().onBackPressed();
+        }
+    };
 
     public DefaultContactBrowseListFragment() {
         setPhotoLoaderEnabled(true);
@@ -79,10 +223,7 @@
         setSectionHeaderDisplayEnabled(true);
         setVisibleScrollbarEnabled(true);
         setDisplayDirectoryHeader(false);
-    }
-
-    public void setFeatureHighlightCallback(FeatureHighlightCallback callback) {
-        mCallback = callback;
+        setHasOptionsMenu(true);
     }
 
     @Override
@@ -96,8 +237,21 @@
             bindListHeader(data.getCount());
         }
         super.onLoadFinished(loader, data);
-        if (!isSearchMode() && mCallback != null) {
-            mCallback.onLoadFinishedCallback();
+        if (!isSearchMode()) {
+            maybeShowHamburgerFeatureHighlight();
+        }
+    }
+
+    public void maybeShowHamburgerFeatureHighlight() {
+        if (mActionBarAdapter != null && !mActionBarAdapter.isSearchMode()
+                && !mActionBarAdapter.isSelectionMode()
+                && SharedPreferenceUtil.getShouldShowHamburgerPromo(getContext())) {
+            final FeatureHighlight hamburgerFeatureHighlight =
+                    mActionBarAdapter.getHamburgerFeatureHighlight();
+            if (hamburgerFeatureHighlight != null) {
+                hamburgerFeatureHighlight.show((FragmentActivity) getActivity());
+                SharedPreferenceUtil.setHamburgerPromoDisplayedBefore(getContext());
+            }
         }
     }
 
@@ -263,11 +417,10 @@
 
         if (Flags.getInstance(getActivity()).getBoolean(Experiments.PULL_TO_REFRESH)) {
             initSwipeRefreshLayout();
-
         }
         // Putting the header view inside a container will allow us to make
         // it invisible later. See checkHeaderViewVisibility()
-        FrameLayout headerContainer = new FrameLayout(inflater.getContext());
+        final FrameLayout headerContainer = new FrameLayout(inflater.getContext());
         mSearchHeaderView = inflater.inflate(R.layout.search_header, null, false);
         headerContainer.addView(mSearchHeaderView);
         getListView().addHeaderView(headerContainer, null, false);
@@ -317,7 +470,7 @@
         final List<Account> syncableAccounts = filter.getSyncableAccounts(accounts);
         if (syncableAccounts != null && syncableAccounts.size() > 0) {
             for (Account account : syncableAccounts) {
-                 // We can prioritize Contacts sync if sync is not initialized yet.
+                // We can prioritize Contacts sync if sync is not initialized yet.
                 if (!SyncUtil.isSyncStatusPendingOrActive(account)
                         || SyncUtil.isUnsyncableGoogleAccount(account)) {
                     ContentResolver.requestSync(account, ContactsContract.AUTHORITY, bundle);
@@ -327,6 +480,64 @@
     }
 
     @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+        mIsRecreatedInstance = (savedInstanceState != null);
+        mContactListFilterController = ContactListFilterController.getInstance(getContext());
+        mContactListFilterController.checkFilterValidity(false);
+        mContactListFilterController.addListener(mFilterListener);
+
+        // Use FILTER_TYPE_ALL_ACCOUNTS filter if the instance is not a re-created one.
+        // This is useful when user upgrades app while an account filter or a custom filter was
+        // stored in sharedPreference in a previous version of Contacts app.
+        final ContactListFilter filter = mIsRecreatedInstance
+                ? mContactListFilterController.getFilter()
+                : AccountFilterUtil.createContactsFilter(getContext());
+        setContactListFilter(filter);
+
+        final ContactsDrawerActivity activity = (ContactsDrawerActivity) getActivity();
+        mActionBarAdapter = new ActionBarAdapter(activity, mActionBarListener,
+                activity.getSupportActionBar(), activity.getToolbar(), R.string.enter_contact_name);
+        mActionBarAdapter.setShowHomeIcon(true);
+        initializeActionBarAdapter(savedInstanceState);
+        if (isSearchMode()) {
+            mActionBarAdapter.setFocusOnSearchView();
+        }
+
+        setCheckBoxListListener(new CheckBoxListListener());
+        setOnContactListActionListener(new ContactBrowserActionListener());
+        if (mIsRecreatedInstance && savedInstanceState.getBoolean(KEY_DELETION_IN_PROGRESS)) {
+            deleteSelectedContacts();
+        }
+    }
+
+    public void initializeActionBarAdapter(Bundle savedInstanceState) {
+        if (mActionBarAdapter != null) {
+            mActionBarAdapter.initialize(savedInstanceState, mContactsRequest);
+        }
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        // Re-register the listener, which may have been cleared when onSaveInstanceState was
+        // called. See also: onSaveInstanceState
+        mActionBarAdapter.setListener(mActionBarListener);
+        mDisableOptionItemSelected = false;
+        maybeHideCheckBoxes();
+    }
+
+    private void maybeHideCheckBoxes() {
+        if (!mActionBarAdapter.isSelectionMode()) {
+            displayCheckBoxes(false);
+        }
+    }
+
+    public ActionBarAdapter getActionBarAdapter(){
+        return mActionBarAdapter;
+    }
+
+    @Override
     protected void setSearchMode(boolean flag) {
         super.setSearchMode(flag);
         checkHeaderViewVisibility();
@@ -378,4 +589,423 @@
     public SwipeRefreshLayout getSwipeRefreshLayout() {
         return mSwipeRefreshLayout;
     }
+
+    private final class CheckBoxListListener implements OnCheckBoxListActionListener {
+        @Override
+        public void onStartDisplayingCheckBoxes() {
+            mActionBarAdapter.setSelectionMode(true);
+            getActivity().invalidateOptionsMenu();
+        }
+
+        @Override
+        public void onSelectedContactIdsChanged() {
+            mActionBarAdapter.setSelectionCount(getSelectedContactIds().size());
+            getActivity().invalidateOptionsMenu();
+        }
+
+        @Override
+        public void onStopDisplayingCheckBoxes() {
+            mActionBarAdapter.setSelectionMode(false);
+        }
+    }
+
+    private void setFilterAndUpdateTitle(ContactListFilter filter) {
+        setFilterAndUpdateTitle(filter, true);
+    }
+
+    private void setFilterAndUpdateTitle(ContactListFilter filter, boolean restoreSelectedUri) {
+        setFilter(filter, restoreSelectedUri);
+        setListType(mContactListFilterController.getFilterListType());
+
+        ((ContactsDrawerActivity) getActivity()).updateFilterMenu(filter);
+
+        final String actionBarTitle;
+        if (filter.filterType == ContactListFilter.FILTER_TYPE_DEVICE_CONTACTS) {
+            actionBarTitle = getString(R.string.account_phone);
+        } else if (!TextUtils.isEmpty(filter.accountName)) {
+            actionBarTitle = getActionBarTitleForAccount(filter);
+        } else {
+            actionBarTitle = getString(R.string.contactsList);
+        }
+        getActivity().setTitle(actionBarTitle);
+
+        if (CompatUtils.isNCompatible()) {
+            getActivity().setTitle(actionBarTitle);
+            getActivity().getWindow().getDecorView()
+                    .sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+        }
+        // Determine whether the account has pullToRefresh feature
+        if (Flags.getInstance(getContext()).getBoolean(Experiments.PULL_TO_REFRESH)) {
+            setSwipeRefreshLayoutEnabledOrNot(filter);
+        }
+    }
+
+    private String getActionBarTitleForAccount(ContactListFilter filter) {
+        if (GoogleAccountType.ACCOUNT_TYPE.equals(filter.accountType)) {
+            return getString(R.string.title_from_google);
+        }
+        return getString(R.string.title_from_other_accounts, filter.accountName);
+    }
+
+    public void setSwipeRefreshLayoutEnabledOrNot(ContactListFilter filter) {
+        final SwipeRefreshLayout swipeRefreshLayout = getSwipeRefreshLayout();
+        if (swipeRefreshLayout == null) {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "Can not load swipeRefreshLayout, swipeRefreshLayout is null");
+            }
+            return;
+        }
+
+        swipeRefreshLayout.setRefreshing(false);
+        swipeRefreshLayout.setEnabled(false);
+
+        if (filter != null && !mActionBarAdapter.isSearchMode()
+                && !mActionBarAdapter.isSelectionMode()) {
+            final List<AccountWithDataSet> accounts = AccountTypeManager.getInstance(getContext())
+                    .getAccounts(/* contactsWritableOnly */ true);
+            if (filter.isSyncable(accounts)) {
+                swipeRefreshLayout.setEnabled(true);
+            }
+        }
+    }
+
+    public void configureContactListFragment() {
+        // Filter may be changed when activity is in background.
+        setFilterAndUpdateTitle(getFilter());
+        setVerticalScrollbarPosition(getScrollBarPosition());
+        setSelectionVisible(false);
+        getActivity().invalidateOptionsMenu();
+    }
+
+    private int getScrollBarPosition() {
+        final Locale locale = Locale.getDefault();
+        final boolean isRTL =
+                TextUtils.getLayoutDirectionFromLocale(locale) == View.LAYOUT_DIRECTION_RTL;
+        return isRTL ? View.SCROLLBAR_POSITION_LEFT : View.SCROLLBAR_POSITION_RIGHT;
+    }
+
+    private final class ContactBrowserActionListener implements OnContactBrowserActionListener {
+        ContactBrowserActionListener() {}
+
+        @Override
+        public void onSelectionChange() {
+
+        }
+
+        @Override
+        public void onViewContactAction(int position, Uri contactLookupUri,
+                boolean isEnterpriseContact) {
+            if (isEnterpriseContact) {
+                // No implicit intent as user may have a different contacts app in work profile.
+                ContactsContract.QuickContact.showQuickContact(getContext(), new Rect(),
+                        contactLookupUri, QuickContactActivity.MODE_FULLY_EXPANDED, null);
+            } else {
+                final Intent intent = ImplicitIntentsUtil.composeQuickContactIntent(
+                        getContext(), contactLookupUri, QuickContactActivity.MODE_FULLY_EXPANDED);
+                final int previousScreen;
+                if (isSearchMode()) {
+                    previousScreen = ScreenEvent.ScreenType.SEARCH;
+                } else {
+                    if (isAllContactsFilter(mContactListFilterController.getFilter())) {
+                        if (position < getAdapter().getNumberOfFavorites()) {
+                            previousScreen = ScreenEvent.ScreenType.FAVORITES;
+                        } else {
+                            previousScreen = ScreenEvent.ScreenType.ALL_CONTACTS;
+                        }
+                    } else {
+                        previousScreen = ScreenEvent.ScreenType.LIST_ACCOUNT;
+                    }
+                }
+                Logger.logListEvent(ListEvent.ActionType.CLICK,
+                        /* listType */ getListTypeIncludingSearch(),
+                        /* count */ getAdapter().getCount(),
+                        /* clickedIndex */ position, /* numSelected */ 0);
+                intent.putExtra(QuickContactActivity.EXTRA_PREVIOUS_SCREEN_TYPE, previousScreen);
+                ImplicitIntentsUtil.startActivityInApp(getContext(), intent);
+            }
+        }
+
+        @Override
+        public void onDeleteContactAction(Uri contactUri) {
+            ContactDeletionInteraction.start(getActivity(), contactUri, false);
+        }
+
+        @Override
+        public void onFinishAction() {
+            getActivity().onBackPressed();
+        }
+
+        @Override
+        public void onInvalidSelection() {
+            ContactListFilter filter;
+            ContactListFilter currentFilter = getFilter();
+            if (currentFilter != null
+                    && currentFilter.filterType == ContactListFilter.FILTER_TYPE_SINGLE_CONTACT) {
+                filter = AccountFilterUtil.createContactsFilter(getContext());
+                setFilterAndUpdateTitle(filter);
+            } else {
+                filter = ContactListFilter.createFilterWithType(
+                        ContactListFilter.FILTER_TYPE_SINGLE_CONTACT);
+                setFilterAndUpdateTitle(filter, /* restoreSelectedUri */ false);
+            }
+            setContactListFilter(filter);
+        }
+    }
+
+    private boolean isAllContactsFilter(ContactListFilter filter) {
+        return filter != null && filter.isContactsFilterType();
+    }
+
+    public void setContactsAvailable(boolean contactsAvailable) {
+        mContactsAvailable = contactsAvailable;
+    }
+
+    /**
+     * Set filter via ContactListFilterController
+     */
+    public void setContactListFilter(ContactListFilter filter) {
+        mContactListFilterController.setContactListFilter(filter,
+                /* persistent */ isAllContactsFilter(filter));
+    }
+
+    @Override
+    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        if (!mContactsAvailable) {
+            // If contacts aren't available, hide all menu items.
+            return;
+        }
+        super.onCreateOptionsMenu(menu, inflater);
+        inflater.inflate(R.menu.people_options, menu);
+    }
+
+    @Override
+    public void onPrepareOptionsMenu(Menu menu) {
+        mOptionsMenuContactsAvailable = mContactsAvailable;
+        if (!mOptionsMenuContactsAvailable) {
+            return;
+        }
+
+        final boolean isSearchOrSelectionMode = mActionBarAdapter.isSearchMode()
+                || mActionBarAdapter.isSelectionMode();
+        makeMenuItemVisible(menu, R.id.menu_search, !isSearchOrSelectionMode);
+
+        final boolean showSelectedContactOptions = mActionBarAdapter.isSelectionMode()
+                && getSelectedContactIds().size() != 0;
+        makeMenuItemVisible(menu, R.id.menu_share, showSelectedContactOptions);
+        makeMenuItemVisible(menu, R.id.menu_delete, showSelectedContactOptions);
+        final boolean showLinkContactsOptions = mActionBarAdapter.isSelectionMode()
+                && getSelectedContactIds().size() > 1;
+        makeMenuItemVisible(menu, R.id.menu_join, showLinkContactsOptions);
+
+        // Debug options need to be visible even in search mode.
+        makeMenuItemVisible(menu, R.id.export_database, mEnableDebugMenuOptions &&
+                hasExportIntentHandler());
+    }
+
+    private void makeMenuItemVisible(Menu menu, int itemId, boolean visible) {
+        final MenuItem item = menu.findItem(itemId);
+        if (item != null) {
+            item.setVisible(visible);
+        }
+    }
+
+    private boolean hasExportIntentHandler() {
+        final Intent intent = new Intent();
+        intent.setAction("com.android.providers.contacts.DUMP_DATABASE");
+        final List<ResolveInfo> receivers =
+                getContext().getPackageManager().queryIntentActivities(intent,
+                PackageManager.MATCH_DEFAULT_ONLY);
+        return receivers != null && receivers.size() > 0;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        if (mDisableOptionItemSelected) {
+            return false;
+        }
+
+        switch (item.getItemId()) {
+            case android.R.id.home: {
+                // The home icon on the action bar is pressed
+                if (mActionBarAdapter.isUpShowing()) {
+                    // "UP" icon press -- should be treated as "back".
+                    getActivity().onBackPressed();
+                }
+                return true;
+            }
+            case R.id.menu_search: {
+                if (!mActionBarAdapter.isSelectionMode()) {
+                    mActionBarAdapter.setSearchMode(true);
+                }
+                return true;
+            }
+            case R.id.menu_share: {
+                shareSelectedContacts();
+                return true;
+            }
+            case R.id.menu_join: {
+                Logger.logListEvent(ListEvent.ActionType.LINK,
+                        /* listType */ getListTypeIncludingSearch(),
+                        /* count */ getAdapter().getCount(), /* clickedIndex */ -1,
+                        /* numSelected */ getAdapter().getSelectedContactIds().size());
+                joinSelectedContacts();
+                return true;
+            }
+            case R.id.menu_delete: {
+                deleteSelectedContacts();
+                return true;
+            }
+            case R.id.export_database: {
+                final Intent intent = new Intent("com.android.providers.contacts.DUMP_DATABASE");
+                intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
+                ImplicitIntentsUtil.startActivityOutsideApp(getContext(), intent);
+                return true;
+            }
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    /**
+     * Share all contacts that are currently selected in mAllFragment. This method is pretty
+     * inefficient for handling large numbers of contacts. I don't expect this to be a problem.
+     */
+    private void shareSelectedContacts() {
+        final StringBuilder uriListBuilder = new StringBuilder();
+        for (Long contactId : getSelectedContactIds()) {
+            final Uri contactUri = ContentUris.withAppendedId(
+                    ContactsContract.Contacts.CONTENT_URI, contactId);
+            final Uri lookupUri = ContactsContract.Contacts.getLookupUri(
+                    getContext().getContentResolver(), contactUri);
+            if (lookupUri == null) {
+                continue;
+            }
+            final List<String> pathSegments = lookupUri.getPathSegments();
+            if (pathSegments.size() < 2) {
+                continue;
+            }
+            final String lookupKey = pathSegments.get(pathSegments.size() - 2);
+            if (uriListBuilder.length() > 0) {
+                uriListBuilder.append(':');
+            }
+            uriListBuilder.append(Uri.encode(lookupKey));
+        }
+        if (uriListBuilder.length() == 0) {
+            return;
+        }
+        final Uri uri = Uri.withAppendedPath(
+                ContactsContract.Contacts.CONTENT_MULTI_VCARD_URI,
+                Uri.encode(uriListBuilder.toString()));
+        final Intent intent = new Intent(Intent.ACTION_SEND);
+        intent.setType(ContactsContract.Contacts.CONTENT_VCARD_TYPE);
+        intent.putExtra(Intent.EXTRA_STREAM, uri);
+        try {
+            startActivityForResult(Intent.createChooser(intent, getResources().getQuantityString(
+                    R.plurals.title_share_via,/* quantity */ getSelectedContactIds().size()))
+                    , ACTIVITY_REQUEST_CODE_SHARE);
+        } catch (final ActivityNotFoundException ex) {
+            Toast.makeText(getContext(), R.string.share_error, Toast.LENGTH_SHORT).show();
+        }
+    }
+
+    private void joinSelectedContacts() {
+        final Context context = getContext();
+        final Intent intent = ContactSaveService.createJoinSeveralContactsIntent(
+                context, getSelectedContactIdsArray());
+        context.startService(intent);
+
+        mActionBarAdapter.setSelectionMode(false);
+    }
+
+    private void deleteSelectedContacts() {
+        mMultiDeletionInteraction =
+                ContactMultiDeletionInteraction.start(this, getSelectedContactIds());
+        mMultiDeletionInteraction.setListener(new MultiDeleteListener());
+        mIsDeletionInProgress = true;
+    }
+
+    private final class MultiDeleteListener implements MultiContactDeleteListener {
+        @Override
+        public void onDeletionFinished() {
+            // The parameters count and numSelected are both the number of contacts before deletion.
+            Logger.logListEvent(ListEvent.ActionType.DELETE,
+                /* listType */ getListTypeIncludingSearch(),
+                /* count */ getAdapter().getCount(), /* clickedIndex */ -1,
+                /* numSelected */ getSelectedContactIds().size());
+            mActionBarAdapter.setSelectionMode(false);
+            mIsDeletionInProgress = false;
+        }
+    }
+
+    private int getListTypeIncludingSearch() {
+        return isSearchMode() ? ListEvent.ListType.SEARCH_RESULT : getListType();
+    }
+
+    public void setListType() {
+        mContactListFilterController = ContactListFilterController.getInstance(getContext());
+        setListType(mContactListFilterController.getFilterListType());
+    }
+
+    public void setContactsRequest(ContactsRequest contactsRequest) {
+        mContactsRequest = contactsRequest;
+    }
+
+    @Override
+    public void onActivityResult(int requestCode, int resultCode, Intent data) {
+        switch (requestCode) {
+            // TODO: Using the new startActivityWithResultFromFragment API this should not be needed
+            // anymore
+            case ContactEntryListFragment.ACTIVITY_REQUEST_CODE_PICKER:
+                if (resultCode == Activity.RESULT_OK) {
+                    onPickerResult(data);
+                }
+            case ACTIVITY_REQUEST_CODE_SHARE:
+                Logger.logListEvent(ListEvent.ActionType.SHARE,
+                    /* listType */ getListTypeIncludingSearch(),
+                    /* count */ getAdapter().getCount(), /* clickedIndex */ -1,
+                    /* numSelected */ getAdapter().getSelectedContactIds().size());
+
+// TODO fix or remove multipicker code: ag/54762
+//                else if (resultCode == RESULT_CANCELED && mMode == MODE_PICK_MULTIPLE_PHONES) {
+//                    // Finish the activity if the sub activity was canceled as back key is used
+//                    // to confirm user selection in MODE_PICK_MULTIPLE_PHONES.
+//                    finish();
+//                }
+//                break;
+        }
+    }
+
+    public boolean getOptionsMenuContactsAvailable() {
+        return mOptionsMenuContactsAvailable;
+    }
+
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        // Clear the listener to make sure we don't get callbacks after onSaveInstanceState,
+        // in order to avoid doing fragment transactions after it.
+        // TODO Figure out a better way to deal with the issue (ag/120686).
+        if (mActionBarAdapter != null) {
+            mActionBarAdapter.setListener(null);
+            mActionBarAdapter.onSaveInstanceState(outState);
+        }
+        mDisableOptionItemSelected = true;
+        outState.putBoolean(KEY_DELETION_IN_PROGRESS, mIsDeletionInProgress);
+    }
+
+    @Override
+    public void onPause() {
+        mOptionsMenuContactsAvailable = false;
+        super.onPause();
+    }
+
+    @Override
+    public void onDestroy() {
+        if (mActionBarAdapter != null) {
+            mActionBarAdapter.setListener(null);
+        }
+        if (mContactListFilterController != null) {
+            mContactListFilterController.removeListener(mFilterListener);
+        }
+        super.onDestroy();
+    }
 }