Home | History | Annotate | Download | only in activities
      1 /*
      2  * Copyright (C) 2007 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.content.ActivityNotFoundException;
     21 import android.content.Intent;
     22 import android.graphics.PorterDuff;
     23 import android.graphics.drawable.Drawable;
     24 import android.net.Uri;
     25 import android.os.Bundle;
     26 import android.provider.ContactsContract.Contacts;
     27 import android.support.v4.content.ContextCompat;
     28 import android.support.v7.widget.Toolbar;
     29 import android.text.TextUtils;
     30 import android.util.Log;
     31 import android.view.Menu;
     32 import android.view.MenuInflater;
     33 import android.view.MenuItem;
     34 import android.view.View;
     35 import android.view.View.OnClickListener;
     36 import android.view.View.OnFocusChangeListener;
     37 import android.widget.TextView;
     38 import android.widget.Toast;
     39 
     40 import com.android.contacts.AppCompatContactsActivity;
     41 import com.android.contacts.R;
     42 import com.android.contacts.editor.EditorIntents;
     43 import com.android.contacts.list.ContactEntryListFragment;
     44 import com.android.contacts.list.ContactPickerFragment;
     45 import com.android.contacts.list.ContactsIntentResolver;
     46 import com.android.contacts.list.ContactsRequest;
     47 import com.android.contacts.list.DirectoryListLoader;
     48 import com.android.contacts.list.EmailAddressPickerFragment;
     49 import com.android.contacts.list.GroupMemberPickerFragment;
     50 import com.android.contacts.list.JoinContactListFragment;
     51 import com.android.contacts.list.LegacyPhoneNumberPickerFragment;
     52 import com.android.contacts.list.MultiSelectContactsListFragment;
     53 import com.android.contacts.list.MultiSelectContactsListFragment.OnCheckBoxListActionListener;
     54 import com.android.contacts.list.MultiSelectEmailAddressesListFragment;
     55 import com.android.contacts.list.MultiSelectPhoneNumbersListFragment;
     56 import com.android.contacts.list.OnContactPickerActionListener;
     57 import com.android.contacts.list.OnEmailAddressPickerActionListener;
     58 import com.android.contacts.list.OnPhoneNumberPickerActionListener;
     59 import com.android.contacts.list.OnPostalAddressPickerActionListener;
     60 import com.android.contacts.list.PhoneNumberPickerFragment;
     61 import com.android.contacts.list.PostalAddressPickerFragment;
     62 import com.android.contacts.list.UiIntentActions;
     63 import com.android.contacts.logging.ListEvent;
     64 import com.android.contacts.util.ImplicitIntentsUtil;
     65 import com.android.contacts.util.ViewUtil;
     66 
     67 import java.util.ArrayList;
     68 
     69 /**
     70  * Displays a list of contacts (or phone numbers or postal addresses) for the
     71  * purposes of selecting one.
     72  */
     73 public class ContactSelectionActivity extends AppCompatContactsActivity implements
     74         View.OnCreateContextMenuListener, ActionBarAdapter.Listener, OnClickListener,
     75         OnFocusChangeListener, OnCheckBoxListActionListener {
     76     private static final String TAG = "ContactSelection";
     77 
     78     private static final String KEY_ACTION_CODE = "actionCode";
     79     private static final String KEY_SEARCH_MODE = "searchMode";
     80     private static final int DEFAULT_DIRECTORY_RESULT_LIMIT = 20;
     81 
     82     private ContactsIntentResolver mIntentResolver;
     83     protected ContactEntryListFragment<?> mListFragment;
     84 
     85     private int mActionCode = -1;
     86     private boolean mIsSearchMode;
     87     private boolean mIsSearchSupported;
     88 
     89     private ContactsRequest mRequest;
     90 
     91     private ActionBarAdapter mActionBarAdapter;
     92     private Toolbar mToolbar;
     93 
     94     public ContactSelectionActivity() {
     95         mIntentResolver = new ContactsIntentResolver(this);
     96     }
     97 
     98     @Override
     99     public void onAttachFragment(Fragment fragment) {
    100         if (fragment instanceof ContactEntryListFragment<?>) {
    101             mListFragment = (ContactEntryListFragment<?>) fragment;
    102             setupActionListener();
    103         }
    104     }
    105 
    106     @Override
    107     protected void onCreate(Bundle savedState) {
    108         super.onCreate(savedState);
    109 
    110         RequestPermissionsActivity.startPermissionActivityIfNeeded(this);
    111 
    112         if (savedState != null) {
    113             mActionCode = savedState.getInt(KEY_ACTION_CODE);
    114             mIsSearchMode = savedState.getBoolean(KEY_SEARCH_MODE);
    115         }
    116 
    117         // Extract relevant information from the intent
    118         mRequest = mIntentResolver.resolveIntent(getIntent());
    119         if (!mRequest.isValid()) {
    120             setResult(RESULT_CANCELED);
    121             finish();
    122             return;
    123         }
    124 
    125         setContentView(R.layout.contact_picker);
    126 
    127         if (mActionCode != mRequest.getActionCode()) {
    128             mActionCode = mRequest.getActionCode();
    129             configureListFragment();
    130         }
    131 
    132         prepareSearchViewAndActionBar(savedState);
    133         configureActivityTitle();
    134     }
    135 
    136     public boolean isSelectionMode() {
    137         return mActionBarAdapter.isSelectionMode();
    138     }
    139 
    140     public boolean isSearchMode() {
    141         return mActionBarAdapter.isSearchMode();
    142     }
    143 
    144     private void prepareSearchViewAndActionBar(Bundle savedState) {
    145         mToolbar = getView(R.id.toolbar);
    146         setSupportActionBar(mToolbar);
    147 
    148         // Add a shadow under the toolbar.
    149         ViewUtil.addRectangularOutlineProvider(findViewById(R.id.toolbar_parent), getResources());
    150 
    151         mActionBarAdapter = new ActionBarAdapter(this, this, getSupportActionBar(), mToolbar,
    152                 R.string.enter_contact_name);
    153         mActionBarAdapter.setShowHomeIcon(true);
    154         mActionBarAdapter.setShowHomeAsUp(true);
    155         mActionBarAdapter.initialize(savedState, mRequest);
    156 
    157         // Postal address pickers (and legacy pickers) don't support search, so just show
    158         // "HomeAsUp" button and title.
    159         mIsSearchSupported = mRequest.getActionCode() != ContactsRequest.ACTION_PICK_POSTAL
    160                 && mRequest.getActionCode() != ContactsRequest.ACTION_PICK_EMAILS
    161                 && mRequest.getActionCode() != ContactsRequest.ACTION_PICK_PHONES
    162                 && !mRequest.isLegacyCompatibilityMode();
    163         configureSearchMode();
    164     }
    165 
    166     private void configureSearchMode() {
    167         mActionBarAdapter.setSearchMode(mIsSearchMode);
    168         invalidateOptionsMenu();
    169     }
    170 
    171     @Override
    172     public boolean onOptionsItemSelected(MenuItem item) {
    173         final int id = item.getItemId();
    174         if (id == android.R.id.home) {// Go back to previous screen, intending "cancel"
    175             setResult(RESULT_CANCELED);
    176             onBackPressed();
    177         } else if (id == R.id.menu_search) {
    178             mIsSearchMode = !mIsSearchMode;
    179             configureSearchMode();
    180         } else {
    181             return super.onOptionsItemSelected(item);
    182         }
    183         return true;
    184     }
    185 
    186     @Override
    187     protected void onSaveInstanceState(Bundle outState) {
    188         super.onSaveInstanceState(outState);
    189         outState.putInt(KEY_ACTION_CODE, mActionCode);
    190         outState.putBoolean(KEY_SEARCH_MODE, mIsSearchMode);
    191         if (mActionBarAdapter != null) {
    192             mActionBarAdapter.onSaveInstanceState(outState);
    193         }
    194     }
    195 
    196     private void configureActivityTitle() {
    197         if (!TextUtils.isEmpty(mRequest.getActivityTitle())) {
    198             getSupportActionBar().setTitle(mRequest.getActivityTitle());
    199             return;
    200         }
    201         int titleResId = -1;
    202         int actionCode = mRequest.getActionCode();
    203         switch (actionCode) {
    204             case ContactsRequest.ACTION_INSERT_OR_EDIT_CONTACT: {
    205                 titleResId = R.string.contactInsertOrEditActivityTitle;
    206                 break;
    207             }
    208             case ContactsRequest.ACTION_PICK_CONTACT: {
    209                 titleResId = R.string.contactPickerActivityTitle;
    210                 break;
    211             }
    212             case ContactsRequest.ACTION_PICK_OR_CREATE_CONTACT: {
    213                 titleResId = R.string.contactPickerActivityTitle;
    214                 break;
    215             }
    216             case ContactsRequest.ACTION_CREATE_SHORTCUT_CONTACT: {
    217                 titleResId = R.string.shortcutActivityTitle;
    218                 break;
    219             }
    220             case ContactsRequest.ACTION_PICK_PHONE: {
    221                 titleResId = R.string.contactPickerActivityTitle;
    222                 break;
    223             }
    224             case ContactsRequest.ACTION_PICK_EMAIL: {
    225                 titleResId = R.string.contactPickerActivityTitle;
    226                 break;
    227             }
    228             case ContactsRequest.ACTION_PICK_PHONES: {
    229                 titleResId = R.string.pickerSelectContactsActivityTitle;
    230                 break;
    231             }
    232             case ContactsRequest.ACTION_PICK_EMAILS: {
    233                 titleResId = R.string.pickerSelectContactsActivityTitle;
    234                 break;
    235             }
    236             case ContactsRequest.ACTION_CREATE_SHORTCUT_CALL: {
    237                 titleResId = R.string.shortcutActivityTitle;
    238                 break;
    239             }
    240             case ContactsRequest.ACTION_CREATE_SHORTCUT_SMS: {
    241                 titleResId = R.string.shortcutActivityTitle;
    242                 break;
    243             }
    244             case ContactsRequest.ACTION_PICK_POSTAL: {
    245                 titleResId = R.string.contactPickerActivityTitle;
    246                 break;
    247             }
    248             case ContactsRequest.ACTION_PICK_JOIN: {
    249                 titleResId = R.string.titleJoinContactDataWith;
    250                 break;
    251             }
    252             case ContactsRequest.ACTION_PICK_GROUP_MEMBERS: {
    253                 titleResId = R.string.groupMemberPickerActivityTitle;
    254                 break;
    255             }
    256         }
    257         if (titleResId > 0) {
    258             getSupportActionBar().setTitle(titleResId);
    259         }
    260     }
    261 
    262     /**
    263      * Creates the fragment based on the current request.
    264      */
    265     public void configureListFragment() {
    266         switch (mActionCode) {
    267             case ContactsRequest.ACTION_INSERT_OR_EDIT_CONTACT: {
    268                 ContactPickerFragment fragment = new ContactPickerFragment();
    269                 fragment.setEditMode(true);
    270                 fragment.setDirectorySearchMode(DirectoryListLoader.SEARCH_MODE_NONE);
    271                 fragment.setCreateContactEnabled(!mRequest.isSearchMode());
    272                 fragment.setListType(ListEvent.ListType.PICK_CONTACT);
    273                 mListFragment = fragment;
    274                 break;
    275             }
    276 
    277             case ContactsRequest.ACTION_DEFAULT:
    278             case ContactsRequest.ACTION_PICK_CONTACT: {
    279                 ContactPickerFragment fragment = new ContactPickerFragment();
    280                 fragment.setIncludeFavorites(mRequest.shouldIncludeFavorites());
    281                 fragment.setListType(ListEvent.ListType.PICK_CONTACT);
    282                 mListFragment = fragment;
    283                 break;
    284             }
    285 
    286             case ContactsRequest.ACTION_PICK_OR_CREATE_CONTACT: {
    287                 ContactPickerFragment fragment = new ContactPickerFragment();
    288                 fragment.setCreateContactEnabled(!mRequest.isSearchMode());
    289                 fragment.setListType(ListEvent.ListType.PICK_CONTACT);
    290                 mListFragment = fragment;
    291                 break;
    292             }
    293 
    294             case ContactsRequest.ACTION_CREATE_SHORTCUT_CONTACT: {
    295                 ContactPickerFragment fragment = new ContactPickerFragment();
    296                 fragment.setShortcutRequested(true);
    297                 fragment.setListType(ListEvent.ListType.PICK_CONTACT_FOR_SHORTCUT);
    298                 mListFragment = fragment;
    299                 break;
    300             }
    301 
    302             case ContactsRequest.ACTION_PICK_PHONE: {
    303                 PhoneNumberPickerFragment fragment = getPhoneNumberPickerFragment(mRequest);
    304                 fragment.setListType(ListEvent.ListType.PICK_PHONE);
    305                 mListFragment = fragment;
    306                 break;
    307             }
    308 
    309             case ContactsRequest.ACTION_PICK_EMAIL: {
    310                 mListFragment = new EmailAddressPickerFragment();
    311                 mListFragment.setListType(ListEvent.ListType.PICK_EMAIL);
    312                 break;
    313             }
    314 
    315             case ContactsRequest.ACTION_PICK_PHONES: {
    316                 mListFragment = new MultiSelectPhoneNumbersListFragment();
    317                 mListFragment.setArguments(getIntent().getExtras());
    318                 break;
    319             }
    320 
    321             case ContactsRequest.ACTION_PICK_EMAILS: {
    322                 mListFragment = new MultiSelectEmailAddressesListFragment();
    323                 mListFragment.setArguments(getIntent().getExtras());
    324                 break;
    325             }
    326             case ContactsRequest.ACTION_CREATE_SHORTCUT_CALL: {
    327                 PhoneNumberPickerFragment fragment = getPhoneNumberPickerFragment(mRequest);
    328                 fragment.setShortcutAction(Intent.ACTION_CALL);
    329                 fragment.setListType(ListEvent.ListType.PICK_CONTACT_FOR_SHORTCUT);
    330                 mListFragment = fragment;
    331                 break;
    332             }
    333 
    334             case ContactsRequest.ACTION_CREATE_SHORTCUT_SMS: {
    335                 PhoneNumberPickerFragment fragment = getPhoneNumberPickerFragment(mRequest);
    336                 fragment.setShortcutAction(Intent.ACTION_SENDTO);
    337                 fragment.setListType(ListEvent.ListType.PICK_CONTACT_FOR_SHORTCUT);
    338                 mListFragment = fragment;
    339                 break;
    340             }
    341 
    342             case ContactsRequest.ACTION_PICK_POSTAL: {
    343                 PostalAddressPickerFragment fragment = new PostalAddressPickerFragment();
    344                 fragment.setListType(ListEvent.ListType.PICK_POSTAL);
    345                 mListFragment = fragment;
    346                 break;
    347             }
    348 
    349             case ContactsRequest.ACTION_PICK_JOIN: {
    350                 JoinContactListFragment joinFragment = new JoinContactListFragment();
    351                 joinFragment.setTargetContactId(getTargetContactId());
    352                 joinFragment.setListType(ListEvent.ListType.PICK_JOIN);
    353                 mListFragment = joinFragment;
    354                 break;
    355             }
    356 
    357             case ContactsRequest.ACTION_PICK_GROUP_MEMBERS: {
    358                 final String accountName = getIntent().getStringExtra(
    359                         UiIntentActions.GROUP_ACCOUNT_NAME);
    360                 final String accountType = getIntent().getStringExtra(
    361                         UiIntentActions.GROUP_ACCOUNT_TYPE);
    362                 final String accountDataSet = getIntent().getStringExtra(
    363                         UiIntentActions.GROUP_ACCOUNT_DATA_SET);
    364                 final ArrayList<String> contactIds = getIntent().getStringArrayListExtra(
    365                         UiIntentActions.GROUP_CONTACT_IDS);
    366                 mListFragment = GroupMemberPickerFragment.newInstance(
    367                         accountName, accountType, accountDataSet, contactIds);
    368                 mListFragment.setListType(ListEvent.ListType.PICK_GROUP_MEMBERS);
    369                 break;
    370             }
    371 
    372             default:
    373                 throw new IllegalStateException("Invalid action code: " + mActionCode);
    374         }
    375 
    376         // Setting compatibility is no longer needed for PhoneNumberPickerFragment since that logic
    377         // has been separated into LegacyPhoneNumberPickerFragment.  But we still need to set
    378         // compatibility for other fragments.
    379         mListFragment.setLegacyCompatibilityMode(mRequest.isLegacyCompatibilityMode());
    380         mListFragment.setDirectoryResultLimit(DEFAULT_DIRECTORY_RESULT_LIMIT);
    381 
    382         getFragmentManager().beginTransaction()
    383                 .replace(R.id.list_container, mListFragment)
    384                 .commitAllowingStateLoss();
    385     }
    386 
    387     private PhoneNumberPickerFragment getPhoneNumberPickerFragment(ContactsRequest request) {
    388         if (mRequest.isLegacyCompatibilityMode()) {
    389             return new LegacyPhoneNumberPickerFragment();
    390         } else {
    391             return new PhoneNumberPickerFragment();
    392         }
    393     }
    394 
    395     public void setupActionListener() {
    396         if (mListFragment instanceof ContactPickerFragment) {
    397             ((ContactPickerFragment) mListFragment).setOnContactPickerActionListener(
    398                     new ContactPickerActionListener());
    399         } else if (mListFragment instanceof PhoneNumberPickerFragment) {
    400             ((PhoneNumberPickerFragment) mListFragment).setOnPhoneNumberPickerActionListener(
    401                     new PhoneNumberPickerActionListener());
    402         } else if (mListFragment instanceof PostalAddressPickerFragment) {
    403             ((PostalAddressPickerFragment) mListFragment).setOnPostalAddressPickerActionListener(
    404                     new PostalAddressPickerActionListener());
    405         } else if (mListFragment instanceof EmailAddressPickerFragment) {
    406             ((EmailAddressPickerFragment) mListFragment).setOnEmailAddressPickerActionListener(
    407                     new EmailAddressPickerActionListener());
    408         } else if (mListFragment instanceof MultiSelectEmailAddressesListFragment) {
    409             ((MultiSelectEmailAddressesListFragment) mListFragment).setCheckBoxListListener(this);
    410         } else if (mListFragment instanceof MultiSelectPhoneNumbersListFragment) {
    411             ((MultiSelectPhoneNumbersListFragment) mListFragment).setCheckBoxListListener(this);
    412         } else if (mListFragment instanceof JoinContactListFragment) {
    413             ((JoinContactListFragment) mListFragment).setOnContactPickerActionListener(
    414                     new JoinContactActionListener());
    415         } else if (mListFragment instanceof GroupMemberPickerFragment) {
    416             ((GroupMemberPickerFragment) mListFragment).setListener(
    417                     new GroupMemberPickerListener());
    418             getMultiSelectListFragment().setCheckBoxListListener(this);
    419         } else {
    420             throw new IllegalStateException("Unsupported list fragment type: " + mListFragment);
    421         }
    422     }
    423 
    424     private MultiSelectContactsListFragment getMultiSelectListFragment() {
    425         if (mListFragment instanceof MultiSelectContactsListFragment) {
    426             return (MultiSelectContactsListFragment) mListFragment;
    427         }
    428         return null;
    429     }
    430 
    431     @Override
    432     public void onAction(int action) {
    433         switch (action) {
    434             case ActionBarAdapter.Listener.Action.START_SEARCH_MODE:
    435                 mIsSearchMode = true;
    436                 configureSearchMode();
    437                 break;
    438             case ActionBarAdapter.Listener.Action.CHANGE_SEARCH_QUERY:
    439                 final String queryString = mActionBarAdapter.getQueryString();
    440                 mListFragment.setQueryString(queryString, /* delaySelection */ false);
    441                 break;
    442             case ActionBarAdapter.Listener.Action.START_SELECTION_MODE:
    443                 if (getMultiSelectListFragment() != null) {
    444                     getMultiSelectListFragment().displayCheckBoxes(true);
    445                 }
    446                 invalidateOptionsMenu();
    447                 break;
    448             case ActionBarAdapter.Listener.Action.STOP_SEARCH_AND_SELECTION_MODE:
    449                 mListFragment.setQueryString("", /* delaySelection */ false);
    450                 mActionBarAdapter.setSearchMode(false);
    451                 if (getMultiSelectListFragment() != null) {
    452                     getMultiSelectListFragment().displayCheckBoxes(false);
    453                 }
    454                 invalidateOptionsMenu();
    455                 break;
    456         }
    457     }
    458 
    459     @Override
    460     public void onUpButtonPressed() {
    461         onBackPressed();
    462     }
    463 
    464     @Override
    465     public void onStartDisplayingCheckBoxes() {
    466         mActionBarAdapter.setSelectionMode(true);
    467     }
    468 
    469     @Override
    470     public void onSelectedContactIdsChanged() {
    471         if (mListFragment instanceof MultiSelectContactsListFragment) {
    472             final int count = getMultiSelectListFragment().getSelectedContactIds().size();
    473             mActionBarAdapter.setSelectionCount(count);
    474             updateAddContactsButton(count);
    475 
    476             // Show or hide the multi select "Done" button
    477             invalidateOptionsMenu();
    478         }
    479     }
    480 
    481     private void updateAddContactsButton(int count) {
    482         final TextView textView = (TextView) mActionBarAdapter.getSelectionContainer()
    483                 .findViewById(R.id.add_contacts);
    484         if (count > 0) {
    485             textView.setVisibility(View.VISIBLE);
    486             textView.setAllCaps(true);
    487             textView.setOnClickListener(new OnClickListener() {
    488                 @Override
    489                 public void onClick(View v) {
    490                     final long[] contactIds =
    491                             getMultiSelectListFragment().getSelectedContactIdsArray();
    492                     returnSelectedContacts(contactIds);
    493                 }
    494             });
    495         } else {
    496             textView.setVisibility(View.GONE);
    497         }
    498     }
    499 
    500     @Override
    501     public void onStopDisplayingCheckBoxes() {
    502         mActionBarAdapter.setSelectionMode(false);
    503     }
    504 
    505     private final class ContactPickerActionListener implements OnContactPickerActionListener {
    506         @Override
    507         public void onCreateNewContactAction() {
    508             startCreateNewContactActivity();
    509         }
    510 
    511         @Override
    512         public void onEditContactAction(Uri contactLookupUri) {
    513             startActivityAndForwardResult(EditorIntents.createEditContactIntent(
    514                     ContactSelectionActivity.this, contactLookupUri, /* materialPalette =*/ null,
    515                     /* photoId =*/ -1));
    516         }
    517 
    518         @Override
    519         public void onPickContactAction(Uri contactUri) {
    520             returnPickerResult(contactUri);
    521         }
    522 
    523         @Override
    524         public void onShortcutIntentCreated(Intent intent) {
    525             returnPickerResult(intent);
    526         }
    527     }
    528 
    529     private final class PhoneNumberPickerActionListener implements
    530             OnPhoneNumberPickerActionListener {
    531         @Override
    532         public void onPickDataUri(Uri dataUri, boolean isVideoCall, int callInitiationType) {
    533             returnPickerResult(dataUri);
    534         }
    535 
    536         @Override
    537         public void onPickPhoneNumber(String phoneNumber, boolean isVideoCall,
    538                                       int callInitiationType) {
    539             Log.w(TAG, "Unsupported call.");
    540         }
    541 
    542         @Override
    543         public void onShortcutIntentCreated(Intent intent) {
    544             returnPickerResult(intent);
    545         }
    546 
    547         @Override
    548         public void onHomeInActionBarSelected() {
    549             ContactSelectionActivity.this.onBackPressed();
    550         }
    551     }
    552 
    553     private final class JoinContactActionListener implements OnContactPickerActionListener {
    554         @Override
    555         public void onPickContactAction(Uri contactUri) {
    556             Intent intent = new Intent(null, contactUri);
    557             setResult(RESULT_OK, intent);
    558             finish();
    559         }
    560 
    561         @Override
    562         public void onShortcutIntentCreated(Intent intent) {
    563         }
    564 
    565         @Override
    566         public void onCreateNewContactAction() {
    567         }
    568 
    569         @Override
    570         public void onEditContactAction(Uri contactLookupUri) {
    571         }
    572     }
    573 
    574     private final class GroupMemberPickerListener implements GroupMemberPickerFragment.Listener {
    575 
    576         @Override
    577         public void onGroupMemberClicked(long contactId) {
    578             final Intent intent = new Intent();
    579             intent.putExtra(UiIntentActions.TARGET_CONTACT_ID_EXTRA_KEY, contactId);
    580             returnPickerResult(intent);
    581         }
    582 
    583         @Override
    584         public void onSelectGroupMembers() {
    585             mActionBarAdapter.setSelectionMode(true);
    586         }
    587     }
    588 
    589     private void returnSelectedContacts(long[] contactIds) {
    590         final Intent intent = new Intent();
    591         intent.putExtra(UiIntentActions.TARGET_CONTACT_IDS_EXTRA_KEY, contactIds);
    592         returnPickerResult(intent);
    593     }
    594 
    595     private final class PostalAddressPickerActionListener implements
    596             OnPostalAddressPickerActionListener {
    597         @Override
    598         public void onPickPostalAddressAction(Uri dataUri) {
    599             returnPickerResult(dataUri);
    600         }
    601     }
    602 
    603     private final class EmailAddressPickerActionListener implements
    604             OnEmailAddressPickerActionListener {
    605         @Override
    606         public void onPickEmailAddressAction(Uri dataUri) {
    607             returnPickerResult(dataUri);
    608         }
    609     }
    610 
    611     public void startActivityAndForwardResult(final Intent intent) {
    612         intent.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
    613 
    614         // Forward extras to the new activity
    615         Bundle extras = getIntent().getExtras();
    616         if (extras != null) {
    617             intent.putExtras(extras);
    618         }
    619         try {
    620             ImplicitIntentsUtil.startActivityInApp(ContactSelectionActivity.this, intent);
    621         } catch (ActivityNotFoundException e) {
    622             Log.e(TAG, "startActivity() failed: " + e);
    623             Toast.makeText(ContactSelectionActivity.this, R.string.missing_app,
    624                     Toast.LENGTH_SHORT).show();
    625         }
    626         finish();
    627     }
    628 
    629     @Override
    630     public void onFocusChange(View view, boolean hasFocus) {
    631         if (view.getId() == R.id.search_view) {
    632             if (hasFocus) {
    633                 mActionBarAdapter.setFocusOnSearchView();
    634             }
    635         }
    636     }
    637 
    638     public void returnPickerResult(Uri data) {
    639         Intent intent = new Intent();
    640         intent.setData(data);
    641         returnPickerResult(intent);
    642     }
    643 
    644     public void returnPickerResult(Intent intent) {
    645         intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    646         setResult(RESULT_OK, intent);
    647         finish();
    648     }
    649 
    650     @Override
    651     public void onClick(View view) {
    652         if (view.getId() == R.id.floating_action_button) {
    653             startCreateNewContactActivity();
    654         }
    655     }
    656 
    657     private long getTargetContactId() {
    658         Intent intent = getIntent();
    659         final long targetContactId = intent.getLongExtra(
    660                 UiIntentActions.TARGET_CONTACT_ID_EXTRA_KEY, -1);
    661         if (targetContactId == -1) {
    662             Log.e(TAG, "Intent " + intent.getAction() + " is missing required extra: "
    663                     + UiIntentActions.TARGET_CONTACT_ID_EXTRA_KEY);
    664             setResult(RESULT_CANCELED);
    665             finish();
    666             return -1;
    667         }
    668         return targetContactId;
    669     }
    670 
    671     private void startCreateNewContactActivity() {
    672         Intent intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI);
    673         intent.putExtra(ContactEditorActivity.
    674                 INTENT_KEY_FINISH_ACTIVITY_ON_SAVE_COMPLETED, true);
    675         startActivityAndForwardResult(intent);
    676     }
    677 
    678     @Override
    679     public boolean onCreateOptionsMenu(Menu menu) {
    680         super.onCreateOptionsMenu(menu);
    681 
    682         final MenuInflater inflater = getMenuInflater();
    683         inflater.inflate(R.menu.search_menu, menu);
    684 
    685         final MenuItem searchItem = menu.findItem(R.id.menu_search);
    686         searchItem.setVisible(!mIsSearchMode && mIsSearchSupported);
    687 
    688         final Drawable searchIcon = searchItem.getIcon();
    689         if (searchIcon != null) {
    690             searchIcon.mutate().setColorFilter(ContextCompat.getColor(this,
    691                     R.color.actionbar_icon_color), PorterDuff.Mode.SRC_ATOP);
    692         }
    693         return true;
    694     }
    695 
    696     @Override
    697     public void onBackPressed() {
    698         if (!isSafeToCommitTransactions()) {
    699             return;
    700         }
    701 
    702         if (isSelectionMode()) {
    703             mActionBarAdapter.setSelectionMode(false);
    704             if (getMultiSelectListFragment() != null) {
    705                 getMultiSelectListFragment().displayCheckBoxes(false);
    706             }
    707         } else if (mIsSearchMode) {
    708             mIsSearchMode = false;
    709             configureSearchMode();
    710         } else {
    711             super.onBackPressed();
    712         }
    713     }
    714 }
    715