ActionBarAdapter.java revision 8d5eec3c552c2ac23bc4d3324063627d31582615
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 { 8852aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann public static int GROUPS = 0; 8952aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann public static int ALL = 1; 9052aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann public static int FAVORITES = 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.GROUPS, R.drawable.ic_tab_groups, R.string.contactsGroupsLabel); 1821ff189a390ce5011f729637baf248646560c1bc6Daisuke Miyakawa addTab(TabState.ALL, R.drawable.ic_tab_all, R.string.contactsAllLabel); 1831ff189a390ce5011f729637baf248646560c1bc6Daisuke Miyakawa addTab(TabState.FAVORITES, R.drawable.ic_tab_starred, R.string.contactsFavoritesLabel); 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.contactsAllLabel)); 1907f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu navAdapter.add(mContext.getString(R.string.contactsFavoritesLabel)); 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.ALL; 2037f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu case 1: 2047f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu return TabState.FAVORITES; 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.ALL: 2197f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu return 0; 2207f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu case TabState.FAVORITES: 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