Home | History | Annotate | Download | only in activities
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.contacts.activities;
     18 
     19 import android.app.Fragment;
     20 import android.app.FragmentManager;
     21 import android.app.FragmentTransaction;
     22 import android.content.Intent;
     23 import android.graphics.Rect;
     24 import android.net.Uri;
     25 import android.os.Bundle;
     26 import android.os.Parcelable;
     27 import android.os.UserManager;
     28 import android.preference.PreferenceActivity;
     29 import android.provider.ContactsContract;
     30 import android.provider.ContactsContract.Contacts;
     31 import android.provider.ContactsContract.ProviderStatus;
     32 import android.provider.ContactsContract.QuickContact;
     33 import android.provider.Settings;
     34 import android.support.v13.app.FragmentPagerAdapter;
     35 import android.support.v4.view.PagerAdapter;
     36 import android.support.v4.view.ViewPager;
     37 import android.text.TextUtils;
     38 import android.util.Log;
     39 import android.view.KeyCharacterMap;
     40 import android.view.KeyEvent;
     41 import android.view.Menu;
     42 import android.view.MenuInflater;
     43 import android.view.MenuItem;
     44 import android.view.View;
     45 import android.view.ViewGroup;
     46 import android.view.Window;
     47 import android.widget.ImageButton;
     48 import android.widget.Toolbar;
     49 
     50 import com.android.contacts.ContactsActivity;
     51 import com.android.contacts.R;
     52 import com.android.contacts.activities.ActionBarAdapter.TabState;
     53 import com.android.contacts.common.ContactsUtils;
     54 import com.android.contacts.common.dialog.ClearFrequentsDialog;
     55 import com.android.contacts.interactions.ContactDeletionInteraction;
     56 import com.android.contacts.common.interactions.ImportExportDialogFragment;
     57 import com.android.contacts.common.list.ContactEntryListFragment;
     58 import com.android.contacts.common.list.ContactListFilter;
     59 import com.android.contacts.common.list.ContactListFilterController;
     60 import com.android.contacts.common.list.ContactTileAdapter.DisplayType;
     61 import com.android.contacts.list.ContactTileListFragment;
     62 import com.android.contacts.list.ContactsIntentResolver;
     63 import com.android.contacts.list.ContactsRequest;
     64 import com.android.contacts.list.ContactsUnavailableFragment;
     65 import com.android.contacts.list.DefaultContactBrowseListFragment;
     66 import com.android.contacts.common.list.DirectoryListLoader;
     67 import com.android.contacts.common.preference.DisplayOptionsPreferenceFragment;
     68 import com.android.contacts.list.OnContactBrowserActionListener;
     69 import com.android.contacts.list.OnContactsUnavailableActionListener;
     70 import com.android.contacts.list.ProviderStatusWatcher;
     71 import com.android.contacts.list.ProviderStatusWatcher.ProviderStatusListener;
     72 import com.android.contacts.common.list.ViewPagerTabs;
     73 import com.android.contacts.preference.ContactsPreferenceActivity;
     74 import com.android.contacts.common.util.AccountFilterUtil;
     75 import com.android.contacts.common.util.ViewUtil;
     76 import com.android.contacts.quickcontact.QuickContactActivity;
     77 import com.android.contacts.util.AccountPromptUtils;
     78 import com.android.contacts.common.util.Constants;
     79 import com.android.contacts.util.DialogManager;
     80 import com.android.contacts.util.HelpUtils;
     81 
     82 import java.util.Locale;
     83 import java.util.concurrent.atomic.AtomicInteger;
     84 
     85 /**
     86  * Displays a list to browse contacts.
     87  */
     88 public class PeopleActivity extends ContactsActivity implements
     89         View.OnCreateContextMenuListener,
     90         View.OnClickListener,
     91         ActionBarAdapter.Listener,
     92         DialogManager.DialogShowingViewActivity,
     93         ContactListFilterController.ContactListFilterListener,
     94         ProviderStatusListener {
     95 
     96     private static final String TAG = "PeopleActivity";
     97 
     98     private static final String ENABLE_DEBUG_OPTIONS_HIDDEN_CODE = "debug debug!";
     99 
    100     // These values needs to start at 2. See {@link ContactEntryListFragment}.
    101     private static final int SUBACTIVITY_ACCOUNT_FILTER = 2;
    102 
    103     private final DialogManager mDialogManager = new DialogManager(this);
    104 
    105     private ContactsIntentResolver mIntentResolver;
    106     private ContactsRequest mRequest;
    107 
    108     private ActionBarAdapter mActionBarAdapter;
    109 
    110     private ContactTileListFragment.Listener mFavoritesFragmentListener =
    111             new StrequentContactListFragmentListener();
    112 
    113     private ContactListFilterController mContactListFilterController;
    114 
    115     private ContactsUnavailableFragment mContactsUnavailableFragment;
    116     private ProviderStatusWatcher mProviderStatusWatcher;
    117     private ProviderStatusWatcher.Status mProviderStatus;
    118 
    119     private boolean mOptionsMenuContactsAvailable;
    120 
    121     /**
    122      * Showing a list of Contacts. Also used for showing search results in search mode.
    123      */
    124     private DefaultContactBrowseListFragment mAllFragment;
    125     private ContactTileListFragment mFavoritesFragment;
    126 
    127     /** ViewPager for swipe */
    128     private ViewPager mTabPager;
    129     private ViewPagerTabs mViewPagerTabs;
    130     private TabPagerAdapter mTabPagerAdapter;
    131     private String[] mTabTitles;
    132     private final TabPagerListener mTabPagerListener = new TabPagerListener();
    133 
    134     private boolean mEnableDebugMenuOptions;
    135 
    136     /**
    137      * True if this activity instance is a re-created one.  i.e. set true after orientation change.
    138      * This is set in {@link #onCreate} for later use in {@link #onStart}.
    139      */
    140     private boolean mIsRecreatedInstance;
    141 
    142     /**
    143      * If {@link #configureFragments(boolean)} is already called.  Used to avoid calling it twice
    144      * in {@link #onStart}.
    145      * (This initialization only needs to be done once in onStart() when the Activity was just
    146      * created from scratch -- i.e. onCreate() was just called)
    147      */
    148     private boolean mFragmentInitialized;
    149 
    150     /**
    151      * This is to disable {@link #onOptionsItemSelected} when we trying to stop the activity.
    152      */
    153     private boolean mDisableOptionItemSelected;
    154 
    155     /** Sequential ID assigned to each instance; used for logging */
    156     private final int mInstanceId;
    157     private static final AtomicInteger sNextInstanceId = new AtomicInteger();
    158 
    159     public PeopleActivity() {
    160         mInstanceId = sNextInstanceId.getAndIncrement();
    161         mIntentResolver = new ContactsIntentResolver(this);
    162         mProviderStatusWatcher = ProviderStatusWatcher.getInstance(this);
    163     }
    164 
    165     @Override
    166     public String toString() {
    167         // Shown on logcat
    168         return String.format("%s@%d", getClass().getSimpleName(), mInstanceId);
    169     }
    170 
    171     public boolean areContactsAvailable() {
    172         return (mProviderStatus != null)
    173                 && mProviderStatus.status == ProviderStatus.STATUS_NORMAL;
    174     }
    175 
    176     private boolean areContactWritableAccountsAvailable() {
    177         return ContactsUtils.areContactWritableAccountsAvailable(this);
    178     }
    179 
    180     private boolean areGroupWritableAccountsAvailable() {
    181         return ContactsUtils.areGroupWritableAccountsAvailable(this);
    182     }
    183 
    184     /**
    185      * Initialize fragments that are (or may not be) in the layout.
    186      *
    187      * For the fragments that are in the layout, we initialize them in
    188      * {@link #createViewsAndFragments(Bundle)} after inflating the layout.
    189      *
    190      * However, the {@link ContactsUnavailableFragment} is a special fragment which may not
    191      * be in the layout, so we have to do the initialization here.
    192      *
    193      * The ContactsUnavailableFragment is always created at runtime.
    194      */
    195     @Override
    196     public void onAttachFragment(Fragment fragment) {
    197         if (fragment instanceof ContactsUnavailableFragment) {
    198             mContactsUnavailableFragment = (ContactsUnavailableFragment)fragment;
    199             mContactsUnavailableFragment.setOnContactsUnavailableActionListener(
    200                     new ContactsUnavailableFragmentListener());
    201         }
    202     }
    203 
    204     @Override
    205     protected void onCreate(Bundle savedState) {
    206         if (Log.isLoggable(Constants.PERFORMANCE_TAG, Log.DEBUG)) {
    207             Log.d(Constants.PERFORMANCE_TAG, "PeopleActivity.onCreate start");
    208         }
    209         super.onCreate(savedState);
    210 
    211         if (!processIntent(false)) {
    212             finish();
    213             return;
    214         }
    215         mContactListFilterController = ContactListFilterController.getInstance(this);
    216         mContactListFilterController.checkFilterValidity(false);
    217         mContactListFilterController.addListener(this);
    218 
    219         mProviderStatusWatcher.addListener(this);
    220 
    221         mIsRecreatedInstance = (savedState != null);
    222         createViewsAndFragments(savedState);
    223 
    224         if (Log.isLoggable(Constants.PERFORMANCE_TAG, Log.DEBUG)) {
    225             Log.d(Constants.PERFORMANCE_TAG, "PeopleActivity.onCreate finish");
    226         }
    227         getWindow().setBackgroundDrawable(null);
    228     }
    229 
    230     @Override
    231     protected void onNewIntent(Intent intent) {
    232         setIntent(intent);
    233         if (!processIntent(true)) {
    234             finish();
    235             return;
    236         }
    237         mActionBarAdapter.initialize(null, mRequest);
    238 
    239         mContactListFilterController.checkFilterValidity(false);
    240 
    241         // Re-configure fragments.
    242         configureFragments(true /* from request */);
    243         invalidateOptionsMenuIfNeeded();
    244     }
    245 
    246     /**
    247      * Resolve the intent and initialize {@link #mRequest}, and launch another activity if redirect
    248      * is needed.
    249      *
    250      * @param forNewIntent set true if it's called from {@link #onNewIntent(Intent)}.
    251      * @return {@code true} if {@link PeopleActivity} should continue running.  {@code false}
    252      *         if it shouldn't, in which case the caller should finish() itself and shouldn't do
    253      *         farther initialization.
    254      */
    255     private boolean processIntent(boolean forNewIntent) {
    256         // Extract relevant information from the intent
    257         mRequest = mIntentResolver.resolveIntent(getIntent());
    258         if (Log.isLoggable(TAG, Log.DEBUG)) {
    259             Log.d(TAG, this + " processIntent: forNewIntent=" + forNewIntent
    260                     + " intent=" + getIntent() + " request=" + mRequest);
    261         }
    262         if (!mRequest.isValid()) {
    263             setResult(RESULT_CANCELED);
    264             return false;
    265         }
    266 
    267         Intent redirect = mRequest.getRedirectIntent();
    268         if (redirect != null) {
    269             // Need to start a different activity
    270             startActivity(redirect);
    271             return false;
    272         }
    273 
    274         if (mRequest.getActionCode() == ContactsRequest.ACTION_VIEW_CONTACT) {
    275             redirect = new Intent(this, QuickContactActivity.class);
    276             redirect.setAction(Intent.ACTION_VIEW);
    277             redirect.setData(mRequest.getContactUri());
    278             startActivity(redirect);
    279             return false;
    280         }
    281         return true;
    282     }
    283 
    284     private void createViewsAndFragments(Bundle savedState) {
    285         // Disable the ActionBar so that we can use a Toolbar. This needs to be called before
    286         // setContentView().
    287         getWindow().requestFeature(Window.FEATURE_NO_TITLE);
    288 
    289         setContentView(R.layout.people_activity);
    290 
    291         final FragmentManager fragmentManager = getFragmentManager();
    292 
    293         // Hide all tabs (the current tab will later be reshown once a tab is selected)
    294         final FragmentTransaction transaction = fragmentManager.beginTransaction();
    295 
    296         mTabTitles = new String[TabState.COUNT];
    297         mTabTitles[TabState.FAVORITES] = getString(R.string.favorites_tab_label);
    298         mTabTitles[TabState.ALL] = getString(R.string.all_contacts_tab_label);
    299         mTabPager = getView(R.id.tab_pager);
    300         mTabPagerAdapter = new TabPagerAdapter();
    301         mTabPager.setAdapter(mTabPagerAdapter);
    302         mTabPager.setOnPageChangeListener(mTabPagerListener);
    303 
    304         // Configure toolbar and toolbar tabs. If in landscape mode, we  configure tabs differntly.
    305         final Toolbar toolbar = getView(R.id.toolbar);
    306         setActionBar(toolbar);
    307         final ViewPagerTabs portraitViewPagerTabs
    308                 = (ViewPagerTabs) findViewById(R.id.lists_pager_header);
    309         ViewPagerTabs landscapeViewPagerTabs = null;
    310         if (portraitViewPagerTabs ==  null) {
    311             landscapeViewPagerTabs = (ViewPagerTabs) getLayoutInflater().inflate(
    312                     R.layout.people_activity_tabs_lands, toolbar, /* attachToRoot = */ false);
    313             mViewPagerTabs = landscapeViewPagerTabs;
    314         } else {
    315             mViewPagerTabs = portraitViewPagerTabs;
    316         }
    317         mViewPagerTabs.setViewPager(mTabPager);
    318 
    319         final String FAVORITE_TAG = "tab-pager-favorite";
    320         final String ALL_TAG = "tab-pager-all";
    321 
    322         // Create the fragments and add as children of the view pager.
    323         // The pager adapter will only change the visibility; it'll never create/destroy
    324         // fragments.
    325         // However, if it's after screen rotation, the fragments have been re-created by
    326         // the fragment manager, so first see if there're already the target fragments
    327         // existing.
    328         mFavoritesFragment = (ContactTileListFragment)
    329                 fragmentManager.findFragmentByTag(FAVORITE_TAG);
    330         mAllFragment = (DefaultContactBrowseListFragment)
    331                 fragmentManager.findFragmentByTag(ALL_TAG);
    332 
    333         if (mFavoritesFragment == null) {
    334             mFavoritesFragment = new ContactTileListFragment();
    335             mAllFragment = new DefaultContactBrowseListFragment();
    336 
    337             transaction.add(R.id.tab_pager, mFavoritesFragment, FAVORITE_TAG);
    338             transaction.add(R.id.tab_pager, mAllFragment, ALL_TAG);
    339         }
    340 
    341         mFavoritesFragment.setListener(mFavoritesFragmentListener);
    342 
    343         mAllFragment.setOnContactListActionListener(new ContactBrowserActionListener());
    344 
    345         // Hide all fragments for now.  We adjust visibility when we get onSelectedTabChanged()
    346         // from ActionBarAdapter.
    347         transaction.hide(mFavoritesFragment);
    348         transaction.hide(mAllFragment);
    349 
    350         transaction.commitAllowingStateLoss();
    351         fragmentManager.executePendingTransactions();
    352 
    353         // Setting Properties after fragment is created
    354         mFavoritesFragment.setDisplayType(DisplayType.STREQUENT);
    355 
    356         mActionBarAdapter = new ActionBarAdapter(this, this, getActionBar(),
    357                 portraitViewPagerTabs, landscapeViewPagerTabs, toolbar);
    358         mActionBarAdapter.initialize(savedState, mRequest);
    359 
    360         // Add shadow under toolbar
    361         ViewUtil.addRectangularOutlineProvider(findViewById(R.id.toolbar_parent), getResources());
    362 
    363         // Configure action button
    364         final View floatingActionButtonContainer = findViewById(
    365                 R.id.floating_action_button_container);
    366         ViewUtil.setupFloatingActionButton(floatingActionButtonContainer, getResources());
    367         final ImageButton floatingActionButton = (ImageButton) findViewById(R.id.floating_action_button);
    368         floatingActionButton.setOnClickListener(this);
    369 
    370         invalidateOptionsMenuIfNeeded();
    371     }
    372 
    373     @Override
    374     protected void onStart() {
    375         if (!mFragmentInitialized) {
    376             mFragmentInitialized = true;
    377             /* Configure fragments if we haven't.
    378              *
    379              * Note it's a one-shot initialization, so we want to do this in {@link #onCreate}.
    380              *
    381              * However, because this method may indirectly touch views in fragments but fragments
    382              * created in {@link #configureContentView} using a {@link FragmentTransaction} will NOT
    383              * have views until {@link Activity#onCreate} finishes (they would if they were inflated
    384              * from a layout), we need to do it here in {@link #onStart()}.
    385              *
    386              * (When {@link Fragment#onCreateView} is called is different in the former case and
    387              * in the latter case, unfortunately.)
    388              *
    389              * Also, we skip most of the work in it if the activity is a re-created one.
    390              * (so the argument.)
    391              */
    392             configureFragments(!mIsRecreatedInstance);
    393         }
    394         super.onStart();
    395     }
    396 
    397     @Override
    398     protected void onPause() {
    399         mOptionsMenuContactsAvailable = false;
    400         mProviderStatusWatcher.stop();
    401         super.onPause();
    402     }
    403 
    404     @Override
    405     protected void onResume() {
    406         super.onResume();
    407 
    408         mProviderStatusWatcher.start();
    409         updateViewConfiguration(true);
    410 
    411         // Re-register the listener, which may have been cleared when onSaveInstanceState was
    412         // called.  See also: onSaveInstanceState
    413         mActionBarAdapter.setListener(this);
    414         mDisableOptionItemSelected = false;
    415         if (mTabPager != null) {
    416             mTabPager.setOnPageChangeListener(mTabPagerListener);
    417         }
    418         // Current tab may have changed since the last onSaveInstanceState().  Make sure
    419         // the actual contents match the tab.
    420         updateFragmentsVisibility();
    421     }
    422 
    423     @Override
    424     protected void onStop() {
    425         super.onStop();
    426     }
    427 
    428     @Override
    429     protected void onDestroy() {
    430         mProviderStatusWatcher.removeListener(this);
    431 
    432         // Some of variables will be null if this Activity redirects Intent.
    433         // See also onCreate() or other methods called during the Activity's initialization.
    434         if (mActionBarAdapter != null) {
    435             mActionBarAdapter.setListener(null);
    436         }
    437         if (mContactListFilterController != null) {
    438             mContactListFilterController.removeListener(this);
    439         }
    440 
    441         super.onDestroy();
    442     }
    443 
    444     private void configureFragments(boolean fromRequest) {
    445         if (fromRequest) {
    446             ContactListFilter filter = null;
    447             int actionCode = mRequest.getActionCode();
    448             boolean searchMode = mRequest.isSearchMode();
    449             final int tabToOpen;
    450             switch (actionCode) {
    451                 case ContactsRequest.ACTION_ALL_CONTACTS:
    452                     filter = ContactListFilter.createFilterWithType(
    453                             ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS);
    454                     tabToOpen = TabState.ALL;
    455                     break;
    456                 case ContactsRequest.ACTION_CONTACTS_WITH_PHONES:
    457                     filter = ContactListFilter.createFilterWithType(
    458                             ContactListFilter.FILTER_TYPE_WITH_PHONE_NUMBERS_ONLY);
    459                     tabToOpen = TabState.ALL;
    460                     break;
    461 
    462                 case ContactsRequest.ACTION_FREQUENT:
    463                 case ContactsRequest.ACTION_STREQUENT:
    464                 case ContactsRequest.ACTION_STARRED:
    465                     tabToOpen = TabState.FAVORITES;
    466                     break;
    467                 case ContactsRequest.ACTION_VIEW_CONTACT:
    468                     tabToOpen = TabState.ALL;
    469                     break;
    470                 default:
    471                     tabToOpen = -1;
    472                     break;
    473             }
    474             if (tabToOpen != -1) {
    475                 mActionBarAdapter.setCurrentTab(tabToOpen);
    476             }
    477 
    478             if (filter != null) {
    479                 mContactListFilterController.setContactListFilter(filter, false);
    480                 searchMode = false;
    481             }
    482 
    483             if (mRequest.getContactUri() != null) {
    484                 searchMode = false;
    485             }
    486 
    487             mActionBarAdapter.setSearchMode(searchMode);
    488             configureContactListFragmentForRequest();
    489         }
    490 
    491         configureContactListFragment();
    492 
    493         invalidateOptionsMenuIfNeeded();
    494     }
    495 
    496     @Override
    497     public void onContactListFilterChanged() {
    498         if (mAllFragment == null || !mAllFragment.isAdded()) {
    499             return;
    500         }
    501 
    502         mAllFragment.setFilter(mContactListFilterController.getFilter());
    503 
    504         invalidateOptionsMenuIfNeeded();
    505     }
    506 
    507     /**
    508      * Handler for action bar actions.
    509      */
    510     @Override
    511     public void onAction(int action) {
    512         switch (action) {
    513             case ActionBarAdapter.Listener.Action.START_SEARCH_MODE:
    514                 // Tell the fragments that we're in the search mode
    515                 configureFragments(false /* from request */);
    516                 updateFragmentsVisibility();
    517                 invalidateOptionsMenu();
    518                 break;
    519             case ActionBarAdapter.Listener.Action.STOP_SEARCH_MODE:
    520                 setQueryTextToFragment("");
    521                 updateFragmentsVisibility();
    522                 invalidateOptionsMenu();
    523                 break;
    524             case ActionBarAdapter.Listener.Action.CHANGE_SEARCH_QUERY:
    525                 final String queryString = mActionBarAdapter.getQueryString();
    526                 setQueryTextToFragment(queryString);
    527                 updateDebugOptionsVisibility(
    528                         ENABLE_DEBUG_OPTIONS_HIDDEN_CODE.equals(queryString));
    529                 break;
    530             default:
    531                 throw new IllegalStateException("Unkonwn ActionBarAdapter action: " + action);
    532         }
    533     }
    534 
    535     @Override
    536     public void onSelectedTabChanged() {
    537         updateFragmentsVisibility();
    538     }
    539 
    540     @Override
    541     public void onUpButtonPressed() {
    542         onBackPressed();
    543     }
    544 
    545     private void updateDebugOptionsVisibility(boolean visible) {
    546         if (mEnableDebugMenuOptions != visible) {
    547             mEnableDebugMenuOptions = visible;
    548             invalidateOptionsMenu();
    549         }
    550     }
    551 
    552     /**
    553      * Updates the fragment/view visibility according to the current mode, such as
    554      * {@link ActionBarAdapter#isSearchMode()} and {@link ActionBarAdapter#getCurrentTab()}.
    555      */
    556     private void updateFragmentsVisibility() {
    557         int tab = mActionBarAdapter.getCurrentTab();
    558 
    559         if (mActionBarAdapter.isSearchMode()) {
    560             mTabPagerAdapter.setSearchMode(true);
    561         } else {
    562             // No smooth scrolling if quitting from the search mode.
    563             final boolean wasSearchMode = mTabPagerAdapter.isSearchMode();
    564             mTabPagerAdapter.setSearchMode(false);
    565             if (mTabPager.getCurrentItem() != tab) {
    566                 mTabPager.setCurrentItem(tab, !wasSearchMode);
    567             }
    568         }
    569         invalidateOptionsMenu();
    570         showEmptyStateForTab(tab);
    571     }
    572 
    573     private void showEmptyStateForTab(int tab) {
    574         if (mContactsUnavailableFragment != null) {
    575             switch (tab) {
    576                 case TabState.FAVORITES:
    577                     mContactsUnavailableFragment.setMessageText(
    578                             R.string.listTotalAllContactsZeroStarred, -1);
    579                     break;
    580                 case TabState.ALL:
    581                     mContactsUnavailableFragment.setMessageText(R.string.noContacts, -1);
    582                     break;
    583             }
    584             // When using the mContactsUnavailableFragment the ViewPager doesn't contain two views.
    585             // Therefore, we have to trick the ViewPagerTabs into thinking we have changed tabs
    586             // when the mContactsUnavailableFragment changes. Otherwise the tab strip won't move.
    587             mViewPagerTabs.onPageScrolled(tab, 0, 0);
    588         }
    589     }
    590 
    591     private class TabPagerListener implements ViewPager.OnPageChangeListener {
    592 
    593         // This package-protected constructor is here because of a possible compiler bug.
    594         // PeopleActivity$1.class should be generated due to the private outer/inner class access
    595         // needed here.  But for some reason, PeopleActivity$1.class is missing.
    596         // Since $1 class is needed as a jvm work around to get access to the inner class,
    597         // changing the constructor to package-protected or public will solve the problem.
    598         // To verify whether $1 class is needed, javap PeopleActivity$TabPagerListener and look for
    599         // references to PeopleActivity$1.
    600         //
    601         // When the constructor is private and PeopleActivity$1.class is missing, proguard will
    602         // correctly catch this and throw warnings and error out the build on user/userdebug builds.
    603         //
    604         // All private inner classes below also need this fix.
    605         TabPagerListener() {}
    606 
    607         @Override
    608         public void onPageScrollStateChanged(int state) {
    609             if (!mTabPagerAdapter.isSearchMode()) {
    610                 mViewPagerTabs.onPageScrollStateChanged(state);
    611             }
    612         }
    613 
    614         @Override
    615         public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
    616             if (!mTabPagerAdapter.isSearchMode()) {
    617                 mViewPagerTabs.onPageScrolled(position, positionOffset, positionOffsetPixels);
    618             }
    619         }
    620 
    621         @Override
    622         public void onPageSelected(int position) {
    623             // Make sure not in the search mode, in which case position != TabState.ordinal().
    624             if (!mTabPagerAdapter.isSearchMode()) {
    625                 mActionBarAdapter.setCurrentTab(position, false);
    626                 mViewPagerTabs.onPageSelected(position);
    627                 showEmptyStateForTab(position);
    628                 invalidateOptionsMenu();
    629             }
    630         }
    631     }
    632 
    633     /**
    634      * Adapter for the {@link ViewPager}.  Unlike {@link FragmentPagerAdapter},
    635      * {@link #instantiateItem} returns existing fragments, and {@link #instantiateItem}/
    636      * {@link #destroyItem} show/hide fragments instead of attaching/detaching.
    637      *
    638      * In search mode, we always show the "all" fragment, and disable the swipe.  We change the
    639      * number of items to 1 to disable the swipe.
    640      *
    641      * TODO figure out a more straight way to disable swipe.
    642      */
    643     private class TabPagerAdapter extends PagerAdapter {
    644         private final FragmentManager mFragmentManager;
    645         private FragmentTransaction mCurTransaction = null;
    646 
    647         private boolean mTabPagerAdapterSearchMode;
    648 
    649         private Fragment mCurrentPrimaryItem;
    650 
    651         public TabPagerAdapter() {
    652             mFragmentManager = getFragmentManager();
    653         }
    654 
    655         public boolean isSearchMode() {
    656             return mTabPagerAdapterSearchMode;
    657         }
    658 
    659         public void setSearchMode(boolean searchMode) {
    660             if (searchMode == mTabPagerAdapterSearchMode) {
    661                 return;
    662             }
    663             mTabPagerAdapterSearchMode = searchMode;
    664             notifyDataSetChanged();
    665         }
    666 
    667         @Override
    668         public int getCount() {
    669             return mTabPagerAdapterSearchMode ? 1 : TabState.COUNT;
    670         }
    671 
    672         /** Gets called when the number of items changes. */
    673         @Override
    674         public int getItemPosition(Object object) {
    675             if (mTabPagerAdapterSearchMode) {
    676                 if (object == mAllFragment) {
    677                     return 0; // Only 1 page in search mode
    678                 }
    679             } else {
    680                 if (object == mFavoritesFragment) {
    681                     return getTabPositionForTextDirection(TabState.FAVORITES);
    682                 }
    683                 if (object == mAllFragment) {
    684                     return getTabPositionForTextDirection(TabState.ALL);
    685                 }
    686             }
    687             return POSITION_NONE;
    688         }
    689 
    690         @Override
    691         public void startUpdate(ViewGroup container) {
    692         }
    693 
    694         private Fragment getFragment(int position) {
    695             position = getTabPositionForTextDirection(position);
    696             if (mTabPagerAdapterSearchMode) {
    697                 if (position != 0) {
    698                     // This has only been observed in monkey tests.
    699                     // Let's log this issue, but not crash
    700                     Log.w(TAG, "Request fragment at position=" + position + ", eventhough we " +
    701                             "are in search mode");
    702                 }
    703                 return mAllFragment;
    704             } else {
    705                 if (position == TabState.FAVORITES) {
    706                     return mFavoritesFragment;
    707                 } else if (position == TabState.ALL) {
    708                     return mAllFragment;
    709                 }
    710             }
    711             throw new IllegalArgumentException("position: " + position);
    712         }
    713 
    714         @Override
    715         public Object instantiateItem(ViewGroup container, int position) {
    716             if (mCurTransaction == null) {
    717                 mCurTransaction = mFragmentManager.beginTransaction();
    718             }
    719             Fragment f = getFragment(position);
    720             mCurTransaction.show(f);
    721 
    722             // Non primary pages are not visible.
    723             f.setUserVisibleHint(f == mCurrentPrimaryItem);
    724             return f;
    725         }
    726 
    727         @Override
    728         public void destroyItem(ViewGroup container, int position, Object object) {
    729             if (mCurTransaction == null) {
    730                 mCurTransaction = mFragmentManager.beginTransaction();
    731             }
    732             mCurTransaction.hide((Fragment) object);
    733         }
    734 
    735         @Override
    736         public void finishUpdate(ViewGroup container) {
    737             if (mCurTransaction != null) {
    738                 mCurTransaction.commitAllowingStateLoss();
    739                 mCurTransaction = null;
    740                 mFragmentManager.executePendingTransactions();
    741             }
    742         }
    743 
    744         @Override
    745         public boolean isViewFromObject(View view, Object object) {
    746             return ((Fragment) object).getView() == view;
    747         }
    748 
    749         @Override
    750         public void setPrimaryItem(ViewGroup container, int position, Object object) {
    751             Fragment fragment = (Fragment) object;
    752             if (mCurrentPrimaryItem != fragment) {
    753                 if (mCurrentPrimaryItem != null) {
    754                     mCurrentPrimaryItem.setUserVisibleHint(false);
    755                 }
    756                 if (fragment != null) {
    757                     fragment.setUserVisibleHint(true);
    758                 }
    759                 mCurrentPrimaryItem = fragment;
    760             }
    761         }
    762 
    763         @Override
    764         public Parcelable saveState() {
    765             return null;
    766         }
    767 
    768         @Override
    769         public void restoreState(Parcelable state, ClassLoader loader) {
    770         }
    771 
    772         @Override
    773         public CharSequence getPageTitle(int position) {
    774             return mTabTitles[position];
    775         }
    776     }
    777 
    778     private void setQueryTextToFragment(String query) {
    779         mAllFragment.setQueryString(query, true);
    780         mAllFragment.setVisibleScrollbarEnabled(!mAllFragment.isSearchMode());
    781     }
    782 
    783     private void configureContactListFragmentForRequest() {
    784         Uri contactUri = mRequest.getContactUri();
    785         if (contactUri != null) {
    786             mAllFragment.setSelectedContactUri(contactUri);
    787         }
    788 
    789         mAllFragment.setFilter(mContactListFilterController.getFilter());
    790         setQueryTextToFragment(mActionBarAdapter.getQueryString());
    791 
    792         if (mRequest.isDirectorySearchEnabled()) {
    793             mAllFragment.setDirectorySearchMode(DirectoryListLoader.SEARCH_MODE_DEFAULT);
    794         } else {
    795             mAllFragment.setDirectorySearchMode(DirectoryListLoader.SEARCH_MODE_NONE);
    796         }
    797     }
    798 
    799     private void configureContactListFragment() {
    800         // Filter may be changed when this Activity is in background.
    801         mAllFragment.setFilter(mContactListFilterController.getFilter());
    802 
    803         mAllFragment.setVerticalScrollbarPosition(getScrollBarPosition());
    804         mAllFragment.setSelectionVisible(false);
    805     }
    806 
    807     private int getScrollBarPosition() {
    808         return isRTL() ? View.SCROLLBAR_POSITION_LEFT : View.SCROLLBAR_POSITION_RIGHT;
    809     }
    810 
    811     private boolean isRTL() {
    812         final Locale locale = Locale.getDefault();
    813         return TextUtils.getLayoutDirectionFromLocale(locale) == View.LAYOUT_DIRECTION_RTL;
    814     }
    815 
    816     @Override
    817     public void onProviderStatusChange() {
    818         updateViewConfiguration(false);
    819     }
    820 
    821     private void updateViewConfiguration(boolean forceUpdate) {
    822         ProviderStatusWatcher.Status providerStatus = mProviderStatusWatcher.getProviderStatus();
    823         if (!forceUpdate && (mProviderStatus != null)
    824                 && (providerStatus.status == mProviderStatus.status)) return;
    825         mProviderStatus = providerStatus;
    826 
    827         View contactsUnavailableView = findViewById(R.id.contacts_unavailable_view);
    828 
    829         if (mProviderStatus.status == ProviderStatus.STATUS_NORMAL) {
    830             // Ensure that the mTabPager is visible; we may have made it invisible below.
    831             contactsUnavailableView.setVisibility(View.GONE);
    832             if (mTabPager != null) {
    833                 mTabPager.setVisibility(View.VISIBLE);
    834             }
    835 
    836             if (mAllFragment != null) {
    837                 mAllFragment.setEnabled(true);
    838             }
    839         } else {
    840             // If there are no accounts on the device and we should show the "no account" prompt
    841             // (based on {@link SharedPreferences}), then launch the account setup activity so the
    842             // user can sign-in or create an account.
    843             //
    844             // Also check for ability to modify accounts.  In limited user mode, you can't modify
    845             // accounts so there is no point sending users to account setup activity.
    846             final UserManager userManager = UserManager.get(this);
    847             final boolean disallowModifyAccounts = userManager.getUserRestrictions().getBoolean(
    848                     UserManager.DISALLOW_MODIFY_ACCOUNTS);
    849             if (!disallowModifyAccounts && !areContactWritableAccountsAvailable() &&
    850                     AccountPromptUtils.shouldShowAccountPrompt(this)) {
    851                 AccountPromptUtils.neverShowAccountPromptAgain(this);
    852                 AccountPromptUtils.launchAccountPrompt(this);
    853                 return;
    854             }
    855 
    856             // Otherwise, continue setting up the page so that the user can still use the app
    857             // without an account.
    858             if (mAllFragment != null) {
    859                 mAllFragment.setEnabled(false);
    860             }
    861             if (mContactsUnavailableFragment == null) {
    862                 mContactsUnavailableFragment = new ContactsUnavailableFragment();
    863                 mContactsUnavailableFragment.setOnContactsUnavailableActionListener(
    864                         new ContactsUnavailableFragmentListener());
    865                 getFragmentManager().beginTransaction()
    866                         .replace(R.id.contacts_unavailable_container, mContactsUnavailableFragment)
    867                         .commitAllowingStateLoss();
    868             }
    869             mContactsUnavailableFragment.updateStatus(mProviderStatus);
    870 
    871             // Show the contactsUnavailableView, and hide the mTabPager so that we don't
    872             // see it sliding in underneath the contactsUnavailableView at the edges.
    873             contactsUnavailableView.setVisibility(View.VISIBLE);
    874             if (mTabPager != null) {
    875                 mTabPager.setVisibility(View.GONE);
    876             }
    877 
    878             showEmptyStateForTab(mActionBarAdapter.getCurrentTab());
    879         }
    880 
    881         invalidateOptionsMenuIfNeeded();
    882     }
    883 
    884     private final class ContactBrowserActionListener implements OnContactBrowserActionListener {
    885         ContactBrowserActionListener() {}
    886 
    887         @Override
    888         public void onSelectionChange() {
    889 
    890         }
    891 
    892         @Override
    893         public void onViewContactAction(Uri contactLookupUri) {
    894             Intent intent = QuickContact.composeQuickContactsIntent(PeopleActivity.this,
    895                     (Rect) null, contactLookupUri, QuickContactActivity.MODE_FULLY_EXPANDED, null);
    896             startActivity(intent);
    897         }
    898 
    899         @Override
    900         public void onDeleteContactAction(Uri contactUri) {
    901             ContactDeletionInteraction.start(PeopleActivity.this, contactUri, false);
    902         }
    903 
    904         @Override
    905         public void onFinishAction() {
    906             onBackPressed();
    907         }
    908 
    909         @Override
    910         public void onInvalidSelection() {
    911             ContactListFilter filter;
    912             ContactListFilter currentFilter = mAllFragment.getFilter();
    913             if (currentFilter != null
    914                     && currentFilter.filterType == ContactListFilter.FILTER_TYPE_SINGLE_CONTACT) {
    915                 filter = ContactListFilter.createFilterWithType(
    916                         ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS);
    917                 mAllFragment.setFilter(filter);
    918             } else {
    919                 filter = ContactListFilter.createFilterWithType(
    920                         ContactListFilter.FILTER_TYPE_SINGLE_CONTACT);
    921                 mAllFragment.setFilter(filter, false);
    922             }
    923             mContactListFilterController.setContactListFilter(filter, true);
    924         }
    925     }
    926 
    927     private class ContactsUnavailableFragmentListener
    928             implements OnContactsUnavailableActionListener {
    929         ContactsUnavailableFragmentListener() {}
    930 
    931         @Override
    932         public void onCreateNewContactAction() {
    933             startActivity(new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI));
    934         }
    935 
    936         @Override
    937         public void onAddAccountAction() {
    938             Intent intent = new Intent(Settings.ACTION_ADD_ACCOUNT);
    939             intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
    940             intent.putExtra(Settings.EXTRA_AUTHORITIES,
    941                     new String[] { ContactsContract.AUTHORITY });
    942             startActivity(intent);
    943         }
    944 
    945         @Override
    946         public void onImportContactsFromFileAction() {
    947             ImportExportDialogFragment.show(getFragmentManager(), areContactsAvailable(),
    948                     PeopleActivity.class);
    949         }
    950 
    951         @Override
    952         public void onFreeInternalStorageAction() {
    953             startActivity(new Intent(Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS));
    954         }
    955     }
    956 
    957     private final class StrequentContactListFragmentListener
    958             implements ContactTileListFragment.Listener {
    959         StrequentContactListFragmentListener() {}
    960 
    961         @Override
    962         public void onContactSelected(Uri contactUri, Rect targetRect) {
    963             Intent intent = QuickContact.composeQuickContactsIntent(PeopleActivity.this,
    964                     targetRect, contactUri, QuickContactActivity.MODE_FULLY_EXPANDED, null);
    965             startActivity(intent);
    966         }
    967 
    968         @Override
    969         public void onCallNumberDirectly(String phoneNumber) {
    970             // No need to call phone number directly from People app.
    971             Log.w(TAG, "unexpected invocation of onCallNumberDirectly()");
    972         }
    973     }
    974 
    975     @Override
    976     public boolean onCreateOptionsMenu(Menu menu) {
    977         if (!areContactsAvailable()) {
    978             // If contacts aren't available, hide all menu items.
    979             return false;
    980         }
    981         super.onCreateOptionsMenu(menu);
    982 
    983         MenuInflater inflater = getMenuInflater();
    984         inflater.inflate(R.menu.people_options, menu);
    985 
    986         return true;
    987     }
    988 
    989     private void invalidateOptionsMenuIfNeeded() {
    990         if (isOptionsMenuChanged()) {
    991             invalidateOptionsMenu();
    992         }
    993     }
    994 
    995     public boolean isOptionsMenuChanged() {
    996         if (mOptionsMenuContactsAvailable != areContactsAvailable()) {
    997             return true;
    998         }
    999 
   1000         if (mAllFragment != null && mAllFragment.isOptionsMenuChanged()) {
   1001             return true;
   1002         }
   1003 
   1004         return false;
   1005     }
   1006 
   1007     @Override
   1008     public boolean onPrepareOptionsMenu(Menu menu) {
   1009         mOptionsMenuContactsAvailable = areContactsAvailable();
   1010         if (!mOptionsMenuContactsAvailable) {
   1011             return false;
   1012         }
   1013 
   1014         // Get references to individual menu items in the menu
   1015         final MenuItem contactsFilterMenu = menu.findItem(R.id.menu_contacts_filter);
   1016         final MenuItem clearFrequentsMenu = menu.findItem(R.id.menu_clear_frequents);
   1017         final MenuItem helpMenu = menu.findItem(R.id.menu_help);
   1018 
   1019         final boolean isSearchMode = mActionBarAdapter.isSearchMode();
   1020         if (isSearchMode) {
   1021             contactsFilterMenu.setVisible(false);
   1022             clearFrequentsMenu.setVisible(false);
   1023             helpMenu.setVisible(false);
   1024         } else {
   1025             switch (mActionBarAdapter.getCurrentTab()) {
   1026                 case TabState.FAVORITES:
   1027                     contactsFilterMenu.setVisible(false);
   1028                     clearFrequentsMenu.setVisible(hasFrequents());
   1029                     break;
   1030                 case TabState.ALL:
   1031                     contactsFilterMenu.setVisible(true);
   1032                     clearFrequentsMenu.setVisible(false);
   1033                     break;
   1034             }
   1035             HelpUtils.prepareHelpMenuItem(this, helpMenu, R.string.help_url_people_main);
   1036         }
   1037         final boolean showMiscOptions = !isSearchMode;
   1038         makeMenuItemVisible(menu, R.id.menu_search, showMiscOptions);
   1039         makeMenuItemVisible(menu, R.id.menu_import_export, showMiscOptions);
   1040         makeMenuItemVisible(menu, R.id.menu_accounts, showMiscOptions);
   1041         makeMenuItemVisible(menu, R.id.menu_settings,
   1042                 showMiscOptions && !ContactsPreferenceActivity.isEmpty(this));
   1043 
   1044         // Debug options need to be visible even in search mode.
   1045         makeMenuItemVisible(menu, R.id.export_database, mEnableDebugMenuOptions);
   1046 
   1047         return true;
   1048     }
   1049 
   1050     /**
   1051      * Returns whether there are any frequently contacted people being displayed
   1052      * @return
   1053      */
   1054     private boolean hasFrequents() {
   1055         return mFavoritesFragment.hasFrequents();
   1056     }
   1057 
   1058     private void makeMenuItemVisible(Menu menu, int itemId, boolean visible) {
   1059         MenuItem item =menu.findItem(itemId);
   1060         if (item != null) {
   1061             item.setVisible(visible);
   1062         }
   1063     }
   1064 
   1065     @Override
   1066     public boolean onOptionsItemSelected(MenuItem item) {
   1067         if (mDisableOptionItemSelected) {
   1068             return false;
   1069         }
   1070 
   1071         switch (item.getItemId()) {
   1072             case android.R.id.home: {
   1073                 // The home icon on the action bar is pressed
   1074                 if (mActionBarAdapter.isUpShowing()) {
   1075                     // "UP" icon press -- should be treated as "back".
   1076                     onBackPressed();
   1077                 }
   1078                 return true;
   1079             }
   1080             case R.id.menu_settings: {
   1081                 final Intent intent = new Intent(this, ContactsPreferenceActivity.class);
   1082                 // Since there is only one section right now, make sure it is selected on
   1083                 // small screens.
   1084                 intent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT,
   1085                         DisplayOptionsPreferenceFragment.class.getName());
   1086                 // By default, the title of the activity should be equivalent to the fragment
   1087                 // title. We set this argument to avoid this. Because of a bug, the following
   1088                 // line isn't necessary. But, once the bug is fixed this may become necessary.
   1089                 // b/5045558 refers to this issue, as well as another.
   1090                 intent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT_TITLE,
   1091                         R.string.activity_title_settings);
   1092                 startActivity(intent);
   1093                 return true;
   1094             }
   1095             case R.id.menu_contacts_filter: {
   1096                 AccountFilterUtil.startAccountFilterActivityForResult(
   1097                         this, SUBACTIVITY_ACCOUNT_FILTER,
   1098                         mContactListFilterController.getFilter());
   1099                 return true;
   1100             }
   1101             case R.id.menu_search: {
   1102                 onSearchRequested();
   1103                 return true;
   1104             }
   1105             case R.id.menu_import_export: {
   1106                 ImportExportDialogFragment.show(getFragmentManager(), areContactsAvailable(),
   1107                         PeopleActivity.class);
   1108                 return true;
   1109             }
   1110             case R.id.menu_clear_frequents: {
   1111                 ClearFrequentsDialog.show(getFragmentManager());
   1112                 return true;
   1113             }
   1114             case R.id.menu_accounts: {
   1115                 final Intent intent = new Intent(Settings.ACTION_SYNC_SETTINGS);
   1116                 intent.putExtra(Settings.EXTRA_AUTHORITIES, new String[] {
   1117                     ContactsContract.AUTHORITY
   1118                 });
   1119                 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
   1120                 startActivity(intent);
   1121                 return true;
   1122             }
   1123             case R.id.export_database: {
   1124                 final Intent intent = new Intent("com.android.providers.contacts.DUMP_DATABASE");
   1125                 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
   1126                 startActivity(intent);
   1127                 return true;
   1128             }
   1129         }
   1130         return false;
   1131     }
   1132 
   1133     @Override
   1134     public boolean onSearchRequested() { // Search key pressed.
   1135         mActionBarAdapter.setSearchMode(true);
   1136         return true;
   1137     }
   1138 
   1139     @Override
   1140     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
   1141         switch (requestCode) {
   1142             case SUBACTIVITY_ACCOUNT_FILTER: {
   1143                 AccountFilterUtil.handleAccountFilterResult(
   1144                         mContactListFilterController, resultCode, data);
   1145                 break;
   1146             }
   1147 
   1148             // TODO: Using the new startActivityWithResultFromFragment API this should not be needed
   1149             // anymore
   1150             case ContactEntryListFragment.ACTIVITY_REQUEST_CODE_PICKER:
   1151                 if (resultCode == RESULT_OK) {
   1152                     mAllFragment.onPickerResult(data);
   1153                 }
   1154 
   1155 // TODO fix or remove multipicker code
   1156 //                else if (resultCode == RESULT_CANCELED && mMode == MODE_PICK_MULTIPLE_PHONES) {
   1157 //                    // Finish the activity if the sub activity was canceled as back key is used
   1158 //                    // to confirm user selection in MODE_PICK_MULTIPLE_PHONES.
   1159 //                    finish();
   1160 //                }
   1161 //                break;
   1162         }
   1163     }
   1164 
   1165     @Override
   1166     public boolean onKeyDown(int keyCode, KeyEvent event) {
   1167         // TODO move to the fragment
   1168         switch (keyCode) {
   1169 //            case KeyEvent.KEYCODE_CALL: {
   1170 //                if (callSelection()) {
   1171 //                    return true;
   1172 //                }
   1173 //                break;
   1174 //            }
   1175 
   1176             case KeyEvent.KEYCODE_DEL: {
   1177                 if (deleteSelection()) {
   1178                     return true;
   1179                 }
   1180                 break;
   1181             }
   1182             default: {
   1183                 // Bring up the search UI if the user starts typing
   1184                 final int unicodeChar = event.getUnicodeChar();
   1185                 if ((unicodeChar != 0)
   1186                         // If COMBINING_ACCENT is set, it's not a unicode character.
   1187                         && ((unicodeChar & KeyCharacterMap.COMBINING_ACCENT) == 0)
   1188                         && !Character.isWhitespace(unicodeChar)) {
   1189                     String query = new String(new int[]{ unicodeChar }, 0, 1);
   1190                     if (!mActionBarAdapter.isSearchMode()) {
   1191                         mActionBarAdapter.setQueryString(query);
   1192                         mActionBarAdapter.setSearchMode(true);
   1193                         return true;
   1194                     }
   1195                 }
   1196             }
   1197         }
   1198 
   1199         return super.onKeyDown(keyCode, event);
   1200     }
   1201 
   1202     @Override
   1203     public void onBackPressed() {
   1204         if (mActionBarAdapter.isSearchMode()) {
   1205             mActionBarAdapter.setSearchMode(false);
   1206         } else {
   1207             super.onBackPressed();
   1208         }
   1209     }
   1210 
   1211     private boolean deleteSelection() {
   1212         // TODO move to the fragment
   1213 //        if (mActionCode == ContactsRequest.ACTION_DEFAULT) {
   1214 //            final int position = mListView.getSelectedItemPosition();
   1215 //            if (position != ListView.INVALID_POSITION) {
   1216 //                Uri contactUri = getContactUri(position);
   1217 //                if (contactUri != null) {
   1218 //                    doContactDelete(contactUri);
   1219 //                    return true;
   1220 //                }
   1221 //            }
   1222 //        }
   1223         return false;
   1224     }
   1225 
   1226     @Override
   1227     protected void onSaveInstanceState(Bundle outState) {
   1228         super.onSaveInstanceState(outState);
   1229         mActionBarAdapter.onSaveInstanceState(outState);
   1230 
   1231         // Clear the listener to make sure we don't get callbacks after onSaveInstanceState,
   1232         // in order to avoid doing fragment transactions after it.
   1233         // TODO Figure out a better way to deal with the issue.
   1234         mDisableOptionItemSelected = true;
   1235         mActionBarAdapter.setListener(null);
   1236         if (mTabPager != null) {
   1237             mTabPager.setOnPageChangeListener(null);
   1238         }
   1239     }
   1240 
   1241     @Override
   1242     protected void onRestoreInstanceState(Bundle savedInstanceState) {
   1243         super.onRestoreInstanceState(savedInstanceState);
   1244         // In our own lifecycle, the focus is saved and restore but later taken away by the
   1245         // ViewPager. As a hack, we force focus on the SearchView if we know that we are searching.
   1246         // This fixes the keyboard going away on screen rotation
   1247         if (mActionBarAdapter.isSearchMode()) {
   1248             mActionBarAdapter.setFocusOnSearchView();
   1249         }
   1250     }
   1251 
   1252     @Override
   1253     public DialogManager getDialogManager() {
   1254         return mDialogManager;
   1255     }
   1256 
   1257     @Override
   1258     public void onClick(View view) {
   1259         switch (view.getId()) {
   1260             case R.id.floating_action_button:
   1261                 Intent intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI);
   1262                 Bundle extras = getIntent().getExtras();
   1263                 if (extras != null) {
   1264                     intent.putExtras(extras);
   1265                 }
   1266                 startActivity(intent);
   1267                 break;
   1268         default:
   1269             Log.wtf(TAG, "Unexpected onClick event from " + view);
   1270         }
   1271     }
   1272 
   1273     /**
   1274      * Returns the tab position adjusted for the text direction.
   1275      */
   1276     private int getTabPositionForTextDirection(int position) {
   1277         if (isRTL()) {
   1278             return TabState.COUNT - 1 - position;
   1279         }
   1280         return position;
   1281     }
   1282 }
   1283