108e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov/*
2fcfdffb439ccf1ddef971109b82e782c47161572Dmitri Plotnikov * Copyright (C) 2010 The Android Open Source Project
308e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov *
408e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov * Licensed under the Apache License, Version 2.0 (the "License");
508e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov * you may not use this file except in compliance with the License.
608e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov * You may obtain a copy of the License at
708e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov *
808e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov *      http://www.apache.org/licenses/LICENSE-2.0
908e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov *
1008e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov * Unless required by applicable law or agreed to in writing, software
1108e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov * distributed under the License is distributed on an "AS IS" BASIS,
1208e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1308e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov * See the License for the specific language governing permissions and
1408e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov * limitations under the License.
1508e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov */
1608e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov
1708e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikovpackage com.android.contacts.activities;
1808e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov
191a59cffd839069ce91a9febb8a136442340ab4c8Dmitri Plotnikovimport android.app.ActionBar;
201ee9df6facd2340416d6a33aeb739707643d2fc3Katherine Kuanimport android.app.ActionBar.LayoutParams;
214d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onukiimport android.app.ActionBar.Tab;
224d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onukiimport android.app.FragmentTransaction;
2308e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikovimport android.content.Context;
2435d4aec605ce915ff5c574892a2069a37e0b9a77Makoto Onukiimport android.content.SharedPreferences;
2508e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikovimport android.os.Bundle;
2635d4aec605ce915ff5c574892a2069a37e0b9a77Makoto Onukiimport android.preference.PreferenceManager;
2715ccbb4d22fd65165cacb7970cbe61de1aa9aac4Dmitri Plotnikovimport android.text.TextUtils;
281ee9df6facd2340416d6a33aeb739707643d2fc3Katherine Kuanimport android.view.LayoutInflater;
291ee9df6facd2340416d6a33aeb739707643d2fc3Katherine Kuanimport android.view.View;
307f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chuimport android.view.ViewGroup;
31d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuanimport android.view.inputmethod.InputMethodManager;
327f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chuimport android.widget.ArrayAdapter;
331a59cffd839069ce91a9febb8a136442340ab4c8Dmitri Plotnikovimport android.widget.SearchView;
341a59cffd839069ce91a9febb8a136442340ab4c8Dmitri Plotnikovimport android.widget.SearchView.OnCloseListener;
35c5792ae6760291d435e91e0fdd28ece6b3311439Adam Powellimport android.widget.SearchView.OnQueryTextListener;
367f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chuimport android.widget.TextView;
3792a6fdf1b07b8f1447560174e24455fd46aee7cdDmitri Plotnikov
38e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.R;
39e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.activities.ActionBarAdapter.Listener.Action;
40e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.list.ContactsRequest;
41e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Cheng
4208e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov/**
43fcfdffb439ccf1ddef971109b82e782c47161572Dmitri Plotnikov * Adapter for the action bar at the top of the Contacts activity.
4408e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov */
45495db43f0a08bd71ba28a42f89b80d38af15afecKatherine Kuanpublic class ActionBarAdapter implements OnQueryTextListener, OnCloseListener {
4608e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov
4708e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov    public interface Listener {
48311882ab2fc1e9c8264f5892a6d50722b834e348Daniel Lehmann        public abstract class Action {
49311882ab2fc1e9c8264f5892a6d50722b834e348Daniel Lehmann            public static final int CHANGE_SEARCH_QUERY = 0;
50311882ab2fc1e9c8264f5892a6d50722b834e348Daniel Lehmann            public static final int START_SEARCH_MODE = 1;
51311882ab2fc1e9c8264f5892a6d50722b834e348Daniel Lehmann            public static final int STOP_SEARCH_MODE = 2;
52b5760b94bbf56ce348876ec36f4669d20a1530f5Katherine Kuan        }
53b5760b94bbf56ce348876ec36f4669d20a1530f5Katherine Kuan
54311882ab2fc1e9c8264f5892a6d50722b834e348Daniel Lehmann        void onAction(int action);
554d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki
564d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki        /**
574d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki         * Called when the user selects a tab.  The new tab can be obtained using
584d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki         * {@link #getCurrentTab}.
594d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki         */
604d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki        void onSelectedTabChanged();
6108e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov    }
6208e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov
6315ccbb4d22fd65165cacb7970cbe61de1aa9aac4Dmitri Plotnikov    private static final String EXTRA_KEY_SEARCH_MODE = "navBar.searchMode";
6408e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov    private static final String EXTRA_KEY_QUERY = "navBar.query";
6559dc2751d64f60f743b8a9e78186aa5b79dcaf83Isaac Katzenelson    private static final String EXTRA_KEY_SELECTED_TAB = "navBar.selectedTab";
6608e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov
6735d4aec605ce915ff5c574892a2069a37e0b9a77Makoto Onuki    private static final String PERSISTENT_LAST_TAB = "actionBarAdapter.lastTab";
6835d4aec605ce915ff5c574892a2069a37e0b9a77Makoto Onuki
6915ccbb4d22fd65165cacb7970cbe61de1aa9aac4Dmitri Plotnikov    private boolean mSearchMode;
7008e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov    private String mQueryString;
7115ccbb4d22fd65165cacb7970cbe61de1aa9aac4Dmitri Plotnikov
7215ccbb4d22fd65165cacb7970cbe61de1aa9aac4Dmitri Plotnikov    private SearchView mSearchView;
7392a6fdf1b07b8f1447560174e24455fd46aee7cdDmitri Plotnikov
7408e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov    private final Context mContext;
7535d4aec605ce915ff5c574892a2069a37e0b9a77Makoto Onuki    private final SharedPreferences mPrefs;
7608e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov
7708e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov    private Listener mListener;
7808e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov
794d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki    private final ActionBar mActionBar;
807f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu    private final int mActionBarNavigationMode;
817f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu    private final MyTabListener mTabListener;
827f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu    private final MyNavigationListener mNavigationListener;
838b8264620f9362e089322d1e3a7cc5620900e6f9Dmitri Plotnikov
84e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki    private boolean mShowHomeIcon;
85aaadf9393e98b04a40d249cd97ec758047268ed9Katherine Kuan    private boolean mShowTabsAsText;
86e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki
8752aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann    public interface TabState {
883b6a6f6ac9dce6028248ed7a695ed2c76890add8Paul Sliwowski        public static int FAVORITES = 0;
8952aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann        public static int ALL = 1;
903b6a6f6ac9dce6028248ed7a695ed2c76890add8Paul Sliwowski        public static int GROUPS = 2;
9152aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann
9252aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann        public static int COUNT = 3;
9352aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann        public static int DEFAULT = ALL;
944d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki    }
954d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki
9652aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann    private int mCurrentTab = TabState.DEFAULT;
974d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki
987f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu    /**
997f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu     * Extension of ArrayAdapter to be used for the action bar navigation drop list.  It is not
1007f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu     * possible to change the text appearance of a text item that is in the spinner header or
1017f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu     * in the drop down list using a selector xml file.  The only way to differentiate the two
1027f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu     * is if the view is gotten via {@link #getView(int, View, ViewGroup)} or
1037f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu     * {@link #getDropDownView(int, View, ViewGroup)}.
1047f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu     */
1057f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu    private class CustomArrayAdapter extends ArrayAdapter<String> {
1067f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu
1077f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu        public CustomArrayAdapter(Context context, int textResId) {
1087f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu            super(context, textResId);
1097f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu        }
1107f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu
1117f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu        public View getView (int position, View convertView, ViewGroup parent) {
1127f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu            TextView textView = (TextView) super.getView(position, convertView, parent);
1137f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu            textView.setTextAppearance(mContext,
1147f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu                    R.style.PeopleNavigationDropDownHeaderTextAppearance);
1157f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu            return textView;
1167f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu        }
1177f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu
1187f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu        public View getDropDownView (int position, View convertView, ViewGroup parent) {
1197f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu            TextView textView = (TextView) super.getDropDownView(position, convertView, parent);
1207f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu            textView.setTextAppearance(mContext,
1217f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu                    R.style.PeopleNavigationDropDownTextAppearance);
1227f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu            return textView;
1237f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu        }
1247f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu    }
1257f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu
126aaadf9393e98b04a40d249cd97ec758047268ed9Katherine Kuan    public ActionBarAdapter(Context context, Listener listener, ActionBar actionBar,
127aaadf9393e98b04a40d249cd97ec758047268ed9Katherine Kuan            boolean isUsingTwoPanes) {
12808e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov        mContext = context;
1291ee9df6facd2340416d6a33aeb739707643d2fc3Katherine Kuan        mListener = listener;
1304d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki        mActionBar = actionBar;
13135d4aec605ce915ff5c574892a2069a37e0b9a77Makoto Onuki        mPrefs = PreferenceManager.getDefaultSharedPreferences(mContext);
13208e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov
133e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki        mShowHomeIcon = mContext.getResources().getBoolean(R.bool.show_home_icon);
134e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki
135aaadf9393e98b04a40d249cd97ec758047268ed9Katherine Kuan        // On wide screens, show the tabs as text (instead of icons)
136aaadf9393e98b04a40d249cd97ec758047268ed9Katherine Kuan        mShowTabsAsText = isUsingTwoPanes;
1377f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu        if (isUsingTwoPanes) {
1387f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu            mActionBarNavigationMode = ActionBar.NAVIGATION_MODE_LIST;
1397f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu            mTabListener = null;
1407f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu            mNavigationListener = new MyNavigationListener();
1417f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu        } else {
1427f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu            mActionBarNavigationMode = ActionBar.NAVIGATION_MODE_TABS;
1437f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu            mTabListener = new MyTabListener();
1447f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu            mNavigationListener = null;
1457f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu        }
146aaadf9393e98b04a40d249cd97ec758047268ed9Katherine Kuan
1474ba903cdf132a6be2e5efa33187b18ca8446e503Makoto Onuki        // Set up search view.
1480bf7cd0124fa6f74fe3d64619740420ded86dcceKatherine Kuan        View customSearchView = LayoutInflater.from(mActionBar.getThemedContext()).inflate(
1490bf7cd0124fa6f74fe3d64619740420ded86dcceKatherine Kuan                R.layout.custom_action_bar, null);
1504ba903cdf132a6be2e5efa33187b18ca8446e503Makoto Onuki        int searchViewWidth = mContext.getResources().getDimensionPixelSize(
1514ba903cdf132a6be2e5efa33187b18ca8446e503Makoto Onuki                R.dimen.search_view_width);
1524ba903cdf132a6be2e5efa33187b18ca8446e503Makoto Onuki        if (searchViewWidth == 0) {
1534ba903cdf132a6be2e5efa33187b18ca8446e503Makoto Onuki            searchViewWidth = LayoutParams.MATCH_PARENT;
1541173ae29217fc83f254404f8a5fa10419ee83c93Dmitri Plotnikov        }
1554ba903cdf132a6be2e5efa33187b18ca8446e503Makoto Onuki        LayoutParams layoutParams = new LayoutParams(searchViewWidth, LayoutParams.WRAP_CONTENT);
1564ba903cdf132a6be2e5efa33187b18ca8446e503Makoto Onuki        mSearchView = (SearchView) customSearchView.findViewById(R.id.search_view);
157d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan        // Since the {@link SearchView} in this app is "click-to-expand", set the below mode on the
158d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan        // {@link SearchView} so that the magnifying glass icon appears inside the editable text
159d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan        // field. (In the "click-to-expand" search pattern, the user must explicitly expand the
160d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan        // search field and already knows a search is being conducted, so the icon is redundant
161d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan        // and can go away once the user starts typing.)
162d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan        mSearchView.setIconifiedByDefault(true);
1634ba903cdf132a6be2e5efa33187b18ca8446e503Makoto Onuki        mSearchView.setQueryHint(mContext.getString(R.string.hint_findContacts));
164c5792ae6760291d435e91e0fdd28ece6b3311439Adam Powell        mSearchView.setOnQueryTextListener(this);
16515ccbb4d22fd65165cacb7970cbe61de1aa9aac4Dmitri Plotnikov        mSearchView.setOnCloseListener(this);
16615ccbb4d22fd65165cacb7970cbe61de1aa9aac4Dmitri Plotnikov        mSearchView.setQuery(mQueryString, false);
1674ba903cdf132a6be2e5efa33187b18ca8446e503Makoto Onuki        mActionBar.setCustomView(customSearchView, layoutParams);
1684ba903cdf132a6be2e5efa33187b18ca8446e503Makoto Onuki
1697f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu        // Set up tabs or navigation list
1707f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu        switch(mActionBarNavigationMode) {
1717f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu            case ActionBar.NAVIGATION_MODE_TABS:
1727f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu                setupTabs();
1737f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu                break;
1747f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu            case ActionBar.NAVIGATION_MODE_LIST:
1757f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu                setupNavigationList();
1767f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu                break;
1777f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu        }
1787f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu    }
1797f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu
1807f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu    private void setupTabs() {
1811ff189a390ce5011f729637baf248646560c1bc6Daisuke Miyakawa        addTab(TabState.FAVORITES, R.drawable.ic_tab_starred, R.string.contactsFavoritesLabel);
1823b6a6f6ac9dce6028248ed7a695ed2c76890add8Paul Sliwowski        addTab(TabState.ALL, R.drawable.ic_tab_all, R.string.contactsAllLabel);
1833b6a6f6ac9dce6028248ed7a695ed2c76890add8Paul Sliwowski        addTab(TabState.GROUPS, R.drawable.ic_tab_groups, R.string.contactsGroupsLabel);
1844d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki    }
1854d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki
1867f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu    private void setupNavigationList() {
1877f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu        ArrayAdapter<String> navAdapter = new CustomArrayAdapter(mContext,
1887f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu                R.layout.people_navigation_item);
1897f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu        navAdapter.add(mContext.getString(R.string.contactsFavoritesLabel));
190db2adcb4d4da6361301701da08c4f3c72b577fd3Paul Sliwowski        navAdapter.add(mContext.getString(R.string.contactsAllLabel));
1917f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu        navAdapter.add(mContext.getString(R.string.contactsGroupsLabel));
1927f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu        mActionBar.setListNavigationCallbacks(navAdapter, mNavigationListener);
1937f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu    }
1947f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu
1957f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu    /**
1967f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu     * Because the navigation list items are in a different order than tab items, this returns
1977f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu     * the appropriate tab from the navigation item position.
1987f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu     */
1997f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu    private int getTabPositionFromNavigationItemPosition(int navItemPos) {
2007f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu        switch(navItemPos) {
2017f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu            case 0:
2027f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu                return TabState.FAVORITES;
2033b6a6f6ac9dce6028248ed7a695ed2c76890add8Paul Sliwowski            case 1:
2043b6a6f6ac9dce6028248ed7a695ed2c76890add8Paul Sliwowski                return TabState.ALL;
2057f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu            case 2:
2067f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu                return TabState.GROUPS;
2077f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu        }
2087f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu        throw new IllegalArgumentException(
2097f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu                "Parameter must be between 0 and " + Integer.toString(TabState.COUNT-1)
2107f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu                + " inclusive.");
2117f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu    }
2127f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu
2137f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu    /**
2147f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu     * This is the inverse of {@link getTabPositionFromNavigationItemPosition}.
2157f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu     */
2167f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu    private int getNavigationItemPositionFromTabPosition(int tabPos) {
2177f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu        switch(tabPos) {
2187f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu            case TabState.FAVORITES:
2193b6a6f6ac9dce6028248ed7a695ed2c76890add8Paul Sliwowski                return 0;
2203b6a6f6ac9dce6028248ed7a695ed2c76890add8Paul Sliwowski            case TabState.ALL:
2217f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu                return 1;
2227f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu            case TabState.GROUPS:
2237f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu                return 2;
2247f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu        }
2257f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu        throw new IllegalArgumentException(
2267f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu                "Parameter must be between 0 and " + Integer.toString(TabState.COUNT-1)
2277f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu                + " inclusive.");
2287f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu    }
2297f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu
2304d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki    public void initialize(Bundle savedState, ContactsRequest request) {
2314d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki        if (savedState == null) {
2324d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki            mSearchMode = request.isSearchMode();
2334d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki            mQueryString = request.getQueryString();
23435d4aec605ce915ff5c574892a2069a37e0b9a77Makoto Onuki            mCurrentTab = loadLastTabPreference();
2354d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki        } else {
2364d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki            mSearchMode = savedState.getBoolean(EXTRA_KEY_SEARCH_MODE);
2374d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki            mQueryString = savedState.getString(EXTRA_KEY_QUERY);
2384d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki
2394d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki            // Just set to the field here.  The listener will be notified by update().
24052aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann            mCurrentTab = savedState.getInt(EXTRA_KEY_SELECTED_TAB);
2414d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki        }
2423c877e33cb7fecc7a63af1cf3c25061d53811bf6Katherine Kuan        // Show tabs or the expanded {@link SearchView}, depending on whether or not we are in
2433c877e33cb7fecc7a63af1cf3c25061d53811bf6Katherine Kuan        // search mode.
2444ba903cdf132a6be2e5efa33187b18ca8446e503Makoto Onuki        update();
2453c877e33cb7fecc7a63af1cf3c25061d53811bf6Katherine Kuan        // Expanding the {@link SearchView} clears the query, so set the query from the
2463c877e33cb7fecc7a63af1cf3c25061d53811bf6Katherine Kuan        // {@link ContactsRequest} after it has been expanded, if applicable.
2473c877e33cb7fecc7a63af1cf3c25061d53811bf6Katherine Kuan        if (mSearchMode && !TextUtils.isEmpty(mQueryString)) {
2483c877e33cb7fecc7a63af1cf3c25061d53811bf6Katherine Kuan            setQueryString(mQueryString);
2493c877e33cb7fecc7a63af1cf3c25061d53811bf6Katherine Kuan        }
2508b8264620f9362e089322d1e3a7cc5620900e6f9Dmitri Plotnikov    }
2518b8264620f9362e089322d1e3a7cc5620900e6f9Dmitri Plotnikov
2521a59cffd839069ce91a9febb8a136442340ab4c8Dmitri Plotnikov    public void setListener(Listener listener) {
2531a59cffd839069ce91a9febb8a136442340ab4c8Dmitri Plotnikov        mListener = listener;
25408e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov    }
25508e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov
25652aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann    private void addTab(int expectedTabIndex, int icon, int description) {
2574d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki        final Tab tab = mActionBar.newTab();
2584d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki        tab.setTabListener(mTabListener);
259aaadf9393e98b04a40d249cd97ec758047268ed9Katherine Kuan        if (mShowTabsAsText) {
260aaadf9393e98b04a40d249cd97ec758047268ed9Katherine Kuan            tab.setText(description);
261aaadf9393e98b04a40d249cd97ec758047268ed9Katherine Kuan        } else {
262aaadf9393e98b04a40d249cd97ec758047268ed9Katherine Kuan            tab.setIcon(icon);
263aaadf9393e98b04a40d249cd97ec758047268ed9Katherine Kuan            tab.setContentDescription(description);
264aaadf9393e98b04a40d249cd97ec758047268ed9Katherine Kuan        }
2654d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki        mActionBar.addTab(tab);
26652aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann        if (expectedTabIndex != tab.getPosition()) {
26752aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann            throw new IllegalStateException("Tabs must be created in the right order");
26852aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann        }
2694d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki    }
2704d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki
2714d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki    private class MyTabListener implements ActionBar.TabListener {
2724d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki        /**
2734d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki         * If true, it won't call {@link #setCurrentTab} in {@link #onTabSelected}.
2744d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki         * This flag is used when we want to programmatically update the current tab without
2754d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki         * {@link #onTabSelected} getting called.
2764d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki         */
2774d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki        public boolean mIgnoreTabSelected;
2784d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki
2794d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki        @Override public void onTabReselected(Tab tab, FragmentTransaction ft) { }
2804d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki        @Override public void onTabUnselected(Tab tab, FragmentTransaction ft) { }
2814d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki
2824d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki        @Override public void onTabSelected(Tab tab, FragmentTransaction ft) {
2834d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki            if (!mIgnoreTabSelected) {
28452aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann                setCurrentTab(tab.getPosition());
2854d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki            }
2864d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki        }
2874d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki    }
2884d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki
2897f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu    private class MyNavigationListener implements ActionBar.OnNavigationListener {
2907f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu        public boolean mIgnoreNavigationItemSelected;
2917f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu
2927f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu        public boolean onNavigationItemSelected(int itemPosition, long itemId) {
2937f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu            if (!mIgnoreNavigationItemSelected) {
2947f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu                setCurrentTab(getTabPositionFromNavigationItemPosition(itemPosition));
2957f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu            }
2967f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu            return true;
2977f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu        }
2987f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu    }
2997f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu
3004d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki    /**
3014d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki     * Change the current tab, and notify the listener.
3024d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki     */
30352aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann    public void setCurrentTab(int tab) {
304250ce43794cdf6820f7a13ef0195a566bd0c8c64Makoto Onuki        setCurrentTab(tab, true);
305250ce43794cdf6820f7a13ef0195a566bd0c8c64Makoto Onuki    }
306250ce43794cdf6820f7a13ef0195a566bd0c8c64Makoto Onuki
307250ce43794cdf6820f7a13ef0195a566bd0c8c64Makoto Onuki    /**
308250ce43794cdf6820f7a13ef0195a566bd0c8c64Makoto Onuki     * Change the current tab
309250ce43794cdf6820f7a13ef0195a566bd0c8c64Makoto Onuki     */
31052aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann    public void setCurrentTab(int tab, boolean notifyListener) {
3114d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki        if (tab == mCurrentTab) {
3124d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki            return;
3134d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki        }
3144d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki        mCurrentTab = tab;
3154d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki
3167f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu        final int actionBarSelectedNavIndex = mActionBar.getSelectedNavigationIndex();
3177f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu        switch(mActionBar.getNavigationMode()) {
3187f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu            case ActionBar.NAVIGATION_MODE_TABS:
3197f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu                if (mCurrentTab != actionBarSelectedNavIndex) {
3207f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu                    mActionBar.setSelectedNavigationItem(mCurrentTab);
3217f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu                }
3227f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu                break;
3237f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu            case ActionBar.NAVIGATION_MODE_LIST:
3247f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu                if (mCurrentTab != getTabPositionFromNavigationItemPosition(
3257f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu                        actionBarSelectedNavIndex)) {
3267f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu                    mActionBar.setSelectedNavigationItem(
3277f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu                            getNavigationItemPositionFromTabPosition(mCurrentTab));
3287f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu                }
3297f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu                break;
3304d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki        }
3314d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki
332250ce43794cdf6820f7a13ef0195a566bd0c8c64Makoto Onuki        if (notifyListener && mListener != null) mListener.onSelectedTabChanged();
33335d4aec605ce915ff5c574892a2069a37e0b9a77Makoto Onuki        saveLastTabPreference(mCurrentTab);
3344d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki    }
3354d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki
33652aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann    public int getCurrentTab() {
3374d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki        return mCurrentTab;
3384d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki    }
3394d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki
3401db00f68b34f6cf7e9d19fedb559cf12f8c05e9cMakoto Onuki    /**
3411db00f68b34f6cf7e9d19fedb559cf12f8c05e9cMakoto Onuki     * @return Whether in search mode, i.e. if the search view is visible/expanded.
3421db00f68b34f6cf7e9d19fedb559cf12f8c05e9cMakoto Onuki     *
3431db00f68b34f6cf7e9d19fedb559cf12f8c05e9cMakoto Onuki     * Note even if the action bar is in search mode, if the query is empty, the search fragment
3441db00f68b34f6cf7e9d19fedb559cf12f8c05e9cMakoto Onuki     * will not be in search mode.
3451db00f68b34f6cf7e9d19fedb559cf12f8c05e9cMakoto Onuki     */
34615ccbb4d22fd65165cacb7970cbe61de1aa9aac4Dmitri Plotnikov    public boolean isSearchMode() {
34715ccbb4d22fd65165cacb7970cbe61de1aa9aac4Dmitri Plotnikov        return mSearchMode;
34808e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov    }
34908e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov
35015ccbb4d22fd65165cacb7970cbe61de1aa9aac4Dmitri Plotnikov    public void setSearchMode(boolean flag) {
35115ccbb4d22fd65165cacb7970cbe61de1aa9aac4Dmitri Plotnikov        if (mSearchMode != flag) {
35215ccbb4d22fd65165cacb7970cbe61de1aa9aac4Dmitri Plotnikov            mSearchMode = flag;
353bee8d3bd37edf44c535c0cc401e8d03f095b8328Dmitri Plotnikov            update();
354f3f933a798c9cfffb1c1c0cc770187b5b0b763ebKatherine Kuan            if (mSearchView == null) {
355f3f933a798c9cfffb1c1c0cc770187b5b0b763ebKatherine Kuan                return;
356f3f933a798c9cfffb1c1c0cc770187b5b0b763ebKatherine Kuan            }
3570b51a8d4539cc516dc2c02948335347d1df8769bDmitri Plotnikov            if (mSearchMode) {
3584ba903cdf132a6be2e5efa33187b18ca8446e503Makoto Onuki                setFocusOnSearchView();
359ab4d29f6a2edbfae008dbaff35f25baad73aa0dfDmitri Plotnikov            } else {
360ab4d29f6a2edbfae008dbaff35f25baad73aa0dfDmitri Plotnikov                mSearchView.setQuery(null, false);
3610b51a8d4539cc516dc2c02948335347d1df8769bDmitri Plotnikov            }
362311882ab2fc1e9c8264f5892a6d50722b834e348Daniel Lehmann        } else if (flag) {
363311882ab2fc1e9c8264f5892a6d50722b834e348Daniel Lehmann            // Everything is already set up. Still make sure the keyboard is up
364311882ab2fc1e9c8264f5892a6d50722b834e348Daniel Lehmann            if (mSearchView != null) setFocusOnSearchView();
36508e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov        }
36608e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov    }
36708e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov
36808e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov    public String getQueryString() {
3691db00f68b34f6cf7e9d19fedb559cf12f8c05e9cMakoto Onuki        return mSearchMode ? mQueryString : null;
37008e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov    }
37108e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov
37208e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov    public void setQueryString(String query) {
37308e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov        mQueryString = query;
374f3f933a798c9cfffb1c1c0cc770187b5b0b763ebKatherine Kuan        if (mSearchView != null) {
375f3f933a798c9cfffb1c1c0cc770187b5b0b763ebKatherine Kuan            mSearchView.setQuery(query, false);
376f3f933a798c9cfffb1c1c0cc770187b5b0b763ebKatherine Kuan        }
37708e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov    }
37808e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov
379e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki    /** @return true if the "UP" icon is showing. */
380e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki    public boolean isUpShowing() {
381e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki        return mSearchMode; // Only shown on the search mode.
382e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki    }
383e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki
384e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki    private void updateDisplayOptions() {
385e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki        // All the flags we may change in this method.
386e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki        final int MASK = ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_SHOW_HOME
387d84ea5c8b0a8376e7cf80b0e15b65a72fd99d7a9Adam Powell                | ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_CUSTOM;
388e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki
389e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki        // The current flags set to the action bar.  (only the ones that we may change here)
390e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki        final int current = mActionBar.getDisplayOptions() & MASK;
391e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki
392e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki        // Build the new flags...
393e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki        int newFlags = 0;
394e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki        newFlags |= ActionBar.DISPLAY_SHOW_TITLE;
395e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki        if (mShowHomeIcon) {
396e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki            newFlags |= ActionBar.DISPLAY_SHOW_HOME;
397e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki        }
398e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki        if (mSearchMode) {
399e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki            newFlags |= ActionBar.DISPLAY_SHOW_HOME;
400e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki            newFlags |= ActionBar.DISPLAY_HOME_AS_UP;
401e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki            newFlags |= ActionBar.DISPLAY_SHOW_CUSTOM;
402e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki        }
403d84ea5c8b0a8376e7cf80b0e15b65a72fd99d7a9Adam Powell        mActionBar.setHomeButtonEnabled(mSearchMode);
404e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki
405e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki        if (current != newFlags) {
406e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki            // Pass the mask here to preserve other flags that we're not interested here.
407e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki            mActionBar.setDisplayOptions(newFlags, MASK);
408e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki        }
409e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki    }
410e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki
4114d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki    private void update() {
412b0d82d2703d66b3bd4fe8dc4208cdf6a09f2f4afDaniel Lehmann        boolean isIconifiedChanging = mSearchView.isIconified() == mSearchMode;
413b5760b94bbf56ce348876ec36f4669d20a1530f5Katherine Kuan        if (mSearchMode) {
4145267367e202dcb39ef0fe912a7be9209548ec436Makoto Onuki            setFocusOnSearchView();
415d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan            // Since we have the {@link SearchView} in a custom action bar, we must manually handle
4163c877e33cb7fecc7a63af1cf3c25061d53811bf6Katherine Kuan            // expanding the {@link SearchView} when a search is initiated. Note that a side effect
4173c877e33cb7fecc7a63af1cf3c25061d53811bf6Katherine Kuan            // of this method is that the {@link SearchView} query text is set to empty string.
418b0d82d2703d66b3bd4fe8dc4208cdf6a09f2f4afDaniel Lehmann            if (isIconifiedChanging) {
4198d5eec3c552c2ac23bc4d3324063627d31582615Yorke Lee                final CharSequence queryText = mSearchView.getQuery();
420b0d82d2703d66b3bd4fe8dc4208cdf6a09f2f4afDaniel Lehmann                mSearchView.onActionViewExpanded();
4218d5eec3c552c2ac23bc4d3324063627d31582615Yorke Lee                if (!TextUtils.isEmpty(queryText)) {
4228d5eec3c552c2ac23bc4d3324063627d31582615Yorke Lee                    mSearchView.setQuery(queryText, false);
4238d5eec3c552c2ac23bc4d3324063627d31582615Yorke Lee                }
424b0d82d2703d66b3bd4fe8dc4208cdf6a09f2f4afDaniel Lehmann            }
4254d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki            if (mActionBar.getNavigationMode() != ActionBar.NAVIGATION_MODE_STANDARD) {
4264d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki                mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
4274d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki            }
428b5760b94bbf56ce348876ec36f4669d20a1530f5Katherine Kuan            if (mListener != null) {
429b5760b94bbf56ce348876ec36f4669d20a1530f5Katherine Kuan                mListener.onAction(Action.START_SEARCH_MODE);
430c9916d303cc48b4a4ff94ef9c56d7ca5da72c4deDmitri Plotnikov            }
43115ccbb4d22fd65165cacb7970cbe61de1aa9aac4Dmitri Plotnikov        } else {
4327f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu            final int currentNavigationMode = mActionBar.getNavigationMode();
4337f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu            if (mActionBarNavigationMode == ActionBar.NAVIGATION_MODE_TABS
4347f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu                    && currentNavigationMode != ActionBar.NAVIGATION_MODE_TABS) {
4354d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki                // setNavigationMode will trigger onTabSelected() with the tab which was previously
4364d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki                // selected.
4374d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki                // The issue is that when we're first switching to the tab navigation mode after
4384d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki                // screen orientation changes, onTabSelected() will get called with the first tab
4394d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki                // (i.e. favorite), which would results in mCurrentTab getting set to FAVORITES and
4404d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki                // we'd lose restored tab.
4414d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki                // So let's just disable the callback here temporarily.  We'll notify the listener
4424d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki                // after this anyway.
4434d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki                mTabListener.mIgnoreTabSelected = true;
4444d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki                mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
44552aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann                mActionBar.setSelectedNavigationItem(mCurrentTab);
4464d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki                mTabListener.mIgnoreTabSelected = false;
4477f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu            } else if (mActionBarNavigationMode == ActionBar.NAVIGATION_MODE_LIST
4487f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu                    && currentNavigationMode != ActionBar.NAVIGATION_MODE_LIST) {
4497f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu                mNavigationListener.mIgnoreNavigationItemSelected = true;
4507f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu                mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
4517f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu                mActionBar.setSelectedNavigationItem(
4527f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu                        getNavigationItemPositionFromTabPosition(mCurrentTab));
4537f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu                mNavigationListener.mIgnoreNavigationItemSelected = false;
4544d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki            }
455b5760b94bbf56ce348876ec36f4669d20a1530f5Katherine Kuan            mActionBar.setTitle(null);
456d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan            // Since we have the {@link SearchView} in a custom action bar, we must manually handle
457d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan            // collapsing the {@link SearchView} when search mode is exited.
458b0d82d2703d66b3bd4fe8dc4208cdf6a09f2f4afDaniel Lehmann            if (isIconifiedChanging) {
459b0d82d2703d66b3bd4fe8dc4208cdf6a09f2f4afDaniel Lehmann                mSearchView.onActionViewCollapsed();
460b0d82d2703d66b3bd4fe8dc4208cdf6a09f2f4afDaniel Lehmann            }
461b5760b94bbf56ce348876ec36f4669d20a1530f5Katherine Kuan            if (mListener != null) {
462b5760b94bbf56ce348876ec36f4669d20a1530f5Katherine Kuan                mListener.onAction(Action.STOP_SEARCH_MODE);
4634d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki                mListener.onSelectedTabChanged();
464bee8d3bd37edf44c535c0cc401e8d03f095b8328Dmitri Plotnikov            }
46508e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov        }
466e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki        updateDisplayOptions();
46708e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov    }
46808e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov
46908e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov    @Override
470c5792ae6760291d435e91e0fdd28ece6b3311439Adam Powell    public boolean onQueryTextChange(String queryString) {
471b5760b94bbf56ce348876ec36f4669d20a1530f5Katherine Kuan        // TODO: Clean up SearchView code because it keeps setting the SearchView query,
472b5760b94bbf56ce348876ec36f4669d20a1530f5Katherine Kuan        // invoking onQueryChanged, setting up the fragment again, invalidating the options menu,
473b5760b94bbf56ce348876ec36f4669d20a1530f5Katherine Kuan        // storing the SearchView again, and etc... unless we add in the early return statements.
474b5760b94bbf56ce348876ec36f4669d20a1530f5Katherine Kuan        if (queryString.equals(mQueryString)) {
475b5760b94bbf56ce348876ec36f4669d20a1530f5Katherine Kuan            return false;
476b5760b94bbf56ce348876ec36f4669d20a1530f5Katherine Kuan        }
47708e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov        mQueryString = queryString;
478ab4d29f6a2edbfae008dbaff35f25baad73aa0dfDmitri Plotnikov        if (!mSearchMode) {
479ab4d29f6a2edbfae008dbaff35f25baad73aa0dfDmitri Plotnikov            if (!TextUtils.isEmpty(queryString)) {
480ab4d29f6a2edbfae008dbaff35f25baad73aa0dfDmitri Plotnikov                setSearchMode(true);
4819806ed099226a19e92c29d9efa791cd187fd2a53Dmitri Plotnikov            }
482ab4d29f6a2edbfae008dbaff35f25baad73aa0dfDmitri Plotnikov        } else if (mListener != null) {
483b5760b94bbf56ce348876ec36f4669d20a1530f5Katherine Kuan            mListener.onAction(Action.CHANGE_SEARCH_QUERY);
4849806ed099226a19e92c29d9efa791cd187fd2a53Dmitri Plotnikov        }
485ab4d29f6a2edbfae008dbaff35f25baad73aa0dfDmitri Plotnikov
4861a59cffd839069ce91a9febb8a136442340ab4c8Dmitri Plotnikov        return true;
4871a59cffd839069ce91a9febb8a136442340ab4c8Dmitri Plotnikov    }
4881a59cffd839069ce91a9febb8a136442340ab4c8Dmitri Plotnikov
4891a59cffd839069ce91a9febb8a136442340ab4c8Dmitri Plotnikov    @Override
490c5792ae6760291d435e91e0fdd28ece6b3311439Adam Powell    public boolean onQueryTextSubmit(String query) {
491d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan        // When the search is "committed" by the user, then hide the keyboard so the user can
492d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan        // more easily browse the list of results.
493d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan        if (mSearchView != null) {
494d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan            InputMethodManager imm = (InputMethodManager) mContext.getSystemService(
495d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan                    Context.INPUT_METHOD_SERVICE);
496d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan            if (imm != null) {
497d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan                imm.hideSoftInputFromWindow(mSearchView.getWindowToken(), 0);
498d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan            }
499d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan            mSearchView.clearFocus();
500d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan        }
5011a59cffd839069ce91a9febb8a136442340ab4c8Dmitri Plotnikov        return true;
50208e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov    }
50308e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov
50408e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov    @Override
5051a59cffd839069ce91a9febb8a136442340ab4c8Dmitri Plotnikov    public boolean onClose() {
50615ccbb4d22fd65165cacb7970cbe61de1aa9aac4Dmitri Plotnikov        setSearchMode(false);
50715ccbb4d22fd65165cacb7970cbe61de1aa9aac4Dmitri Plotnikov        return false;
50808e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov    }
50908e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov
51015ccbb4d22fd65165cacb7970cbe61de1aa9aac4Dmitri Plotnikov    public void onSaveInstanceState(Bundle outState) {
51115ccbb4d22fd65165cacb7970cbe61de1aa9aac4Dmitri Plotnikov        outState.putBoolean(EXTRA_KEY_SEARCH_MODE, mSearchMode);
51215ccbb4d22fd65165cacb7970cbe61de1aa9aac4Dmitri Plotnikov        outState.putString(EXTRA_KEY_QUERY, mQueryString);
51352aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann        outState.putInt(EXTRA_KEY_SELECTED_TAB, mCurrentTab);
514fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov    }
515fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov
5165c3a0a1440625fab859aab420cb08bc0276358a0Katherine Kuan    /**
5175c3a0a1440625fab859aab420cb08bc0276358a0Katherine Kuan     * Clears the focus from the {@link SearchView} if we are in search mode.
5185c3a0a1440625fab859aab420cb08bc0276358a0Katherine Kuan     * This will suppress the IME if it is visible.
5195c3a0a1440625fab859aab420cb08bc0276358a0Katherine Kuan     */
5205c3a0a1440625fab859aab420cb08bc0276358a0Katherine Kuan    public void clearFocusOnSearchView() {
5215c3a0a1440625fab859aab420cb08bc0276358a0Katherine Kuan        if (isSearchMode()) {
5225c3a0a1440625fab859aab420cb08bc0276358a0Katherine Kuan            if (mSearchView != null) {
5235c3a0a1440625fab859aab420cb08bc0276358a0Katherine Kuan                mSearchView.clearFocus();
5245c3a0a1440625fab859aab420cb08bc0276358a0Katherine Kuan            }
5255c3a0a1440625fab859aab420cb08bc0276358a0Katherine Kuan        }
5265c3a0a1440625fab859aab420cb08bc0276358a0Katherine Kuan    }
5275c3a0a1440625fab859aab420cb08bc0276358a0Katherine Kuan
52809d66a382d1f94618b52fec11ba54d9243a95a18Daniel Lehmann    public void setFocusOnSearchView() {
5294ba903cdf132a6be2e5efa33187b18ca8446e503Makoto Onuki        mSearchView.requestFocus();
5304ba903cdf132a6be2e5efa33187b18ca8446e503Makoto Onuki        mSearchView.setIconified(false); // Workaround for the "IME not popping up" issue.
5314ba903cdf132a6be2e5efa33187b18ca8446e503Makoto Onuki    }
53235d4aec605ce915ff5c574892a2069a37e0b9a77Makoto Onuki
53352aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann    private void saveLastTabPreference(int tab) {
53452aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann        mPrefs.edit().putInt(PERSISTENT_LAST_TAB, tab).apply();
53535d4aec605ce915ff5c574892a2069a37e0b9a77Makoto Onuki    }
53635d4aec605ce915ff5c574892a2069a37e0b9a77Makoto Onuki
53752aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann    private int loadLastTabPreference() {
53835d4aec605ce915ff5c574892a2069a37e0b9a77Makoto Onuki        try {
53952aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann            return mPrefs.getInt(PERSISTENT_LAST_TAB, TabState.DEFAULT);
54035d4aec605ce915ff5c574892a2069a37e0b9a77Makoto Onuki        } catch (IllegalArgumentException e) {
54135d4aec605ce915ff5c574892a2069a37e0b9a77Makoto Onuki            // Preference is corrupt?
54252aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann            return TabState.DEFAULT;
54335d4aec605ce915ff5c574892a2069a37e0b9a77Makoto Onuki        }
54435d4aec605ce915ff5c574892a2069a37e0b9a77Makoto Onuki    }
54508e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov}
546