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