ActionBarAdapter.java revision 7f5220e23b37b76cf484b28c182a0c98749b59e2
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 1908e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikovimport com.android.contacts.R; 20b5760b94bbf56ce348876ec36f4669d20a1530f5Katherine Kuanimport com.android.contacts.activities.ActionBarAdapter.Listener.Action; 2108e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikovimport com.android.contacts.list.ContactsRequest; 2208e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov 231a59cffd839069ce91a9febb8a136442340ab4c8Dmitri Plotnikovimport android.app.ActionBar; 241ee9df6facd2340416d6a33aeb739707643d2fc3Katherine Kuanimport android.app.ActionBar.LayoutParams; 254d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onukiimport android.app.ActionBar.Tab; 264d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onukiimport android.app.FragmentTransaction; 2708e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikovimport android.content.Context; 2835d4aec605ce915ff5c574892a2069a37e0b9a77Makoto Onukiimport android.content.SharedPreferences; 297f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chuimport android.graphics.Color; 3008e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikovimport android.os.Bundle; 3135d4aec605ce915ff5c574892a2069a37e0b9a77Makoto Onukiimport android.preference.PreferenceManager; 3215ccbb4d22fd65165cacb7970cbe61de1aa9aac4Dmitri Plotnikovimport android.text.TextUtils; 331ee9df6facd2340416d6a33aeb739707643d2fc3Katherine Kuanimport android.view.LayoutInflater; 341ee9df6facd2340416d6a33aeb739707643d2fc3Katherine Kuanimport android.view.View; 357f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chuimport android.view.ViewGroup; 36d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuanimport android.view.inputmethod.InputMethodManager; 377f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chuimport android.widget.ArrayAdapter; 381a59cffd839069ce91a9febb8a136442340ab4c8Dmitri Plotnikovimport android.widget.SearchView; 391a59cffd839069ce91a9febb8a136442340ab4c8Dmitri Plotnikovimport android.widget.SearchView.OnCloseListener; 40c5792ae6760291d435e91e0fdd28ece6b3311439Adam Powellimport android.widget.SearchView.OnQueryTextListener; 417f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chuimport android.widget.TextView; 4292a6fdf1b07b8f1447560174e24455fd46aee7cdDmitri Plotnikov 4308e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov/** 44fcfdffb439ccf1ddef971109b82e782c47161572Dmitri Plotnikov * Adapter for the action bar at the top of the Contacts activity. 4508e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov */ 46495db43f0a08bd71ba28a42f89b80d38af15afecKatherine Kuanpublic class ActionBarAdapter implements OnQueryTextListener, OnCloseListener { 4708e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov 4808e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov public interface Listener { 49311882ab2fc1e9c8264f5892a6d50722b834e348Daniel Lehmann public abstract class Action { 50311882ab2fc1e9c8264f5892a6d50722b834e348Daniel Lehmann public static final int CHANGE_SEARCH_QUERY = 0; 51311882ab2fc1e9c8264f5892a6d50722b834e348Daniel Lehmann public static final int START_SEARCH_MODE = 1; 52311882ab2fc1e9c8264f5892a6d50722b834e348Daniel Lehmann public static final int STOP_SEARCH_MODE = 2; 53b5760b94bbf56ce348876ec36f4669d20a1530f5Katherine Kuan } 54b5760b94bbf56ce348876ec36f4669d20a1530f5Katherine Kuan 55311882ab2fc1e9c8264f5892a6d50722b834e348Daniel Lehmann void onAction(int action); 564d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki 574d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki /** 584d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki * Called when the user selects a tab. The new tab can be obtained using 594d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki * {@link #getCurrentTab}. 604d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki */ 614d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki void onSelectedTabChanged(); 6208e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov } 6308e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov 6415ccbb4d22fd65165cacb7970cbe61de1aa9aac4Dmitri Plotnikov private static final String EXTRA_KEY_SEARCH_MODE = "navBar.searchMode"; 6508e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov private static final String EXTRA_KEY_QUERY = "navBar.query"; 6659dc2751d64f60f743b8a9e78186aa5b79dcaf83Isaac Katzenelson private static final String EXTRA_KEY_SELECTED_TAB = "navBar.selectedTab"; 6708e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov 6835d4aec605ce915ff5c574892a2069a37e0b9a77Makoto Onuki private static final String PERSISTENT_LAST_TAB = "actionBarAdapter.lastTab"; 6935d4aec605ce915ff5c574892a2069a37e0b9a77Makoto Onuki 7015ccbb4d22fd65165cacb7970cbe61de1aa9aac4Dmitri Plotnikov private boolean mSearchMode; 7108e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov private String mQueryString; 7215ccbb4d22fd65165cacb7970cbe61de1aa9aac4Dmitri Plotnikov 7315ccbb4d22fd65165cacb7970cbe61de1aa9aac4Dmitri Plotnikov private SearchView mSearchView; 7492a6fdf1b07b8f1447560174e24455fd46aee7cdDmitri Plotnikov 7508e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov private final Context mContext; 7635d4aec605ce915ff5c574892a2069a37e0b9a77Makoto Onuki private final SharedPreferences mPrefs; 7708e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov 7808e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov private Listener mListener; 7908e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov 804d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki private final ActionBar mActionBar; 817f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu private final int mActionBarNavigationMode; 827f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu private final MyTabListener mTabListener; 837f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu private final MyNavigationListener mNavigationListener; 848b8264620f9362e089322d1e3a7cc5620900e6f9Dmitri Plotnikov 85e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki private boolean mShowHomeIcon; 86aaadf9393e98b04a40d249cd97ec758047268ed9Katherine Kuan private boolean mShowTabsAsText; 87e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki 8852aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann public interface TabState { 8952aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann public static int GROUPS = 0; 9052aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann public static int ALL = 1; 9152aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann public static int FAVORITES = 2; 9252aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann 9352aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann public static int COUNT = 3; 9452aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann public static int DEFAULT = ALL; 954d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki } 964d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki 9752aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann private int mCurrentTab = TabState.DEFAULT; 984d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki 997f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu /** 1007f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu * Extension of ArrayAdapter to be used for the action bar navigation drop list. It is not 1017f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu * possible to change the text appearance of a text item that is in the spinner header or 1027f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu * in the drop down list using a selector xml file. The only way to differentiate the two 1037f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu * is if the view is gotten via {@link #getView(int, View, ViewGroup)} or 1047f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu * {@link #getDropDownView(int, View, ViewGroup)}. 1057f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu */ 1067f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu private class CustomArrayAdapter extends ArrayAdapter<String> { 1077f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu 1087f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu public CustomArrayAdapter(Context context, int textResId) { 1097f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu super(context, textResId); 1107f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu } 1117f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu 1127f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu public View getView (int position, View convertView, ViewGroup parent) { 1137f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu TextView textView = (TextView) super.getView(position, convertView, parent); 1147f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu textView.setTextAppearance(mContext, 1157f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu R.style.PeopleNavigationDropDownHeaderTextAppearance); 1167f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu return textView; 1177f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu } 1187f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu 1197f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu public View getDropDownView (int position, View convertView, ViewGroup parent) { 1207f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu TextView textView = (TextView) super.getDropDownView(position, convertView, parent); 1217f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu textView.setTextAppearance(mContext, 1227f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu R.style.PeopleNavigationDropDownTextAppearance); 1237f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu return textView; 1247f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu } 1257f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu } 1267f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu 127aaadf9393e98b04a40d249cd97ec758047268ed9Katherine Kuan public ActionBarAdapter(Context context, Listener listener, ActionBar actionBar, 128aaadf9393e98b04a40d249cd97ec758047268ed9Katherine Kuan boolean isUsingTwoPanes) { 12908e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov mContext = context; 1301ee9df6facd2340416d6a33aeb739707643d2fc3Katherine Kuan mListener = listener; 1314d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki mActionBar = actionBar; 13235d4aec605ce915ff5c574892a2069a37e0b9a77Makoto Onuki mPrefs = PreferenceManager.getDefaultSharedPreferences(mContext); 13308e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov 134e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki mShowHomeIcon = mContext.getResources().getBoolean(R.bool.show_home_icon); 135e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki 136aaadf9393e98b04a40d249cd97ec758047268ed9Katherine Kuan // On wide screens, show the tabs as text (instead of icons) 137aaadf9393e98b04a40d249cd97ec758047268ed9Katherine Kuan mShowTabsAsText = isUsingTwoPanes; 1387f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu if (isUsingTwoPanes) { 1397f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu mActionBarNavigationMode = ActionBar.NAVIGATION_MODE_LIST; 1407f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu mTabListener = null; 1417f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu mNavigationListener = new MyNavigationListener(); 1427f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu } else { 1437f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu mActionBarNavigationMode = ActionBar.NAVIGATION_MODE_TABS; 1447f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu mTabListener = new MyTabListener(); 1457f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu mNavigationListener = null; 1467f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu } 147aaadf9393e98b04a40d249cd97ec758047268ed9Katherine Kuan 1484ba903cdf132a6be2e5efa33187b18ca8446e503Makoto Onuki // Set up search view. 1490bf7cd0124fa6f74fe3d64619740420ded86dcceKatherine Kuan View customSearchView = LayoutInflater.from(mActionBar.getThemedContext()).inflate( 1500bf7cd0124fa6f74fe3d64619740420ded86dcceKatherine Kuan R.layout.custom_action_bar, null); 1514ba903cdf132a6be2e5efa33187b18ca8446e503Makoto Onuki int searchViewWidth = mContext.getResources().getDimensionPixelSize( 1524ba903cdf132a6be2e5efa33187b18ca8446e503Makoto Onuki R.dimen.search_view_width); 1534ba903cdf132a6be2e5efa33187b18ca8446e503Makoto Onuki if (searchViewWidth == 0) { 1544ba903cdf132a6be2e5efa33187b18ca8446e503Makoto Onuki searchViewWidth = LayoutParams.MATCH_PARENT; 1551173ae29217fc83f254404f8a5fa10419ee83c93Dmitri Plotnikov } 1564ba903cdf132a6be2e5efa33187b18ca8446e503Makoto Onuki LayoutParams layoutParams = new LayoutParams(searchViewWidth, LayoutParams.WRAP_CONTENT); 1574ba903cdf132a6be2e5efa33187b18ca8446e503Makoto Onuki mSearchView = (SearchView) customSearchView.findViewById(R.id.search_view); 158d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan // Since the {@link SearchView} in this app is "click-to-expand", set the below mode on the 159d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan // {@link SearchView} so that the magnifying glass icon appears inside the editable text 160d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan // field. (In the "click-to-expand" search pattern, the user must explicitly expand the 161d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan // search field and already knows a search is being conducted, so the icon is redundant 162d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan // and can go away once the user starts typing.) 163d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan mSearchView.setIconifiedByDefault(true); 1644ba903cdf132a6be2e5efa33187b18ca8446e503Makoto Onuki mSearchView.setQueryHint(mContext.getString(R.string.hint_findContacts)); 165c5792ae6760291d435e91e0fdd28ece6b3311439Adam Powell mSearchView.setOnQueryTextListener(this); 16615ccbb4d22fd65165cacb7970cbe61de1aa9aac4Dmitri Plotnikov mSearchView.setOnCloseListener(this); 16715ccbb4d22fd65165cacb7970cbe61de1aa9aac4Dmitri Plotnikov mSearchView.setQuery(mQueryString, false); 1684ba903cdf132a6be2e5efa33187b18ca8446e503Makoto Onuki mActionBar.setCustomView(customSearchView, layoutParams); 1694ba903cdf132a6be2e5efa33187b18ca8446e503Makoto Onuki 1707f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu // Set up tabs or navigation list 1717f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu switch(mActionBarNavigationMode) { 1727f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu case ActionBar.NAVIGATION_MODE_TABS: 1737f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu setupTabs(); 1747f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu break; 1757f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu case ActionBar.NAVIGATION_MODE_LIST: 1767f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu setupNavigationList(); 1777f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu break; 1787f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu } 1797f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu } 1807f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu 1817f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu private void setupTabs() { 1821ff189a390ce5011f729637baf248646560c1bc6Daisuke Miyakawa addTab(TabState.GROUPS, R.drawable.ic_tab_groups, R.string.contactsGroupsLabel); 1831ff189a390ce5011f729637baf248646560c1bc6Daisuke Miyakawa addTab(TabState.ALL, R.drawable.ic_tab_all, R.string.contactsAllLabel); 1841ff189a390ce5011f729637baf248646560c1bc6Daisuke Miyakawa addTab(TabState.FAVORITES, R.drawable.ic_tab_starred, R.string.contactsFavoritesLabel); 1854d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki } 1864d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki 1877f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu private void setupNavigationList() { 1887f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu ArrayAdapter<String> navAdapter = new CustomArrayAdapter(mContext, 1897f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu R.layout.people_navigation_item); 1907f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu navAdapter.add(mContext.getString(R.string.contactsAllLabel)); 1917f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu navAdapter.add(mContext.getString(R.string.contactsFavoritesLabel)); 1927f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu navAdapter.add(mContext.getString(R.string.contactsGroupsLabel)); 1937f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu mActionBar.setListNavigationCallbacks(navAdapter, mNavigationListener); 1947f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu } 1957f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu 1967f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu /** 1977f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu * Because the navigation list items are in a different order than tab items, this returns 1987f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu * the appropriate tab from the navigation item position. 1997f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu */ 2007f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu private int getTabPositionFromNavigationItemPosition(int navItemPos) { 2017f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu switch(navItemPos) { 2027f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu case 0: 2037f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu return TabState.ALL; 2047f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu case 1: 2057f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu return TabState.FAVORITES; 2067f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu case 2: 2077f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu return TabState.GROUPS; 2087f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu } 2097f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu throw new IllegalArgumentException( 2107f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu "Parameter must be between 0 and " + Integer.toString(TabState.COUNT-1) 2117f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu + " inclusive."); 2127f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu } 2137f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu 2147f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu /** 2157f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu * This is the inverse of {@link getTabPositionFromNavigationItemPosition}. 2167f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu */ 2177f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu private int getNavigationItemPositionFromTabPosition(int tabPos) { 2187f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu switch(tabPos) { 2197f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu case TabState.ALL: 2207f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu return 0; 2217f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu case TabState.FAVORITES: 2227f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu return 1; 2237f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu case TabState.GROUPS: 2247f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu return 2; 2257f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu } 2267f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu throw new IllegalArgumentException( 2277f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu "Parameter must be between 0 and " + Integer.toString(TabState.COUNT-1) 2287f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu + " inclusive."); 2297f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu } 2307f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu 2314d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki public void initialize(Bundle savedState, ContactsRequest request) { 2324d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki if (savedState == null) { 2334d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki mSearchMode = request.isSearchMode(); 2344d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki mQueryString = request.getQueryString(); 23535d4aec605ce915ff5c574892a2069a37e0b9a77Makoto Onuki mCurrentTab = loadLastTabPreference(); 2364d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki } else { 2374d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki mSearchMode = savedState.getBoolean(EXTRA_KEY_SEARCH_MODE); 2384d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki mQueryString = savedState.getString(EXTRA_KEY_QUERY); 2394d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki 2404d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki // Just set to the field here. The listener will be notified by update(). 24152aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann mCurrentTab = savedState.getInt(EXTRA_KEY_SELECTED_TAB); 2424d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki } 2433c877e33cb7fecc7a63af1cf3c25061d53811bf6Katherine Kuan // Show tabs or the expanded {@link SearchView}, depending on whether or not we are in 2443c877e33cb7fecc7a63af1cf3c25061d53811bf6Katherine Kuan // search mode. 2454ba903cdf132a6be2e5efa33187b18ca8446e503Makoto Onuki update(); 2463c877e33cb7fecc7a63af1cf3c25061d53811bf6Katherine Kuan // Expanding the {@link SearchView} clears the query, so set the query from the 2473c877e33cb7fecc7a63af1cf3c25061d53811bf6Katherine Kuan // {@link ContactsRequest} after it has been expanded, if applicable. 2483c877e33cb7fecc7a63af1cf3c25061d53811bf6Katherine Kuan if (mSearchMode && !TextUtils.isEmpty(mQueryString)) { 2493c877e33cb7fecc7a63af1cf3c25061d53811bf6Katherine Kuan setQueryString(mQueryString); 2503c877e33cb7fecc7a63af1cf3c25061d53811bf6Katherine Kuan } 2518b8264620f9362e089322d1e3a7cc5620900e6f9Dmitri Plotnikov } 2528b8264620f9362e089322d1e3a7cc5620900e6f9Dmitri Plotnikov 2531a59cffd839069ce91a9febb8a136442340ab4c8Dmitri Plotnikov public void setListener(Listener listener) { 2541a59cffd839069ce91a9febb8a136442340ab4c8Dmitri Plotnikov mListener = listener; 25508e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov } 25608e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov 25752aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann private void addTab(int expectedTabIndex, int icon, int description) { 2584d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki final Tab tab = mActionBar.newTab(); 2594d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki tab.setTabListener(mTabListener); 260aaadf9393e98b04a40d249cd97ec758047268ed9Katherine Kuan if (mShowTabsAsText) { 261aaadf9393e98b04a40d249cd97ec758047268ed9Katherine Kuan tab.setText(description); 262aaadf9393e98b04a40d249cd97ec758047268ed9Katherine Kuan } else { 263aaadf9393e98b04a40d249cd97ec758047268ed9Katherine Kuan tab.setIcon(icon); 264aaadf9393e98b04a40d249cd97ec758047268ed9Katherine Kuan tab.setContentDescription(description); 265aaadf9393e98b04a40d249cd97ec758047268ed9Katherine Kuan } 2664d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki mActionBar.addTab(tab); 26752aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann if (expectedTabIndex != tab.getPosition()) { 26852aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann throw new IllegalStateException("Tabs must be created in the right order"); 26952aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann } 2704d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki } 2714d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki 2724d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki private class MyTabListener implements ActionBar.TabListener { 2734d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki /** 2744d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki * If true, it won't call {@link #setCurrentTab} in {@link #onTabSelected}. 2754d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki * This flag is used when we want to programmatically update the current tab without 2764d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki * {@link #onTabSelected} getting called. 2774d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki */ 2784d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki public boolean mIgnoreTabSelected; 2794d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki 2804d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki @Override public void onTabReselected(Tab tab, FragmentTransaction ft) { } 2814d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki @Override public void onTabUnselected(Tab tab, FragmentTransaction ft) { } 2824d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki 2834d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki @Override public void onTabSelected(Tab tab, FragmentTransaction ft) { 2844d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki if (!mIgnoreTabSelected) { 28552aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann setCurrentTab(tab.getPosition()); 2864d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki } 2874d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki } 2884d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki } 2894d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki 2907f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu private class MyNavigationListener implements ActionBar.OnNavigationListener { 2917f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu public boolean mIgnoreNavigationItemSelected; 2927f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu 2937f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu public boolean onNavigationItemSelected(int itemPosition, long itemId) { 2947f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu if (!mIgnoreNavigationItemSelected) { 2957f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu setCurrentTab(getTabPositionFromNavigationItemPosition(itemPosition)); 2967f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu } 2977f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu return true; 2987f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu } 2997f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu } 3007f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu 3014d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki /** 3024d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki * Change the current tab, and notify the listener. 3034d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki */ 30452aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann public void setCurrentTab(int tab) { 305250ce43794cdf6820f7a13ef0195a566bd0c8c64Makoto Onuki setCurrentTab(tab, true); 306250ce43794cdf6820f7a13ef0195a566bd0c8c64Makoto Onuki } 307250ce43794cdf6820f7a13ef0195a566bd0c8c64Makoto Onuki 308250ce43794cdf6820f7a13ef0195a566bd0c8c64Makoto Onuki /** 309250ce43794cdf6820f7a13ef0195a566bd0c8c64Makoto Onuki * Change the current tab 310250ce43794cdf6820f7a13ef0195a566bd0c8c64Makoto Onuki */ 31152aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann public void setCurrentTab(int tab, boolean notifyListener) { 3124d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki if (tab == mCurrentTab) { 3134d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki return; 3144d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki } 3154d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki mCurrentTab = tab; 3164d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki 3177f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu final int actionBarSelectedNavIndex = mActionBar.getSelectedNavigationIndex(); 3187f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu switch(mActionBar.getNavigationMode()) { 3197f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu case ActionBar.NAVIGATION_MODE_TABS: 3207f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu if (mCurrentTab != actionBarSelectedNavIndex) { 3217f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu mActionBar.setSelectedNavigationItem(mCurrentTab); 3227f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu } 3237f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu break; 3247f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu case ActionBar.NAVIGATION_MODE_LIST: 3257f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu if (mCurrentTab != getTabPositionFromNavigationItemPosition( 3267f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu actionBarSelectedNavIndex)) { 3277f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu mActionBar.setSelectedNavigationItem( 3287f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu getNavigationItemPositionFromTabPosition(mCurrentTab)); 3297f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu } 3307f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu break; 3314d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki } 3324d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki 333250ce43794cdf6820f7a13ef0195a566bd0c8c64Makoto Onuki if (notifyListener && mListener != null) mListener.onSelectedTabChanged(); 33435d4aec605ce915ff5c574892a2069a37e0b9a77Makoto Onuki saveLastTabPreference(mCurrentTab); 3354d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki } 3364d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki 33752aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann public int getCurrentTab() { 3384d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki return mCurrentTab; 3394d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki } 3404d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki 3411db00f68b34f6cf7e9d19fedb559cf12f8c05e9cMakoto Onuki /** 3421db00f68b34f6cf7e9d19fedb559cf12f8c05e9cMakoto Onuki * @return Whether in search mode, i.e. if the search view is visible/expanded. 3431db00f68b34f6cf7e9d19fedb559cf12f8c05e9cMakoto Onuki * 3441db00f68b34f6cf7e9d19fedb559cf12f8c05e9cMakoto Onuki * Note even if the action bar is in search mode, if the query is empty, the search fragment 3451db00f68b34f6cf7e9d19fedb559cf12f8c05e9cMakoto Onuki * will not be in search mode. 3461db00f68b34f6cf7e9d19fedb559cf12f8c05e9cMakoto Onuki */ 34715ccbb4d22fd65165cacb7970cbe61de1aa9aac4Dmitri Plotnikov public boolean isSearchMode() { 34815ccbb4d22fd65165cacb7970cbe61de1aa9aac4Dmitri Plotnikov return mSearchMode; 34908e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov } 35008e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov 35115ccbb4d22fd65165cacb7970cbe61de1aa9aac4Dmitri Plotnikov public void setSearchMode(boolean flag) { 35215ccbb4d22fd65165cacb7970cbe61de1aa9aac4Dmitri Plotnikov if (mSearchMode != flag) { 35315ccbb4d22fd65165cacb7970cbe61de1aa9aac4Dmitri Plotnikov mSearchMode = flag; 354bee8d3bd37edf44c535c0cc401e8d03f095b8328Dmitri Plotnikov update(); 355f3f933a798c9cfffb1c1c0cc770187b5b0b763ebKatherine Kuan if (mSearchView == null) { 356f3f933a798c9cfffb1c1c0cc770187b5b0b763ebKatherine Kuan return; 357f3f933a798c9cfffb1c1c0cc770187b5b0b763ebKatherine Kuan } 3580b51a8d4539cc516dc2c02948335347d1df8769bDmitri Plotnikov if (mSearchMode) { 3594ba903cdf132a6be2e5efa33187b18ca8446e503Makoto Onuki setFocusOnSearchView(); 360ab4d29f6a2edbfae008dbaff35f25baad73aa0dfDmitri Plotnikov } else { 361ab4d29f6a2edbfae008dbaff35f25baad73aa0dfDmitri Plotnikov mSearchView.setQuery(null, false); 3620b51a8d4539cc516dc2c02948335347d1df8769bDmitri Plotnikov } 363311882ab2fc1e9c8264f5892a6d50722b834e348Daniel Lehmann } else if (flag) { 364311882ab2fc1e9c8264f5892a6d50722b834e348Daniel Lehmann // Everything is already set up. Still make sure the keyboard is up 365311882ab2fc1e9c8264f5892a6d50722b834e348Daniel Lehmann if (mSearchView != null) setFocusOnSearchView(); 36608e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov } 36708e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov } 36808e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov 36908e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov public String getQueryString() { 3701db00f68b34f6cf7e9d19fedb559cf12f8c05e9cMakoto Onuki return mSearchMode ? mQueryString : null; 37108e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov } 37208e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov 37308e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov public void setQueryString(String query) { 37408e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov mQueryString = query; 375f3f933a798c9cfffb1c1c0cc770187b5b0b763ebKatherine Kuan if (mSearchView != null) { 376f3f933a798c9cfffb1c1c0cc770187b5b0b763ebKatherine Kuan mSearchView.setQuery(query, false); 377f3f933a798c9cfffb1c1c0cc770187b5b0b763ebKatherine Kuan } 37808e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov } 37908e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov 380e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki /** @return true if the "UP" icon is showing. */ 381e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki public boolean isUpShowing() { 382e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki return mSearchMode; // Only shown on the search mode. 383e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki } 384e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki 385e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki private void updateDisplayOptions() { 386e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki // All the flags we may change in this method. 387e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki final int MASK = ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_SHOW_HOME 388d84ea5c8b0a8376e7cf80b0e15b65a72fd99d7a9Adam Powell | ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_CUSTOM; 389e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki 390e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki // The current flags set to the action bar. (only the ones that we may change here) 391e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki final int current = mActionBar.getDisplayOptions() & MASK; 392e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki 393e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki // Build the new flags... 394e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki int newFlags = 0; 395e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki newFlags |= ActionBar.DISPLAY_SHOW_TITLE; 396e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki if (mShowHomeIcon) { 397e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki newFlags |= ActionBar.DISPLAY_SHOW_HOME; 398e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki } 399e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki if (mSearchMode) { 400e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki newFlags |= ActionBar.DISPLAY_SHOW_HOME; 401e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki newFlags |= ActionBar.DISPLAY_HOME_AS_UP; 402e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki newFlags |= ActionBar.DISPLAY_SHOW_CUSTOM; 403e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki } 404d84ea5c8b0a8376e7cf80b0e15b65a72fd99d7a9Adam Powell mActionBar.setHomeButtonEnabled(mSearchMode); 405e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki 406e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki if (current != newFlags) { 407e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki // Pass the mask here to preserve other flags that we're not interested here. 408e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki mActionBar.setDisplayOptions(newFlags, MASK); 409e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki } 410e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki } 411e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki 4124d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki private void update() { 413b0d82d2703d66b3bd4fe8dc4208cdf6a09f2f4afDaniel Lehmann boolean isIconifiedChanging = mSearchView.isIconified() == mSearchMode; 414b5760b94bbf56ce348876ec36f4669d20a1530f5Katherine Kuan if (mSearchMode) { 4155267367e202dcb39ef0fe912a7be9209548ec436Makoto Onuki setFocusOnSearchView(); 416d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan // Since we have the {@link SearchView} in a custom action bar, we must manually handle 4173c877e33cb7fecc7a63af1cf3c25061d53811bf6Katherine Kuan // expanding the {@link SearchView} when a search is initiated. Note that a side effect 4183c877e33cb7fecc7a63af1cf3c25061d53811bf6Katherine Kuan // of this method is that the {@link SearchView} query text is set to empty string. 419b0d82d2703d66b3bd4fe8dc4208cdf6a09f2f4afDaniel Lehmann if (isIconifiedChanging) { 420b0d82d2703d66b3bd4fe8dc4208cdf6a09f2f4afDaniel Lehmann mSearchView.onActionViewExpanded(); 421b0d82d2703d66b3bd4fe8dc4208cdf6a09f2f4afDaniel Lehmann } 4224d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki if (mActionBar.getNavigationMode() != ActionBar.NAVIGATION_MODE_STANDARD) { 4234d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); 4244d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki } 425b5760b94bbf56ce348876ec36f4669d20a1530f5Katherine Kuan if (mListener != null) { 426b5760b94bbf56ce348876ec36f4669d20a1530f5Katherine Kuan mListener.onAction(Action.START_SEARCH_MODE); 427c9916d303cc48b4a4ff94ef9c56d7ca5da72c4deDmitri Plotnikov } 42815ccbb4d22fd65165cacb7970cbe61de1aa9aac4Dmitri Plotnikov } else { 4297f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu final int currentNavigationMode = mActionBar.getNavigationMode(); 4307f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu if (mActionBarNavigationMode == ActionBar.NAVIGATION_MODE_TABS 4317f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu && currentNavigationMode != ActionBar.NAVIGATION_MODE_TABS) { 4324d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki // setNavigationMode will trigger onTabSelected() with the tab which was previously 4334d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki // selected. 4344d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki // The issue is that when we're first switching to the tab navigation mode after 4354d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki // screen orientation changes, onTabSelected() will get called with the first tab 4364d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki // (i.e. favorite), which would results in mCurrentTab getting set to FAVORITES and 4374d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki // we'd lose restored tab. 4384d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki // So let's just disable the callback here temporarily. We'll notify the listener 4394d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki // after this anyway. 4404d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki mTabListener.mIgnoreTabSelected = true; 4414d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); 44252aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann mActionBar.setSelectedNavigationItem(mCurrentTab); 4434d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki mTabListener.mIgnoreTabSelected = false; 4447f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu } else if (mActionBarNavigationMode == ActionBar.NAVIGATION_MODE_LIST 4457f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu && currentNavigationMode != ActionBar.NAVIGATION_MODE_LIST) { 4467f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu mNavigationListener.mIgnoreNavigationItemSelected = true; 4477f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); 4487f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu mActionBar.setSelectedNavigationItem( 4497f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu getNavigationItemPositionFromTabPosition(mCurrentTab)); 4507f5220e23b37b76cf484b28c182a0c98749b59e2Maurice Chu mNavigationListener.mIgnoreNavigationItemSelected = false; 4514d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki } 452b5760b94bbf56ce348876ec36f4669d20a1530f5Katherine Kuan mActionBar.setTitle(null); 453d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan // Since we have the {@link SearchView} in a custom action bar, we must manually handle 454d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan // collapsing the {@link SearchView} when search mode is exited. 455b0d82d2703d66b3bd4fe8dc4208cdf6a09f2f4afDaniel Lehmann if (isIconifiedChanging) { 456b0d82d2703d66b3bd4fe8dc4208cdf6a09f2f4afDaniel Lehmann mSearchView.onActionViewCollapsed(); 457b0d82d2703d66b3bd4fe8dc4208cdf6a09f2f4afDaniel Lehmann } 458b5760b94bbf56ce348876ec36f4669d20a1530f5Katherine Kuan if (mListener != null) { 459b5760b94bbf56ce348876ec36f4669d20a1530f5Katherine Kuan mListener.onAction(Action.STOP_SEARCH_MODE); 4604d788fc27ac855bd6e0cec17dff39a18564f0089Makoto Onuki mListener.onSelectedTabChanged(); 461bee8d3bd37edf44c535c0cc401e8d03f095b8328Dmitri Plotnikov } 46208e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov } 463e0c66aff27473d0edbd95660b95f0f2a80ab63ecMakoto Onuki updateDisplayOptions(); 46408e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov } 46508e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov 46608e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov @Override 467c5792ae6760291d435e91e0fdd28ece6b3311439Adam Powell public boolean onQueryTextChange(String queryString) { 468b5760b94bbf56ce348876ec36f4669d20a1530f5Katherine Kuan // TODO: Clean up SearchView code because it keeps setting the SearchView query, 469b5760b94bbf56ce348876ec36f4669d20a1530f5Katherine Kuan // invoking onQueryChanged, setting up the fragment again, invalidating the options menu, 470b5760b94bbf56ce348876ec36f4669d20a1530f5Katherine Kuan // storing the SearchView again, and etc... unless we add in the early return statements. 471b5760b94bbf56ce348876ec36f4669d20a1530f5Katherine Kuan if (queryString.equals(mQueryString)) { 472b5760b94bbf56ce348876ec36f4669d20a1530f5Katherine Kuan return false; 473b5760b94bbf56ce348876ec36f4669d20a1530f5Katherine Kuan } 47408e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov mQueryString = queryString; 475ab4d29f6a2edbfae008dbaff35f25baad73aa0dfDmitri Plotnikov if (!mSearchMode) { 476ab4d29f6a2edbfae008dbaff35f25baad73aa0dfDmitri Plotnikov if (!TextUtils.isEmpty(queryString)) { 477ab4d29f6a2edbfae008dbaff35f25baad73aa0dfDmitri Plotnikov setSearchMode(true); 4789806ed099226a19e92c29d9efa791cd187fd2a53Dmitri Plotnikov } 479ab4d29f6a2edbfae008dbaff35f25baad73aa0dfDmitri Plotnikov } else if (mListener != null) { 480b5760b94bbf56ce348876ec36f4669d20a1530f5Katherine Kuan mListener.onAction(Action.CHANGE_SEARCH_QUERY); 4819806ed099226a19e92c29d9efa791cd187fd2a53Dmitri Plotnikov } 482ab4d29f6a2edbfae008dbaff35f25baad73aa0dfDmitri Plotnikov 4831a59cffd839069ce91a9febb8a136442340ab4c8Dmitri Plotnikov return true; 4841a59cffd839069ce91a9febb8a136442340ab4c8Dmitri Plotnikov } 4851a59cffd839069ce91a9febb8a136442340ab4c8Dmitri Plotnikov 4861a59cffd839069ce91a9febb8a136442340ab4c8Dmitri Plotnikov @Override 487c5792ae6760291d435e91e0fdd28ece6b3311439Adam Powell public boolean onQueryTextSubmit(String query) { 488d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan // When the search is "committed" by the user, then hide the keyboard so the user can 489d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan // more easily browse the list of results. 490d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan if (mSearchView != null) { 491d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan InputMethodManager imm = (InputMethodManager) mContext.getSystemService( 492d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan Context.INPUT_METHOD_SERVICE); 493d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan if (imm != null) { 494d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan imm.hideSoftInputFromWindow(mSearchView.getWindowToken(), 0); 495d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan } 496d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan mSearchView.clearFocus(); 497d8a61b7296bf7388505f0211d7ef44700e766193Katherine Kuan } 4981a59cffd839069ce91a9febb8a136442340ab4c8Dmitri Plotnikov return true; 49908e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov } 50008e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov 50108e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov @Override 5021a59cffd839069ce91a9febb8a136442340ab4c8Dmitri Plotnikov public boolean onClose() { 50315ccbb4d22fd65165cacb7970cbe61de1aa9aac4Dmitri Plotnikov setSearchMode(false); 50415ccbb4d22fd65165cacb7970cbe61de1aa9aac4Dmitri Plotnikov return false; 50508e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov } 50608e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov 50715ccbb4d22fd65165cacb7970cbe61de1aa9aac4Dmitri Plotnikov public void onSaveInstanceState(Bundle outState) { 50815ccbb4d22fd65165cacb7970cbe61de1aa9aac4Dmitri Plotnikov outState.putBoolean(EXTRA_KEY_SEARCH_MODE, mSearchMode); 50915ccbb4d22fd65165cacb7970cbe61de1aa9aac4Dmitri Plotnikov outState.putString(EXTRA_KEY_QUERY, mQueryString); 51052aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann outState.putInt(EXTRA_KEY_SELECTED_TAB, mCurrentTab); 511fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov } 512fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov 5135c3a0a1440625fab859aab420cb08bc0276358a0Katherine Kuan /** 5145c3a0a1440625fab859aab420cb08bc0276358a0Katherine Kuan * Clears the focus from the {@link SearchView} if we are in search mode. 5155c3a0a1440625fab859aab420cb08bc0276358a0Katherine Kuan * This will suppress the IME if it is visible. 5165c3a0a1440625fab859aab420cb08bc0276358a0Katherine Kuan */ 5175c3a0a1440625fab859aab420cb08bc0276358a0Katherine Kuan public void clearFocusOnSearchView() { 5185c3a0a1440625fab859aab420cb08bc0276358a0Katherine Kuan if (isSearchMode()) { 5195c3a0a1440625fab859aab420cb08bc0276358a0Katherine Kuan if (mSearchView != null) { 5205c3a0a1440625fab859aab420cb08bc0276358a0Katherine Kuan mSearchView.clearFocus(); 5215c3a0a1440625fab859aab420cb08bc0276358a0Katherine Kuan } 5225c3a0a1440625fab859aab420cb08bc0276358a0Katherine Kuan } 5235c3a0a1440625fab859aab420cb08bc0276358a0Katherine Kuan } 5245c3a0a1440625fab859aab420cb08bc0276358a0Katherine Kuan 52509d66a382d1f94618b52fec11ba54d9243a95a18Daniel Lehmann public void setFocusOnSearchView() { 5264ba903cdf132a6be2e5efa33187b18ca8446e503Makoto Onuki mSearchView.requestFocus(); 5274ba903cdf132a6be2e5efa33187b18ca8446e503Makoto Onuki mSearchView.setIconified(false); // Workaround for the "IME not popping up" issue. 5284ba903cdf132a6be2e5efa33187b18ca8446e503Makoto Onuki } 52935d4aec605ce915ff5c574892a2069a37e0b9a77Makoto Onuki 53052aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann private void saveLastTabPreference(int tab) { 53152aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann mPrefs.edit().putInt(PERSISTENT_LAST_TAB, tab).apply(); 53235d4aec605ce915ff5c574892a2069a37e0b9a77Makoto Onuki } 53335d4aec605ce915ff5c574892a2069a37e0b9a77Makoto Onuki 53452aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann private int loadLastTabPreference() { 53535d4aec605ce915ff5c574892a2069a37e0b9a77Makoto Onuki try { 53652aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann return mPrefs.getInt(PERSISTENT_LAST_TAB, TabState.DEFAULT); 53735d4aec605ce915ff5c574892a2069a37e0b9a77Makoto Onuki } catch (IllegalArgumentException e) { 53835d4aec605ce915ff5c574892a2069a37e0b9a77Makoto Onuki // Preference is corrupt? 53952aa32db432085ab2cd4864bd1edd1ef843da867Daniel Lehmann return TabState.DEFAULT; 54035d4aec605ce915ff5c574892a2069a37e0b9a77Makoto Onuki } 54135d4aec605ce915ff5c574892a2069a37e0b9a77Makoto Onuki } 54208e1c4e49947daee26cfc435d01605febb7ae6faDmitri Plotnikov} 543