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