blob: 623a2c7998ece07ad2361a3a8b775ff52d8d6b28 [file] [log] [blame]
Mindy Pereira68f2e222012-03-07 10:36:54 -08001/*
2 * Copyright (C) 2012 Google Inc.
3 * Licensed to The Android Open Source Project.
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -08004 *
Mindy Pereira68f2e222012-03-07 10:36:54 -08005 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -08008 *
Mindy Pereira68f2e222012-03-07 10:36:54 -08009 * http://www.apache.org/licenses/LICENSE-2.0
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -080010 *
Mindy Pereira68f2e222012-03-07 10:36:54 -080011 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -080017
Vikram Aggarwal1ddcf0f2012-01-13 11:45:02 -080018package com.android.mail.ui;
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -080019
20import android.app.ActionBar;
Mindy Pereira68f2e222012-03-07 10:36:54 -080021import android.app.SearchManager;
22import android.app.SearchableInfo;
Vikram Aggarwal2175d0a2012-02-17 16:04:23 -080023import android.app.ActionBar.OnNavigationListener;
Mindy Pereira68f2e222012-03-07 10:36:54 -080024import android.content.Context;
Vikram Aggarwal12a7c042012-03-28 16:48:08 -070025import android.database.Cursor;
Vikram Aggarwal1e57e672012-05-07 14:48:24 -070026import android.net.Uri;
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -080027import android.os.Bundle;
Mindy Pereira9b623802012-03-07 17:15:49 -080028import android.os.Handler;
Mindy Pereira68f2e222012-03-07 10:36:54 -080029import android.util.AttributeSet;
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -080030import android.view.Menu;
Mindy Pereira68f2e222012-03-07 10:36:54 -080031import android.view.MenuItem;
32import android.view.View;
33import android.widget.LinearLayout;
34import android.widget.SearchView;
35import android.widget.SearchView.OnQueryTextListener;
Vikram Aggarwal12a7c042012-03-28 16:48:08 -070036import android.widget.SearchView.OnSuggestionListener;
Mindy Pereira68f2e222012-03-07 10:36:54 -080037import android.widget.TextView;
38import android.widget.Toast;
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -080039
Mindy Pereira68f2e222012-03-07 10:36:54 -080040import com.android.mail.R;
41import com.android.mail.AccountSpinnerAdapter;
42import com.android.mail.ConversationListContext;
Vikram Aggarwala9b93f32012-02-23 14:51:58 -080043import com.android.mail.providers.Account;
Vikram Aggarwal1e57e672012-05-07 14:48:24 -070044import com.android.mail.providers.Settings;
Mindy Pereira68f2e222012-03-07 10:36:54 -080045import com.android.mail.providers.UIProvider.AccountCapabilities;
Marc Blankedcab012012-04-04 12:42:38 -070046import com.android.mail.providers.UIProvider.FolderCapabilities;
Mindy Pereira9b623802012-03-07 17:15:49 -080047import com.android.mail.providers.UIProvider.LastSyncResult;
Mindy Pereiraf9323cd2012-02-29 13:47:09 -080048import com.android.mail.providers.Folder;
Andy Huang0d647352012-03-21 21:48:16 -070049import com.android.mail.utils.LogUtils;
Mindy Pereira9b623802012-03-07 17:15:49 -080050import com.android.mail.utils.Utils;
Vikram Aggarwala9b93f32012-02-23 14:51:58 -080051
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -080052/**
Mindy Pereira68f2e222012-03-07 10:36:54 -080053 * View to manage the various states of the Mail Action Bar
54 *
55 * TODO(viki): Include ConversationSubjectDisplayer here as well.
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -080056 */
Mindy Pereira68f2e222012-03-07 10:36:54 -080057public final class ActionBarView extends LinearLayout implements OnNavigationListener,
Vikram Aggarwal0dda5732012-04-06 11:20:16 -070058 ViewMode.ModeChangeListener, OnQueryTextListener, OnSuggestionListener,
59 MenuItem.OnActionExpandListener {
Mindy Pereira68f2e222012-03-07 10:36:54 -080060 private ActionBar mActionBar;
61 private RestrictedActivity mActivity;
Vikram Aggarwala7997952012-03-09 10:30:13 -080062 private ActivityController mController;
Mindy Pereira68f2e222012-03-07 10:36:54 -080063 private View mFolderView;
64 /**
65 * The current mode of the ActionBar. This references constants in {@link ViewMode}
66 */
67 private int mMode = ViewMode.UNKNOWN;
68
69 private MenuItem mSearch;
Vikram Aggarwal37263972012-04-17 15:51:14 -070070 private AccountSpinnerAdapter mSpinner;
Mindy Pereira68f2e222012-03-07 10:36:54 -080071 /**
72 * The account currently being shown
73 */
74 private Account mAccount;
Marc Blankedcab012012-04-04 12:42:38 -070075 /**
76 * The folder currently being shown
77 */
78 private Folder mFolder;
Mindy Pereira68f2e222012-03-07 10:36:54 -080079
Mindy Pereira68f2e222012-03-07 10:36:54 -080080 private TextView mSubjectView;
81 private SearchView mSearchWidget;
82 private MenuItem mHelpItem;
Paul Westbrook517743e2012-03-22 10:40:46 -070083 private MenuItem mSendFeedbackItem;
Mindy Pereira9b623802012-03-07 17:15:49 -080084 private MenuItem mRefreshItem;
Marc Blankedcab012012-04-04 12:42:38 -070085 private MenuItem mFolderSettingsItem;
Mindy Pereira9b623802012-03-07 17:15:49 -080086 private View mRefreshActionView;
87 private boolean mRefreshInProgress;
88
Andy Huang0d647352012-03-21 21:48:16 -070089 public static final String LOG_TAG = new LogUtils().getLogTag();
90
Mindy Pereira9b623802012-03-07 17:15:49 -080091 private final Handler mHandler = new Handler();
92 private final Runnable mInvalidateMenu = new Runnable() {
93 @Override
94 public void run() {
95 mActivity.invalidateOptionsMenu();
96 }
97 };
Vikram Aggarwalabd24d82012-04-26 13:23:14 -070098 /**
99 * Whether the first navigation event should be ignored. The {@link #ignoreFirstNavigation(int)}
100 * method talks about why this is required.
101 */
102 private boolean mIgnoreFirstNavigation = true;
Mindy Pereira205ae502012-05-17 08:43:59 -0700103 private Boolean mShowConversationSubject;
Mindy Pereira68f2e222012-03-07 10:36:54 -0800104
105 public ActionBarView(Context context) {
106 this(context, null);
107 }
108
109 public ActionBarView(Context context, AttributeSet attrs) {
110 this(context, attrs, 0);
111 }
112
113 public ActionBarView(Context context, AttributeSet attrs, int defStyle) {
114 super(context, attrs, defStyle);
115 }
116
Vikram Aggarwalb17cbc02012-04-06 15:41:46 -0700117 /**
Vikram Aggarwal0dda5732012-04-06 11:20:16 -0700118 * Close the search view if it is expanded.
Vikram Aggarwalb17cbc02012-04-06 15:41:46 -0700119 */
120 public void collapseSearch() {
121 if (mSearch != null) {
122 mSearch.collapseActionView();
123 }
124 }
125
Mindy Pereira68f2e222012-03-07 10:36:54 -0800126 public boolean onCreateOptionsMenu(Menu menu) {
127 // If the mode is valid, then set the initial menu
128 if (mMode == ViewMode.UNKNOWN) {
129 return false;
130 }
Mindy Pereira9b623802012-03-07 17:15:49 -0800131 mSearch = menu.findItem(R.id.search);
132 if (mSearch != null) {
133 mSearchWidget = (SearchView) mSearch.getActionView();
Vikram Aggarwal0dda5732012-04-06 11:20:16 -0700134 mSearch.setOnActionExpandListener(this);
Mindy Pereira68f2e222012-03-07 10:36:54 -0800135 SearchManager searchManager = (SearchManager) mActivity.getActivityContext()
136 .getSystemService(Context.SEARCH_SERVICE);
Mindy Pereirafb178492012-03-07 18:56:42 -0800137 if (searchManager != null && mSearchWidget != null) {
Mindy Pereira68f2e222012-03-07 10:36:54 -0800138 SearchableInfo info = searchManager.getSearchableInfo(mActivity.getComponentName());
139 mSearchWidget.setSearchableInfo(info);
140 mSearchWidget.setOnQueryTextListener(this);
Vikram Aggarwal12a7c042012-03-28 16:48:08 -0700141 mSearchWidget.setOnSuggestionListener(this);
Vikram Aggarwal0dda5732012-04-06 11:20:16 -0700142 mSearchWidget.setIconifiedByDefault(true);
Mindy Pereira68f2e222012-03-07 10:36:54 -0800143 }
144 }
145 mHelpItem = menu.findItem(R.id.help_info_menu_item);
Paul Westbrook517743e2012-03-22 10:40:46 -0700146 mSendFeedbackItem = menu.findItem(R.id.feedback_menu_item);
Mindy Pereira9b623802012-03-07 17:15:49 -0800147 mRefreshItem = menu.findItem(R.id.refresh);
Marc Blankedcab012012-04-04 12:42:38 -0700148 mFolderSettingsItem = menu.findItem(R.id.folder_options);
Mindy Pereira68f2e222012-03-07 10:36:54 -0800149 return true;
150 }
151
152 public int getOptionsMenuId() {
153 // Relies on the ordering of the view modes, since they are integer constants.
154 final int[] modeMenu = {
155 // 0: UNKNOWN
156 R.menu.conversation_list_menu,
157 // 1: CONVERSATION
158 R.menu.conversation_actions,
159 // 2: CONVERSATION_LIST
160 R.menu.conversation_list_menu,
161 // 3: FOLDER_LIST
162 R.menu.folder_list_menu,
163 // 4: SEARCH_RESULTS_LIST
164 R.menu.conversation_list_search_results_actions,
165 // 5: SEARCH_RESULTS_CONVERSATION
Paul Westbrook2d50bcd2012-04-10 11:53:47 -0700166 R.menu.conversation_search_results_actions,
167 // 6: WAITING_FOR_ACCOUNT_INITIALIZATION
168 R.menu.wait_mode_actions
Mindy Pereira68f2e222012-03-07 10:36:54 -0800169 };
170 return modeMenu[mMode];
171 }
172
173 public void handleRestore(Bundle savedInstanceState) {
174 }
175
176 public void handleSaveInstanceState(Bundle outState) {
177 }
178
179 public void initialize(RestrictedActivity activity, ActivityController callback,
Vikram Aggarwalec5cbf72012-03-08 15:10:35 -0800180 ViewMode viewMode, ActionBar actionBar, RecentFolderList recentFolders) {
Mindy Pereira68f2e222012-03-07 10:36:54 -0800181 mActionBar = actionBar;
Vikram Aggarwala7997952012-03-09 10:30:13 -0800182 mController = callback;
Mindy Pereira68f2e222012-03-07 10:36:54 -0800183 mActivity = activity;
Paul Westbrook904b5f22012-04-12 00:29:58 -0700184 // We don't want to include the "Show all folders" menu item on tablet devices
185 final boolean showAllFolders = !Utils.useTabletUI(getContext());
186 mSpinner = new AccountSpinnerAdapter(getContext(), recentFolders, showAllFolders);
Vikram Aggarwalabd24d82012-04-26 13:23:14 -0700187 }
Andy Huange303b9b2012-04-19 16:31:09 -0700188
Vikram Aggarwalabd24d82012-04-26 13:23:14 -0700189 /**
190 * Attach the action bar to the view.
191 */
192 public void attach() {
Mindy Pereira68f2e222012-03-07 10:36:54 -0800193 mActionBar.setListNavigationCallbacks(mSpinner, this);
194 }
195
196 public void setAccounts(Account[] accounts) {
Vikram Aggarwal630489a2012-04-11 17:08:09 -0700197 final Account currentAccount = mController.getCurrentAccount();
Vikram Aggarwalabd24d82012-04-26 13:23:14 -0700198 mSpinner.setAccountArray(accounts);
Andy Huang0d647352012-03-21 21:48:16 -0700199
200 int position;
201 for (position = 0; position < accounts.length; position++) {
Vikram Aggarwal630489a2012-04-11 17:08:09 -0700202 if (accounts[position].uri.equals(currentAccount.uri)) {
Andy Huang0d647352012-03-21 21:48:16 -0700203 break;
Mindy Pereira68f2e222012-03-07 10:36:54 -0800204 }
205 }
Andy Huang0d647352012-03-21 21:48:16 -0700206 if (position >= accounts.length) {
207 position = 0;
208 LogUtils.w(LOG_TAG, "IN actionbarview setAccounts, account not found, using first.");
209 }
Vikram Aggarwal1e57e672012-05-07 14:48:24 -0700210 final Uri defaultInbox = Settings.getDefaultInboxUri(mAccount.settings);
Vikram Aggarwalc323f5d2012-04-26 16:26:07 -0700211 final boolean viewingDefaultInbox =
212 (mFolder == null || mAccount == null || mAccount.settings == null) ? false :
Vikram Aggarwal1e57e672012-05-07 14:48:24 -0700213 mFolder.uri.equals(defaultInbox);
Vikram Aggarwal95b28ab2012-04-26 15:53:09 -0700214 final boolean accountInSpinner = (position >= 0);
215 if (accountInSpinner && viewingDefaultInbox) {
216 // This position corresponds to current account and default Inbox. Select it.
217 setSelectedPosition(position);
218 } else {
219 // Set the selected position to a dead spacer. The user is either viewing a different
220 // folder, or the account is missing from the spinner.
221 setSelectedPosition(mSpinner.getSpacerPosition());
222 }
Vikram Aggarwal3a104732012-03-27 11:35:17 -0700223 }
224
225 /**
226 * Sets the selected navigation position in the spinner to the position given here.
227 * @param position
228 */
229 private void setSelectedPosition(int position) {
230 // Only change the position if we are in the correct mode.
Vikram Aggarwaleb7d3292012-04-20 17:07:20 -0700231 if (mActionBar.getNavigationMode() != ActionBar.NAVIGATION_MODE_LIST) {
Vikram Aggarwal3a104732012-03-27 11:35:17 -0700232 return;
Vikram Aggarwaleb7d3292012-04-20 17:07:20 -0700233 }
234 LogUtils.d(LOG_TAG, "ActionBarView.setSelectedNavigationItem(%d)", position);
Andy Huang0d647352012-03-21 21:48:16 -0700235 mActionBar.setSelectedNavigationItem(position);
Mindy Pereira68f2e222012-03-07 10:36:54 -0800236 }
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800237
238 /**
Mindy Pereira68f2e222012-03-07 10:36:54 -0800239 * Called by the owner of the ActionBar to set the
240 * folder that is currently being displayed.
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800241 */
Mindy Pereira68f2e222012-03-07 10:36:54 -0800242 public void setFolder(Folder folder) {
Vikram Aggarwale6340bc2012-03-26 15:57:09 -0700243 // Change the currently selected item to an element which is a spacer: valid but not useful
244 // This allows us to receive a tap on the account name when the user taps on it, and we can
245 // take the user to the default inbox.
Vikram Aggarwal3a104732012-03-27 11:35:17 -0700246 setSelectedPosition(mSpinner.getSpacerPosition());
Mindy Pereira68f2e222012-03-07 10:36:54 -0800247 mSpinner.setCurrentFolder(folder);
248 mSpinner.notifyDataSetChanged();
Marc Blankedcab012012-04-04 12:42:38 -0700249 mFolder = folder;
Mindy Pereira68f2e222012-03-07 10:36:54 -0800250 }
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800251
252 /**
Mindy Pereira68f2e222012-03-07 10:36:54 -0800253 * Called by the owner of the ActionBar to set the
254 * account that is currently being displayed.
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800255 */
Mindy Pereira68f2e222012-03-07 10:36:54 -0800256 public void setAccount(Account account) {
Mindy Pereira9b623802012-03-07 17:15:49 -0800257 mAccount = account;
Mindy Pereira68f2e222012-03-07 10:36:54 -0800258 mSpinner.setCurrentAccount(account);
259 mSpinner.notifyDataSetChanged();
260 }
261
Vikram Aggarwalabd24d82012-04-26 13:23:14 -0700262 /**
263 * Returns true if this list navigation event is erroneous and should be ignored.
264 *
265 * Rationale: When a spinner is brought up for the first time, and it has never been brought up
266 * before, it shows the 0th element. This is fine in most cases, since the navigation mode has
267 * to select something. However, if we already have an account: for example if we went from the
268 * widget to Conversation view, and the spinner never got a chance to initialize, it needs to
269 * ignore this first navigation. If the spinner has ever been shown, then we will allow
270 * subsequent calls to onNavigationItemSelected.
271 * @param position the position selected in the drop down.
272 */
273 private boolean ignoreFirstNavigation(int position) {
274 if (mIgnoreFirstNavigation && position == 0 && mAccount != null) {
275 // Ignore the first navigation item selected because it is the list initializing
276 // We already have an account.
277 LogUtils.d(LOG_TAG, "ignoreFirstNavigation: Ignoring navigation to position 0."
278 + " mAccount = %s", mAccount.uri);
279 // All user taps are now valid: even a tap on the current account to take the user to
280 // the default inbox.
281 mIgnoreFirstNavigation = false;
282 setSelectedPosition(mSpinner.getSpacerPosition());
283 // Yes, we want to ignore this navigation. It is not a user-initiated navigation.
284 return true;
285 }
286 // Spinner was correctly initialized and is receiving a valid first tap. All subsequent
287 // taps are user events.
288 mIgnoreFirstNavigation = false;
289 // No, we don't want to ignore this navigation.
290 return false;
291 }
292
Mindy Pereira68f2e222012-03-07 10:36:54 -0800293 @Override
294 public boolean onNavigationItemSelected(int position, long id) {
Vikram Aggarwalabd24d82012-04-26 13:23:14 -0700295 if (ignoreFirstNavigation(position)) {
296 return false;
297 }
Vikram Aggarwaleb7d3292012-04-20 17:07:20 -0700298 LogUtils.d(LOG_TAG, "onNavigationItemSelected(%d, %d) called", position, id);
Marc Blank41e764d2012-03-20 20:46:28 -0700299 final int type = mSpinner.getType(position);
Mindy Pereira68f2e222012-03-07 10:36:54 -0800300 switch (type) {
301 case AccountSpinnerAdapter.TYPE_ACCOUNT:
302 // Get the capabilities associated with this account.
Vikram Aggarwaleb7d3292012-04-20 17:07:20 -0700303 final Account account = (Account) mSpinner.getItem(position);
304 LogUtils.d(LOG_TAG, "onNavigationItemSelected: Selecting account: %s",
305 account.name);
306 if (mAccount.uri.equals(account.uri)) {
307 // The selected account is the same, let's load the default inbox.
308 mController.loadAccountInbox();
309 } else {
310 // Switching accounts.
311 mController.onAccountChanged(account);
312 }
Mindy Pereira68f2e222012-03-07 10:36:54 -0800313 break;
314 case AccountSpinnerAdapter.TYPE_FOLDER:
315 final Object folder = mSpinner.getItem(position);
316 assert (folder instanceof Folder);
Vikram Aggarwaleb7d3292012-04-20 17:07:20 -0700317 LogUtils.d(LOG_TAG, "onNavigationItemSelected: Selecting folder: %s",
318 ((Folder)folder).name);
Vikram Aggarwala7997952012-03-09 10:30:13 -0800319 mController.onFolderChanged((Folder) folder);
Mindy Pereira68f2e222012-03-07 10:36:54 -0800320 break;
Paul Westbrook904b5f22012-04-12 00:29:58 -0700321 case AccountSpinnerAdapter.TYPE_ALL_FOLDERS:
322 // Change the currently selected item to an element which is a spacer: valid
323 // but not useful. This allows us to receive subsequent taps on the
324 // "show all folders" menu item.
325 setSelectedPosition(mSpinner.getSpacerPosition());
326 mController.showFolderList();
327 break;
Mindy Pereira68f2e222012-03-07 10:36:54 -0800328 }
329 return false;
330 }
331
332 public void onPause() {
333 }
334
335 public void onResume() {
336 }
337
Vikram Aggarwala7997952012-03-09 10:30:13 -0800338 @Override
Mindy Pereira68f2e222012-03-07 10:36:54 -0800339 public void onViewModeChanged(int newMode) {
340 mMode = newMode;
341 // Always update the options menu and redraw. This will read the new mode and redraw
342 // the options menu.
343 mActivity.invalidateOptionsMenu();
344 }
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800345
Mindy Pereirab849dfb2012-03-07 18:13:15 -0800346 public boolean onPrepareOptionsMenu(Menu menu) {
Mindy Pereira68f2e222012-03-07 10:36:54 -0800347 // We start out with every option enabled. Based on the current view, we disable actions
348 // that are possible.
Vikram Aggarwal95b28ab2012-04-26 15:53:09 -0700349 LogUtils.d(LOG_TAG, "ActionBarView.onPrepareOptionsMenu().");
Mindy Pereira68f2e222012-03-07 10:36:54 -0800350 if (mSubjectView != null){
351 mSubjectView.setVisibility(GONE);
352 }
353 if (mFolderView != null){
354 mFolderView.setVisibility(GONE);
355 }
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800356
Mindy Pereira9b623802012-03-07 17:15:49 -0800357 if (mRefreshInProgress) {
358 if (mRefreshItem != null) {
359 if (mRefreshActionView == null) {
360 mRefreshItem.setActionView(R.layout.action_bar_indeterminate_progress);
361 mRefreshActionView = mRefreshItem.getActionView();
362 } else {
363 mRefreshItem.setActionView(mRefreshActionView);
364 }
365 }
366 } else {
367 if (mRefreshItem != null) {
368 mRefreshItem.setActionView(null);
369 }
370 }
Mindy Pereira68f2e222012-03-07 10:36:54 -0800371 if (mHelpItem != null) {
372 mHelpItem.setVisible(mAccount != null
373 && mAccount.supportsCapability(AccountCapabilities.HELP_CONTENT));
374 }
Paul Westbrook517743e2012-03-22 10:40:46 -0700375 if (mSendFeedbackItem != null) {
376 mSendFeedbackItem.setVisible(mAccount != null
377 && mAccount.supportsCapability(AccountCapabilities.SEND_FEEDBACK));
378 }
Marc Blankedcab012012-04-04 12:42:38 -0700379 if (mFolderSettingsItem != null) {
380 mFolderSettingsItem.setVisible(mFolder != null
381 && mFolder.supportsCapability(FolderCapabilities.SUPPORTS_SETTINGS));
382 }
Mindy Pereira9b623802012-03-07 17:15:49 -0800383 switch (mMode) {
Mindy Pereira68f2e222012-03-07 10:36:54 -0800384 case ViewMode.UNKNOWN:
Mindy Pereira9b623802012-03-07 17:15:49 -0800385 if (mSearch != null) {
Mindy Pereira68f2e222012-03-07 10:36:54 -0800386 mSearch.collapseActionView();
387 }
388 break;
389 case ViewMode.CONVERSATION_LIST:
Mindy Pereira30fd47b2012-03-09 09:24:00 -0800390 // Show compose, search, folders, and sync based on the account
Mindy Pereira68f2e222012-03-07 10:36:54 -0800391 // The only option that needs to be disabled is search
Mindy Pereira72a9f392012-03-21 09:41:09 -0700392 showNavList();
Mindy Pereira863e4412012-03-23 12:21:38 -0700393 Utils.setMenuItemVisibility(menu, R.id.search,
Mindy Pereira9b623802012-03-07 17:15:49 -0800394 mAccount.supportsCapability(AccountCapabilities.FOLDER_SERVER_SEARCH));
Mindy Pereira68f2e222012-03-07 10:36:54 -0800395 break;
396 case ViewMode.CONVERSATION:
Mindy Pereira72a9f392012-03-21 09:41:09 -0700397 mActionBar.setDisplayHomeAsUpEnabled(true);
Andy Huange303b9b2012-04-19 16:31:09 -0700398 // FIXME: use a resource to have fine-grained control over whether the spinner
399 // or the subject appears
Mindy Pereira205ae502012-05-17 08:43:59 -0700400 if (Utils.useTabletUI(mActivity.getActivityContext())
401 && !showConversationSubject()) {
Andy Huange303b9b2012-04-19 16:31:09 -0700402 showNavList();
403 } else {
Vikram Aggarwalabd24d82012-04-26 13:23:14 -0700404 setStandardMode();
Andy Huange303b9b2012-04-19 16:31:09 -0700405 }
Mindy Pereira68f2e222012-03-07 10:36:54 -0800406 break;
407 case ViewMode.SEARCH_RESULTS_LIST:
Vikram Aggarwalabd24d82012-04-26 13:23:14 -0700408 setStandardMode();
Mindy Pereirab849dfb2012-03-07 18:13:15 -0800409 setPopulatedSearchView();
Vikram Aggarwal8c355002012-04-09 09:07:40 -0700410 // Remove focus from the search action menu in search results mode so the IME and
411 // the suggestions don't get in the way.
412 if (mMode == ViewMode.SEARCH_RESULTS_LIST && mSearch != null) {
413 mSearchWidget = (SearchView) mSearch.getActionView();
414 mSearchWidget.clearFocus();
415 }
Mindy Pereira68f2e222012-03-07 10:36:54 -0800416 break;
417 case ViewMode.SEARCH_RESULTS_CONVERSATION:
418 mActionBar.setDisplayHomeAsUpEnabled(true);
Vikram Aggarwalabd24d82012-04-26 13:23:14 -0700419 setStandardMode();
Mindy Pereirab849dfb2012-03-07 18:13:15 -0800420 if (Utils.useTabletUI(mActivity.getActivityContext())) {
421 setPopulatedSearchView();
422 }
Mindy Pereira68f2e222012-03-07 10:36:54 -0800423 break;
424 case ViewMode.FOLDER_LIST:
Mindy Pereira72a9f392012-03-21 09:41:09 -0700425 mActionBar.setDisplayHomeAsUpEnabled(true);
426 mActionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE,
427 ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_SHOW_CUSTOM);
Vikram Aggarwalabd24d82012-04-26 13:23:14 -0700428 setStandardMode();
Mindy Pereira72a9f392012-03-21 09:41:09 -0700429 mActionBar.setTitle(R.string.folder_list_title);
Mindy Pereira68f2e222012-03-07 10:36:54 -0800430 break;
431 }
432 return false;
433 }
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800434
Mindy Pereira205ae502012-05-17 08:43:59 -0700435 private boolean showConversationSubject() {
436 if (mShowConversationSubject == null) {
437 mShowConversationSubject = new Boolean(mActivity.getActivityContext().getResources()
438 .getBoolean(R.bool.show_conversation_subject));
439 }
440 return mShowConversationSubject;
441 }
442
Vikram Aggarwalabd24d82012-04-26 13:23:14 -0700443 /**
444 * Put the ActionBar in List navigation mode. This starts the spinner up if it is missing.
445 */
Mindy Pereira72a9f392012-03-21 09:41:09 -0700446 private void showNavList() {
447 mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
448 mActionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM,
449 ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_SHOW_CUSTOM);
450 }
451
Vikram Aggarwalabd24d82012-04-26 13:23:14 -0700452 /**
453 * Set the actionbar mode to standard mode: no list navigation.
454 */
455 private void setStandardMode() {
456 mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
457 }
458
Mindy Pereirab849dfb2012-03-07 18:13:15 -0800459 private void setPopulatedSearchView() {
460 if (mSearch != null) {
461 mSearch.expandActionView();
Vikram Aggarwala7997952012-03-09 10:30:13 -0800462 ConversationListContext context = mController.getCurrentListContext();
Mindy Pereirab849dfb2012-03-07 18:13:15 -0800463 if (context != null) {
464 mSearchWidget.setQuery(context.searchQuery, false);
465 }
466 }
467 }
468
Mindy Pereira68f2e222012-03-07 10:36:54 -0800469 public void removeBackButton() {
470 if (mActionBar == null) {
471 return;
472 }
473 mActionBar.setDisplayOptions(
474 ActionBar.DISPLAY_SHOW_HOME,
475 ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME);
476 mActivity.getActionBar().setHomeButtonEnabled(false);
477 }
Mindy Pereirabc57bf12012-02-29 14:39:09 -0800478
Mindy Pereira68f2e222012-03-07 10:36:54 -0800479 public void setBackButton() {
480 if (mActionBar == null){
481 return;
482 }
483 mActionBar.setDisplayOptions(
484 ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME,
485 ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME);
486 mActivity.getActionBar().setHomeButtonEnabled(true);
487 }
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800488
Mindy Pereira68f2e222012-03-07 10:36:54 -0800489 @Override
490 public boolean onQueryTextSubmit(String query) {
Mindy Pereira4ce59942012-03-08 09:57:35 -0800491 if (mSearch != null) {
492 mSearch.collapseActionView();
493 mSearchWidget.setQuery("", false);
494 }
Mindy Pereira68f2e222012-03-07 10:36:54 -0800495 mActivity.onSearchRequested(query);
496 return true;
497 }
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800498
Mindy Pereira68f2e222012-03-07 10:36:54 -0800499 @Override
500 public boolean onQueryTextChange(String newText) {
501 // TODO Auto-generated method stub
502 return false;
503 }
Mindy Pereira9b623802012-03-07 17:15:49 -0800504
505 public boolean setRefreshInProgress(boolean inProgress) {
506 if (inProgress != mRefreshInProgress) {
507 mRefreshInProgress = inProgress;
508 if (mSearch == null || !mSearch.isActionViewExpanded()) {
509 mHandler.post(mInvalidateMenu);
510 }
511 return true;
512 }
513 return false;
514 }
515
516 public void onRefreshStarted() {
517 setRefreshInProgress(true);
518 }
519
520 public void onRefreshStopped(int status) {
521 if (setRefreshInProgress(false)) {
522 switch (status) {
523 case LastSyncResult.SUCCESS:
524 break;
525 default:
526 Context context = mActivity.getActivityContext();
527 Toast.makeText(context, Utils.getSyncStatusText(context, status),
528 Toast.LENGTH_LONG).show();
529 break;
530 }
531 }
532 }
Mindy Pereirafd0c2972012-03-27 13:50:39 -0700533
534 /**
535 * Get the query text the user entered in the search widget, or empty string
536 * if there is none.
537 */
538 public String getQuery() {
539 return mSearchWidget != null ? mSearchWidget.getQuery().toString() : "";
540 }
Vikram Aggarwal12a7c042012-03-28 16:48:08 -0700541
542 // Next two methods are called when search suggestions are clicked.
543 @Override
544 public boolean onSuggestionSelect(int position) {
545 return onSuggestionClick(position);
546 }
547
548 @Override
549 public boolean onSuggestionClick(int position) {
550 final Cursor c = mSearchWidget.getSuggestionsAdapter().getCursor();
551 final boolean haveValidQuery = (c != null) && c.moveToPosition(position);
552 if (!haveValidQuery) {
553 LogUtils.d(LOG_TAG, "onSuggestionClick: Couldn't get a search query");
554 // We haven't handled this query, but the default behavior will leave EXTRA_ACCOUNT
555 // un-populated, leading to a crash. So claim that we have handled the event.
556 return true;
557 }
558 final String query = c.getString(c.getColumnIndex(SearchManager.SUGGEST_COLUMN_QUERY));
559 mController.onSearchRequested(query);
560 return true;
561 }
Mindy Pereiraa46a57f2012-04-03 17:19:31 -0700562
563 /**
564 * Notify that the folder has changed.
565 */
566 public void onFolderUpdated(Folder folder) {
567 mSpinner.onFolderUpdated(folder);
568 }
Vikram Aggarwal0dda5732012-04-06 11:20:16 -0700569
570 @Override
571 public boolean onMenuItemActionExpand(MenuItem item) {
572 // Do nothing. Required as part of the interface, we ar only interested in
573 // onMenuItemActionCollapse(MenuItem).
574 // Have to return true here. Unlike other callbacks, the return value here is whether
575 // we want to suppress the action (rather than consume the action). We don't want to
576 // suppress the action.
577 return true;
578 }
579
580 @Override
581 public boolean onMenuItemActionCollapse(MenuItem item) {
582 // When the action menu is collapsed, we have performed a search, pop the search fragment.
583 mController.exitSearchMode();
584 // Have to return true here. Unlike other callbacks, the return value here is whether
585 // we want to suppress the action (rather than consume the action). We don't want to
586 // suppress the action.
587 return true;
588 }
Vikram Aggarwal37263972012-04-17 15:51:14 -0700589
590 /**
591 * Request the Accounts spinner to redraw itself in light of new data that it needs to request.
592 */
593 public void requestRecentFoldersAndRedraw() {
594 mSpinner.requestRecentFoldersAndRedraw();
595 }
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800596}