DialtactsActivity.java revision bd762dc826d85e5b7db634ef14a0dbb70c42eaab
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.PhoneNumberInteraction; 23import com.android.contacts.list.OnPhoneNumberPickerActionListener; 24import com.android.contacts.list.PhoneNumberPickerFragment; 25import com.android.contacts.list.StrequentContactListFragment; 26import com.android.internal.telephony.ITelephony; 27 28import android.app.ActionBar; 29import android.app.ActionBar.LayoutParams; 30import android.app.ActionBar.Tab; 31import android.app.ActionBar.TabListener; 32import android.app.Activity; 33import android.app.Fragment; 34import android.app.FragmentManager; 35import android.app.FragmentTransaction; 36import android.content.Context; 37import android.content.Intent; 38import android.content.SharedPreferences; 39import android.net.Uri; 40import android.os.Bundle; 41import android.os.RemoteException; 42import android.os.ServiceManager; 43import android.provider.CallLog.Calls; 44import android.provider.ContactsContract.Intents.UI; 45import android.support.v13.app.FragmentPagerAdapter; 46import android.support.v4.view.ViewPager; 47import android.support.v4.view.ViewPager.OnPageChangeListener; 48import android.text.TextUtils; 49import android.util.Log; 50import android.view.Menu; 51import android.view.MenuInflater; 52import android.view.MenuItem; 53import android.view.MenuItem.OnMenuItemClickListener; 54import android.view.View; 55import android.view.View.OnAttachStateChangeListener; 56import android.view.inputmethod.InputMethodManager; 57import android.widget.SearchView; 58import android.widget.SearchView.OnCloseListener; 59import android.widget.SearchView.OnQueryTextListener; 60 61/** 62 * The dialer activity that has one tab with the virtual 12key 63 * dialer, a tab with recent calls in it, a tab with the contacts and 64 * a tab with the favorite. This is the container and the tabs are 65 * embedded using intents. 66 * The dialer tab's title is 'phone', a more common name (see strings.xml). 67 */ 68public class DialtactsActivity extends Activity { 69 private static final String TAG = "DialtactsActivity"; 70 71 /** Used to open Call Setting */ 72 private static final String PHONE_PACKAGE = "com.android.phone"; 73 private static final String CALL_SETTINGS_CLASS_NAME = 74 "com.android.phone.CallFeaturesSetting"; 75 76 /** Used both by {@link ActionBar} and {@link ViewPagerAdapter} */ 77 private static final int TAB_INDEX_DIALER = 0; 78 private static final int TAB_INDEX_CALL_LOG = 1; 79 private static final int TAB_INDEX_FAVORITES = 2; 80 81 private static final int TAB_INDEX_COUNT = 3; 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 /** 92 * Listener interface for Fragments accommodated in {@link ViewPager} enabling them to know 93 * when it becomes visible or invisible inside the ViewPager. 94 */ 95 public interface ViewPagerVisibilityListener { 96 public void onVisibilityChanged(boolean visible); 97 } 98 99 public class ViewPagerAdapter extends FragmentPagerAdapter { 100 public ViewPagerAdapter(FragmentManager fm) { 101 super(fm); 102 } 103 104 @Override 105 public Fragment getItem(int position) { 106 switch (position) { 107 case TAB_INDEX_DIALER: 108 return new DialpadFragment(); 109 case TAB_INDEX_CALL_LOG: 110 return new CallLogFragment(); 111 case TAB_INDEX_FAVORITES: 112 return new StrequentContactListFragment(); 113 } 114 throw new IllegalStateException("No fragment at position " + position); 115 } 116 117 @Override 118 public int getCount() { 119 return TAB_INDEX_COUNT; 120 } 121 } 122 123 private class PageChangeListener implements OnPageChangeListener { 124 private int mPreviousPosition = -1; // Invalid at first 125 126 @Override 127 public void onPageScrolled( 128 int position, float positionOffset, int positionOffsetPixels) { 129 } 130 131 @Override 132 public void onPageSelected(int position) { 133 final ActionBar actionBar = getActionBar(); 134 if (mPreviousPosition == position) { 135 Log.w(TAG, "Previous position and next position became same (" + position + ")"); 136 } 137 138 if (mPreviousPosition >= 0) { 139 sendFragmentVisibilityChange(mPreviousPosition, false); 140 } 141 sendFragmentVisibilityChange(position, true); 142 143 actionBar.selectTab(actionBar.getTabAt(position)); 144 145 // Activity#onPrepareOptionsMenu() may not be called when Fragment has it's own 146 // options menu. We force this Activity to call it to hide/show bottom bar. Also 147 // we don't want to do so when it is unnecessary (buttons may flicker). 148 if (mPreviousPosition == TAB_INDEX_DIALER || position == TAB_INDEX_DIALER) { 149 // Force this Activity to prepare Menu again. 150 invalidateOptionsMenu(); 151 } 152 153 mPreviousPosition = position; 154 } 155 156 public void setCurrentPosition(int position) { 157 mPreviousPosition = position; 158 } 159 160 @Override 161 public void onPageScrollStateChanged(int state) { 162 } 163 } 164 165 private String mFilterText; 166 private Uri mDialUri; 167 168 /** Enables horizontal swipe between Fragments. */ 169 private ViewPager mViewPager; 170 private final PageChangeListener mPageChangeListener = new PageChangeListener(); 171 private DialpadFragment mDialpadFragment; 172 private CallLogFragment mCallLogFragment; 173 private StrequentContactListFragment mStrequentFragment; 174 175 private final TabListener mTabListener = new TabListener() { 176 @Override 177 public void onTabUnselected(Tab tab, FragmentTransaction ft) { 178 } 179 180 @Override 181 public void onTabSelected(Tab tab, FragmentTransaction ft) { 182 if (mViewPager.getCurrentItem() != tab.getPosition()) { 183 mViewPager.setCurrentItem(tab.getPosition(), false /* smoothScroll */); 184 } 185 186 // During the call, we don't remember the tab position. 187 if (!DialpadFragment.phoneIsInUse()) { 188 // Remember this tab index. This function is also called, if the tab is set 189 // automatically in which case the setter (setCurrentTab) has to set this to its old 190 // value afterwards 191 mLastManuallySelectedFragment = tab.getPosition(); 192 } 193 } 194 195 @Override 196 public void onTabReselected(Tab tab, FragmentTransaction ft) { 197 } 198 }; 199 200 /** 201 * Fragment for searching phone numbers. Unlike the other Fragments, this doesn't correspond 202 * to tab but is shown by a search action. 203 */ 204 private PhoneNumberPickerFragment mSearchFragment; 205 /** 206 * True when this Activity is in its search UI (with a {@link SearchView} and 207 * {@link PhoneNumberPickerFragment}). 208 */ 209 private boolean mInSearchUi; 210 private SearchView mSearchView; 211 212 /** 213 * The index of the Fragment (or, the tab) that has last been manually selected. 214 * This value does not keep track of programmatically set Tabs (e.g. Call Log after a Call) 215 */ 216 private int mLastManuallySelectedFragment; 217 218 /** 219 * Listener used when one of phone numbers in search UI is selected. This will initiate a 220 * phone call using the phone number. 221 */ 222 private final OnPhoneNumberPickerActionListener mPhoneNumberPickerActionListener = 223 new OnPhoneNumberPickerActionListener() { 224 @Override 225 public void onPickPhoneNumberAction(Uri dataUri) { 226 PhoneNumberInteraction.startInteractionForPhoneCall( 227 DialtactsActivity.this, dataUri); 228 } 229 230 @Override 231 public void onShortcutIntentCreated(Intent intent) { 232 Log.w(TAG, "Unsupported intent has come (" + intent + "). Ignoring."); 233 } 234 235 @Override 236 public void onHomeInActionBarSelected() { 237 exitSearchUi(); 238 } 239 }; 240 241 /** 242 * Listener used to send search queries to the phone search fragment. 243 */ 244 private final OnQueryTextListener mPhoneSearchQueryTextListener = 245 new OnQueryTextListener() { 246 @Override 247 public boolean onQueryTextSubmit(String query) { 248 // Ignore. 249 return true; 250 } 251 252 @Override 253 public boolean onQueryTextChange(String newText) { 254 // Show search result with non-empty text. Show a bare list otherwise. 255 mSearchFragment.setQueryString(newText, true); 256 mSearchFragment.setSearchMode(!TextUtils.isEmpty(newText)); 257 return true; 258 } 259 }; 260 261 /** 262 * Listener used to handle the "close" button on the right side of {@link SearchView}. 263 * If some text is in the search view, this will clean it up. Otherwise this will exit 264 * the search UI and let users go back to usual Phone UI. 265 * 266 * This does _not_ handle back button. 267 * 268 * TODO: need "up" button instead of close button 269 */ 270 private final OnCloseListener mPhoneSearchCloseListener = 271 new OnCloseListener() { 272 @Override 273 public boolean onClose() { 274 if (TextUtils.isEmpty(mSearchView.getQuery())) { 275 exitSearchUi(); 276 } else { 277 mSearchView.setQuery(null, true); 278 } 279 return true; 280 } 281 }; 282 283 @Override 284 protected void onCreate(Bundle icicle) { 285 super.onCreate(icicle); 286 287 final Intent intent = getIntent(); 288 fixIntent(intent); 289 290 setContentView(R.layout.dialtacts_activity); 291 292 mViewPager = (ViewPager) findViewById(R.id.pager); 293 mViewPager.setAdapter(new ViewPagerAdapter(getFragmentManager())); 294 mViewPager.setOnPageChangeListener(mPageChangeListener); 295 296 // Setup the ActionBar tabs (the order matches the tab-index contants TAB_INDEX_*) 297 setupDialer(); 298 setupCallLog(); 299 setupFavorites(); 300 getActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); 301 getActionBar().setDisplayShowTitleEnabled(false); 302 getActionBar().setDisplayShowHomeEnabled(false); 303 304 // Load the last manually loaded tab 305 final SharedPreferences prefs = getSharedPreferences(PREFS_DIALTACTS, MODE_PRIVATE); 306 mLastManuallySelectedFragment = prefs.getInt(PREF_LAST_MANUALLY_SELECTED_TAB, 307 PREF_LAST_MANUALLY_SELECTED_TAB_DEFAULT); 308 if (mLastManuallySelectedFragment >= TAB_INDEX_COUNT) { 309 // Stored value may have exceeded the number of current tabs. Reset it. 310 mLastManuallySelectedFragment = PREF_LAST_MANUALLY_SELECTED_TAB_DEFAULT; 311 } 312 313 setCurrentTab(intent); 314 315 if (UI.FILTER_CONTACTS_ACTION.equals(intent.getAction()) 316 && icicle == null) { 317 setupFilterText(intent); 318 } 319 } 320 321 @Override 322 public void onAttachFragment(Fragment fragment) { 323 // This method can be called before onCreate(), at which point we cannot rely on ViewPager. 324 // In that case, we will setup the "current position" soon after the ViewPager is ready. 325 final int currentPosition = mViewPager != null ? mViewPager.getCurrentItem() : -1; 326 327 if (fragment instanceof DialpadFragment) { 328 mDialpadFragment = (DialpadFragment) fragment; 329 mDialpadFragment.setListener(mDialpadListener); 330 mDialpadFragment.onVisibilityChanged(currentPosition == TAB_INDEX_DIALER); 331 } else if (fragment instanceof CallLogFragment) { 332 mCallLogFragment = (CallLogFragment) fragment; 333 mCallLogFragment.onVisibilityChanged(currentPosition == TAB_INDEX_CALL_LOG); 334 } else if (fragment instanceof StrequentContactListFragment) { 335 mStrequentFragment = (StrequentContactListFragment) fragment; 336 mStrequentFragment.setListener(mStrequentListener); 337 } else if (fragment instanceof PhoneNumberPickerFragment) { 338 mSearchFragment = (PhoneNumberPickerFragment) fragment; 339 mSearchFragment.setOnPhoneNumberPickerActionListener(mPhoneNumberPickerActionListener); 340 mSearchFragment.setNameHighlightingEnabled(true); 341 mSearchFragment.setQuickContactEnabled(true); 342 final FragmentTransaction transaction = getFragmentManager().beginTransaction(); 343 if (mInSearchUi) { 344 transaction.show(mSearchFragment); 345 } else { 346 transaction.hide(mSearchFragment); 347 } 348 transaction.commit(); 349 } 350 } 351 352 @Override 353 protected void onPause() { 354 super.onPause(); 355 356 final SharedPreferences.Editor editor = 357 getSharedPreferences(PREFS_DIALTACTS, MODE_PRIVATE).edit(); 358 editor.putInt(PREF_LAST_MANUALLY_SELECTED_TAB, mLastManuallySelectedFragment); 359 360 editor.apply(); 361 } 362 363 private void fixIntent(Intent intent) { 364 // This should be cleaned up: the call key used to send an Intent 365 // that just said to go to the recent calls list. It now sends this 366 // abstract action, but this class hasn't been rewritten to deal with it. 367 if (Intent.ACTION_CALL_BUTTON.equals(intent.getAction())) { 368 intent.setDataAndType(Calls.CONTENT_URI, Calls.CONTENT_TYPE); 369 intent.putExtra("call_key", true); 370 setIntent(intent); 371 } 372 } 373 374 private void setupDialer() { 375 final Tab tab = getActionBar().newTab(); 376 // TODO: Temporarily disable tab text labels (in all 4 tabs in this 377 // activity) so that the current tabs will all fit onscreen in 378 // portrait (bug 4520620). (Also note we do setText("") rather 379 // leaving the text null, to work around bug 4521549.) 380 tab.setText(""); // R.string.dialerIconLabel 381 tab.setTabListener(mTabListener); 382 tab.setIcon(R.drawable.ic_tab_dialer); 383 getActionBar().addTab(tab); 384 } 385 386 private void setupCallLog() { 387 final Tab tab = getActionBar().newTab(); 388 tab.setText(""); // R.string.recentCallsIconLabel 389 tab.setIcon(R.drawable.ic_tab_recent); 390 tab.setTabListener(mTabListener); 391 getActionBar().addTab(tab); 392 } 393 394 private void setupFavorites() { 395 final Tab tab = getActionBar().newTab(); 396 tab.setText(""); // R.string.contactsFavoritesLabel 397 tab.setIcon(R.drawable.ic_tab_starred); 398 tab.setTabListener(mTabListener); 399 getActionBar().addTab(tab); 400 } 401 402 /** 403 * Returns true if the intent is due to hitting the green send key while in a call. 404 * 405 * @param intent the intent that launched this activity 406 * @param recentCallsRequest true if the intent is requesting to view recent calls 407 * @return true if the intent is due to hitting the green send key while in a call 408 */ 409 private boolean isSendKeyWhileInCall(final Intent intent, 410 final boolean recentCallsRequest) { 411 // If there is a call in progress go to the call screen 412 if (recentCallsRequest) { 413 final boolean callKey = intent.getBooleanExtra("call_key", false); 414 415 try { 416 ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone")); 417 if (callKey && phone != null && phone.showCallScreen()) { 418 return true; 419 } 420 } catch (RemoteException e) { 421 Log.e(TAG, "Failed to handle send while in call", e); 422 } 423 } 424 425 return false; 426 } 427 428 /** 429 * Sets the current tab based on the intent's request type 430 * 431 * @param intent Intent that contains information about which tab should be selected 432 */ 433 private void setCurrentTab(Intent intent) { 434 // If we got here by hitting send and we're in call forward along to the in-call activity 435 final boolean recentCallsRequest = Calls.CONTENT_TYPE.equals(intent.getType()); 436 if (isSendKeyWhileInCall(intent, recentCallsRequest)) { 437 finish(); 438 return; 439 } 440 441 // Remember the old manually selected tab index so that it can be restored if it is 442 // overwritten by one of the programmatic tab selections 443 final int savedTabIndex = mLastManuallySelectedFragment; 444 445 final int tabIndex; 446 if (DialpadFragment.phoneIsInUse() || isDialIntent(intent)) { 447 tabIndex = TAB_INDEX_DIALER; 448 } else if (recentCallsRequest) { 449 tabIndex = TAB_INDEX_CALL_LOG; 450 } else { 451 tabIndex = mLastManuallySelectedFragment; 452 } 453 mViewPager.setCurrentItem(tabIndex, false /* smoothScroll */); 454 if (mViewPager.getCurrentItem() == tabIndex) { 455 mPageChangeListener.setCurrentPosition(tabIndex); 456 sendFragmentVisibilityChange(tabIndex, true); 457 } else { 458 getActionBar().selectTab(getActionBar().getTabAt(tabIndex)); 459 } 460 461 // Restore to the previous manual selection 462 mLastManuallySelectedFragment = savedTabIndex; 463 } 464 465 @Override 466 public void onNewIntent(Intent newIntent) { 467 setIntent(newIntent); 468 fixIntent(newIntent); 469 setCurrentTab(newIntent); 470 final String action = newIntent.getAction(); 471 if (UI.FILTER_CONTACTS_ACTION.equals(action)) { 472 setupFilterText(newIntent); 473 } else if (isDialIntent(newIntent)) { 474 setupDialUri(newIntent); 475 } 476 if (mInSearchUi || mSearchFragment.isVisible()) { 477 exitSearchUi(); 478 } 479 } 480 481 /** Returns true if the given intent contains a phone number to populate the dialer with */ 482 private boolean isDialIntent(Intent intent) { 483 final String action = intent.getAction(); 484 if (Intent.ACTION_DIAL.equals(action)) { 485 return true; 486 } 487 if (Intent.ACTION_VIEW.equals(action)) { 488 final Uri data = intent.getData(); 489 if (data != null && "tel".equals(data.getScheme())) { 490 return true; 491 } 492 } 493 return false; 494 } 495 496 /** 497 * Retrieves the filter text stored in {@link #setupFilterText(Intent)}. 498 * This text originally came from a FILTER_CONTACTS_ACTION intent received 499 * by this activity. The stored text will then be cleared after after this 500 * method returns. 501 * 502 * @return The stored filter text 503 */ 504 public String getAndClearFilterText() { 505 String filterText = mFilterText; 506 mFilterText = null; 507 return filterText; 508 } 509 510 /** 511 * Stores the filter text associated with a FILTER_CONTACTS_ACTION intent. 512 * This is so child activities can check if they are supposed to display a filter. 513 * 514 * @param intent The intent received in {@link #onNewIntent(Intent)} 515 */ 516 private void setupFilterText(Intent intent) { 517 // If the intent was relaunched from history, don't apply the filter text. 518 if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0) { 519 return; 520 } 521 String filter = intent.getStringExtra(UI.FILTER_TEXT_EXTRA_KEY); 522 if (filter != null && filter.length() > 0) { 523 mFilterText = filter; 524 } 525 } 526 527 /** 528 * Retrieves the uri stored in {@link #setupDialUri(Intent)}. This uri 529 * originally came from a dial intent received by this activity. The stored 530 * uri will then be cleared after after this method returns. 531 * 532 * @return The stored uri 533 */ 534 public Uri getAndClearDialUri() { 535 Uri dialUri = mDialUri; 536 mDialUri = null; 537 return dialUri; 538 } 539 540 /** 541 * Stores the uri associated with a dial intent. This is so child activities can 542 * check if they are supposed to display new dial info. 543 * 544 * @param intent The intent received in {@link #onNewIntent(Intent)} 545 */ 546 private void setupDialUri(Intent intent) { 547 // If the intent was relaunched from history, don't reapply the intent. 548 if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0) { 549 return; 550 } 551 mDialUri = intent.getData(); 552 } 553 554 @Override 555 public void onBackPressed() { 556 if (mInSearchUi) { 557 // We should let the user go back to usual screens with tabs. 558 exitSearchUi(); 559 } else if (isTaskRoot()) { 560 // Instead of stopping, simply push this to the back of the stack. 561 // This is only done when running at the top of the stack; 562 // otherwise, we have been launched by someone else so need to 563 // allow the user to go back to the caller. 564 moveTaskToBack(false); 565 } else { 566 super.onBackPressed(); 567 } 568 } 569 570 private DialpadFragment.Listener mDialpadListener = new DialpadFragment.Listener() { 571 @Override 572 public void onSearchButtonPressed() { 573 enterSearchUi(); 574 } 575 }; 576 577 private StrequentContactListFragment.Listener mStrequentListener = 578 new StrequentContactListFragment.Listener() { 579 @Override 580 public void onContactSelected(Uri contactUri) { 581 PhoneNumberInteraction.startInteractionForPhoneCall( 582 DialtactsActivity.this, contactUri); 583 } 584 }; 585 586 @Override 587 public boolean onCreateOptionsMenu(Menu menu) { 588 MenuInflater inflater = getMenuInflater(); 589 inflater.inflate(R.menu.dialtacts_options, menu); 590 return true; 591 } 592 593 @Override 594 public boolean onPrepareOptionsMenu(Menu menu) { 595 final MenuItem searchMenuItem = menu.findItem(R.id.search_on_action_bar); 596 if (mInSearchUi || getActionBar().getSelectedTab().getPosition() == TAB_INDEX_DIALER) { 597 searchMenuItem.setVisible(false); 598 } else { 599 searchMenuItem.setVisible(true); 600 searchMenuItem.setOnMenuItemClickListener(new OnMenuItemClickListener() { 601 @Override 602 public boolean onMenuItemClick(MenuItem item) { 603 enterSearchUi(); 604 return true; 605 } 606 }); 607 } 608 609 return true; 610 } 611 612 @Override 613 public void startSearch(String initialQuery, boolean selectInitialQuery, 614 Bundle appSearchData, boolean globalSearch) { 615 if (mSearchFragment != null && mSearchFragment.isAdded() && !globalSearch) { 616 enterSearchUi(); 617 } else { 618 super.startSearch(initialQuery, selectInitialQuery, appSearchData, globalSearch); 619 } 620 } 621 622 /** 623 * Hides every tab and shows search UI for phone lookup. 624 */ 625 private void enterSearchUi() { 626 final ActionBar actionBar = getActionBar(); 627 628 final Tab tab = actionBar.getSelectedTab(); 629 630 // User can search during the call, but we don't want to remember the status. 631 if (tab != null && !DialpadFragment.phoneIsInUse()) { 632 mLastManuallySelectedFragment = tab.getPosition(); 633 } 634 635 // Instantiate or reset SearchView in ActionBar. 636 if (mSearchView == null) { 637 // TODO: layout is not what we want. Need "up" button instead of "close" button, etc. 638 final View searchViewLayout = 639 getLayoutInflater().inflate(R.layout.custom_action_bar, null); 640 mSearchView = (SearchView) searchViewLayout.findViewById(R.id.search_view); 641 mSearchView.setQueryHint(getString(R.string.hint_findContacts)); 642 mSearchView.setOnQueryTextListener(mPhoneSearchQueryTextListener); 643 mSearchView.setOnCloseListener(mPhoneSearchCloseListener); 644 mSearchView.requestFocus(); 645 // Show soft keyboard when SearchView has a focus. Need to delay the request in order 646 // to let InputMethodManager handle it correctly. 647 mSearchView.addOnAttachStateChangeListener(new OnAttachStateChangeListener() { 648 @Override 649 public void onViewDetachedFromWindow(View v) { 650 } 651 652 @Override 653 public void onViewAttachedToWindow(View v) { 654 if (mSearchView.hasFocus()) { 655 mSearchView.postDelayed(new Runnable() { 656 public void run() { 657 showInputMethod(mSearchView.findFocus()); 658 } 659 }, 0); 660 } 661 } 662 }); 663 actionBar.setCustomView(searchViewLayout, 664 new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); 665 } else { 666 mSearchView.setQuery(null, true); 667 } 668 669 actionBar.setDisplayShowCustomEnabled(true); 670 actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); 671 actionBar.setDisplayShowHomeEnabled(true); 672 actionBar.setDisplayHomeAsUpEnabled(true); 673 674 sendFragmentVisibilityChange(mViewPager.getCurrentItem(), false); 675 676 // Show the search fragment and hide everything else. 677 final FragmentTransaction transaction = getFragmentManager().beginTransaction(); 678 transaction.show(mSearchFragment); 679 transaction.commit(); 680 mViewPager.setVisibility(View.GONE); 681 682 mInSearchUi = true; 683 } 684 685 private void showInputMethod(View view) { 686 InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); 687 if (imm != null) { 688 imm.showSoftInput(view, 0); 689 } 690 } 691 692 private void hideInputMethod(View view) { 693 InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); 694 if (imm != null) { 695 imm.hideSoftInputFromWindow(view.getWindowToken(), 0); 696 } 697 } 698 699 /** 700 * Goes back to usual Phone UI with tags. Previously selected Tag and associated Fragment 701 * should be automatically focused again. 702 */ 703 private void exitSearchUi() { 704 final ActionBar actionBar = getActionBar(); 705 706 // We want to hide SearchView and show Tabs. Also focus on previously selected one. 707 actionBar.setDisplayShowCustomEnabled(false); 708 actionBar.setDisplayShowHomeEnabled(false); 709 actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); 710 711 sendFragmentVisibilityChange(mViewPager.getCurrentItem(), true); 712 713 final FragmentTransaction transaction = getFragmentManager().beginTransaction(); 714 transaction.hide(mSearchFragment); 715 transaction.commit(); 716 717 mViewPager.setVisibility(View.VISIBLE); 718 719 hideInputMethod(getCurrentFocus()); 720 721 // Request to update option menu. 722 invalidateOptionsMenu(); 723 724 mInSearchUi = false; 725 } 726 727 private Fragment getFragmentAt(int position) { 728 switch (position) { 729 case TAB_INDEX_DIALER: 730 return mDialpadFragment; 731 case TAB_INDEX_CALL_LOG: 732 return mCallLogFragment; 733 case TAB_INDEX_FAVORITES: 734 return mStrequentFragment; 735 default: 736 throw new IllegalStateException("Unknown fragment index: " + position); 737 } 738 } 739 740 private void sendFragmentVisibilityChange(int position, boolean visibility) { 741 final Fragment fragment = getFragmentAt(position); 742 if (fragment instanceof ViewPagerVisibilityListener) { 743 ((ViewPagerVisibilityListener) fragment).onVisibilityChanged(visibility); 744 } 745 } 746 747 /** Returns an Intent to launch Call Settings screen */ 748 public static Intent getCallSettingsIntent() { 749 final Intent intent = new Intent(Intent.ACTION_MAIN); 750 intent.setClassName(PHONE_PACKAGE, CALL_SETTINGS_CLASS_NAME); 751 return intent; 752 } 753} 754