DialtactsActivity.java revision cfcd0764a1ec53c6014df9ce3e7d3a3da511599f
1/* 2 * Copyright (C) 2008 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 17package com.android.contacts.activities; 18 19import com.android.contacts.R; 20import com.android.contacts.calllog.CallLogFragment; 21import com.android.contacts.dialpad.DialpadFragment; 22import com.android.contacts.interactions.ImportExportDialogFragment; 23import com.android.contacts.interactions.PhoneNumberInteraction; 24import com.android.contacts.list.ContactListFilter; 25import com.android.contacts.list.ContactsIntentResolver; 26import com.android.contacts.list.ContactsRequest; 27import com.android.contacts.list.DefaultContactBrowseListFragment; 28import com.android.contacts.list.DirectoryListLoader; 29import com.android.contacts.list.OnContactBrowserActionListener; 30import com.android.contacts.list.OnPhoneNumberPickerActionListener; 31import com.android.contacts.list.PhoneNumberPickerFragment; 32import com.android.contacts.list.StrequentContactListFragment; 33import com.android.contacts.preference.ContactsPreferenceActivity; 34import com.android.internal.telephony.ITelephony; 35 36import android.app.ActionBar; 37import android.app.ActionBar.LayoutParams; 38import android.app.ActionBar.Tab; 39import android.app.ActionBar.TabListener; 40import android.app.Activity; 41import android.app.Fragment; 42import android.app.FragmentManager; 43import android.app.FragmentTransaction; 44import android.content.Intent; 45import android.content.SharedPreferences; 46import android.net.Uri; 47import android.os.Bundle; 48import android.os.RemoteException; 49import android.os.ServiceManager; 50import android.provider.CallLog.Calls; 51import android.provider.ContactsContract; 52import android.provider.ContactsContract.Contacts; 53import android.provider.ContactsContract.Intents.UI; 54import android.provider.Settings; 55import android.text.TextUtils; 56import android.util.Log; 57import android.view.Menu; 58import android.view.MenuInflater; 59import android.view.MenuItem; 60import android.view.View; 61import android.widget.SearchView; 62import android.widget.SearchView.OnCloseListener; 63import android.widget.SearchView.OnQueryTextListener; 64 65/** 66 * The dialer activity that has one tab with the virtual 12key 67 * dialer, a tab with recent calls in it, a tab with the contacts and 68 * a tab with the favorite. This is the container and the tabs are 69 * embedded using intents. 70 * The dialer tab's title is 'phone', a more common name (see strings.xml). 71 */ 72public class DialtactsActivity extends Activity { 73 private static final String TAG = "DialtactsActivity"; 74 75 private static final int TAB_INDEX_DIALER = 0; 76 private static final int TAB_INDEX_CALL_LOG = 1; 77 private static final int TAB_INDEX_FAVORITES = 2; 78 79 private static final int TAB_INDEX_COUNT = 3; 80 81 public static final String EXTRA_IGNORE_STATE = "ignore-state"; 82 83 /** Name of the dialtacts shared preferences */ 84 static final String PREFS_DIALTACTS = "dialtacts"; 85 static final boolean PREF_FAVORITES_AS_CONTACTS_DEFAULT = false; 86 87 /** Last manually selected tab index */ 88 private static final String PREF_LAST_MANUALLY_SELECTED_TAB = "last_manually_selected_tab"; 89 private static final int PREF_LAST_MANUALLY_SELECTED_TAB_DEFAULT = TAB_INDEX_DIALER; 90 91 private String mFilterText; 92 private Uri mDialUri; 93 private DialpadFragment mDialpadFragment; 94 private CallLogFragment mCallLogFragment; 95 private DefaultContactBrowseListFragment mContactsFragment; 96 private StrequentContactListFragment mStrequentFragment; 97 98 /** 99 * Fragment for searching phone numbers. Unlike the other Fragments, this doesn't correspond 100 * to tab but is shown by a search action. 101 */ 102 private PhoneNumberPickerFragment mPhoneNumberPickerFragment; 103 /** 104 * True when this Activity is in its search UI (with a {@link SearchView} and 105 * {@link PhoneNumberPickerFragment}). 106 */ 107 private boolean mInSearchUi; 108 109 /** 110 * The index of the tab that has last been manually selected (the user clicked on a tab). 111 * This value does not keep track of programmatically set Tabs (e.g. Call Log after a Call) 112 */ 113 private int mLastManuallySelectedTab; 114 115 private SearchView mSearchView; 116 117 /** 118 * Listener used when one of phone numbers in search UI is selected. This will initiate a 119 * phone call using the phone number. 120 */ 121 private final OnPhoneNumberPickerActionListener mPhoneNumberPickerActionListener = 122 new OnPhoneNumberPickerActionListener() { 123 @Override 124 public void onPickPhoneNumberAction(Uri dataUri) { 125 PhoneNumberInteraction.startInteractionForPhoneCall( 126 DialtactsActivity.this, dataUri); 127 } 128 129 @Override 130 public void onShortcutIntentCreated(Intent intent) { 131 Log.w(TAG, "Unsupported intent has come (" + intent + "). Ignoring."); 132 } 133 }; 134 135 /** 136 * Listener used to send search queries to the phone search fragment. 137 */ 138 private final OnQueryTextListener mPhoneSearchQueryTextListener = 139 new OnQueryTextListener() { 140 @Override 141 public boolean onQueryTextSubmit(String query) { 142 // Ignore. 143 return true; 144 } 145 146 @Override 147 public boolean onQueryTextChange(String newText) { 148 // Show search result with non-empty text. Show a bare list otherwise. 149 mPhoneNumberPickerFragment.setQueryString(newText, true); 150 mPhoneNumberPickerFragment.setSearchMode(!TextUtils.isEmpty(newText)); 151 return true; 152 } 153 }; 154 155 /** 156 * Listener used to handle the "close" button on the right side of {@link SearchView}. 157 * If some text is in the search view, this will clean it up. Otherwise this will exit 158 * the search UI and let users go back to usual Phone UI. 159 * 160 * This does _not_ handle back button. 161 * 162 * TODO: need "up" button instead of close button 163 */ 164 private final OnCloseListener mPhoneSearchCloseListener = 165 new OnCloseListener() { 166 @Override 167 public boolean onClose() { 168 if (TextUtils.isEmpty(mSearchView.getQuery())) { 169 exitSearchUi(); 170 } else { 171 mSearchView.setQuery(null, true); 172 } 173 return true; 174 } 175 }; 176 177 @Override 178 protected void onCreate(Bundle icicle) { 179 super.onCreate(icicle); 180 181 final Intent intent = getIntent(); 182 fixIntent(intent); 183 184 setContentView(R.layout.dialtacts_activity); 185 186 final FragmentManager fragmentManager = getFragmentManager(); 187 mDialpadFragment = (DialpadFragment) fragmentManager 188 .findFragmentById(R.id.dialpad_fragment); 189 mDialpadFragment.setListener(new DialpadFragment.Listener() { 190 @Override 191 public void onSearchButtonPressed() { 192 enterSearchUi(); 193 } 194 }); 195 mCallLogFragment = (CallLogFragment) fragmentManager 196 .findFragmentById(R.id.call_log_fragment); 197 mContactsFragment = (DefaultContactBrowseListFragment) fragmentManager 198 .findFragmentById(R.id.contacts_fragment); 199 mStrequentFragment = (StrequentContactListFragment) fragmentManager 200 .findFragmentById(R.id.favorites_fragment); 201 mPhoneNumberPickerFragment = (PhoneNumberPickerFragment) fragmentManager 202 .findFragmentById(R.id.phone_number_picker_fragment); 203 mPhoneNumberPickerFragment.setOnPhoneNumberPickerActionListener( 204 mPhoneNumberPickerActionListener); 205 mPhoneNumberPickerFragment.setHighlightSearchPrefix(true); 206 207 // Hide all tabs (the current tab will later be reshown once a tab is selected) 208 final FragmentTransaction transaction = fragmentManager.beginTransaction(); 209 transaction.hide(mDialpadFragment); 210 transaction.hide(mCallLogFragment); 211 transaction.hide(mStrequentFragment); 212 transaction.hide(mPhoneNumberPickerFragment); 213 transaction.commit(); 214 215 // Setup the ActionBar tabs (the order matches the tab-index contants TAB_INDEX_*) 216 setupDialer(); 217 setupCallLog(); 218 setupFavorites(); 219 getActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); 220 getActionBar().setDisplayShowTitleEnabled(false); 221 getActionBar().setDisplayShowHomeEnabled(false); 222 223 // Load the last manually loaded tab 224 final SharedPreferences prefs = getSharedPreferences(PREFS_DIALTACTS, MODE_PRIVATE); 225 mLastManuallySelectedTab = prefs.getInt(PREF_LAST_MANUALLY_SELECTED_TAB, 226 PREF_LAST_MANUALLY_SELECTED_TAB_DEFAULT); 227 if (mLastManuallySelectedTab >= TAB_INDEX_COUNT) { 228 // Stored value may have exceeded the number of current tabs. Reset it. 229 mLastManuallySelectedTab = PREF_LAST_MANUALLY_SELECTED_TAB_DEFAULT; 230 } 231 232 setCurrentTab(intent); 233 234 if (UI.FILTER_CONTACTS_ACTION.equals(intent.getAction()) 235 && icicle == null) { 236 setupFilterText(intent); 237 } 238 } 239 240 @Override 241 protected void onPause() { 242 super.onPause(); 243 244 final SharedPreferences.Editor editor = 245 getSharedPreferences(PREFS_DIALTACTS, MODE_PRIVATE).edit(); 246 editor.putInt(PREF_LAST_MANUALLY_SELECTED_TAB, mLastManuallySelectedTab); 247 248 editor.apply(); 249 } 250 251 private void fixIntent(Intent intent) { 252 // This should be cleaned up: the call key used to send an Intent 253 // that just said to go to the recent calls list. It now sends this 254 // abstract action, but this class hasn't been rewritten to deal with it. 255 if (Intent.ACTION_CALL_BUTTON.equals(intent.getAction())) { 256 intent.setDataAndType(Calls.CONTENT_URI, Calls.CONTENT_TYPE); 257 intent.putExtra("call_key", true); 258 setIntent(intent); 259 } 260 } 261 262 private void setupDialer() { 263 final Tab tab = getActionBar().newTab(); 264 // TODO: Temporarily disable tab text labels (in all 4 tabs in this 265 // activity) so that the current tabs will all fit onscreen in 266 // portrait (bug 4520620). (Also note we do setText("") rather 267 // leaving the text null, to work around bug 4521549.) 268 tab.setText(""); // R.string.dialerIconLabel 269 tab.setTabListener(new TabChangeListener(mDialpadFragment)); 270 tab.setIcon(R.drawable.ic_tab_dialer); 271 getActionBar().addTab(tab); 272 mDialpadFragment.resolveIntent(); 273 } 274 275 private void setupCallLog() { 276 final Tab tab = getActionBar().newTab(); 277 tab.setText(""); // R.string.recentCallsIconLabel 278 tab.setIcon(R.drawable.ic_tab_recent); 279 tab.setTabListener(new TabChangeListener(mCallLogFragment)); 280 getActionBar().addTab(tab); 281 } 282 283 private void setupContacts() { 284 final Tab tab = getActionBar().newTab(); 285 tab.setText(""); // R.string.contactsIconLabel 286 tab.setIcon(R.drawable.ic_tab_contacts); 287 tab.setTabListener(new TabChangeListener(mContactsFragment)); 288 getActionBar().addTab(tab); 289 290 // TODO: We should not artificially create Intents and put them into the Fragment. 291 // It would be nicer to directly pass in the UI constant 292 Intent intent = new Intent(UI.LIST_ALL_CONTACTS_ACTION); 293 intent.setClass(this, PeopleActivity.class); 294 295 ContactsIntentResolver resolver = new ContactsIntentResolver(this); 296 ContactsRequest request = resolver.resolveIntent(intent); 297 final ContactListFilter filter = ContactListFilter.createFilterWithType( 298 ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS); 299 mContactsFragment.setFilter(filter, false); 300 mContactsFragment.setSearchMode(request.isSearchMode()); 301 mContactsFragment.setQueryString(request.getQueryString(), false); 302 mContactsFragment.setContactsRequest(request); 303 mContactsFragment.setDirectorySearchMode(request.isDirectorySearchEnabled() 304 ? DirectoryListLoader.SEARCH_MODE_DEFAULT 305 : DirectoryListLoader.SEARCH_MODE_NONE); 306 mContactsFragment.setOnContactListActionListener(mListFragmentListener); 307 } 308 309 private void setupFavorites() { 310 final Tab tab = getActionBar().newTab(); 311 tab.setText(""); // R.string.contactsFavoritesLabel 312 tab.setIcon(R.drawable.ic_tab_starred); 313 tab.setTabListener(new TabChangeListener(mStrequentFragment)); 314 getActionBar().addTab(tab); 315 mStrequentFragment.setListener(mStrequentListener); 316 } 317 318 /** 319 * Returns true if the intent is due to hitting the green send key while in a call. 320 * 321 * @param intent the intent that launched this activity 322 * @param recentCallsRequest true if the intent is requesting to view recent calls 323 * @return true if the intent is due to hitting the green send key while in a call 324 */ 325 private boolean isSendKeyWhileInCall(final Intent intent, final boolean recentCallsRequest) { 326 // If there is a call in progress go to the call screen 327 if (recentCallsRequest) { 328 final boolean callKey = intent.getBooleanExtra("call_key", false); 329 330 try { 331 ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone")); 332 if (callKey && phone != null && phone.showCallScreen()) { 333 return true; 334 } 335 } catch (RemoteException e) { 336 Log.e(TAG, "Failed to handle send while in call", e); 337 } 338 } 339 340 return false; 341 } 342 343 /** 344 * Sets the current tab based on the intent's request type 345 * 346 * @param intent Intent that contains information about which tab should be selected 347 */ 348 private void setCurrentTab(Intent intent) { 349 // If we got here by hitting send and we're in call forward along to the in-call activity 350 final boolean recentCallsRequest = Calls.CONTENT_TYPE.equals(intent.getType()); 351 if (isSendKeyWhileInCall(intent, recentCallsRequest)) { 352 finish(); 353 return; 354 } 355 356 // Tell the children activities that they should ignore any possible saved 357 // state and instead reload their state from the parent's intent 358 intent.putExtra(EXTRA_IGNORE_STATE, true); 359 360 // Remember the old manually selected tab index so that it can be restored if it is 361 // overwritten by one of the programmatic tab selections 362 final int savedTabIndex = mLastManuallySelectedTab; 363 364 if (recentCallsRequest) { 365 getActionBar().selectTab(getActionBar().getTabAt(TAB_INDEX_CALL_LOG)); 366 } else { 367 getActionBar().selectTab(getActionBar().getTabAt(mLastManuallySelectedTab)); 368 } 369 370 // Restore to the previous manual selection 371 mLastManuallySelectedTab = savedTabIndex; 372 373 // Tell the children activities that they should honor their saved states 374 // instead of the state from the parent's intent 375 intent.putExtra(EXTRA_IGNORE_STATE, false); 376 } 377 378 @Override 379 public void onNewIntent(Intent newIntent) { 380 setIntent(newIntent); 381 fixIntent(newIntent); 382 setCurrentTab(newIntent); 383 final String action = newIntent.getAction(); 384 if (UI.FILTER_CONTACTS_ACTION.equals(action)) { 385 setupFilterText(newIntent); 386 } else if (isDialIntent(newIntent)) { 387 setupDialUri(newIntent); 388 } 389 // Fill in a phone number again. 390 mDialpadFragment.resolveIntent(); 391 } 392 393 /** Returns true if the given intent contains a phone number to populate the dialer with */ 394 private boolean isDialIntent(Intent intent) { 395 final String action = intent.getAction(); 396 if (Intent.ACTION_DIAL.equals(action)) { 397 return true; 398 } 399 if (Intent.ACTION_VIEW.equals(action)) { 400 final Uri data = intent.getData(); 401 if (data != null && "tel".equals(data.getScheme())) { 402 return true; 403 } 404 } 405 return false; 406 } 407 408 /** 409 * Retrieves the filter text stored in {@link #setupFilterText(Intent)}. 410 * This text originally came from a FILTER_CONTACTS_ACTION intent received 411 * by this activity. The stored text will then be cleared after after this 412 * method returns. 413 * 414 * @return The stored filter text 415 */ 416 public String getAndClearFilterText() { 417 String filterText = mFilterText; 418 mFilterText = null; 419 return filterText; 420 } 421 422 /** 423 * Stores the filter text associated with a FILTER_CONTACTS_ACTION intent. 424 * This is so child activities can check if they are supposed to display a filter. 425 * 426 * @param intent The intent received in {@link #onNewIntent(Intent)} 427 */ 428 private void setupFilterText(Intent intent) { 429 // If the intent was relaunched from history, don't apply the filter text. 430 if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0) { 431 return; 432 } 433 String filter = intent.getStringExtra(UI.FILTER_TEXT_EXTRA_KEY); 434 if (filter != null && filter.length() > 0) { 435 mFilterText = filter; 436 } 437 } 438 439 /** 440 * Retrieves the uri stored in {@link #setupDialUri(Intent)}. This uri 441 * originally came from a dial intent received by this activity. The stored 442 * uri will then be cleared after after this method returns. 443 * 444 * @return The stored uri 445 */ 446 public Uri getAndClearDialUri() { 447 Uri dialUri = mDialUri; 448 mDialUri = null; 449 return dialUri; 450 } 451 452 /** 453 * Stores the uri associated with a dial intent. This is so child activities can 454 * check if they are supposed to display new dial info. 455 * 456 * @param intent The intent received in {@link #onNewIntent(Intent)} 457 */ 458 private void setupDialUri(Intent intent) { 459 // If the intent was relaunched from history, don't reapply the intent. 460 if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0) { 461 return; 462 } 463 mDialUri = intent.getData(); 464 } 465 466 @Override 467 public void onBackPressed() { 468 if (mInSearchUi) { 469 // We should let the user go back to usual screens with tabs. 470 exitSearchUi(); 471 } else if (isTaskRoot()) { 472 // Instead of stopping, simply push this to the back of the stack. 473 // This is only done when running at the top of the stack; 474 // otherwise, we have been launched by someone else so need to 475 // allow the user to go back to the caller. 476 moveTaskToBack(false); 477 } else { 478 super.onBackPressed(); 479 } 480 } 481 482 @Override 483 protected void onPostCreate(Bundle savedInstanceState) { 484 super.onPostCreate(savedInstanceState); 485 486 // Pass this lifecycle event down to the fragment 487 mDialpadFragment.onPostCreate(); 488 } 489 490 /** 491 * Tab change listener that is instantiated once for each tab. Handles showing/hiding tabs 492 * and remembers manual tab selections 493 */ 494 private class TabChangeListener implements TabListener { 495 private final Fragment mFragment; 496 497 public TabChangeListener(Fragment fragment) { 498 mFragment = fragment; 499 } 500 501 @Override 502 public void onTabUnselected(Tab tab, FragmentTransaction ft) { 503 ft.hide(mFragment); 504 } 505 506 @Override 507 public void onTabSelected(Tab tab, FragmentTransaction ft) { 508 ft.show(mFragment); 509 ft.hide(mPhoneNumberPickerFragment); 510 511 // Remember this tab index. This function is also called, if the tab is set 512 // automatically in which case the setter (setCurrentTab) has to set this to its old 513 // value afterwards 514 mLastManuallySelectedTab = tab.getPosition(); 515 } 516 517 @Override 518 public void onTabReselected(Tab tab, FragmentTransaction ft) { 519 } 520 } 521 522 private OnContactBrowserActionListener mListFragmentListener = 523 new OnContactBrowserActionListener() { 524 @Override 525 public void onViewContactAction(Uri contactLookupUri) { 526 startActivity(new Intent(Intent.ACTION_VIEW, contactLookupUri)); 527 } 528 529 @Override 530 public void onSmsContactAction(Uri contactUri) { 531 } 532 533 @Override 534 public void onSelectionChange() { 535 } 536 537 @Override 538 public void onRemoveFromFavoritesAction(Uri contactUri) { 539 } 540 541 @Override 542 public void onInvalidSelection() { 543 } 544 545 @Override 546 public void onFinishAction() { 547 } 548 549 @Override 550 public void onEditContactAction(Uri contactLookupUri) { 551 } 552 553 @Override 554 public void onDeleteContactAction(Uri contactUri) { 555 } 556 557 @Override 558 public void onCreateNewContactAction() { 559 } 560 561 @Override 562 public void onCallContactAction(Uri contactUri) { 563 PhoneNumberInteraction.startInteractionForPhoneCall( 564 DialtactsActivity.this, contactUri); 565 } 566 567 @Override 568 public void onAddToFavoritesAction(Uri contactUri) { 569 } 570 }; 571 572 private StrequentContactListFragment.Listener mStrequentListener = 573 new StrequentContactListFragment.Listener() { 574 @Override 575 public void onContactSelected(Uri contactUri) { 576 PhoneNumberInteraction.startInteractionForPhoneCall( 577 DialtactsActivity.this, contactUri); 578 } 579 }; 580 581 @Override 582 public boolean onCreateOptionsMenu(Menu menu) { 583 // For now, create the menu in here. It would be nice to do this in the Fragment, 584 // but that Fragment is re-used in other views. 585 final ActionBar actionBar = getActionBar(); 586 if (actionBar == null) return false; 587 final Tab tab = actionBar.getSelectedTab(); 588 if (tab == null) return false; 589 final int tabIndex = tab.getPosition(); 590 if (tabIndex != TAB_INDEX_FAVORITES) return false; 591 592 MenuInflater inflater = getMenuInflater(); 593 inflater.inflate(R.menu.list, menu); 594 return true; 595 } 596 597 @Override 598 public boolean onOptionsItemSelected(MenuItem item) { 599 // This is currently a copy of the equivalent code of PeopleActivity (with the 600 // exception of menu_add, because we do not select items in the list). 601 // Should be consolidated 602 switch (item.getItemId()) { 603 case R.id.menu_settings: { 604 final Intent intent = new Intent(this, ContactsPreferenceActivity.class); 605 startActivity(intent); 606 return true; 607 } 608 case R.id.menu_search: { 609 onSearchRequested(); 610 return true; 611 } 612 case R.id.menu_add: { 613 final Intent intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI); 614 startActivity(intent); 615 return true; 616 } 617 case R.id.menu_import_export: { 618 ImportExportDialogFragment.show(getFragmentManager()); 619 return true; 620 } 621 case R.id.menu_accounts: { 622 final Intent intent = new Intent(Settings.ACTION_SYNC_SETTINGS); 623 intent.putExtra(Settings.EXTRA_AUTHORITIES, new String[] { 624 ContactsContract.AUTHORITY 625 }); 626 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); 627 startActivity(intent); 628 return true; 629 } 630 default: 631 return super.onOptionsItemSelected(item); 632 } 633 } 634 635 @Override 636 public void startSearch(String initialQuery, boolean selectInitialQuery, 637 Bundle appSearchData, boolean globalSearch) { 638 if (mPhoneNumberPickerFragment != null && mPhoneNumberPickerFragment.isAdded() 639 && !globalSearch) { 640 enterSearchUi(); 641 } else { 642 super.startSearch(initialQuery, selectInitialQuery, appSearchData, globalSearch); 643 } 644 } 645 646 /** 647 * Hides every tab and shows search UI for phone lookup. 648 */ 649 private void enterSearchUi() { 650 final ActionBar actionBar = getActionBar(); 651 652 final Tab tab = actionBar.getSelectedTab(); 653 if (tab != null) { 654 mLastManuallySelectedTab = tab.getPosition(); 655 } 656 657 // Instantiate or reset SearchView in ActionBar. 658 if (mSearchView == null) { 659 // TODO: layout is not what we want. Need "up" button instead of "close" button, etc. 660 final View searchViewLayout = 661 getLayoutInflater().inflate(R.layout.custom_action_bar, null); 662 mSearchView = (SearchView) searchViewLayout.findViewById(R.id.search_view); 663 mSearchView.setQueryHint(getString(R.string.hint_findContacts)); 664 mSearchView.setOnQueryTextListener(mPhoneSearchQueryTextListener); 665 mSearchView.setOnCloseListener(mPhoneSearchCloseListener); 666 mSearchView.requestFocus(); 667 actionBar.setCustomView(searchViewLayout, 668 new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); 669 } else { 670 mSearchView.setQuery(null, true); 671 } 672 673 actionBar.setDisplayShowCustomEnabled(true); 674 actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); 675 676 // Show the search fragment and hide everything else. 677 final FragmentTransaction transaction = getFragmentManager().beginTransaction(); 678 transaction.show(mPhoneNumberPickerFragment); 679 transaction.hide(mDialpadFragment); 680 transaction.hide(mCallLogFragment); 681 transaction.hide(mStrequentFragment); 682 transaction.commit(); 683 684 mInSearchUi = true; 685 } 686 687 /** 688 * Goes back to usual Phone UI with tags. Previously selected Tag and associated Fragment 689 * should be automatically focused again. 690 */ 691 private void exitSearchUi() { 692 final ActionBar actionBar = getActionBar(); 693 694 // We want to hide SearchView and show Tabs. Also focus on previously selected one. 695 actionBar.setDisplayShowCustomEnabled(false); 696 actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); 697 698 // Request to update option menu. 699 invalidateOptionsMenu(); 700 701 mInSearchUi = false; 702 } 703} 704