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