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.ActionBar;
     20 import android.app.ActionBar.LayoutParams;
     21 import android.app.Activity;
     22 import android.app.Fragment;
     23 import android.content.ActivityNotFoundException;
     24 import android.content.Context;
     25 import android.content.Intent;
     26 import android.net.Uri;
     27 import android.os.Bundle;
     28 import android.provider.ContactsContract.Contacts;
     29 import android.provider.ContactsContract.Intents.Insert;
     30 import android.provider.ContactsContract.Intents.UI;
     31 import android.text.TextUtils;
     32 import android.util.Log;
     33 import android.view.LayoutInflater;
     34 import android.view.Menu;
     35 import android.view.MenuInflater;
     36 import android.view.MenuItem;
     37 import android.view.View;
     38 import android.view.View.OnClickListener;
     39 import android.view.View.OnFocusChangeListener;
     40 import android.view.inputmethod.InputMethodManager;
     41 import android.widget.SearchView;
     42 import android.widget.SearchView.OnCloseListener;
     43 import android.widget.SearchView.OnQueryTextListener;
     44 import android.widget.Toast;
     45 
     46 import com.android.contacts.ContactsActivity;
     47 import com.android.contacts.R;
     48 import com.android.contacts.common.list.ContactEntryListFragment;
     49 import com.android.contacts.list.ContactPickerFragment;
     50 import com.android.contacts.list.ContactsIntentResolver;
     51 import com.android.contacts.list.ContactsRequest;
     52 import com.android.contacts.common.list.DirectoryListLoader;
     53 import com.android.contacts.list.EmailAddressPickerFragment;
     54 import com.android.contacts.list.JoinContactListFragment;
     55 import com.android.contacts.list.LegacyPhoneNumberPickerFragment;
     56 import com.android.contacts.list.OnContactPickerActionListener;
     57 import com.android.contacts.list.OnEmailAddressPickerActionListener;
     58 import com.android.contacts.common.list.OnPhoneNumberPickerActionListener;
     59 import com.android.contacts.list.OnPostalAddressPickerActionListener;
     60 import com.android.contacts.common.list.PhoneNumberPickerFragment;
     61 import com.android.contacts.list.PostalAddressPickerFragment;
     62 import com.google.common.collect.Sets;
     63 
     64 import java.util.Set;
     65 
     66 /**
     67  * Displays a list of contacts (or phone numbers or postal addresses) for the
     68  * purposes of selecting one.
     69  */
     70 public class ContactSelectionActivity extends ContactsActivity
     71         implements View.OnCreateContextMenuListener, OnQueryTextListener, OnClickListener,
     72                 OnCloseListener, OnFocusChangeListener {
     73     private static final String TAG = "ContactSelectionActivity";
     74 
     75     private static final int SUBACTIVITY_ADD_TO_EXISTING_CONTACT = 0;
     76 
     77     private static final String KEY_ACTION_CODE = "actionCode";
     78     private static final String KEY_SEARCH_MODE = "searchMode";
     79     private static final int DEFAULT_DIRECTORY_RESULT_LIMIT = 20;
     80 
     81     private ContactsIntentResolver mIntentResolver;
     82     protected ContactEntryListFragment<?> mListFragment;
     83 
     84     private int mActionCode = -1;
     85     private boolean mIsSearchMode;
     86 
     87     private ContactsRequest mRequest;
     88     private SearchView mSearchView;
     89     private View mSearchViewContainer;
     90 
     91     public ContactSelectionActivity() {
     92         mIntentResolver = new ContactsIntentResolver(this);
     93     }
     94 
     95     @Override
     96     public void onAttachFragment(Fragment fragment) {
     97         if (fragment instanceof ContactEntryListFragment<?>) {
     98             mListFragment = (ContactEntryListFragment<?>) fragment;
     99             setupActionListener();
    100         }
    101     }
    102 
    103     @Override
    104     protected void onCreate(Bundle savedState) {
    105         super.onCreate(savedState);
    106 
    107         if (savedState != null) {
    108             mActionCode = savedState.getInt(KEY_ACTION_CODE);
    109             mIsSearchMode = savedState.getBoolean(KEY_SEARCH_MODE);
    110         }
    111 
    112         // Extract relevant information from the intent
    113         mRequest = mIntentResolver.resolveIntent(getIntent());
    114         if (!mRequest.isValid()) {
    115             setResult(RESULT_CANCELED);
    116             finish();
    117             return;
    118         }
    119 
    120         Intent redirect = mRequest.getRedirectIntent();
    121         if (redirect != null) {
    122             // Need to start a different activity
    123             startActivity(redirect);
    124             finish();
    125             return;
    126         }
    127 
    128         configureActivityTitle();
    129 
    130         setContentView(R.layout.contact_picker);
    131 
    132         if (mActionCode != mRequest.getActionCode()) {
    133             mActionCode = mRequest.getActionCode();
    134             configureListFragment();
    135         }
    136 
    137         prepareSearchViewAndActionBar();
    138     }
    139 
    140     private void prepareSearchViewAndActionBar() {
    141         final ActionBar actionBar = getActionBar();
    142         mSearchViewContainer = LayoutInflater.from(actionBar.getThemedContext())
    143                 .inflate(R.layout.custom_action_bar, null);
    144         mSearchView = (SearchView) mSearchViewContainer.findViewById(R.id.search_view);
    145 
    146         // Postal address pickers (and legacy pickers) don't support search, so just show
    147         // "HomeAsUp" button and title.
    148         if (mRequest.getActionCode() == ContactsRequest.ACTION_PICK_POSTAL ||
    149                 mRequest.isLegacyCompatibilityMode()) {
    150             mSearchView.setVisibility(View.GONE);
    151             if (actionBar != null) {
    152                 actionBar.setDisplayShowHomeEnabled(true);
    153                 actionBar.setDisplayHomeAsUpEnabled(true);
    154                 actionBar.setDisplayShowTitleEnabled(true);
    155             }
    156             return;
    157         }
    158 
    159         actionBar.setDisplayShowHomeEnabled(true);
    160         actionBar.setDisplayHomeAsUpEnabled(true);
    161 
    162         // In order to make the SearchView look like "shown via search menu", we need to
    163         // manually setup its state. See also DialtactsActivity.java and ActionBarAdapter.java.
    164         mSearchView.setIconifiedByDefault(true);
    165         mSearchView.setQueryHint(getString(R.string.hint_findContacts));
    166         mSearchView.setIconified(false);
    167         mSearchView.setFocusable(true);
    168 
    169         mSearchView.setOnQueryTextListener(this);
    170         mSearchView.setOnCloseListener(this);
    171         mSearchView.setOnQueryTextFocusChangeListener(this);
    172 
    173         actionBar.setCustomView(mSearchViewContainer,
    174                 new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
    175         actionBar.setDisplayShowCustomEnabled(true);
    176 
    177         configureSearchMode();
    178     }
    179 
    180     private void configureSearchMode() {
    181         final ActionBar actionBar = getActionBar();
    182         if (mIsSearchMode) {
    183             actionBar.setDisplayShowTitleEnabled(false);
    184             mSearchViewContainer.setVisibility(View.VISIBLE);
    185             mSearchView.requestFocus();
    186         } else {
    187             actionBar.setDisplayShowTitleEnabled(true);
    188             mSearchViewContainer.setVisibility(View.GONE);
    189             mSearchView.setQuery(null, true);
    190         }
    191         invalidateOptionsMenu();
    192     }
    193 
    194     @Override
    195     public boolean onOptionsItemSelected(MenuItem item) {
    196         switch (item.getItemId()) {
    197             case android.R.id.home:
    198                 // Go back to previous screen, intending "cancel"
    199                 setResult(RESULT_CANCELED);
    200                 onBackPressed();
    201                 return true;
    202             case R.id.menu_search:
    203                 mIsSearchMode = !mIsSearchMode;
    204                 configureSearchMode();
    205                 return true;
    206         }
    207         return super.onOptionsItemSelected(item);
    208     }
    209 
    210     @Override
    211     protected void onSaveInstanceState(Bundle outState) {
    212         super.onSaveInstanceState(outState);
    213         outState.putInt(KEY_ACTION_CODE, mActionCode);
    214         outState.putBoolean(KEY_SEARCH_MODE, mIsSearchMode);
    215     }
    216 
    217     private void configureActivityTitle() {
    218         if (!TextUtils.isEmpty(mRequest.getActivityTitle())) {
    219             setTitle(mRequest.getActivityTitle());
    220             return;
    221         }
    222 
    223         int actionCode = mRequest.getActionCode();
    224         switch (actionCode) {
    225             case ContactsRequest.ACTION_INSERT_OR_EDIT_CONTACT: {
    226                 setTitle(R.string.contactPickerActivityTitle);
    227                 break;
    228             }
    229 
    230             case ContactsRequest.ACTION_PICK_CONTACT: {
    231                 setTitle(R.string.contactPickerActivityTitle);
    232                 break;
    233             }
    234 
    235             case ContactsRequest.ACTION_PICK_OR_CREATE_CONTACT: {
    236                 setTitle(R.string.contactPickerActivityTitle);
    237                 break;
    238             }
    239 
    240             case ContactsRequest.ACTION_CREATE_SHORTCUT_CONTACT: {
    241                 setTitle(R.string.shortcutActivityTitle);
    242                 break;
    243             }
    244 
    245             case ContactsRequest.ACTION_PICK_PHONE: {
    246                 setTitle(R.string.contactPickerActivityTitle);
    247                 break;
    248             }
    249 
    250             case ContactsRequest.ACTION_PICK_EMAIL: {
    251                 setTitle(R.string.contactPickerActivityTitle);
    252                 break;
    253             }
    254 
    255             case ContactsRequest.ACTION_CREATE_SHORTCUT_CALL: {
    256                 setTitle(R.string.callShortcutActivityTitle);
    257                 break;
    258             }
    259 
    260             case ContactsRequest.ACTION_CREATE_SHORTCUT_SMS: {
    261                 setTitle(R.string.messageShortcutActivityTitle);
    262                 break;
    263             }
    264 
    265             case ContactsRequest.ACTION_PICK_POSTAL: {
    266                 setTitle(R.string.contactPickerActivityTitle);
    267                 break;
    268             }
    269 
    270             case ContactsRequest.ACTION_PICK_JOIN: {
    271                 setTitle(R.string.titleJoinContactDataWith);
    272                 break;
    273             }
    274         }
    275     }
    276 
    277     /**
    278      * Creates the fragment based on the current request.
    279      */
    280     public void configureListFragment() {
    281         switch (mActionCode) {
    282             case ContactsRequest.ACTION_INSERT_OR_EDIT_CONTACT: {
    283                 ContactPickerFragment fragment = new ContactPickerFragment();
    284                 fragment.setEditMode(true);
    285                 fragment.setDirectorySearchMode(DirectoryListLoader.SEARCH_MODE_NONE);
    286                 fragment.setCreateContactEnabled(!mRequest.isSearchMode());
    287                 mListFragment = fragment;
    288                 break;
    289             }
    290 
    291             case ContactsRequest.ACTION_DEFAULT:
    292             case ContactsRequest.ACTION_PICK_CONTACT: {
    293                 ContactPickerFragment fragment = new ContactPickerFragment();
    294                 fragment.setIncludeProfile(mRequest.shouldIncludeProfile());
    295                 mListFragment = fragment;
    296                 break;
    297             }
    298 
    299             case ContactsRequest.ACTION_PICK_OR_CREATE_CONTACT: {
    300                 ContactPickerFragment fragment = new ContactPickerFragment();
    301                 fragment.setCreateContactEnabled(!mRequest.isSearchMode());
    302                 mListFragment = fragment;
    303                 break;
    304             }
    305 
    306             case ContactsRequest.ACTION_CREATE_SHORTCUT_CONTACT: {
    307                 ContactPickerFragment fragment = new ContactPickerFragment();
    308                 fragment.setShortcutRequested(true);
    309                 mListFragment = fragment;
    310                 break;
    311             }
    312 
    313             case ContactsRequest.ACTION_PICK_PHONE: {
    314                 PhoneNumberPickerFragment fragment = getPhoneNumberPickerFragment(mRequest);
    315                 mListFragment = fragment;
    316                 break;
    317             }
    318 
    319             case ContactsRequest.ACTION_PICK_EMAIL: {
    320                 mListFragment = new EmailAddressPickerFragment();
    321                 break;
    322             }
    323 
    324             case ContactsRequest.ACTION_CREATE_SHORTCUT_CALL: {
    325                 PhoneNumberPickerFragment fragment = getPhoneNumberPickerFragment(mRequest);
    326                 fragment.setShortcutAction(Intent.ACTION_CALL);
    327 
    328                 mListFragment = fragment;
    329                 break;
    330             }
    331 
    332             case ContactsRequest.ACTION_CREATE_SHORTCUT_SMS: {
    333                 PhoneNumberPickerFragment fragment = getPhoneNumberPickerFragment(mRequest);
    334                 fragment.setShortcutAction(Intent.ACTION_SENDTO);
    335 
    336                 mListFragment = fragment;
    337                 break;
    338             }
    339 
    340             case ContactsRequest.ACTION_PICK_POSTAL: {
    341                 PostalAddressPickerFragment fragment = new PostalAddressPickerFragment();
    342 
    343                 mListFragment = fragment;
    344                 break;
    345             }
    346 
    347             case ContactsRequest.ACTION_PICK_JOIN: {
    348                 JoinContactListFragment joinFragment = new JoinContactListFragment();
    349                 joinFragment.setTargetContactId(getTargetContactId());
    350                 mListFragment = joinFragment;
    351                 break;
    352             }
    353 
    354             default:
    355                 throw new IllegalStateException("Invalid action code: " + mActionCode);
    356         }
    357 
    358         // Setting compatibility is no longer needed for PhoneNumberPickerFragment since that logic
    359         // has been separated into LegacyPhoneNumberPickerFragment.  But we still need to set
    360         // compatibility for other fragments.
    361         mListFragment.setLegacyCompatibilityMode(mRequest.isLegacyCompatibilityMode());
    362         mListFragment.setDirectoryResultLimit(DEFAULT_DIRECTORY_RESULT_LIMIT);
    363 
    364         getFragmentManager().beginTransaction()
    365                 .replace(R.id.list_container, mListFragment)
    366                 .commitAllowingStateLoss();
    367     }
    368 
    369     private PhoneNumberPickerFragment getPhoneNumberPickerFragment(ContactsRequest request) {
    370         if (mRequest.isLegacyCompatibilityMode()) {
    371             return new LegacyPhoneNumberPickerFragment();
    372         } else {
    373             return new PhoneNumberPickerFragment();
    374         }
    375     }
    376 
    377     public void setupActionListener() {
    378         if (mListFragment instanceof ContactPickerFragment) {
    379             ((ContactPickerFragment) mListFragment).setOnContactPickerActionListener(
    380                     new ContactPickerActionListener());
    381         } else if (mListFragment instanceof PhoneNumberPickerFragment) {
    382             ((PhoneNumberPickerFragment) mListFragment).setOnPhoneNumberPickerActionListener(
    383                     new PhoneNumberPickerActionListener());
    384         } else if (mListFragment instanceof PostalAddressPickerFragment) {
    385             ((PostalAddressPickerFragment) mListFragment).setOnPostalAddressPickerActionListener(
    386                     new PostalAddressPickerActionListener());
    387         } else if (mListFragment instanceof EmailAddressPickerFragment) {
    388             ((EmailAddressPickerFragment) mListFragment).setOnEmailAddressPickerActionListener(
    389                     new EmailAddressPickerActionListener());
    390         } else if (mListFragment instanceof JoinContactListFragment) {
    391             ((JoinContactListFragment) mListFragment).setOnContactPickerActionListener(
    392                     new JoinContactActionListener());
    393         } else {
    394             throw new IllegalStateException("Unsupported list fragment type: " + mListFragment);
    395         }
    396     }
    397 
    398     private final class ContactPickerActionListener implements OnContactPickerActionListener {
    399         @Override
    400         public void onCreateNewContactAction() {
    401             startCreateNewContactActivity();
    402         }
    403 
    404         @Override
    405         public void onEditContactAction(Uri contactLookupUri) {
    406             Bundle extras = getIntent().getExtras();
    407             if (launchAddToContactDialog(extras)) {
    408                 // Show a confirmation dialog to add the value(s) to the existing contact.
    409                 Intent intent = new Intent(ContactSelectionActivity.this,
    410                         ConfirmAddDetailActivity.class);
    411                 intent.setData(contactLookupUri);
    412                 if (extras != null) {
    413                     // First remove name key if present because the dialog does not support name
    414                     // editing. This is fine because the user wants to add information to an
    415                     // existing contact, who should already have a name and we wouldn't want to
    416                     // override the name.
    417                     extras.remove(Insert.NAME);
    418                     intent.putExtras(extras);
    419                 }
    420 
    421                 // Wait for the activity result because we want to keep the picker open (in case the
    422                 // user cancels adding the info to a contact and wants to pick someone else).
    423                 startActivityForResult(intent, SUBACTIVITY_ADD_TO_EXISTING_CONTACT);
    424             } else {
    425                 // Otherwise launch the full contact editor.
    426                 startActivityAndForwardResult(new Intent(Intent.ACTION_EDIT, contactLookupUri));
    427             }
    428         }
    429 
    430         @Override
    431         public void onPickContactAction(Uri contactUri) {
    432             returnPickerResult(contactUri);
    433         }
    434 
    435         @Override
    436         public void onShortcutIntentCreated(Intent intent) {
    437             returnPickerResult(intent);
    438         }
    439 
    440         /**
    441          * Returns true if is a single email or single phone number provided in the {@link Intent}
    442          * extras bundle so that a pop-up confirmation dialog can be used to add the data to
    443          * a contact. Otherwise return false if there are other intent extras that require launching
    444          * the full contact editor. Ignore extras with the key {@link Insert.NAME} because names
    445          * are a special case and we typically don't want to replace the name of an existing
    446          * contact.
    447          */
    448         private boolean launchAddToContactDialog(Bundle extras) {
    449             if (extras == null) {
    450                 return false;
    451             }
    452 
    453             // Copy extras because the set may be modified in the next step
    454             Set<String> intentExtraKeys = Sets.newHashSet();
    455             intentExtraKeys.addAll(extras.keySet());
    456 
    457             // Ignore name key because this is an existing contact.
    458             if (intentExtraKeys.contains(Insert.NAME)) {
    459                 intentExtraKeys.remove(Insert.NAME);
    460             }
    461 
    462             int numIntentExtraKeys = intentExtraKeys.size();
    463             if (numIntentExtraKeys == 2) {
    464                 boolean hasPhone = intentExtraKeys.contains(Insert.PHONE) &&
    465                         intentExtraKeys.contains(Insert.PHONE_TYPE);
    466                 boolean hasEmail = intentExtraKeys.contains(Insert.EMAIL) &&
    467                         intentExtraKeys.contains(Insert.EMAIL_TYPE);
    468                 return hasPhone || hasEmail;
    469             } else if (numIntentExtraKeys == 1) {
    470                 return intentExtraKeys.contains(Insert.PHONE) ||
    471                         intentExtraKeys.contains(Insert.EMAIL);
    472             }
    473             // Having 0 or more than 2 intent extra keys means that we should launch
    474             // the full contact editor to properly handle the intent extras.
    475             return false;
    476         }
    477     }
    478 
    479     private final class PhoneNumberPickerActionListener implements
    480             OnPhoneNumberPickerActionListener {
    481         @Override
    482         public void onPickPhoneNumberAction(Uri dataUri) {
    483             returnPickerResult(dataUri);
    484         }
    485 
    486         @Override
    487         public void onCallNumberDirectly(String phoneNumber) {
    488             Log.w(TAG, "Unsupported call.");
    489         }
    490 
    491         @Override
    492         public void onCallNumberDirectly(String phoneNumber, boolean isVideoCall) {
    493             Log.w(TAG, "Unsupported call.");
    494         }
    495 
    496         @Override
    497         public void onShortcutIntentCreated(Intent intent) {
    498             returnPickerResult(intent);
    499         }
    500 
    501         public void onHomeInActionBarSelected() {
    502             ContactSelectionActivity.this.onBackPressed();
    503         }
    504     }
    505 
    506     private final class JoinContactActionListener implements OnContactPickerActionListener {
    507         @Override
    508         public void onPickContactAction(Uri contactUri) {
    509             Intent intent = new Intent(null, contactUri);
    510             setResult(RESULT_OK, intent);
    511             finish();
    512         }
    513 
    514         @Override
    515         public void onShortcutIntentCreated(Intent intent) {
    516         }
    517 
    518         @Override
    519         public void onCreateNewContactAction() {
    520         }
    521 
    522         @Override
    523         public void onEditContactAction(Uri contactLookupUri) {
    524         }
    525     }
    526 
    527     private final class PostalAddressPickerActionListener implements
    528             OnPostalAddressPickerActionListener {
    529         @Override
    530         public void onPickPostalAddressAction(Uri dataUri) {
    531             returnPickerResult(dataUri);
    532         }
    533     }
    534 
    535     private final class EmailAddressPickerActionListener implements
    536             OnEmailAddressPickerActionListener {
    537         @Override
    538         public void onPickEmailAddressAction(Uri dataUri) {
    539             returnPickerResult(dataUri);
    540         }
    541     }
    542 
    543     public void startActivityAndForwardResult(final Intent intent) {
    544         intent.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
    545 
    546         // Forward extras to the new activity
    547         Bundle extras = getIntent().getExtras();
    548         if (extras != null) {
    549             intent.putExtras(extras);
    550         }
    551         try {
    552             startActivity(intent);
    553         } catch (ActivityNotFoundException e) {
    554             Log.e(TAG, "startActivity() failed: " + e);
    555             Toast.makeText(ContactSelectionActivity.this, R.string.missing_app,
    556                     Toast.LENGTH_SHORT).show();
    557         }
    558         finish();
    559     }
    560 
    561     @Override
    562     public boolean onQueryTextChange(String newText) {
    563         mListFragment.setQueryString(newText, true);
    564         return false;
    565     }
    566 
    567     @Override
    568     public boolean onQueryTextSubmit(String query) {
    569         return false;
    570     }
    571 
    572     @Override
    573     public boolean onClose() {
    574         if (!TextUtils.isEmpty(mSearchView.getQuery())) {
    575             mSearchView.setQuery(null, true);
    576         }
    577         return true;
    578     }
    579 
    580     @Override
    581     public void onFocusChange(View view, boolean hasFocus) {
    582         switch (view.getId()) {
    583             case R.id.search_view: {
    584                 if (hasFocus) {
    585                     showInputMethod(mSearchView.findFocus());
    586                 }
    587             }
    588         }
    589     }
    590 
    591     public void returnPickerResult(Uri data) {
    592         Intent intent = new Intent();
    593         intent.setData(data);
    594         returnPickerResult(intent);
    595     }
    596 
    597     public void returnPickerResult(Intent intent) {
    598         intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    599         setResult(RESULT_OK, intent);
    600         finish();
    601     }
    602 
    603     @Override
    604     public void onClick(View view) {
    605         switch (view.getId()) {
    606             case R.id.floating_action_button: {
    607                 startCreateNewContactActivity();
    608                 break;
    609             }
    610         }
    611     }
    612 
    613     private long getTargetContactId() {
    614         Intent intent = getIntent();
    615         final long targetContactId = intent.getLongExtra(UI.TARGET_CONTACT_ID_EXTRA_KEY, -1);
    616         if (targetContactId == -1) {
    617             Log.e(TAG, "Intent " + intent.getAction() + " is missing required extra: "
    618                     + UI.TARGET_CONTACT_ID_EXTRA_KEY);
    619             setResult(RESULT_CANCELED);
    620             finish();
    621             return -1;
    622         }
    623         return targetContactId;
    624     }
    625 
    626     private void startCreateNewContactActivity() {
    627         Intent intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI);
    628         intent.putExtra(ContactEditorActivity.INTENT_KEY_FINISH_ACTIVITY_ON_SAVE_COMPLETED, true);
    629         startActivityAndForwardResult(intent);
    630     }
    631 
    632     private void showInputMethod(View view) {
    633         final InputMethodManager imm = (InputMethodManager)
    634                 getSystemService(Context.INPUT_METHOD_SERVICE);
    635         if (imm != null) {
    636             if (!imm.showSoftInput(view, 0)) {
    637                 Log.w(TAG, "Failed to show soft input method.");
    638             }
    639         }
    640     }
    641 
    642     @Override
    643     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    644         super.onActivityResult(requestCode, resultCode, data);
    645         if (requestCode == SUBACTIVITY_ADD_TO_EXISTING_CONTACT) {
    646             if (resultCode == Activity.RESULT_OK) {
    647                 if (data != null) {
    648                     startActivity(data);
    649                 }
    650                 finish();
    651             }
    652         }
    653     }
    654 
    655     @Override
    656     public boolean onCreateOptionsMenu(Menu menu) {
    657         super.onCreateOptionsMenu(menu);
    658 
    659         final MenuInflater inflater = getMenuInflater();
    660         inflater.inflate(R.menu.search_menu, menu);
    661 
    662         final MenuItem searchItem = menu.findItem(R.id.menu_search);
    663         searchItem.setVisible(!mIsSearchMode);
    664         return true;
    665     }
    666 
    667     @Override
    668     public void onBackPressed() {
    669         if (mIsSearchMode) {
    670             mIsSearchMode = false;
    671             configureSearchMode();
    672         } else {
    673             super.onBackPressed();
    674         }
    675     }
    676 }
    677