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