blob: 3e808ff41fc7a5c389b66abf7967cce7b2885768 [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;
Scott Banachowski53a615d2012-12-19 15:31:20 -080023import android.content.ContentResolver;
Mindy Pereira68f2e222012-03-07 10:36:54 -080024import android.content.Context;
Vikram Aggarwal12a7c042012-03-28 16:48:08 -070025import android.database.Cursor;
Vikram Aggarwala51ef9f2013-04-02 13:25:35 -070026import android.net.Uri;
27import android.os.AsyncTask;
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -080028import android.os.Bundle;
Mindy Pereira9b623802012-03-07 17:15:49 -080029import android.os.Handler;
Mindy Pereira0531c9f2012-06-25 14:12:59 -070030import android.text.TextUtils;
Mindy Pereira68f2e222012-03-07 10:36:54 -080031import android.util.AttributeSet;
Scott Kennedya85831d2013-04-12 15:54:22 -070032import android.view.ActionProvider;
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -080033import android.view.Menu;
Mindy Pereira68f2e222012-03-07 10:36:54 -080034import android.view.MenuItem;
35import android.view.View;
36import android.widget.LinearLayout;
37import android.widget.SearchView;
38import android.widget.SearchView.OnQueryTextListener;
Vikram Aggarwal12a7c042012-03-28 16:48:08 -070039import android.widget.SearchView.OnSuggestionListener;
Vikram Aggarwal26b0bfd2013-03-29 13:05:08 -070040import android.widget.TextView;
Vikram Aggarwala9b93f32012-02-23 14:51:58 -080041
Alice Yang760d9562013-04-02 13:13:24 -070042import com.android.mail.ConversationListContext;
43import com.android.mail.R;
Scott Kennedya85831d2013-04-12 15:54:22 -070044import com.android.mail.preferences.MailPrefs;
Alice Yang760d9562013-04-02 13:13:24 -070045import com.android.mail.providers.Account;
46import com.android.mail.providers.AccountObserver;
47import com.android.mail.providers.AllAccountObserver;
48import com.android.mail.providers.Conversation;
49import com.android.mail.providers.Folder;
50import com.android.mail.providers.FolderObserver;
51import com.android.mail.providers.SearchRecentSuggestionsProvider;
52import com.android.mail.providers.UIProvider;
53import com.android.mail.providers.UIProvider.AccountCapabilities;
54import com.android.mail.providers.UIProvider.FolderCapabilities;
55import com.android.mail.utils.LogTag;
56import com.android.mail.utils.LogUtils;
57import com.android.mail.utils.Utils;
Scott Kennedya85831d2013-04-12 15:54:22 -070058import com.google.common.collect.Lists;
59
60import java.util.Iterator;
61import java.util.List;
62import java.util.Set;
Alice Yang760d9562013-04-02 13:13:24 -070063
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -080064/**
Andy Huang6681e542012-06-14 14:36:45 -070065 * View to manage the various states of the Mail Action Bar.
66 * <p>
67 * This also happens to be the custom view we supply to ActionBar.
Mindy Pereira68f2e222012-03-07 10:36:54 -080068 *
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -080069 */
mindyp6fb1b622012-09-05 09:27:08 -070070public class MailActionBarView extends LinearLayout implements ViewMode.ModeChangeListener,
Vikram Aggarwalad8b99b2013-04-07 16:37:28 -070071 OnQueryTextListener, OnSuggestionListener, MenuItem.OnActionExpandListener {
Andy Huangaf65e732013-01-28 20:45:40 -080072
Alice Yang15dfaa62013-02-13 15:37:42 -080073 // This is a private setting available starting JB MR1.1.
Andy Huangaf65e732013-01-28 20:45:40 -080074 private static final int DISPLAY_TITLE_MULTIPLE_LINES = 0x20;
75
Mindy Pereiraedb135e2012-06-15 08:34:09 -070076 protected ActionBar mActionBar;
Vikram Aggarwal7c401b72012-08-13 16:43:47 -070077 protected ControllableActivity mActivity;
Mindy Pereiraedb135e2012-06-15 08:34:09 -070078 protected ActivityController mController;
Mindy Pereira68f2e222012-03-07 10:36:54 -080079 /**
80 * The current mode of the ActionBar. This references constants in {@link ViewMode}
81 */
82 private int mMode = ViewMode.UNKNOWN;
83
84 private MenuItem mSearch;
Mindy Pereira68f2e222012-03-07 10:36:54 -080085 /**
86 * The account currently being shown
87 */
88 private Account mAccount;
Marc Blankedcab012012-04-04 12:42:38 -070089 /**
90 * The folder currently being shown
91 */
92 private Folder mFolder;
Mindy Pereira68f2e222012-03-07 10:36:54 -080093
Vikram Aggarwal81064f82013-04-02 13:25:35 -070094 /** The view that shows an unread count. */
Vikram Aggarwal26b0bfd2013-03-29 13:05:08 -070095 private TextView mUnreadView;
96
Mindy Pereira68f2e222012-03-07 10:36:54 -080097 private SearchView mSearchWidget;
98 private MenuItem mHelpItem;
Paul Westbrook517743e2012-03-22 10:40:46 -070099 private MenuItem mSendFeedbackItem;
Mindy Pereira9b623802012-03-07 17:15:49 -0800100 private MenuItem mRefreshItem;
Marc Blankedcab012012-04-04 12:42:38 -0700101 private MenuItem mFolderSettingsItem;
Mindy Pereira9b623802012-03-07 17:15:49 -0800102 private View mRefreshActionView;
Vikram Aggarwalf642b812013-03-15 16:30:21 -0700103 /** True if the current device is a tablet, false otherwise. */
Vikram Aggarwalad8b99b2013-04-07 16:37:28 -0700104 protected final boolean mIsOnTablet;
Mindy Pereira9b623802012-03-07 17:15:49 -0800105 private boolean mRefreshInProgress;
Yorke Leef807ba72012-09-20 17:18:05 -0700106 private Conversation mCurrentConversation;
Vikram Aggarwal6b641ba2013-03-15 16:07:24 -0700107 private AllAccountObserver mAllAccountObserver;
108 private boolean mHaveMultipleAccounts = false;
Mindy Pereira9b623802012-03-07 17:15:49 -0800109
Paul Westbrookb334c902012-06-25 11:42:46 -0700110 public static final String LOG_TAG = LogTag.getLogTag();
Andy Huang0d647352012-03-21 21:48:16 -0700111
Mindy Pereira9b623802012-03-07 17:15:49 -0800112 private final Handler mHandler = new Handler();
113 private final Runnable mInvalidateMenu = new Runnable() {
114 @Override
115 public void run() {
116 mActivity.invalidateOptionsMenu();
117 }
118 };
Vikram Aggarwal50ff0e52013-03-14 13:58:02 -0700119 private FolderObserver mFolderObserver;
Mindy Pereira68f2e222012-03-07 10:36:54 -0800120
Vikram Aggarwala51ef9f2013-04-02 13:25:35 -0700121 /** Updates the resolver and tells it the most recent account. */
122 private final class UpdateProvider extends AsyncTask<Bundle, Void, Void> {
123 final Uri mAccount;
124 final ContentResolver mResolver;
125 public UpdateProvider(Uri account, ContentResolver resolver) {
126 mAccount = account;
127 mResolver = resolver;
128 }
129
130 @Override
131 protected Void doInBackground(Bundle... params) {
132 mResolver.call(mAccount, UIProvider.AccountCallMethods.SET_CURRENT_ACCOUNT,
133 mAccount.toString(), params[0]);
134 return null;
135 }
136 }
137
Vikram Aggarwal7c401b72012-08-13 16:43:47 -0700138 private final AccountObserver mAccountObserver = new AccountObserver() {
139 @Override
140 public void onChanged(Account newAccount) {
Scott Banachowski53a615d2012-12-19 15:31:20 -0800141 updateAccount(newAccount);
Vikram Aggarwal7c401b72012-08-13 16:43:47 -0700142 }
143 };
Andy Huangaf65e732013-01-28 20:45:40 -0800144
Andy Huang6681e542012-06-14 14:36:45 -0700145 public MailActionBarView(Context context) {
Mindy Pereira68f2e222012-03-07 10:36:54 -0800146 this(context, null);
147 }
148
Andy Huang6681e542012-06-14 14:36:45 -0700149 public MailActionBarView(Context context, AttributeSet attrs) {
Mindy Pereira68f2e222012-03-07 10:36:54 -0800150 this(context, attrs, 0);
151 }
152
Andy Huang6681e542012-06-14 14:36:45 -0700153 public MailActionBarView(Context context, AttributeSet attrs, int defStyle) {
Mindy Pereira68f2e222012-03-07 10:36:54 -0800154 super(context, attrs, defStyle);
Vikram Aggarwalad8b99b2013-04-07 16:37:28 -0700155 mIsOnTablet = Utils.useTabletUI(getResources());
Andy Huang5895f7b2012-06-01 17:07:20 -0700156 }
157
158 @Override
159 protected void onFinishInflate() {
160 super.onFinishInflate();
Vikram Aggarwal26b0bfd2013-03-29 13:05:08 -0700161 mUnreadView = (TextView) findViewById(R.id.unread_count);
Mindy Pereira68f2e222012-03-07 10:36:54 -0800162 }
163
Andy Huang313ac132013-03-04 23:40:58 -0800164 public void expandSearch() {
165 if (mSearch != null) {
166 mSearch.expandActionView();
167 }
168 }
169
Vikram Aggarwalb17cbc02012-04-06 15:41:46 -0700170 /**
Vikram Aggarwal0dda5732012-04-06 11:20:16 -0700171 * Close the search view if it is expanded.
Vikram Aggarwalb17cbc02012-04-06 15:41:46 -0700172 */
173 public void collapseSearch() {
174 if (mSearch != null) {
175 mSearch.collapseActionView();
176 }
177 }
178
Mindy Pereiraedb135e2012-06-15 08:34:09 -0700179 /**
180 * Get the search menu item.
181 */
182 protected MenuItem getSearch() {
183 return mSearch;
184 }
185
Mindy Pereira68f2e222012-03-07 10:36:54 -0800186 public boolean onCreateOptionsMenu(Menu menu) {
187 // If the mode is valid, then set the initial menu
188 if (mMode == ViewMode.UNKNOWN) {
189 return false;
190 }
Mindy Pereira9b623802012-03-07 17:15:49 -0800191 mSearch = menu.findItem(R.id.search);
192 if (mSearch != null) {
193 mSearchWidget = (SearchView) mSearch.getActionView();
Vikram Aggarwal0dda5732012-04-06 11:20:16 -0700194 mSearch.setOnActionExpandListener(this);
Mindy Pereira68f2e222012-03-07 10:36:54 -0800195 SearchManager searchManager = (SearchManager) mActivity.getActivityContext()
196 .getSystemService(Context.SEARCH_SERVICE);
Mindy Pereirafb178492012-03-07 18:56:42 -0800197 if (searchManager != null && mSearchWidget != null) {
Mindy Pereira68f2e222012-03-07 10:36:54 -0800198 SearchableInfo info = searchManager.getSearchableInfo(mActivity.getComponentName());
199 mSearchWidget.setSearchableInfo(info);
200 mSearchWidget.setOnQueryTextListener(this);
Vikram Aggarwal12a7c042012-03-28 16:48:08 -0700201 mSearchWidget.setOnSuggestionListener(this);
Vikram Aggarwal0dda5732012-04-06 11:20:16 -0700202 mSearchWidget.setIconifiedByDefault(true);
Mindy Pereira68f2e222012-03-07 10:36:54 -0800203 }
204 }
205 mHelpItem = menu.findItem(R.id.help_info_menu_item);
Paul Westbrook517743e2012-03-22 10:40:46 -0700206 mSendFeedbackItem = menu.findItem(R.id.feedback_menu_item);
Mindy Pereira9b623802012-03-07 17:15:49 -0800207 mRefreshItem = menu.findItem(R.id.refresh);
Marc Blankedcab012012-04-04 12:42:38 -0700208 mFolderSettingsItem = menu.findItem(R.id.folder_options);
Mindy Pereira68f2e222012-03-07 10:36:54 -0800209 return true;
210 }
211
212 public int getOptionsMenuId() {
213 // Relies on the ordering of the view modes, since they are integer constants.
214 final int[] modeMenu = {
215 // 0: UNKNOWN
216 R.menu.conversation_list_menu,
217 // 1: CONVERSATION
218 R.menu.conversation_actions,
219 // 2: CONVERSATION_LIST
220 R.menu.conversation_list_menu,
221 // 3: FOLDER_LIST
222 R.menu.folder_list_menu,
223 // 4: SEARCH_RESULTS_LIST
224 R.menu.conversation_list_search_results_actions,
225 // 5: SEARCH_RESULTS_CONVERSATION
Paul Westbrook2d50bcd2012-04-10 11:53:47 -0700226 R.menu.conversation_search_results_actions,
227 // 6: WAITING_FOR_ACCOUNT_INITIALIZATION
228 R.menu.wait_mode_actions
Mindy Pereira68f2e222012-03-07 10:36:54 -0800229 };
230 return modeMenu[mMode];
231 }
232
Vikram Aggarwal7c401b72012-08-13 16:43:47 -0700233 public void initialize(ControllableActivity activity, ActivityController callback,
Vikram Aggarwaldac89fa2013-03-05 16:43:09 -0800234 ActionBar actionBar) {
Mindy Pereira68f2e222012-03-07 10:36:54 -0800235 mActionBar = actionBar;
Vikram Aggarwala7997952012-03-09 10:30:13 -0800236 mController = callback;
Mindy Pereira68f2e222012-03-07 10:36:54 -0800237 mActivity = activity;
Vikram Aggarwal50ff0e52013-03-14 13:58:02 -0700238 mFolderObserver = new FolderObserver() {
239 @Override
240 public void onChanged(Folder newFolder) {
241 onFolderUpdated(newFolder);
242 }
243 };
Vikram Aggarwal26b0bfd2013-03-29 13:05:08 -0700244 // Return values are purposely discarded. Initialization happens quite early, and we don't
245 // have a valid folder, or a valid list of accounts.
Vikram Aggarwal50ff0e52013-03-14 13:58:02 -0700246 mFolderObserver.initialize(mController);
Vikram Aggarwal6b641ba2013-03-15 16:07:24 -0700247 mAllAccountObserver = new AllAccountObserver() {
248 @Override
249 public void onChanged(Account[] allAccounts) {
250 mHaveMultipleAccounts = (allAccounts.length > 1);
251 }
252 };
253 mAllAccountObserver.initialize(mController);
Scott Banachowski53a615d2012-12-19 15:31:20 -0800254 updateAccount(mAccountObserver.initialize(activity.getAccountController()));
255 }
256
257 private void updateAccount(Account account) {
258 mAccount = account;
259 if (mAccount != null) {
Vikram Aggarwalbc462ca2013-03-15 10:41:03 -0700260 final ContentResolver resolver = mActivity.getActivityContext().getContentResolver();
261 final Bundle bundle = new Bundle(1);
Scott Banachowski53a615d2012-12-19 15:31:20 -0800262 bundle.putParcelable(UIProvider.SetCurrentAccountColumns.ACCOUNT, account);
Vikram Aggarwala51ef9f2013-04-02 13:25:35 -0700263 final UpdateProvider updater = new UpdateProvider(mAccount.uri, resolver);
264 updater.execute(bundle);
Vikram Aggarwalf642b812013-03-15 16:30:21 -0700265 setFolderAndAccount();
Scott Banachowski53a615d2012-12-19 15:31:20 -0800266 }
Vikram Aggarwalabd24d82012-04-26 13:23:14 -0700267 }
Andy Huange303b9b2012-04-19 16:31:09 -0700268
Vikram Aggarwalabd24d82012-04-26 13:23:14 -0700269 /**
Mindy Pereira68f2e222012-03-07 10:36:54 -0800270 * Called by the owner of the ActionBar to set the
271 * folder that is currently being displayed.
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800272 */
Mindy Pereira68f2e222012-03-07 10:36:54 -0800273 public void setFolder(Folder folder) {
Mindy Pereira641de652012-08-02 15:21:50 -0700274 setRefreshInProgress(false);
Marc Blankedcab012012-04-04 12:42:38 -0700275 mFolder = folder;
Vikram Aggarwalf642b812013-03-15 16:30:21 -0700276 setFolderAndAccount();
Vikram Aggarwal1dd77c92012-08-21 09:27:40 -0700277 mActivity.invalidateOptionsMenu();
Mindy Pereira68f2e222012-03-07 10:36:54 -0800278 }
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800279
Mindy Pereira641de652012-08-02 15:21:50 -0700280 public void onDestroy() {
281 if (mFolderObserver != null) {
Vikram Aggarwal50ff0e52013-03-14 13:58:02 -0700282 mFolderObserver.unregisterAndDestroy();
Mindy Pereira641de652012-08-02 15:21:50 -0700283 mFolderObserver = null;
284 }
Vikram Aggarwal6b641ba2013-03-15 16:07:24 -0700285 if (mAllAccountObserver != null) {
286 mAllAccountObserver.unregisterAndDestroy();
287 mAllAccountObserver = null;
288 }
Vikram Aggarwal7c401b72012-08-13 16:43:47 -0700289 mAccountObserver.unregisterAndDestroy();
Mindy Pereira68f2e222012-03-07 10:36:54 -0800290 }
291
Vikram Aggarwala7997952012-03-09 10:30:13 -0800292 @Override
Mindy Pereira68f2e222012-03-07 10:36:54 -0800293 public void onViewModeChanged(int newMode) {
294 mMode = newMode;
Mindy Pereira68f2e222012-03-07 10:36:54 -0800295 mActivity.invalidateOptionsMenu();
Vikram Aggarwal1a3f3fc2012-07-18 14:49:08 -0700296 // Check if we are either on a phone, or in Conversation mode on tablet. For these, the
297 // recent folders is enabled.
Andy Huangd736a382012-08-29 13:08:58 -0700298 switch (mMode) {
299 case ViewMode.UNKNOWN:
Andy Huangd736a382012-08-29 13:08:58 -0700300 break;
301 case ViewMode.CONVERSATION_LIST:
302 showNavList();
303 break;
Vikram Aggarwalad8b99b2013-04-07 16:37:28 -0700304 case ViewMode.SEARCH_RESULTS_CONVERSATION:
Vikram Aggarwale875b662013-04-10 15:56:46 -0700305 mActionBar.setDisplayHomeAsUpEnabled(true);
306 setEmptyMode();
307 break;
Andy Huangd736a382012-08-29 13:08:58 -0700308 case ViewMode.CONVERSATION:
Vikram Aggarwal49499e62013-02-08 16:39:08 -0800309 closeSearchField();
Andy Huangd736a382012-08-29 13:08:58 -0700310 mActionBar.setDisplayHomeAsUpEnabled(true);
Vikram Aggarwalad8b99b2013-04-07 16:37:28 -0700311 setEmptyMode();
Andy Huangd736a382012-08-29 13:08:58 -0700312 break;
313 case ViewMode.FOLDER_LIST:
Vikram Aggarwal49499e62013-02-08 16:39:08 -0800314 closeSearchField();
Andy Huangd736a382012-08-29 13:08:58 -0700315 mActionBar.setDisplayHomeAsUpEnabled(true);
Andy Huangaf65e732013-01-28 20:45:40 -0800316 setFoldersMode();
Andy Huangd736a382012-08-29 13:08:58 -0700317 break;
318 case ViewMode.WAITING_FOR_ACCOUNT_INITIALIZATION:
319 // We want the user to be able to switch accounts while waiting for an account
320 // to sync.
321 showNavList();
322 break;
323 }
Mindy Pereira68f2e222012-03-07 10:36:54 -0800324 }
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800325
Vikram Aggarwal49499e62013-02-08 16:39:08 -0800326 /**
327 * Close the search query entry field to avoid keyboard events, and to restore the actionbar
328 * to non-search mode.
329 */
Vikram Aggarwaldac89fa2013-03-05 16:43:09 -0800330 private void closeSearchField() {
Vikram Aggarwal49499e62013-02-08 16:39:08 -0800331 if (mSearch == null) {
332 return;
333 }
334 mSearch.collapseActionView();
335 }
336
Mindy Pereiraedb135e2012-06-15 08:34:09 -0700337 protected int getMode() {
338 return mMode;
339 }
340
Mindy Pereirab849dfb2012-03-07 18:13:15 -0800341 public boolean onPrepareOptionsMenu(Menu menu) {
Mindy Pereira68f2e222012-03-07 10:36:54 -0800342 // We start out with every option enabled. Based on the current view, we disable actions
343 // that are possible.
Vikram Aggarwal95b28ab2012-04-26 15:53:09 -0700344 LogUtils.d(LOG_TAG, "ActionBarView.onPrepareOptionsMenu().");
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800345
Andy Huangd736a382012-08-29 13:08:58 -0700346 // TODO: move refresh stuff into setRefreshInProgress. can just setActionView without
347 // invalidating.
Mindy Pereira9b623802012-03-07 17:15:49 -0800348 if (mRefreshInProgress) {
349 if (mRefreshItem != null) {
350 if (mRefreshActionView == null) {
351 mRefreshItem.setActionView(R.layout.action_bar_indeterminate_progress);
352 mRefreshActionView = mRefreshItem.getActionView();
353 } else {
354 mRefreshItem.setActionView(mRefreshActionView);
355 }
356 }
357 } else {
358 if (mRefreshItem != null) {
359 mRefreshItem.setActionView(null);
360 }
361 }
Mindy Pereira68f2e222012-03-07 10:36:54 -0800362 if (mHelpItem != null) {
363 mHelpItem.setVisible(mAccount != null
364 && mAccount.supportsCapability(AccountCapabilities.HELP_CONTENT));
365 }
Paul Westbrook517743e2012-03-22 10:40:46 -0700366 if (mSendFeedbackItem != null) {
367 mSendFeedbackItem.setVisible(mAccount != null
368 && mAccount.supportsCapability(AccountCapabilities.SEND_FEEDBACK));
369 }
Marc Blankedcab012012-04-04 12:42:38 -0700370 if (mFolderSettingsItem != null) {
371 mFolderSettingsItem.setVisible(mFolder != null
372 && mFolder.supportsCapability(FolderCapabilities.SUPPORTS_SETTINGS));
373 }
Mindy Pereira62c71792012-07-18 09:14:29 -0700374
Mindy Pereira9b623802012-03-07 17:15:49 -0800375 switch (mMode) {
Yorke Leef807ba72012-09-20 17:18:05 -0700376 case ViewMode.CONVERSATION:
377 case ViewMode.SEARCH_RESULTS_CONVERSATION:
378 // We update the ActionBar options when we are entering conversation view because
379 // waiting for the AbstractConversationViewFragment to do it causes duplicate icons
380 // to show up during the time between the conversation is selected and the fragment
381 // is added.
382 setConversationModeOptions(menu);
Scott Kennedya85831d2013-04-12 15:54:22 -0700383 // We want to use the user's preferred menu order here
384 reorderMenu(getContext(), menu);
Yorke Leef807ba72012-09-20 17:18:05 -0700385 break;
Mindy Pereira68f2e222012-03-07 10:36:54 -0800386 case ViewMode.CONVERSATION_LIST:
Vikram Aggarwalad8b99b2013-04-07 16:37:28 -0700387 // Show compose and search based on the account
Mindy Pereira68f2e222012-03-07 10:36:54 -0800388 // The only option that needs to be disabled is search
Mindy Pereira863e4412012-03-23 12:21:38 -0700389 Utils.setMenuItemVisibility(menu, R.id.search,
Mindy Pereira9b623802012-03-07 17:15:49 -0800390 mAccount.supportsCapability(AccountCapabilities.FOLDER_SERVER_SEARCH));
Mindy Pereira68f2e222012-03-07 10:36:54 -0800391 break;
Vikram Aggarwalad8b99b2013-04-07 16:37:28 -0700392 case ViewMode.SEARCH_RESULTS_LIST:
393 // Show only compose
394 // The only option that needs to be disabled is search
395 Utils.setMenuItemVisibility(menu, R.id.search, false);
396 break;
Mindy Pereira68f2e222012-03-07 10:36:54 -0800397 }
Scott Kennedya85831d2013-04-12 15:54:22 -0700398
399 return false;
400 }
401
402 public static void reorderMenu(final Context context, final Menu menu) {
403 // Bump our preferred items to the top
404 final Set<String> preferredItemIds = MailPrefs.get(context).getPreferredActionItems();
405
406 // Create another copy of the menu that we can rearrange
407 final List<MenuItem> menuCopy = Lists.newArrayListWithCapacity(menu.size());
408
409 for (int i = 0; i < menu.size(); i++) {
410 final MenuItem menuItem = menu.getItem(i);
411 menuCopy.add(menuItem);
412 }
413
414 // Re-sort our menu
415 final List<MenuItem> firstItems = Lists.newArrayListWithCapacity(2);
416 final List<MenuItem> preferredItems =
417 Lists.newArrayListWithCapacity(preferredItemIds.size());
418
419 final Iterator<MenuItem> iterator = menuCopy.iterator();
420 while (iterator.hasNext()) {
421 final MenuItem menuItem = iterator.next();
422 final int menuItemId = menuItem.getItemId();
423
424 // Compose and search must be first, if present
425 if (menuItemId == R.id.compose || menuItemId == R.id.search) {
426 iterator.remove();
427 firstItems.add(menuItem);
428 continue;
429 }
430
431 for (final String preferredItemId : preferredItemIds) {
432 if (matches(preferredItemId, menuItemId)) {
433 iterator.remove();
434 preferredItems.add(menuItem);
435 break;
436 }
437 }
438 }
439
440 // Rebuild the menu
441 menu.clear();
442
443 for (final MenuItem menuItem : firstItems) {
444 addMenuItem(menu, menuItem);
445 }
446
447 for (final MenuItem menuItem : preferredItems) {
448 addMenuItem(menu, menuItem);
449 }
450
451 for (final MenuItem menuItem : menuCopy) {
452 addMenuItem(menu, menuItem);
453 }
454
455 // Set the first few to always show
456 int allowed = context.getResources().getInteger(R.integer.actionbar_items_shown);
457 int i = 0;
458 while (allowed > 0 && i < menu.size()) {
459 final MenuItem menuItem = menu.getItem(i);
460 if (menuItem.isVisible() && menuItem.getIcon() != null) {
461 // We need to collapseActionView, but only for search
462 final int actionEnum;
463 if (menuItem.getItemId() == R.id.search) {
464 actionEnum = MenuItem.SHOW_AS_ACTION_ALWAYS
465 | MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW;
466 } else {
467 actionEnum = MenuItem.SHOW_AS_ACTION_ALWAYS;
468 }
469
470 menuItem.setShowAsAction(actionEnum);
471 allowed--;
472 }
473 i++;
474 }
475 }
476
477 private static void addMenuItem(final Menu menu, final MenuItem menuItem) {
478 final MenuItem newItem = menu.add(Menu.NONE, menuItem.getItemId(), Menu.NONE,
479 menuItem.getTitle());
480 final ActionProvider actionProvider = menuItem.getActionProvider();
481 if (actionProvider != null) {
482 newItem.setActionProvider(actionProvider);
483 }
484 newItem.setActionView(menuItem.getActionView());
485 newItem.setAlphabeticShortcut(menuItem.getAlphabeticShortcut());
486 newItem.setCheckable(menuItem.isCheckable());
487 newItem.setChecked(menuItem.isChecked());
488 newItem.setEnabled(menuItem.isEnabled());
489 newItem.setIcon(menuItem.getIcon());
490 newItem.setIntent(menuItem.getIntent());
491 newItem.setNumericShortcut(menuItem.getNumericShortcut());
492 newItem.setShortcut(menuItem.getNumericShortcut(), menuItem.getAlphabeticShortcut());
493 newItem.setTitle(menuItem.getTitle());
494 newItem.setTitleCondensed(menuItem.getTitleCondensed());
495 newItem.setVisible(menuItem.isVisible());
496 }
497
498 private static boolean matches(final String actionItemId, final int menuItemId) {
499 switch (menuItemId) {
500 case R.id.archive:
501 case R.id.remove_folder:
502 return "archive_remove_folder".equals(actionItemId);
503 case R.id.delete:
504 case R.id.discard_drafts:
505 return "delete_discard_drafts".equals(actionItemId);
506 case R.id.read:
507 case R.id.unread:
508 case R.id.inside_conversation_unread:
509 return "mark_read_unread".equals(actionItemId);
510 case R.id.change_folder:
511 return "change_folders".equals(actionItemId);
512 case R.id.star:
513 case R.id.remove_star:
514 return "add_remove_star".equals(actionItemId);
515 case R.id.move_to:
516 return "move_to".equals(actionItemId);
517 case R.id.mark_important:
518 case R.id.mark_not_important:
519 return "mark_not_important".equals(actionItemId);
520 case R.id.report_spam:
521 case R.id.mark_not_spam:
522 return "report_not_spam".equals(actionItemId);
523 }
524
mindypf5a24422012-09-04 13:28:11 -0700525 return false;
Mindy Pereira68f2e222012-03-07 10:36:54 -0800526 }
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800527
Vikram Aggarwalabd24d82012-04-26 13:23:14 -0700528 /**
Vikram Aggarwalad8b99b2013-04-07 16:37:28 -0700529 * Put the ActionBar in List navigation mode.
Vikram Aggarwalabd24d82012-04-26 13:23:14 -0700530 */
Mindy Pereira72a9f392012-03-21 09:41:09 -0700531 private void showNavList() {
Vikram Aggarwal26b0bfd2013-03-29 13:05:08 -0700532 setTitleModeFlags(ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_SHOW_CUSTOM);
Vikram Aggarwal81064f82013-04-02 13:25:35 -0700533 if (mUnreadView != null) {
534 mUnreadView.setVisibility(View.VISIBLE);
535 }
Vikram Aggarwalf642b812013-03-15 16:30:21 -0700536 setFolderAndAccount();
Mindy Pereira72a9f392012-03-21 09:41:09 -0700537 }
538
Vikram Aggarwalabd24d82012-04-26 13:23:14 -0700539 /**
Vikram Aggarwalad8b99b2013-04-07 16:37:28 -0700540 * Put the ActionBar in standard mode, and show the word "Folders" along with the account name
541 * (if user has multiple accounts)
Vikram Aggarwalabd24d82012-04-26 13:23:14 -0700542 */
Andy Huangaf65e732013-01-28 20:45:40 -0800543 private void setFoldersMode() {
544 setTitleModeFlags(ActionBar.DISPLAY_SHOW_TITLE);
Vikram Aggarwal81064f82013-04-02 13:25:35 -0700545 if (mUnreadView != null) {
546 mUnreadView.setVisibility(View.GONE);
547 }
Andy Huangaf65e732013-01-28 20:45:40 -0800548 mActionBar.setTitle(R.string.folders);
Vikram Aggarwal6b641ba2013-03-15 16:07:24 -0700549 if (mHaveMultipleAccounts) {
550 mActionBar.setSubtitle(mAccount.name);
551 }
mindyp6fb1b622012-09-05 09:27:08 -0700552 }
553
554 /**
Vikram Aggarwalfd7eaba2013-04-11 12:31:46 -0700555 * Set the actionbar mode to empty: no title, no subtitle, no custom view.
mindyp6fb1b622012-09-05 09:27:08 -0700556 */
557 protected void setEmptyMode() {
Vikram Aggarwalfd7eaba2013-04-11 12:31:46 -0700558 // Disable title/subtitle and the custom view by setting the bitmask to all off.
559 setTitleModeFlags(0);
Alice Yang760d9562013-04-02 13:13:24 -0700560 if (mUnreadView != null) {
561 mUnreadView.setVisibility(View.GONE);
562 }
Vikram Aggarwalabd24d82012-04-26 13:23:14 -0700563 }
564
Vikram Aggarwalad8b99b2013-04-07 16:37:28 -0700565 /**
566 * Removes the back button from being shown
567 */
Mindy Pereira68f2e222012-03-07 10:36:54 -0800568 public void removeBackButton() {
569 if (mActionBar == null) {
570 return;
571 }
Vikram Aggarwal649b9ea2012-08-27 12:15:20 -0700572 // Remove the back button but continue showing an icon.
573 final int mask = ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME;
574 mActionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_HOME, mask);
Mindy Pereira68f2e222012-03-07 10:36:54 -0800575 mActivity.getActionBar().setHomeButtonEnabled(false);
576 }
Mindy Pereirabc57bf12012-02-29 14:39:09 -0800577
Mindy Pereira68f2e222012-03-07 10:36:54 -0800578 public void setBackButton() {
579 if (mActionBar == null){
580 return;
581 }
Vikram Aggarwal649b9ea2012-08-27 12:15:20 -0700582 // Show home as up, and show an icon.
583 final int mask = ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME;
584 mActionBar.setDisplayOptions(mask, mask);
Mindy Pereira68f2e222012-03-07 10:36:54 -0800585 mActivity.getActionBar().setHomeButtonEnabled(true);
586 }
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800587
Mindy Pereira68f2e222012-03-07 10:36:54 -0800588 @Override
589 public boolean onQueryTextSubmit(String query) {
Mindy Pereira4ce59942012-03-08 09:57:35 -0800590 if (mSearch != null) {
591 mSearch.collapseActionView();
592 mSearchWidget.setQuery("", false);
593 }
Andy Huang313ac132013-03-04 23:40:58 -0800594 mController.executeSearch(query.trim());
Mindy Pereira68f2e222012-03-07 10:36:54 -0800595 return true;
596 }
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800597
Mindy Pereira68f2e222012-03-07 10:36:54 -0800598 @Override
599 public boolean onQueryTextChange(String newText) {
Mindy Pereira68f2e222012-03-07 10:36:54 -0800600 return false;
601 }
Mindy Pereira9b623802012-03-07 17:15:49 -0800602
Mindy Pereira641de652012-08-02 15:21:50 -0700603 private boolean setRefreshInProgress(boolean inProgress) {
Mindy Pereira9b623802012-03-07 17:15:49 -0800604 if (inProgress != mRefreshInProgress) {
605 mRefreshInProgress = inProgress;
606 if (mSearch == null || !mSearch.isActionViewExpanded()) {
607 mHandler.post(mInvalidateMenu);
608 }
609 return true;
610 }
611 return false;
612 }
613
Mindy Pereira641de652012-08-02 15:21:50 -0700614 private void onRefreshStarted() {
Mindy Pereira9b623802012-03-07 17:15:49 -0800615 setRefreshInProgress(true);
616 }
617
Vikram Aggarwal41b9e8f2012-09-25 10:15:04 -0700618 private void onRefreshStopped() {
Paul Westbrook4f393ec2012-08-10 09:19:50 -0700619 setRefreshInProgress(false);
Mindy Pereira9b623802012-03-07 17:15:49 -0800620 }
Mindy Pereirafd0c2972012-03-27 13:50:39 -0700621
Vikram Aggarwal12a7c042012-03-28 16:48:08 -0700622 // Next two methods are called when search suggestions are clicked.
623 @Override
624 public boolean onSuggestionSelect(int position) {
625 return onSuggestionClick(position);
626 }
627
628 @Override
629 public boolean onSuggestionClick(int position) {
630 final Cursor c = mSearchWidget.getSuggestionsAdapter().getCursor();
631 final boolean haveValidQuery = (c != null) && c.moveToPosition(position);
632 if (!haveValidQuery) {
633 LogUtils.d(LOG_TAG, "onSuggestionClick: Couldn't get a search query");
Mindy Pereiraf8fcb802012-06-25 11:43:06 -0700634 // We haven't handled this query, but the default behavior will
635 // leave EXTRA_ACCOUNT un-populated, leading to a crash. So claim
636 // that we have handled the event.
Vikram Aggarwal12a7c042012-03-28 16:48:08 -0700637 return true;
638 }
Mindy Pereirab466bcf2012-06-14 15:52:26 -0700639 collapseSearch();
Mindy Pereira1e180dd2012-08-16 10:24:10 -0700640 // what is in the text field
Mindy Pereiraca97b312012-06-25 14:00:20 -0700641 String queryText = mSearchWidget.getQuery().toString();
Mindy Pereira1e180dd2012-08-16 10:24:10 -0700642 // What the suggested query is
Mindy Pereiraf8fcb802012-06-25 11:43:06 -0700643 String query = c.getString(c.getColumnIndex(SearchManager.SUGGEST_COLUMN_QUERY));
mindyp0fc8fa52012-09-04 10:43:23 -0700644 // If the text the user typed in is a prefix of what is in the search
645 // widget suggestion query, just take the search widget suggestion
646 // query. Otherwise, it is a suffix and we want to remove matching
647 // prefix portions.
648 if (!TextUtils.isEmpty(queryText) && query.indexOf(queryText) != 0) {
Mindy Pereira5e1403c2012-07-18 13:22:11 -0700649 final int queryTokenIndex = queryText
650 .lastIndexOf(SearchRecentSuggestionsProvider.QUERY_TOKEN_SEPARATOR);
651 if (queryTokenIndex > -1) {
652 queryText = queryText.substring(0, queryTokenIndex);
Mindy Pereiraca97b312012-06-25 14:00:20 -0700653 }
654 // Since we auto-complete on each token in a query, if the query the
655 // user typed up until the last token is a substring of the
656 // suggestion they click, make sure we don't double include the
657 // query text. For example:
658 // user types john, that matches john palo alto
659 // User types john p, that matches john john palo alto
660 // Remove the first john
Mindy Pereira5e1403c2012-07-18 13:22:11 -0700661 // Only do this if we have multiple query tokens.
662 if (queryTokenIndex > -1 && !TextUtils.isEmpty(query) && query.contains(queryText)
Mindy Pereiraca97b312012-06-25 14:00:20 -0700663 && queryText.length() < query.length()) {
664 int start = query.indexOf(queryText);
665 query = query.substring(0, start) + query.substring(start + queryText.length());
666 }
667 }
Andy Huang313ac132013-03-04 23:40:58 -0800668 mController.executeSearch(query.trim());
Vikram Aggarwal12a7c042012-03-28 16:48:08 -0700669 return true;
670 }
Mindy Pereiraa46a57f2012-04-03 17:19:31 -0700671
Vikram Aggarwalf642b812013-03-15 16:30:21 -0700672 /**
673 * Uses the current state to update the current folder {@link #mFolder} and the current
674 * account {@link #mAccount} shown in the actionbar.
675 */
676 private void setFolderAndAccount() {
Vikram Aggarwal5fce9922013-04-01 21:17:42 -0700677 // Very little can be done if the actionbar or activity is null.
678 if (mActionBar == null || mActivity == null) {
679 return;
680 }
Vikram Aggarwalf642b812013-03-15 16:30:21 -0700681 // Check if we should be changing the actionbar at all, and back off if not.
Vikram Aggarwal5fce9922013-04-01 21:17:42 -0700682 final boolean isShowingFolderAndAccount = mIsOnTablet || ViewMode.isListMode(mMode);
683 if (!isShowingFolderAndAccount) {
Vikram Aggarwalf642b812013-03-15 16:30:21 -0700684 return;
685 }
Vikram Aggarwalf642b812013-03-15 16:30:21 -0700686 if (mAccount != null && mHaveMultipleAccounts) {
687 mActionBar.setSubtitle(mAccount.name);
688 }
Vikram Aggarwal26b0bfd2013-03-29 13:05:08 -0700689 if (mFolder == null) {
690 return;
691 }
692 mActionBar.setTitle(mFolder.name);
693 if (mUnreadView != null) {
694 mUnreadView.setText(Utils.getUnreadCountString(
695 mActivity.getApplicationContext(), mFolder.unreadCount));
696 }
Vikram Aggarwalbc462ca2013-03-15 10:41:03 -0700697 }
698
Mindy Pereiraa46a57f2012-04-03 17:19:31 -0700699 /**
700 * Notify that the folder has changed.
701 */
702 public void onFolderUpdated(Folder folder) {
Vikram Aggarwal26b0bfd2013-03-29 13:05:08 -0700703 if (folder == null) {
704 return;
705 }
Vikram Aggarwale875b662013-04-10 15:56:46 -0700706 /** True if we are changing folders. */
707 final boolean changingFolders = (mFolder == null || !mFolder.uri.equals(folder.uri));
Vikram Aggarwalc18c3382013-04-05 15:29:13 -0700708 mFolder = folder;
Vikram Aggarwalf642b812013-03-15 16:30:21 -0700709 setFolderAndAccount();
Mindy Pereira641de652012-08-02 15:21:50 -0700710 if (folder.isSyncInProgress()) {
711 onRefreshStarted();
712 } else {
713 // Stop the spinner here.
Vikram Aggarwal41b9e8f2012-09-25 10:15:04 -0700714 onRefreshStopped();
Mindy Pereira641de652012-08-02 15:21:50 -0700715 }
Vikram Aggarwal49499e62013-02-08 16:39:08 -0800716 final ConversationListContext listContext = mController == null ? null :
717 mController.getCurrentListContext();
Vikram Aggarwale875b662013-04-10 15:56:46 -0700718 if (changingFolders && !ConversationListContext.isSearchResult(listContext)) {
Vikram Aggarwal49499e62013-02-08 16:39:08 -0800719 closeSearchField();
720 }
Mindy Pereiraa46a57f2012-04-03 17:19:31 -0700721 }
Vikram Aggarwal0dda5732012-04-06 11:20:16 -0700722
723 @Override
724 public boolean onMenuItemActionExpand(MenuItem item) {
725 // Do nothing. Required as part of the interface, we ar only interested in
726 // onMenuItemActionCollapse(MenuItem).
727 // Have to return true here. Unlike other callbacks, the return value here is whether
728 // we want to suppress the action (rather than consume the action). We don't want to
729 // suppress the action.
730 return true;
731 }
732
733 @Override
734 public boolean onMenuItemActionCollapse(MenuItem item) {
Mindy Pereirab466bcf2012-06-14 15:52:26 -0700735 // Work around b/6664203 by manually forcing this view to be VISIBLE
736 // upon ActionView collapse. DISPLAY_SHOW_CUSTOM will still control its final
737 // visibility.
Andy Huang5895f7b2012-06-01 17:07:20 -0700738 setVisibility(VISIBLE);
Mindy Pereirab466bcf2012-06-14 15:52:26 -0700739 // Have to return true here. Unlike other callbacks, the return value
740 // here is whether we want to suppress the action (rather than consume the action). We
741 // don't want to suppress the action.
Vikram Aggarwal0dda5732012-04-06 11:20:16 -0700742 return true;
743 }
Vikram Aggarwal37263972012-04-17 15:51:14 -0700744
Vikram Aggarwalfd7eaba2013-04-11 12:31:46 -0700745 /**
746 * Sets the actionbar mode: Pass it an integer which contains each of these values, perhaps
747 * OR'd together: {@link ActionBar#DISPLAY_SHOW_CUSTOM}, {@link ActionBar#DISPLAY_SHOW_TITLE},
748 * and {@link #DISPLAY_TITLE_MULTIPLE_LINES}. To disable all, pass a zero.
749 * @param enabledFlags
750 */
Andy Huangaf65e732013-01-28 20:45:40 -0800751 private void setTitleModeFlags(int enabledFlags) {
752 final int mask = ActionBar.DISPLAY_SHOW_TITLE
753 | ActionBar.DISPLAY_SHOW_CUSTOM | DISPLAY_TITLE_MULTIPLE_LINES;
Andy Huangaf65e732013-01-28 20:45:40 -0800754 mActionBar.setDisplayOptions(enabledFlags, mask);
755 }
756
Yorke Leef807ba72012-09-20 17:18:05 -0700757 public void setCurrentConversation(Conversation conversation) {
758 mCurrentConversation = conversation;
759 }
760
761 //We need to do this here instead of in the fragment
762 public void setConversationModeOptions(Menu menu) {
763 if (mCurrentConversation == null) {
764 return;
765 }
766 final boolean showMarkImportant = !mCurrentConversation.isImportant();
767 Utils.setMenuItemVisibility(menu, R.id.mark_important, showMarkImportant
768 && mAccount.supportsCapability(UIProvider.AccountCapabilities.MARK_IMPORTANT));
769 Utils.setMenuItemVisibility(menu, R.id.mark_not_important, !showMarkImportant
770 && mAccount.supportsCapability(UIProvider.AccountCapabilities.MARK_IMPORTANT));
771 final boolean showDelete = mFolder != null &&
772 mFolder.supportsCapability(UIProvider.FolderCapabilities.DELETE);
773 Utils.setMenuItemVisibility(menu, R.id.delete, showDelete);
774 // We only want to show the discard drafts menu item if we are not showing the delete menu
775 // item, and the current folder is a draft folder and the account supports discarding
776 // drafts for a conversation
777 final boolean showDiscardDrafts = !showDelete && mFolder != null && mFolder.isDraft() &&
778 mAccount.supportsCapability(AccountCapabilities.DISCARD_CONVERSATION_DRAFTS);
779 Utils.setMenuItemVisibility(menu, R.id.discard_drafts, showDiscardDrafts);
780 final boolean archiveVisible = mAccount.supportsCapability(AccountCapabilities.ARCHIVE)
781 && mFolder != null && mFolder.supportsCapability(FolderCapabilities.ARCHIVE)
782 && !mFolder.isTrash();
783 Utils.setMenuItemVisibility(menu, R.id.archive, archiveVisible);
784 Utils.setMenuItemVisibility(menu, R.id.remove_folder, !archiveVisible && mFolder != null
785 && mFolder.supportsCapability(FolderCapabilities.CAN_ACCEPT_MOVED_MESSAGES)
786 && !mFolder.isProviderFolder());
Scott Kennedy28f3d5c2013-04-08 16:53:50 -0700787 Utils.setMenuItemVisibility(menu, R.id.move_to, mFolder != null
788 && mFolder.supportsCapability(FolderCapabilities.ALLOWS_REMOVE_CONVERSATION));
Yorke Leef807ba72012-09-20 17:18:05 -0700789 final MenuItem removeFolder = menu.findItem(R.id.remove_folder);
Alice Yang40698e62013-03-14 11:31:53 -0700790 if (mFolder != null && removeFolder != null) {
Yorke Leef807ba72012-09-20 17:18:05 -0700791 removeFolder.setTitle(mActivity.getApplicationContext().getString(
792 R.string.remove_folder, mFolder.name));
793 }
794 Utils.setMenuItemVisibility(menu, R.id.report_spam,
795 mAccount.supportsCapability(AccountCapabilities.REPORT_SPAM) && mFolder != null
796 && mFolder.supportsCapability(FolderCapabilities.REPORT_SPAM)
797 && !mCurrentConversation.spam);
798 Utils.setMenuItemVisibility(menu, R.id.mark_not_spam,
799 mAccount.supportsCapability(AccountCapabilities.REPORT_SPAM) && mFolder != null
800 && mFolder.supportsCapability(FolderCapabilities.MARK_NOT_SPAM)
801 && mCurrentConversation.spam);
802 Utils.setMenuItemVisibility(menu, R.id.report_phishing,
803 mAccount.supportsCapability(AccountCapabilities.REPORT_PHISHING) && mFolder != null
804 && mFolder.supportsCapability(FolderCapabilities.REPORT_PHISHING)
805 && !mCurrentConversation.phishing);
806 Utils.setMenuItemVisibility(menu, R.id.mute,
807 mAccount.supportsCapability(AccountCapabilities.MUTE) && mFolder != null
808 && mFolder.supportsCapability(FolderCapabilities.DESTRUCTIVE_MUTE)
809 && !mCurrentConversation.muted);
810 }
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800811}