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