blob: e891e0d8681235e48a3b37542c1310d560a6159d [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 Aggarwalbcb16b92013-01-28 18:05:03 -080025import android.content.res.Resources;
Vikram Aggarwal12a7c042012-03-28 16:48:08 -070026import android.database.Cursor;
Vikram Aggarwala51ef9f2013-04-02 13:25:35 -070027import android.net.Uri;
28import android.os.AsyncTask;
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -080029import android.os.Bundle;
Mindy Pereira9b623802012-03-07 17:15:49 -080030import android.os.Handler;
Alice Yang48706db2013-02-01 17:56:52 -080031import android.text.SpannableString;
32import android.text.SpannableStringBuilder;
Mindy Pereira0531c9f2012-06-25 14:12:59 -070033import android.text.TextUtils;
Alice Yang48706db2013-02-01 17:56:52 -080034import android.text.style.TextAppearanceSpan;
Mindy Pereira68f2e222012-03-07 10:36:54 -080035import android.util.AttributeSet;
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -080036import android.view.Menu;
Mindy Pereira68f2e222012-03-07 10:36:54 -080037import android.view.MenuItem;
38import android.view.View;
39import android.widget.LinearLayout;
40import android.widget.SearchView;
41import android.widget.SearchView.OnQueryTextListener;
Vikram Aggarwal12a7c042012-03-28 16:48:08 -070042import android.widget.SearchView.OnSuggestionListener;
Vikram Aggarwal26b0bfd2013-03-29 13:05:08 -070043import android.widget.TextView;
Vikram Aggarwala9b93f32012-02-23 14:51:58 -080044
Alice Yang760d9562013-04-02 13:13:24 -070045import com.android.mail.ConversationListContext;
46import com.android.mail.R;
47import com.android.mail.browse.SnippetTextView;
48import com.android.mail.providers.Account;
49import com.android.mail.providers.AccountObserver;
50import com.android.mail.providers.AllAccountObserver;
51import com.android.mail.providers.Conversation;
52import com.android.mail.providers.Folder;
53import com.android.mail.providers.FolderObserver;
54import com.android.mail.providers.SearchRecentSuggestionsProvider;
55import com.android.mail.providers.UIProvider;
56import com.android.mail.providers.UIProvider.AccountCapabilities;
57import com.android.mail.providers.UIProvider.FolderCapabilities;
58import com.android.mail.utils.LogTag;
59import com.android.mail.utils.LogUtils;
60import com.android.mail.utils.Utils;
61
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -080062/**
Andy Huang6681e542012-06-14 14:36:45 -070063 * View to manage the various states of the Mail Action Bar.
64 * <p>
65 * This also happens to be the custom view we supply to ActionBar.
Mindy Pereira68f2e222012-03-07 10:36:54 -080066 *
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -080067 */
mindyp6fb1b622012-09-05 09:27:08 -070068public class MailActionBarView extends LinearLayout implements ViewMode.ModeChangeListener,
69 OnQueryTextListener, OnSuggestionListener, MenuItem.OnActionExpandListener,
mindyp26760ef2012-09-05 14:15:41 -070070 SubjectDisplayChanger {
Andy Huangaf65e732013-01-28 20:45:40 -080071
Alice Yang15dfaa62013-02-13 15:37:42 -080072 // This is a private setting available starting JB MR1.1.
Andy Huangaf65e732013-01-28 20:45:40 -080073 private static final int DISPLAY_TITLE_MULTIPLE_LINES = 0x20;
74
Vikram Aggarwal19b0e3c2013-03-22 15:35:20 -070075 /** True if we want the subject in the actionbar */
76 public static final boolean SHOW_ACTIONBAR_SUBJECT = true;
77
Mindy Pereiraedb135e2012-06-15 08:34:09 -070078 protected ActionBar mActionBar;
Vikram Aggarwal7c401b72012-08-13 16:43:47 -070079 protected ControllableActivity mActivity;
Mindy Pereiraedb135e2012-06-15 08:34:09 -070080 protected ActivityController mController;
Mindy Pereira68f2e222012-03-07 10:36:54 -080081 /**
82 * The current mode of the ActionBar. This references constants in {@link ViewMode}
83 */
84 private int mMode = ViewMode.UNKNOWN;
85
86 private MenuItem mSearch;
Mindy Pereira68f2e222012-03-07 10:36:54 -080087 /**
88 * The account currently being shown
89 */
90 private Account mAccount;
Marc Blankedcab012012-04-04 12:42:38 -070091 /**
92 * The folder currently being shown
93 */
94 private Folder mFolder;
Mindy Pereira68f2e222012-03-07 10:36:54 -080095
Andy Huang5895f7b2012-06-01 17:07:20 -070096 private SnippetTextView mSubjectView;
Vikram Aggarwal81064f82013-04-02 13:25:35 -070097 /** The view that shows an unread count. */
Vikram Aggarwal26b0bfd2013-03-29 13:05:08 -070098 private TextView mUnreadView;
99
Mindy Pereira68f2e222012-03-07 10:36:54 -0800100 private SearchView mSearchWidget;
101 private MenuItem mHelpItem;
Paul Westbrook517743e2012-03-22 10:40:46 -0700102 private MenuItem mSendFeedbackItem;
Mindy Pereira9b623802012-03-07 17:15:49 -0800103 private MenuItem mRefreshItem;
Marc Blankedcab012012-04-04 12:42:38 -0700104 private MenuItem mFolderSettingsItem;
Mindy Pereira9b623802012-03-07 17:15:49 -0800105 private View mRefreshActionView;
Vikram Aggarwalf642b812013-03-15 16:30:21 -0700106 /** True if the current device is a tablet, false otherwise. */
107 private boolean mIsOnTablet;
Mindy Pereira9b623802012-03-07 17:15:49 -0800108 private boolean mRefreshInProgress;
Yorke Leef807ba72012-09-20 17:18:05 -0700109 private Conversation mCurrentConversation;
Vikram Aggarwal6b641ba2013-03-15 16:07:24 -0700110 private AllAccountObserver mAllAccountObserver;
111 private boolean mHaveMultipleAccounts = false;
Mindy Pereira9b623802012-03-07 17:15:49 -0800112
Paul Westbrookb334c902012-06-25 11:42:46 -0700113 public static final String LOG_TAG = LogTag.getLogTag();
Andy Huang0d647352012-03-21 21:48:16 -0700114
Mindy Pereira9b623802012-03-07 17:15:49 -0800115 private final Handler mHandler = new Handler();
116 private final Runnable mInvalidateMenu = new Runnable() {
117 @Override
118 public void run() {
119 mActivity.invalidateOptionsMenu();
120 }
121 };
Andy Huang5895f7b2012-06-01 17:07:20 -0700122 private final boolean mShowConversationSubject;
Vikram Aggarwal50ff0e52013-03-14 13:58:02 -0700123 private FolderObserver mFolderObserver;
Mindy Pereira68f2e222012-03-07 10:36:54 -0800124
Vikram Aggarwala51ef9f2013-04-02 13:25:35 -0700125 /** Updates the resolver and tells it the most recent account. */
126 private final class UpdateProvider extends AsyncTask<Bundle, Void, Void> {
127 final Uri mAccount;
128 final ContentResolver mResolver;
129 public UpdateProvider(Uri account, ContentResolver resolver) {
130 mAccount = account;
131 mResolver = resolver;
132 }
133
134 @Override
135 protected Void doInBackground(Bundle... params) {
136 mResolver.call(mAccount, UIProvider.AccountCallMethods.SET_CURRENT_ACCOUNT,
137 mAccount.toString(), params[0]);
138 return null;
139 }
140 }
141
Vikram Aggarwal7c401b72012-08-13 16:43:47 -0700142 private final AccountObserver mAccountObserver = new AccountObserver() {
143 @Override
144 public void onChanged(Account newAccount) {
Scott Banachowski53a615d2012-12-19 15:31:20 -0800145 updateAccount(newAccount);
Vikram Aggarwal7c401b72012-08-13 16:43:47 -0700146 }
147 };
Andy Huangaf65e732013-01-28 20:45:40 -0800148
Andy Huang9da91d32013-01-30 15:27:00 -0800149 private final OnLayoutChangeListener mSnippetLayoutListener = new OnLayoutChangeListener() {
150 @Override
151 public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
152 int oldTop, int oldRight, int oldBottom) {
153 v.removeOnLayoutChangeListener(this);
154 // We're in a layout, so try not to do anything layout-related here, and post a
155 // runnable instead.
156 v.post(new Runnable() {
157 @Override
158 public void run() {
Alice Yang15dfaa62013-02-13 15:37:42 -0800159 // Framework only started supporting multi-line action bars in JB MR1.1,
160 // so on earlier versions, always use our custom action bar.
161 if (actionBarReportsMultipleLineTitle(mActionBar)) {
162 // Switch over to title mode when the first fragment asks for a subject
163 // remainder. We assume that layout has happened by now, so the
164 // SnippetTextView already has measurements it needs to calculate
165 // remainders, and it's safe to switch over to TITLE mode to inherit
166 // standard system behaviors.
167 setTitleModeFlags(ActionBar.DISPLAY_SHOW_TITLE |
168 DISPLAY_TITLE_MULTIPLE_LINES);
Andy Huang9da91d32013-01-30 15:27:00 -0800169
Alice Yang15dfaa62013-02-13 15:37:42 -0800170 // Work around a bug where the title's container is stuck GONE when a title
171 // is set while in CUSTOM mode.
172 mActionBar.setTitle(mActionBar.getTitle());
173 }
Andy Huang9da91d32013-01-30 15:27:00 -0800174 }
175 });
176 }
177 };
178
Alice Yang15dfaa62013-02-13 15:37:42 -0800179 private static boolean actionBarReportsMultipleLineTitle(ActionBar bar) {
180 boolean reports = false;
181 try {
182 if (bar != null) {
183 reports = (ActionBar.class.getField("DISPLAY_TITLE_MULTIPLE_LINES") != null);
184 }
185 } catch (NoSuchFieldException e) {
186 // stay false
187 }
188 return reports;
189 }
190
Vikram Aggarwaldac89fa2013-03-05 16:43:09 -0800191 // Created via view inflation.
192 @SuppressWarnings("unused")
Andy Huang6681e542012-06-14 14:36:45 -0700193 public MailActionBarView(Context context) {
Mindy Pereira68f2e222012-03-07 10:36:54 -0800194 this(context, null);
195 }
196
Andy Huang6681e542012-06-14 14:36:45 -0700197 public MailActionBarView(Context context, AttributeSet attrs) {
Mindy Pereira68f2e222012-03-07 10:36:54 -0800198 this(context, attrs, 0);
199 }
200
Andy Huang6681e542012-06-14 14:36:45 -0700201 public MailActionBarView(Context context, AttributeSet attrs, int defStyle) {
Mindy Pereira68f2e222012-03-07 10:36:54 -0800202 super(context, attrs, defStyle);
Vikram Aggarwalbcb16b92013-01-28 18:05:03 -0800203 final Resources r = getResources();
Vikram Aggarwal26b0bfd2013-03-29 13:05:08 -0700204 mShowConversationSubject = SHOW_ACTIONBAR_SUBJECT
205 && r.getBoolean(R.bool.show_conversation_subject);
Vikram Aggarwalf642b812013-03-15 16:30:21 -0700206 mIsOnTablet = Utils.useTabletUI(r);
Andy Huang5895f7b2012-06-01 17:07:20 -0700207 }
208
209 @Override
210 protected void onFinishInflate() {
211 super.onFinishInflate();
Andy Huang5895f7b2012-06-01 17:07:20 -0700212 mSubjectView = (SnippetTextView) findViewById(R.id.conversation_subject);
Vikram Aggarwal26b0bfd2013-03-29 13:05:08 -0700213 mUnreadView = (TextView) findViewById(R.id.unread_count);
Mindy Pereira68f2e222012-03-07 10:36:54 -0800214 }
215
Andy Huang313ac132013-03-04 23:40:58 -0800216 public void expandSearch() {
217 if (mSearch != null) {
218 mSearch.expandActionView();
219 }
220 }
221
Vikram Aggarwalb17cbc02012-04-06 15:41:46 -0700222 /**
Vikram Aggarwal0dda5732012-04-06 11:20:16 -0700223 * Close the search view if it is expanded.
Vikram Aggarwalb17cbc02012-04-06 15:41:46 -0700224 */
225 public void collapseSearch() {
226 if (mSearch != null) {
227 mSearch.collapseActionView();
228 }
229 }
230
Mindy Pereiraedb135e2012-06-15 08:34:09 -0700231 /**
232 * Get the search menu item.
233 */
234 protected MenuItem getSearch() {
235 return mSearch;
236 }
237
238 /**
239 * Get whether to show the conversation subject in the action bar.
240 */
241 protected boolean showConversationSubject() {
Paul Westbrooka79acac2013-01-31 13:19:41 -0800242 return ViewMode.isConversationMode(mMode) && mShowConversationSubject;
Mindy Pereiraedb135e2012-06-15 08:34:09 -0700243 }
244
Mindy Pereira68f2e222012-03-07 10:36:54 -0800245 public boolean onCreateOptionsMenu(Menu menu) {
246 // If the mode is valid, then set the initial menu
247 if (mMode == ViewMode.UNKNOWN) {
248 return false;
249 }
Mindy Pereira9b623802012-03-07 17:15:49 -0800250 mSearch = menu.findItem(R.id.search);
251 if (mSearch != null) {
252 mSearchWidget = (SearchView) mSearch.getActionView();
Vikram Aggarwal0dda5732012-04-06 11:20:16 -0700253 mSearch.setOnActionExpandListener(this);
Mindy Pereira68f2e222012-03-07 10:36:54 -0800254 SearchManager searchManager = (SearchManager) mActivity.getActivityContext()
255 .getSystemService(Context.SEARCH_SERVICE);
Mindy Pereirafb178492012-03-07 18:56:42 -0800256 if (searchManager != null && mSearchWidget != null) {
Mindy Pereira68f2e222012-03-07 10:36:54 -0800257 SearchableInfo info = searchManager.getSearchableInfo(mActivity.getComponentName());
258 mSearchWidget.setSearchableInfo(info);
259 mSearchWidget.setOnQueryTextListener(this);
Vikram Aggarwal12a7c042012-03-28 16:48:08 -0700260 mSearchWidget.setOnSuggestionListener(this);
Vikram Aggarwal0dda5732012-04-06 11:20:16 -0700261 mSearchWidget.setIconifiedByDefault(true);
Mindy Pereira68f2e222012-03-07 10:36:54 -0800262 }
263 }
264 mHelpItem = menu.findItem(R.id.help_info_menu_item);
Paul Westbrook517743e2012-03-22 10:40:46 -0700265 mSendFeedbackItem = menu.findItem(R.id.feedback_menu_item);
Mindy Pereira9b623802012-03-07 17:15:49 -0800266 mRefreshItem = menu.findItem(R.id.refresh);
Marc Blankedcab012012-04-04 12:42:38 -0700267 mFolderSettingsItem = menu.findItem(R.id.folder_options);
Mindy Pereira68f2e222012-03-07 10:36:54 -0800268 return true;
269 }
270
271 public int getOptionsMenuId() {
272 // Relies on the ordering of the view modes, since they are integer constants.
273 final int[] modeMenu = {
274 // 0: UNKNOWN
275 R.menu.conversation_list_menu,
276 // 1: CONVERSATION
277 R.menu.conversation_actions,
278 // 2: CONVERSATION_LIST
279 R.menu.conversation_list_menu,
280 // 3: FOLDER_LIST
281 R.menu.folder_list_menu,
282 // 4: SEARCH_RESULTS_LIST
283 R.menu.conversation_list_search_results_actions,
284 // 5: SEARCH_RESULTS_CONVERSATION
Paul Westbrook2d50bcd2012-04-10 11:53:47 -0700285 R.menu.conversation_search_results_actions,
286 // 6: WAITING_FOR_ACCOUNT_INITIALIZATION
287 R.menu.wait_mode_actions
Mindy Pereira68f2e222012-03-07 10:36:54 -0800288 };
289 return modeMenu[mMode];
290 }
291
Vikram Aggarwal7c401b72012-08-13 16:43:47 -0700292 public void initialize(ControllableActivity activity, ActivityController callback,
Vikram Aggarwaldac89fa2013-03-05 16:43:09 -0800293 ActionBar actionBar) {
Mindy Pereira68f2e222012-03-07 10:36:54 -0800294 mActionBar = actionBar;
Vikram Aggarwala7997952012-03-09 10:30:13 -0800295 mController = callback;
Mindy Pereira68f2e222012-03-07 10:36:54 -0800296 mActivity = activity;
Vikram Aggarwal50ff0e52013-03-14 13:58:02 -0700297 mFolderObserver = new FolderObserver() {
298 @Override
299 public void onChanged(Folder newFolder) {
300 onFolderUpdated(newFolder);
301 }
302 };
Vikram Aggarwal26b0bfd2013-03-29 13:05:08 -0700303 // Return values are purposely discarded. Initialization happens quite early, and we don't
304 // have a valid folder, or a valid list of accounts.
Vikram Aggarwal50ff0e52013-03-14 13:58:02 -0700305 mFolderObserver.initialize(mController);
Vikram Aggarwal6b641ba2013-03-15 16:07:24 -0700306 mAllAccountObserver = new AllAccountObserver() {
307 @Override
308 public void onChanged(Account[] allAccounts) {
309 mHaveMultipleAccounts = (allAccounts.length > 1);
310 }
311 };
312 mAllAccountObserver.initialize(mController);
Scott Banachowski53a615d2012-12-19 15:31:20 -0800313 updateAccount(mAccountObserver.initialize(activity.getAccountController()));
314 }
315
316 private void updateAccount(Account account) {
317 mAccount = account;
318 if (mAccount != null) {
Vikram Aggarwalbc462ca2013-03-15 10:41:03 -0700319 final ContentResolver resolver = mActivity.getActivityContext().getContentResolver();
320 final Bundle bundle = new Bundle(1);
Scott Banachowski53a615d2012-12-19 15:31:20 -0800321 bundle.putParcelable(UIProvider.SetCurrentAccountColumns.ACCOUNT, account);
Vikram Aggarwala51ef9f2013-04-02 13:25:35 -0700322 final UpdateProvider updater = new UpdateProvider(mAccount.uri, resolver);
323 updater.execute(bundle);
Vikram Aggarwalf642b812013-03-15 16:30:21 -0700324 setFolderAndAccount();
Scott Banachowski53a615d2012-12-19 15:31:20 -0800325 }
Vikram Aggarwalabd24d82012-04-26 13:23:14 -0700326 }
Andy Huange303b9b2012-04-19 16:31:09 -0700327
Vikram Aggarwalabd24d82012-04-26 13:23:14 -0700328 /**
Mindy Pereira68f2e222012-03-07 10:36:54 -0800329 * Called by the owner of the ActionBar to set the
330 * folder that is currently being displayed.
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800331 */
Mindy Pereira68f2e222012-03-07 10:36:54 -0800332 public void setFolder(Folder folder) {
Mindy Pereira641de652012-08-02 15:21:50 -0700333 setRefreshInProgress(false);
Marc Blankedcab012012-04-04 12:42:38 -0700334 mFolder = folder;
Vikram Aggarwalf642b812013-03-15 16:30:21 -0700335 setFolderAndAccount();
Vikram Aggarwal1dd77c92012-08-21 09:27:40 -0700336 mActivity.invalidateOptionsMenu();
Mindy Pereira68f2e222012-03-07 10:36:54 -0800337 }
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800338
Mindy Pereira641de652012-08-02 15:21:50 -0700339 public void onDestroy() {
340 if (mFolderObserver != null) {
Vikram Aggarwal50ff0e52013-03-14 13:58:02 -0700341 mFolderObserver.unregisterAndDestroy();
Mindy Pereira641de652012-08-02 15:21:50 -0700342 mFolderObserver = null;
343 }
Vikram Aggarwal6b641ba2013-03-15 16:07:24 -0700344 if (mAllAccountObserver != null) {
345 mAllAccountObserver.unregisterAndDestroy();
346 mAllAccountObserver = null;
347 }
Vikram Aggarwal7c401b72012-08-13 16:43:47 -0700348 mAccountObserver.unregisterAndDestroy();
Mindy Pereira68f2e222012-03-07 10:36:54 -0800349 }
350
Vikram Aggarwala7997952012-03-09 10:30:13 -0800351 @Override
Mindy Pereira68f2e222012-03-07 10:36:54 -0800352 public void onViewModeChanged(int newMode) {
353 mMode = newMode;
Mindy Pereira68f2e222012-03-07 10:36:54 -0800354 mActivity.invalidateOptionsMenu();
Vikram Aggarwal1a3f3fc2012-07-18 14:49:08 -0700355 // Check if we are either on a phone, or in Conversation mode on tablet. For these, the
356 // recent folders is enabled.
Andy Huangd736a382012-08-29 13:08:58 -0700357 switch (mMode) {
358 case ViewMode.UNKNOWN:
Vikram Aggarwal49499e62013-02-08 16:39:08 -0800359 closeSearchField();
Andy Huangd736a382012-08-29 13:08:58 -0700360 break;
361 case ViewMode.CONVERSATION_LIST:
Vikram Aggarwal49499e62013-02-08 16:39:08 -0800362 closeSearchField();
Andy Huangd736a382012-08-29 13:08:58 -0700363 showNavList();
364 break;
365 case ViewMode.CONVERSATION:
Vikram Aggarwal49499e62013-02-08 16:39:08 -0800366 closeSearchField();
Andy Huangd736a382012-08-29 13:08:58 -0700367 mActionBar.setDisplayHomeAsUpEnabled(true);
368 if (!mShowConversationSubject) {
369 showNavList();
370 } else {
Andy Huangaf65e732013-01-28 20:45:40 -0800371 setSnippetMode();
Andy Huangd736a382012-08-29 13:08:58 -0700372 }
373 break;
374 case ViewMode.FOLDER_LIST:
Vikram Aggarwal49499e62013-02-08 16:39:08 -0800375 closeSearchField();
Andy Huangd736a382012-08-29 13:08:58 -0700376 mActionBar.setDisplayHomeAsUpEnabled(true);
Andy Huangaf65e732013-01-28 20:45:40 -0800377 setFoldersMode();
Andy Huangd736a382012-08-29 13:08:58 -0700378 break;
379 case ViewMode.WAITING_FOR_ACCOUNT_INITIALIZATION:
380 // We want the user to be able to switch accounts while waiting for an account
381 // to sync.
382 showNavList();
383 break;
384 }
Mindy Pereira68f2e222012-03-07 10:36:54 -0800385 }
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800386
Vikram Aggarwal49499e62013-02-08 16:39:08 -0800387 /**
388 * Close the search query entry field to avoid keyboard events, and to restore the actionbar
389 * to non-search mode.
390 */
Vikram Aggarwaldac89fa2013-03-05 16:43:09 -0800391 private void closeSearchField() {
Vikram Aggarwal49499e62013-02-08 16:39:08 -0800392 if (mSearch == null) {
393 return;
394 }
395 mSearch.collapseActionView();
396 }
397
Mindy Pereiraedb135e2012-06-15 08:34:09 -0700398 protected int getMode() {
399 return mMode;
400 }
401
Mindy Pereirab849dfb2012-03-07 18:13:15 -0800402 public boolean onPrepareOptionsMenu(Menu menu) {
Mindy Pereira68f2e222012-03-07 10:36:54 -0800403 // We start out with every option enabled. Based on the current view, we disable actions
404 // that are possible.
Vikram Aggarwal95b28ab2012-04-26 15:53:09 -0700405 LogUtils.d(LOG_TAG, "ActionBarView.onPrepareOptionsMenu().");
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800406
Andy Huangd736a382012-08-29 13:08:58 -0700407 // TODO: move refresh stuff into setRefreshInProgress. can just setActionView without
408 // invalidating.
Mindy Pereira9b623802012-03-07 17:15:49 -0800409 if (mRefreshInProgress) {
410 if (mRefreshItem != null) {
411 if (mRefreshActionView == null) {
412 mRefreshItem.setActionView(R.layout.action_bar_indeterminate_progress);
413 mRefreshActionView = mRefreshItem.getActionView();
414 } else {
415 mRefreshItem.setActionView(mRefreshActionView);
416 }
417 }
418 } else {
419 if (mRefreshItem != null) {
420 mRefreshItem.setActionView(null);
421 }
422 }
Mindy Pereira68f2e222012-03-07 10:36:54 -0800423 if (mHelpItem != null) {
424 mHelpItem.setVisible(mAccount != null
425 && mAccount.supportsCapability(AccountCapabilities.HELP_CONTENT));
426 }
Paul Westbrook517743e2012-03-22 10:40:46 -0700427 if (mSendFeedbackItem != null) {
428 mSendFeedbackItem.setVisible(mAccount != null
429 && mAccount.supportsCapability(AccountCapabilities.SEND_FEEDBACK));
430 }
Marc Blankedcab012012-04-04 12:42:38 -0700431 if (mFolderSettingsItem != null) {
432 mFolderSettingsItem.setVisible(mFolder != null
433 && mFolder.supportsCapability(FolderCapabilities.SUPPORTS_SETTINGS));
434 }
Mindy Pereira62c71792012-07-18 09:14:29 -0700435
Mindy Pereira9b623802012-03-07 17:15:49 -0800436 switch (mMode) {
Yorke Leef807ba72012-09-20 17:18:05 -0700437 case ViewMode.CONVERSATION:
438 case ViewMode.SEARCH_RESULTS_CONVERSATION:
439 // We update the ActionBar options when we are entering conversation view because
440 // waiting for the AbstractConversationViewFragment to do it causes duplicate icons
441 // to show up during the time between the conversation is selected and the fragment
442 // is added.
443 setConversationModeOptions(menu);
444 break;
Mindy Pereira68f2e222012-03-07 10:36:54 -0800445 case ViewMode.CONVERSATION_LIST:
Mindy Pereira30fd47b2012-03-09 09:24:00 -0800446 // Show compose, search, folders, and sync based on the account
Mindy Pereira68f2e222012-03-07 10:36:54 -0800447 // The only option that needs to be disabled is search
Mindy Pereira863e4412012-03-23 12:21:38 -0700448 Utils.setMenuItemVisibility(menu, R.id.search,
Mindy Pereira9b623802012-03-07 17:15:49 -0800449 mAccount.supportsCapability(AccountCapabilities.FOLDER_SERVER_SEARCH));
Mindy Pereira68f2e222012-03-07 10:36:54 -0800450 break;
Mindy Pereira68f2e222012-03-07 10:36:54 -0800451 }
mindypf5a24422012-09-04 13:28:11 -0700452 return false;
Mindy Pereira68f2e222012-03-07 10:36:54 -0800453 }
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800454
Vikram Aggarwalabd24d82012-04-26 13:23:14 -0700455 /**
456 * Put the ActionBar in List navigation mode. This starts the spinner up if it is missing.
457 */
Mindy Pereira72a9f392012-03-21 09:41:09 -0700458 private void showNavList() {
Vikram Aggarwal26b0bfd2013-03-29 13:05:08 -0700459 setTitleModeFlags(ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_SHOW_CUSTOM);
Vikram Aggarwal81064f82013-04-02 13:25:35 -0700460 if (mUnreadView != null) {
461 mUnreadView.setVisibility(View.VISIBLE);
462 }
Andy Huangaf65e732013-01-28 20:45:40 -0800463 mSubjectView.setVisibility(View.GONE);
Vikram Aggarwalf642b812013-03-15 16:30:21 -0700464 setFolderAndAccount();
Mindy Pereira72a9f392012-03-21 09:41:09 -0700465 }
466
Vikram Aggarwalabd24d82012-04-26 13:23:14 -0700467 /**
Andy Huangaf65e732013-01-28 20:45:40 -0800468 * Set the actionbar mode to "snippet" mode: no list navigation, show what looks like 2-line
469 * "standard" snippet. Later on, {@link #getUnshownSubject(String)} will seamlessly switch
470 * back to bog-standard SHOW_TITLE mode once the text remainders can safely be determined.
Vikram Aggarwalabd24d82012-04-26 13:23:14 -0700471 */
Paul Westbrooka79acac2013-01-31 13:19:41 -0800472 protected void setSnippetMode() {
Andy Huangaf65e732013-01-28 20:45:40 -0800473 setTitleModeFlags(ActionBar.DISPLAY_SHOW_CUSTOM);
Vikram Aggarwal81064f82013-04-02 13:25:35 -0700474 if (mUnreadView != null) {
475 mUnreadView.setVisibility(View.GONE);
476 }
Andy Huangaf65e732013-01-28 20:45:40 -0800477 mSubjectView.setVisibility(View.VISIBLE);
Andy Huang9da91d32013-01-30 15:27:00 -0800478 mSubjectView.addOnLayoutChangeListener(mSnippetLayoutListener);
Andy Huangaf65e732013-01-28 20:45:40 -0800479 }
480
481 private void setFoldersMode() {
482 setTitleModeFlags(ActionBar.DISPLAY_SHOW_TITLE);
Vikram Aggarwal81064f82013-04-02 13:25:35 -0700483 if (mUnreadView != null) {
484 mUnreadView.setVisibility(View.GONE);
485 }
Andy Huangaf65e732013-01-28 20:45:40 -0800486 mActionBar.setTitle(R.string.folders);
Vikram Aggarwal6b641ba2013-03-15 16:07:24 -0700487 if (mHaveMultipleAccounts) {
488 mActionBar.setSubtitle(mAccount.name);
489 }
mindyp6fb1b622012-09-05 09:27:08 -0700490 }
491
492 /**
493 * Set the actionbar mode to empty: no title, no custom content.
494 */
495 protected void setEmptyMode() {
Vikram Aggarwalbc462ca2013-03-15 10:41:03 -0700496 setTitleModeFlags(ActionBar.DISPLAY_SHOW_TITLE);
Alice Yang760d9562013-04-02 13:13:24 -0700497 if (mSubjectView != null) {
498 mSubjectView.setVisibility(View.GONE);
499 }
500 if (mUnreadView != null) {
501 mUnreadView.setVisibility(View.GONE);
502 }
Vikram Aggarwalabd24d82012-04-26 13:23:14 -0700503 }
504
Mindy Pereira68f2e222012-03-07 10:36:54 -0800505 public void removeBackButton() {
506 if (mActionBar == null) {
507 return;
508 }
Vikram Aggarwal649b9ea2012-08-27 12:15:20 -0700509 // Remove the back button but continue showing an icon.
510 final int mask = ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME;
511 mActionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_HOME, mask);
Mindy Pereira68f2e222012-03-07 10:36:54 -0800512 mActivity.getActionBar().setHomeButtonEnabled(false);
513 }
Mindy Pereirabc57bf12012-02-29 14:39:09 -0800514
Mindy Pereira68f2e222012-03-07 10:36:54 -0800515 public void setBackButton() {
516 if (mActionBar == null){
517 return;
518 }
Vikram Aggarwal649b9ea2012-08-27 12:15:20 -0700519 // Show home as up, and show an icon.
520 final int mask = ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME;
521 mActionBar.setDisplayOptions(mask, mask);
Mindy Pereira68f2e222012-03-07 10:36:54 -0800522 mActivity.getActionBar().setHomeButtonEnabled(true);
523 }
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800524
Mindy Pereira68f2e222012-03-07 10:36:54 -0800525 @Override
526 public boolean onQueryTextSubmit(String query) {
Mindy Pereira4ce59942012-03-08 09:57:35 -0800527 if (mSearch != null) {
528 mSearch.collapseActionView();
529 mSearchWidget.setQuery("", false);
530 }
Andy Huang313ac132013-03-04 23:40:58 -0800531 mController.executeSearch(query.trim());
Mindy Pereira68f2e222012-03-07 10:36:54 -0800532 return true;
533 }
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800534
Mindy Pereira68f2e222012-03-07 10:36:54 -0800535 @Override
536 public boolean onQueryTextChange(String newText) {
Mindy Pereira68f2e222012-03-07 10:36:54 -0800537 return false;
538 }
Mindy Pereira9b623802012-03-07 17:15:49 -0800539
Mindy Pereira641de652012-08-02 15:21:50 -0700540 private boolean setRefreshInProgress(boolean inProgress) {
Mindy Pereira9b623802012-03-07 17:15:49 -0800541 if (inProgress != mRefreshInProgress) {
542 mRefreshInProgress = inProgress;
543 if (mSearch == null || !mSearch.isActionViewExpanded()) {
544 mHandler.post(mInvalidateMenu);
545 }
546 return true;
547 }
548 return false;
549 }
550
Mindy Pereira641de652012-08-02 15:21:50 -0700551 private void onRefreshStarted() {
Mindy Pereira9b623802012-03-07 17:15:49 -0800552 setRefreshInProgress(true);
553 }
554
Vikram Aggarwal41b9e8f2012-09-25 10:15:04 -0700555 private void onRefreshStopped() {
Paul Westbrook4f393ec2012-08-10 09:19:50 -0700556 setRefreshInProgress(false);
Mindy Pereira9b623802012-03-07 17:15:49 -0800557 }
Mindy Pereirafd0c2972012-03-27 13:50:39 -0700558
Vikram Aggarwal12a7c042012-03-28 16:48:08 -0700559 // Next two methods are called when search suggestions are clicked.
560 @Override
561 public boolean onSuggestionSelect(int position) {
562 return onSuggestionClick(position);
563 }
564
565 @Override
566 public boolean onSuggestionClick(int position) {
567 final Cursor c = mSearchWidget.getSuggestionsAdapter().getCursor();
568 final boolean haveValidQuery = (c != null) && c.moveToPosition(position);
569 if (!haveValidQuery) {
570 LogUtils.d(LOG_TAG, "onSuggestionClick: Couldn't get a search query");
Mindy Pereiraf8fcb802012-06-25 11:43:06 -0700571 // We haven't handled this query, but the default behavior will
572 // leave EXTRA_ACCOUNT un-populated, leading to a crash. So claim
573 // that we have handled the event.
Vikram Aggarwal12a7c042012-03-28 16:48:08 -0700574 return true;
575 }
Mindy Pereirab466bcf2012-06-14 15:52:26 -0700576 collapseSearch();
Mindy Pereira1e180dd2012-08-16 10:24:10 -0700577 // what is in the text field
Mindy Pereiraca97b312012-06-25 14:00:20 -0700578 String queryText = mSearchWidget.getQuery().toString();
Mindy Pereira1e180dd2012-08-16 10:24:10 -0700579 // What the suggested query is
Mindy Pereiraf8fcb802012-06-25 11:43:06 -0700580 String query = c.getString(c.getColumnIndex(SearchManager.SUGGEST_COLUMN_QUERY));
mindyp0fc8fa52012-09-04 10:43:23 -0700581 // If the text the user typed in is a prefix of what is in the search
582 // widget suggestion query, just take the search widget suggestion
583 // query. Otherwise, it is a suffix and we want to remove matching
584 // prefix portions.
585 if (!TextUtils.isEmpty(queryText) && query.indexOf(queryText) != 0) {
Mindy Pereira5e1403c2012-07-18 13:22:11 -0700586 final int queryTokenIndex = queryText
587 .lastIndexOf(SearchRecentSuggestionsProvider.QUERY_TOKEN_SEPARATOR);
588 if (queryTokenIndex > -1) {
589 queryText = queryText.substring(0, queryTokenIndex);
Mindy Pereiraca97b312012-06-25 14:00:20 -0700590 }
591 // Since we auto-complete on each token in a query, if the query the
592 // user typed up until the last token is a substring of the
593 // suggestion they click, make sure we don't double include the
594 // query text. For example:
595 // user types john, that matches john palo alto
596 // User types john p, that matches john john palo alto
597 // Remove the first john
Mindy Pereira5e1403c2012-07-18 13:22:11 -0700598 // Only do this if we have multiple query tokens.
599 if (queryTokenIndex > -1 && !TextUtils.isEmpty(query) && query.contains(queryText)
Mindy Pereiraca97b312012-06-25 14:00:20 -0700600 && queryText.length() < query.length()) {
601 int start = query.indexOf(queryText);
602 query = query.substring(0, start) + query.substring(start + queryText.length());
603 }
604 }
Andy Huang313ac132013-03-04 23:40:58 -0800605 mController.executeSearch(query.trim());
Vikram Aggarwal12a7c042012-03-28 16:48:08 -0700606 return true;
607 }
Mindy Pereiraa46a57f2012-04-03 17:19:31 -0700608
Vikram Aggarwalf642b812013-03-15 16:30:21 -0700609 /**
610 * Uses the current state to update the current folder {@link #mFolder} and the current
611 * account {@link #mAccount} shown in the actionbar.
612 */
613 private void setFolderAndAccount() {
Vikram Aggarwal5fce9922013-04-01 21:17:42 -0700614 // Very little can be done if the actionbar or activity is null.
615 if (mActionBar == null || mActivity == null) {
616 return;
617 }
Vikram Aggarwalf642b812013-03-15 16:30:21 -0700618 // Check if we should be changing the actionbar at all, and back off if not.
Vikram Aggarwal5fce9922013-04-01 21:17:42 -0700619 final boolean isShowingFolderAndAccount = mIsOnTablet || ViewMode.isListMode(mMode);
620 if (!isShowingFolderAndAccount) {
Vikram Aggarwalf642b812013-03-15 16:30:21 -0700621 return;
622 }
Vikram Aggarwalf642b812013-03-15 16:30:21 -0700623 if (mAccount != null && mHaveMultipleAccounts) {
624 mActionBar.setSubtitle(mAccount.name);
625 }
Vikram Aggarwal26b0bfd2013-03-29 13:05:08 -0700626 if (mFolder == null) {
627 return;
628 }
629 mActionBar.setTitle(mFolder.name);
630 if (mUnreadView != null) {
631 mUnreadView.setText(Utils.getUnreadCountString(
632 mActivity.getApplicationContext(), mFolder.unreadCount));
633 }
Vikram Aggarwalbc462ca2013-03-15 10:41:03 -0700634 }
635
Mindy Pereiraa46a57f2012-04-03 17:19:31 -0700636 /**
637 * Notify that the folder has changed.
638 */
639 public void onFolderUpdated(Folder folder) {
Vikram Aggarwal26b0bfd2013-03-29 13:05:08 -0700640 if (folder == null) {
641 return;
642 }
Vikram Aggarwalc18c3382013-04-05 15:29:13 -0700643 mFolder = folder;
Vikram Aggarwalf642b812013-03-15 16:30:21 -0700644 setFolderAndAccount();
Mindy Pereira641de652012-08-02 15:21:50 -0700645 if (folder.isSyncInProgress()) {
646 onRefreshStarted();
647 } else {
648 // Stop the spinner here.
Vikram Aggarwal41b9e8f2012-09-25 10:15:04 -0700649 onRefreshStopped();
Mindy Pereira641de652012-08-02 15:21:50 -0700650 }
Vikram Aggarwal49499e62013-02-08 16:39:08 -0800651 final ConversationListContext listContext = mController == null ? null :
652 mController.getCurrentListContext();
653 if (!ConversationListContext.isSearchResult(listContext)) {
654 closeSearchField();
655 }
Mindy Pereiraa46a57f2012-04-03 17:19:31 -0700656 }
Vikram Aggarwal0dda5732012-04-06 11:20:16 -0700657
658 @Override
659 public boolean onMenuItemActionExpand(MenuItem item) {
660 // Do nothing. Required as part of the interface, we ar only interested in
661 // onMenuItemActionCollapse(MenuItem).
662 // Have to return true here. Unlike other callbacks, the return value here is whether
663 // we want to suppress the action (rather than consume the action). We don't want to
664 // suppress the action.
665 return true;
666 }
667
668 @Override
669 public boolean onMenuItemActionCollapse(MenuItem item) {
Mindy Pereirab466bcf2012-06-14 15:52:26 -0700670 // Work around b/6664203 by manually forcing this view to be VISIBLE
671 // upon ActionView collapse. DISPLAY_SHOW_CUSTOM will still control its final
672 // visibility.
Andy Huang5895f7b2012-06-01 17:07:20 -0700673 setVisibility(VISIBLE);
Mindy Pereirab466bcf2012-06-14 15:52:26 -0700674 // Have to return true here. Unlike other callbacks, the return value
675 // here is whether we want to suppress the action (rather than consume the action). We
676 // don't want to suppress the action.
Vikram Aggarwal0dda5732012-04-06 11:20:16 -0700677 return true;
678 }
Vikram Aggarwal37263972012-04-17 15:51:14 -0700679
Andy Huangaf65e732013-01-28 20:45:40 -0800680 private void setTitleModeFlags(int enabledFlags) {
681 final int mask = ActionBar.DISPLAY_SHOW_TITLE
682 | ActionBar.DISPLAY_SHOW_CUSTOM | DISPLAY_TITLE_MULTIPLE_LINES;
Andy Huangaf65e732013-01-28 20:45:40 -0800683 mActionBar.setDisplayOptions(enabledFlags, mask);
684 }
685
Andy Huang5895f7b2012-06-01 17:07:20 -0700686 @Override
687 public void setSubject(String subject) {
688 if (!mShowConversationSubject) {
689 return;
690 }
691
Alice Yang48706db2013-02-01 17:56:52 -0800692 // Use a smaller font size than the default action bar title text size
693 SpannableStringBuilder builder = new SpannableStringBuilder();
694 SpannableString textSizeSpannable = new SpannableString(subject);
695 textSizeSpannable.setSpan(
696 new TextAppearanceSpan(getContext(), R.style.SubjectActionBarTitleText),
697 0, subject.length(), 0);
698 builder.append(textSizeSpannable);
699
700 mActionBar.setTitle(builder);
Andy Huangaf65e732013-01-28 20:45:40 -0800701 mActionBar.setSubtitle(null);
Andy Huang5895f7b2012-06-01 17:07:20 -0700702 mSubjectView.setText(subject);
703 }
704
705 @Override
Rohan Shah2b288b32013-03-20 13:06:18 -0700706 public void clearSubjectAndUpdate() {
Andy Huang5895f7b2012-06-01 17:07:20 -0700707 if (!mShowConversationSubject) {
708 return;
709 }
Rohan Shah2b288b32013-03-20 13:06:18 -0700710 // Wipe subject view text
Andy Huang5895f7b2012-06-01 17:07:20 -0700711 mSubjectView.setText(null);
Rohan Shah2b288b32013-03-20 13:06:18 -0700712 // Set folder and account as title and subtitle
713 setFolderAndAccount();
Andy Huang5895f7b2012-06-01 17:07:20 -0700714 }
715
716 @Override
717 public String getUnshownSubject(String subject) {
718 if (!mShowConversationSubject) {
719 return subject;
720 }
721
Andy Huang9da91d32013-01-30 15:27:00 -0800722 return mSubjectView.getTextRemainder(subject);
Andy Huangaf65e732013-01-28 20:45:40 -0800723 }
724
Yorke Leef807ba72012-09-20 17:18:05 -0700725 public void setCurrentConversation(Conversation conversation) {
726 mCurrentConversation = conversation;
727 }
728
729 //We need to do this here instead of in the fragment
730 public void setConversationModeOptions(Menu menu) {
731 if (mCurrentConversation == null) {
732 return;
733 }
734 final boolean showMarkImportant = !mCurrentConversation.isImportant();
735 Utils.setMenuItemVisibility(menu, R.id.mark_important, showMarkImportant
736 && mAccount.supportsCapability(UIProvider.AccountCapabilities.MARK_IMPORTANT));
737 Utils.setMenuItemVisibility(menu, R.id.mark_not_important, !showMarkImportant
738 && mAccount.supportsCapability(UIProvider.AccountCapabilities.MARK_IMPORTANT));
739 final boolean showDelete = mFolder != null &&
740 mFolder.supportsCapability(UIProvider.FolderCapabilities.DELETE);
741 Utils.setMenuItemVisibility(menu, R.id.delete, showDelete);
742 // We only want to show the discard drafts menu item if we are not showing the delete menu
743 // item, and the current folder is a draft folder and the account supports discarding
744 // drafts for a conversation
745 final boolean showDiscardDrafts = !showDelete && mFolder != null && mFolder.isDraft() &&
746 mAccount.supportsCapability(AccountCapabilities.DISCARD_CONVERSATION_DRAFTS);
747 Utils.setMenuItemVisibility(menu, R.id.discard_drafts, showDiscardDrafts);
748 final boolean archiveVisible = mAccount.supportsCapability(AccountCapabilities.ARCHIVE)
749 && mFolder != null && mFolder.supportsCapability(FolderCapabilities.ARCHIVE)
750 && !mFolder.isTrash();
751 Utils.setMenuItemVisibility(menu, R.id.archive, archiveVisible);
752 Utils.setMenuItemVisibility(menu, R.id.remove_folder, !archiveVisible && mFolder != null
753 && mFolder.supportsCapability(FolderCapabilities.CAN_ACCEPT_MOVED_MESSAGES)
754 && !mFolder.isProviderFolder());
Alice Yangd7d17b62013-03-26 22:23:25 -0700755 // TODO(alice): reenable "move to" after it works properly with section inbox
756 Utils.setMenuItemVisibility(menu, R.id.move_to, false);
757 // Utils.setMenuItemVisibility(menu, R.id.move_to, mFolder != null
758 // && mFolder.supportsCapability(FolderCapabilities.ALLOWS_REMOVE_CONVERSATION));
Yorke Leef807ba72012-09-20 17:18:05 -0700759 final MenuItem removeFolder = menu.findItem(R.id.remove_folder);
Alice Yang40698e62013-03-14 11:31:53 -0700760 if (mFolder != null && removeFolder != null) {
Yorke Leef807ba72012-09-20 17:18:05 -0700761 removeFolder.setTitle(mActivity.getApplicationContext().getString(
762 R.string.remove_folder, mFolder.name));
763 }
764 Utils.setMenuItemVisibility(menu, R.id.report_spam,
765 mAccount.supportsCapability(AccountCapabilities.REPORT_SPAM) && mFolder != null
766 && mFolder.supportsCapability(FolderCapabilities.REPORT_SPAM)
767 && !mCurrentConversation.spam);
768 Utils.setMenuItemVisibility(menu, R.id.mark_not_spam,
769 mAccount.supportsCapability(AccountCapabilities.REPORT_SPAM) && mFolder != null
770 && mFolder.supportsCapability(FolderCapabilities.MARK_NOT_SPAM)
771 && mCurrentConversation.spam);
772 Utils.setMenuItemVisibility(menu, R.id.report_phishing,
773 mAccount.supportsCapability(AccountCapabilities.REPORT_PHISHING) && mFolder != null
774 && mFolder.supportsCapability(FolderCapabilities.REPORT_PHISHING)
775 && !mCurrentConversation.phishing);
776 Utils.setMenuItemVisibility(menu, R.id.mute,
777 mAccount.supportsCapability(AccountCapabilities.MUTE) && mFolder != null
778 && mFolder.supportsCapability(FolderCapabilities.DESTRUCTIVE_MUTE)
779 && !mCurrentConversation.muted);
780 }
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800781}