DialtactsActivity.java revision b2e626ad4fedc0fd726f66b9942d1b2f30d9cfef
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        // Look at the component to determine the tab
367        String componentName = intent.getComponent().getClassName();
368        if (getClass().getName().equals(componentName)) {
369            if (recentCallsRequest) {
370                getActionBar().selectTab(getActionBar().getTabAt(TAB_INDEX_CALL_LOG));
371            } else {
372                getActionBar().selectTab(getActionBar().getTabAt(TAB_INDEX_DIALER));
373            }
374        } else {
375            getActionBar().selectTab(getActionBar().getTabAt(mLastManuallySelectedTab));
376        }
377
378        // Restore to the previous manual selection
379        mLastManuallySelectedTab = savedTabIndex;
380
381        // Tell the children activities that they should honor their saved states
382        // instead of the state from the parent's intent
383        intent.putExtra(EXTRA_IGNORE_STATE, false);
384    }
385
386    @Override
387    public void onNewIntent(Intent newIntent) {
388        setIntent(newIntent);
389        fixIntent(newIntent);
390        setCurrentTab(newIntent);
391        final String action = newIntent.getAction();
392        if (UI.FILTER_CONTACTS_ACTION.equals(action)) {
393            setupFilterText(newIntent);
394        } else if (isDialIntent(newIntent)) {
395            setupDialUri(newIntent);
396        }
397        // Fill in a phone number again.
398        mDialpadFragment.resolveIntent();
399    }
400
401    /** Returns true if the given intent contains a phone number to populate the dialer with */
402    private boolean isDialIntent(Intent intent) {
403        final String action = intent.getAction();
404        if (Intent.ACTION_DIAL.equals(action)) {
405            return true;
406        }
407        if (Intent.ACTION_VIEW.equals(action)) {
408            final Uri data = intent.getData();
409            if (data != null && "tel".equals(data.getScheme())) {
410                return true;
411            }
412        }
413        return false;
414    }
415
416    /**
417     * Retrieves the filter text stored in {@link #setupFilterText(Intent)}.
418     * This text originally came from a FILTER_CONTACTS_ACTION intent received
419     * by this activity. The stored text will then be cleared after after this
420     * method returns.
421     *
422     * @return The stored filter text
423     */
424    public String getAndClearFilterText() {
425        String filterText = mFilterText;
426        mFilterText = null;
427        return filterText;
428    }
429
430    /**
431     * Stores the filter text associated with a FILTER_CONTACTS_ACTION intent.
432     * This is so child activities can check if they are supposed to display a filter.
433     *
434     * @param intent The intent received in {@link #onNewIntent(Intent)}
435     */
436    private void setupFilterText(Intent intent) {
437        // If the intent was relaunched from history, don't apply the filter text.
438        if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0) {
439            return;
440        }
441        String filter = intent.getStringExtra(UI.FILTER_TEXT_EXTRA_KEY);
442        if (filter != null && filter.length() > 0) {
443            mFilterText = filter;
444        }
445    }
446
447    /**
448     * Retrieves the uri stored in {@link #setupDialUri(Intent)}. This uri
449     * originally came from a dial intent received by this activity. The stored
450     * uri will then be cleared after after this method returns.
451     *
452     * @return The stored uri
453     */
454    public Uri getAndClearDialUri() {
455        Uri dialUri = mDialUri;
456        mDialUri = null;
457        return dialUri;
458    }
459
460    /**
461     * Stores the uri associated with a dial intent. This is so child activities can
462     * check if they are supposed to display new dial info.
463     *
464     * @param intent The intent received in {@link #onNewIntent(Intent)}
465     */
466    private void setupDialUri(Intent intent) {
467        // If the intent was relaunched from history, don't reapply the intent.
468        if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0) {
469            return;
470        }
471        mDialUri = intent.getData();
472    }
473
474    @Override
475    public void onBackPressed() {
476        if (mInSearchUi) {
477            // We should let the user go back to usual screens with tabs.
478            exitSearchUi();
479        } else if (isTaskRoot()) {
480            // Instead of stopping, simply push this to the back of the stack.
481            // This is only done when running at the top of the stack;
482            // otherwise, we have been launched by someone else so need to
483            // allow the user to go back to the caller.
484            moveTaskToBack(false);
485        } else {
486            super.onBackPressed();
487        }
488    }
489
490    @Override
491    protected void onPostCreate(Bundle savedInstanceState) {
492        super.onPostCreate(savedInstanceState);
493
494        // Pass this lifecycle event down to the fragment
495        mDialpadFragment.onPostCreate();
496    }
497
498    /**
499     * Tab change listener that is instantiated once for each tab. Handles showing/hiding tabs
500     * and remembers manual tab selections
501     */
502    private class TabChangeListener implements TabListener {
503        private final Fragment mFragment;
504
505        public TabChangeListener(Fragment fragment) {
506            mFragment = fragment;
507        }
508
509        @Override
510        public void onTabUnselected(Tab tab, FragmentTransaction ft) {
511            ft.hide(mFragment);
512        }
513
514        @Override
515        public void onTabSelected(Tab tab, FragmentTransaction ft) {
516            ft.show(mFragment);
517            ft.hide(mPhoneNumberPickerFragment);
518
519            // Remember this tab index. This function is also called, if the tab is set
520            // automatically in which case the setter (setCurrentTab) has to set this to its old
521            // value afterwards
522            mLastManuallySelectedTab = tab.getPosition();
523        }
524
525        @Override
526        public void onTabReselected(Tab tab, FragmentTransaction ft) {
527        }
528    }
529
530    private OnContactBrowserActionListener mListFragmentListener =
531            new OnContactBrowserActionListener() {
532        @Override
533        public void onViewContactAction(Uri contactLookupUri) {
534            startActivity(new Intent(Intent.ACTION_VIEW, contactLookupUri));
535        }
536
537        @Override
538        public void onSmsContactAction(Uri contactUri) {
539        }
540
541        @Override
542        public void onSelectionChange() {
543        }
544
545        @Override
546        public void onRemoveFromFavoritesAction(Uri contactUri) {
547        }
548
549        @Override
550        public void onInvalidSelection() {
551        }
552
553        @Override
554        public void onFinishAction() {
555        }
556
557        @Override
558        public void onEditContactAction(Uri contactLookupUri) {
559        }
560
561        @Override
562        public void onDeleteContactAction(Uri contactUri) {
563        }
564
565        @Override
566        public void onCreateNewContactAction() {
567        }
568
569        @Override
570        public void onCallContactAction(Uri contactUri) {
571            PhoneNumberInteraction.startInteractionForPhoneCall(
572                    DialtactsActivity.this, contactUri);
573        }
574
575        @Override
576        public void onAddToFavoritesAction(Uri contactUri) {
577        }
578    };
579
580    private StrequentContactListFragment.Listener mStrequentListener =
581            new StrequentContactListFragment.Listener() {
582        @Override
583        public void onContactSelected(Uri contactUri) {
584            PhoneNumberInteraction.startInteractionForPhoneCall(
585                    DialtactsActivity.this, contactUri);
586        }
587    };
588
589    @Override
590    public boolean onCreateOptionsMenu(Menu menu) {
591        // For now, create the menu in here. It would be nice to do this in the Fragment,
592        // but that Fragment is re-used in other views.
593        final ActionBar actionBar = getActionBar();
594        if (actionBar == null) return false;
595        final Tab tab = actionBar.getSelectedTab();
596        if (tab == null) return false;
597        final int tabIndex = tab.getPosition();
598        if (tabIndex != TAB_INDEX_CONTACTS && tabIndex != TAB_INDEX_FAVORITES) return false;
599
600        MenuInflater inflater = getMenuInflater();
601        inflater.inflate(R.menu.list, menu);
602        return true;
603    }
604
605    @Override
606    public boolean onOptionsItemSelected(MenuItem item) {
607        // This is currently a copy of the equivalent code of PeopleActivity (with the
608        // exception of menu_add, because we do not select items in the list).
609        // Should be consolidated
610        switch (item.getItemId()) {
611        case R.id.menu_settings: {
612            final Intent intent = new Intent(this, ContactsPreferenceActivity.class);
613            startActivity(intent);
614            return true;
615        }
616        case R.id.menu_search: {
617            onSearchRequested();
618            return true;
619        }
620        case R.id.menu_add: {
621            final Intent intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI);
622            startActivity(intent);
623            return true;
624        }
625        case R.id.menu_import_export: {
626            ImportExportDialogFragment.show(getFragmentManager());
627            return true;
628        }
629        case R.id.menu_accounts: {
630            final Intent intent = new Intent(Settings.ACTION_SYNC_SETTINGS);
631            intent.putExtra(Settings.EXTRA_AUTHORITIES, new String[] {
632                ContactsContract.AUTHORITY
633            });
634            intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
635            startActivity(intent);
636            return true;
637        }
638        default:
639            return super.onOptionsItemSelected(item);
640        }
641    }
642
643    @Override
644    public void startSearch(String initialQuery, boolean selectInitialQuery,
645            Bundle appSearchData, boolean globalSearch) {
646        if (mPhoneNumberPickerFragment != null && mPhoneNumberPickerFragment.isAdded()
647                && !globalSearch) {
648            enterSearchUi();
649        } else {
650            super.startSearch(initialQuery, selectInitialQuery, appSearchData, globalSearch);
651        }
652    }
653
654    /**
655     * Hides every tab and shows search UI for phone lookup.
656     */
657    private void enterSearchUi() {
658        final ActionBar actionBar = getActionBar();
659
660        final Tab tab = actionBar.getSelectedTab();
661        if (tab != null) {
662            mLastManuallySelectedTab = tab.getPosition();
663        }
664
665        // Instantiate or reset SearchView in ActionBar.
666        if (mSearchView == null) {
667            // TODO: layout is not what we want. Need "up" button instead of "close" button, etc.
668            final View searchViewLayout =
669                    getLayoutInflater().inflate(R.layout.custom_action_bar, null);
670            mSearchView = (SearchView) searchViewLayout.findViewById(R.id.search_view);
671            mSearchView.setQueryHint(getString(R.string.hint_findContacts));
672            mSearchView.setOnQueryTextListener(mPhoneSearchQueryTextListener);
673            mSearchView.setOnCloseListener(mPhoneSearchCloseListener);
674            mSearchView.requestFocus();
675            actionBar.setCustomView(searchViewLayout,
676                    new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
677        } else {
678            mSearchView.setQuery(null, true);
679        }
680
681        actionBar.setDisplayShowCustomEnabled(true);
682        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
683
684        // Show the search fragment and hide everything else.
685        final FragmentTransaction transaction = getFragmentManager().beginTransaction();
686        transaction.show(mPhoneNumberPickerFragment);
687        transaction.hide(mDialpadFragment);
688        transaction.hide(mCallLogFragment);
689        transaction.hide(mContactsFragment);
690        transaction.hide(mStrequentFragment);
691        transaction.commit();
692
693        mInSearchUi = true;
694    }
695
696    /**
697     * Goes back to usual Phone UI with tags. Previously selected Tag and associated Fragment
698     * should be automatically focused again.
699     */
700    private void exitSearchUi() {
701        final ActionBar actionBar = getActionBar();
702
703        // We want to hide SearchView and show Tabs. Also focus on previously selected one.
704        actionBar.setDisplayShowCustomEnabled(false);
705        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
706
707        mInSearchUi = false;
708    }
709}
710