blob: f204312777198ed13c36f055781ef09857ea935a [file] [log] [blame]
Mindy Pereira11b0bbd2012-01-24 10:06:17 -08001/*
2 * Copyright (C) 2010 Google Inc.
3 * Licensed to The Android Open Source Project.
4 *
5 * 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
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * 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 */
17
18package com.android.mail.browse;
19
Paul Westbrookbf232c32012-04-18 03:17:41 -070020import android.app.AlertDialog;
Mindy Pereira6c2663d2012-07-20 15:37:29 -070021import android.content.ContentValues;
Paul Westbrookbf232c32012-04-18 03:17:41 -070022import android.content.Context;
23import android.content.DialogInterface;
Marc Blanka6b671d2012-05-25 12:52:02 -070024import android.net.Uri;
Paul Westbrookbf232c32012-04-18 03:17:41 -070025import android.view.ActionMode;
26import android.view.Menu;
27import android.view.MenuInflater;
28import android.view.MenuItem;
Marc Blanka6b671d2012-05-25 12:52:02 -070029import android.widget.Toast;
Paul Westbrookbf232c32012-04-18 03:17:41 -070030
Mindy Pereira11b0bbd2012-01-24 10:06:17 -080031import com.android.mail.R;
Mindy Pereira30d2d322012-02-03 08:40:49 -080032import com.android.mail.providers.Account;
Mindy Pereira11b0bbd2012-01-24 10:06:17 -080033import com.android.mail.providers.Conversation;
Mindy Pereira6c2663d2012-07-20 15:37:29 -070034import com.android.mail.providers.ConversationInfo;
Mindy Pereira4f166de2012-02-14 13:40:58 -080035import com.android.mail.providers.Folder;
Marc Blanka6b671d2012-05-25 12:52:02 -070036import com.android.mail.providers.MailAppProvider;
Mindy Pereira6c2663d2012-07-20 15:37:29 -070037import com.android.mail.providers.MessageInfo;
Mindy Pereiraefe3d252012-03-01 14:20:44 -080038import com.android.mail.providers.Settings;
Mindy Pereiraf98b3182012-02-22 11:07:13 -080039import com.android.mail.providers.UIProvider;
Marc Blankcf164d62012-04-20 08:56:17 -070040import com.android.mail.providers.UIProvider.ConversationColumns;
Paul Westbrookbf232c32012-04-18 03:17:41 -070041import com.android.mail.providers.UIProvider.FolderCapabilities;
Vikram Aggarwal531488e2012-05-29 16:36:52 -070042import com.android.mail.ui.ControllableActivity;
Vikram Aggarwal1ddcf0f2012-01-13 11:45:02 -080043import com.android.mail.ui.ConversationSelectionSet;
44import com.android.mail.ui.ConversationSetObserver;
Vikram Aggarwal531488e2012-05-29 16:36:52 -070045import com.android.mail.ui.ConversationUpdater;
Marc Blanka6b671d2012-05-25 12:52:02 -070046import com.android.mail.ui.DestructiveAction;
Mindy Pereiraf3dfb152012-02-06 12:55:13 -080047import com.android.mail.ui.FoldersSelectionDialog;
Paul Westbrookbf232c32012-04-18 03:17:41 -070048import com.android.mail.ui.RestrictedActivity;
Mindy Pereira07118a02012-04-02 16:35:01 -070049import com.android.mail.ui.SwipeableListView;
Paul Westbrookb334c902012-06-25 11:42:46 -070050import com.android.mail.utils.LogTag;
Mindy Pereira11b0bbd2012-01-24 10:06:17 -080051import com.android.mail.utils.LogUtils;
Mindy Pereiraefe3d252012-03-01 14:20:44 -080052import com.android.mail.utils.Utils;
Mindy Pereira11b0bbd2012-01-24 10:06:17 -080053import com.google.common.annotations.VisibleForTesting;
54
Mindy Pereira6c2663d2012-07-20 15:37:29 -070055import org.json.JSONException;
56
Mindy Pereirad92e9f32012-02-03 09:10:58 -080057import java.util.ArrayList;
Mindy Pereira11b0bbd2012-01-24 10:06:17 -080058import java.util.Collection;
59
Mindy Pereira11b0bbd2012-01-24 10:06:17 -080060/**
61 * A component that displays a custom view for an {@code ActionBar}'s {@code
62 * ContextMode} specific to operating on a set of conversations.
63 */
64public class SelectedConversationsActionMenu implements ActionMode.Callback,
Vikram Aggarwald503df42012-05-11 10:13:35 -070065 ConversationSetObserver {
Mindy Pereira11b0bbd2012-01-24 10:06:17 -080066
Paul Westbrookb334c902012-06-25 11:42:46 -070067 private static final String LOG_TAG = LogTag.getLogTag();
Mindy Pereira11b0bbd2012-01-24 10:06:17 -080068
69 /**
70 * The set of conversations to display the menu for.
71 */
72 protected final ConversationSelectionSet mSelectionSet;
73
Vikram Aggarwald247dc92012-02-10 15:49:01 -080074 private final RestrictedActivity mActivity;
Mindy Pereira11b0bbd2012-01-24 10:06:17 -080075
Vikram Aggarwalcd8bf0a2012-02-14 13:13:18 -080076 /**
77 * Context of the activity. A dialog requires the context of an activity rather than the global
78 * root context of the process. So mContext = mActivity.getApplicationContext() will fail.
79 */
Mindy Pereira11b0bbd2012-01-24 10:06:17 -080080 private final Context mContext;
81
82 @VisibleForTesting
Vikram Aggarwal4f4782b2012-05-30 08:39:09 -070083 private ActionMode mActionMode;
Mindy Pereira11b0bbd2012-01-24 10:06:17 -080084
85 private boolean mActivated = false;
86
87 private Menu mMenu;
88
Vikram Aggarwal531488e2012-05-29 16:36:52 -070089 /** Object that can update conversation state on our behalf. */
90 private final ConversationUpdater mUpdater;
Mindy Pereira30d2d322012-02-03 08:40:49 -080091
Vikram Aggarwal531488e2012-05-29 16:36:52 -070092 private final Account mAccount;
Mindy Pereirad92e9f32012-02-03 09:10:58 -080093
Vikram Aggarwal531488e2012-05-29 16:36:52 -070094 private final Folder mFolder;
Mindy Pereira4f166de2012-02-14 13:40:58 -080095
Vikram Aggarwal531488e2012-05-29 16:36:52 -070096 private final SwipeableListView mListView;
Mindy Pereira07118a02012-04-02 16:35:01 -070097
Vikram Aggarwald247dc92012-02-10 15:49:01 -080098 public SelectedConversationsActionMenu(RestrictedActivity activity,
Vikram Aggarwal4f4782b2012-05-30 08:39:09 -070099 ConversationSelectionSet selectionSet, Account account,
Mindy Pereira07118a02012-04-02 16:35:01 -0700100 Folder folder, SwipeableListView list) {
Mindy Pereira11b0bbd2012-01-24 10:06:17 -0800101 mActivity = activity;
Vikram Aggarwal04dc8192012-04-09 13:07:19 -0700102 mSelectionSet = selectionSet;
Mindy Pereira30d2d322012-02-03 08:40:49 -0800103 mAccount = account;
Mindy Pereira4f166de2012-02-14 13:40:58 -0800104 mFolder = folder;
Mindy Pereira07118a02012-04-02 16:35:01 -0700105 mListView = list;
Vikram Aggarwal04dc8192012-04-09 13:07:19 -0700106
107 mContext = mActivity.getActivityContext();
Vikram Aggarwal531488e2012-05-29 16:36:52 -0700108 mUpdater = ((ControllableActivity) mActivity).getConversationUpdater();
Vikram Aggarwale8a85322012-04-24 09:01:38 -0700109 }
110
Mindy Pereira11b0bbd2012-01-24 10:06:17 -0800111 @Override
112 public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
113 boolean handled = true;
Mindy Pereira8937bf12012-07-23 14:05:02 -0700114 // If the user taps a new menu item, commit any existing destructive actions.
115 mListView.commitDestructiveActions();
Mindy Pereira11b0bbd2012-01-24 10:06:17 -0800116 switch (item.getItemId()) {
117 case R.id.delete:
Vikram Aggarwal7f602f72012-04-30 16:04:06 -0700118 performDestructiveAction(R.id.delete);
Marc Blank8d69d4e2012-01-25 12:04:28 -0800119 break;
Mindy Pereiraf98b3182012-02-22 11:07:13 -0800120 case R.id.archive:
Vikram Aggarwal7f602f72012-04-30 16:04:06 -0700121 performDestructiveAction(R.id.archive);
Mindy Pereiraf98b3182012-02-22 11:07:13 -0800122 break;
Mindy Pereira830c00f2012-02-22 11:43:49 -0800123 case R.id.mute:
Vikram Aggarwal0e091c52012-05-30 15:07:15 -0700124 mUpdater.delete(mSelectionSet.values(), mUpdater.getBatchAction(R.id.mute));
Mindy Pereira830c00f2012-02-22 11:43:49 -0800125 break;
126 case R.id.report_spam:
Vikram Aggarwal0e091c52012-05-30 15:07:15 -0700127 mUpdater.delete(mSelectionSet.values(), mUpdater.getBatchAction(R.id.report_spam));
Mindy Pereira830c00f2012-02-22 11:43:49 -0800128 break;
Paul Westbrook77eee622012-07-10 13:41:57 -0700129 case R.id.mark_not_spam:
130 // Currently, since spam messages are only shown in list with other spam messages,
131 // marking a message not as spam is a destructive action
132 mUpdater.delete(mSelectionSet.values(),
133 mUpdater.getBatchAction(R.id.mark_not_spam));
134 break;
Paul Westbrook76b20622012-07-12 11:45:43 -0700135 case R.id.report_phishing:
136 mUpdater.delete(mSelectionSet.values(),
137 mUpdater.getBatchAction(R.id.report_phishing));
138 break;
Mindy Pereirafebeb5f2012-02-14 15:08:13 -0800139 case R.id.read:
140 markConversationsRead(true);
141 break;
142 case R.id.unread:
143 markConversationsRead(false);
Marc Blank8d69d4e2012-01-25 12:04:28 -0800144 break;
145 case R.id.star:
Mindy Pereirafebeb5f2012-02-14 15:08:13 -0800146 starConversations(true);
147 break;
148 case R.id.remove_star:
Vikram Aggarwal04dc8192012-04-09 13:07:19 -0700149 if (mFolder.type == UIProvider.FolderType.STARRED) {
150 LogUtils.d(LOG_TAG, "We are in a starred folder, removing the star");
Vikram Aggarwal7f602f72012-04-30 16:04:06 -0700151 performDestructiveAction(R.id.remove_star);
Vikram Aggarwal04dc8192012-04-09 13:07:19 -0700152 } else {
153 LogUtils.d(LOG_TAG, "Not in a starred folder.");
154 starConversations(false);
155 }
Mindy Pereira11b0bbd2012-01-24 10:06:17 -0800156 break;
Mindy Pereira30d2d322012-02-03 08:40:49 -0800157 case R.id.change_folder:
Marc Blanka6b671d2012-05-25 12:52:02 -0700158 boolean cantMove = false;
159 Account acct = mAccount;
160 // Special handling for virtual folders
161 if (mFolder.supportsCapability(FolderCapabilities.IS_VIRTUAL)) {
162 Uri accountUri = null;
163 for (Conversation conv: mSelectionSet.values()) {
164 if (accountUri == null) {
165 accountUri = conv.accountUri;
166 } else if (!accountUri.equals(conv.accountUri)) {
167 // Tell the user why we can't do this
168 Toast.makeText(mContext, R.string.cant_move_or_change_labels,
169 Toast.LENGTH_LONG).show();
170 cantMove = true;
171 break;
172 }
173 }
174 if (!cantMove) {
175 // Get the actual account here, so that we display its folders in the dialog
176 acct = MailAppProvider.getAccountFromAccountUri(accountUri);
177 }
178 }
179 if (!cantMove) {
Vikram Aggarwal531488e2012-05-29 16:36:52 -0700180 new FoldersSelectionDialog(mContext, acct, mUpdater,
Marc Blanka6b671d2012-05-25 12:52:02 -0700181 mSelectionSet.values(), true).show();
182 }
Mindy Pereira30d2d322012-02-03 08:40:49 -0800183 break;
Mindy Pereira7f0a9622012-02-29 15:00:34 -0800184 case R.id.mark_important:
185 markConversationsImportant(true);
186 break;
187 case R.id.mark_not_important:
Vikram Aggarwal04dc8192012-04-09 13:07:19 -0700188 if (mFolder.supportsCapability(UIProvider.FolderCapabilities.ONLY_IMPORTANT)) {
Vikram Aggarwal7f602f72012-04-30 16:04:06 -0700189 performDestructiveAction(R.id.mark_not_important);
Vikram Aggarwal04dc8192012-04-09 13:07:19 -0700190 } else {
191 markConversationsImportant(false);
192 }
Mindy Pereira7f0a9622012-02-29 15:00:34 -0800193 break;
Mindy Pereira11b0bbd2012-01-24 10:06:17 -0800194 default:
195 handled = false;
196 break;
197 }
198 return handled;
199 }
200
Vikram Aggarwalad6d6282012-03-28 09:16:14 -0700201 /**
202 * Clear the selection and perform related UI changes to keep the state consistent.
203 */
204 private void clearSelection() {
205 mSelectionSet.clear();
Vikram Aggarwalad6d6282012-03-28 09:16:14 -0700206 }
207
Vikram Aggarwal04dc8192012-04-09 13:07:19 -0700208 /**
209 * Update the underlying list adapter and redraw the menus if necessary.
210 */
211 private void updateSelection() {
Vikram Aggarwal4f4782b2012-05-30 08:39:09 -0700212 mUpdater.refreshConversationList();
Vikram Aggarwal04dc8192012-04-09 13:07:19 -0700213 if (mActionMode != null) {
214 // Calling mActivity.invalidateOptionsMenu doesn't have the correct behavior, since
215 // the action mode is not refreshed when activity's options menu is invalidated.
216 // Since we need to refresh our own menu, it is easy to call onPrepareActionMode
217 // directly.
218 onPrepareActionMode(mActionMode, mActionMode.getMenu());
219 }
220 }
221
Vikram Aggarwal7f602f72012-04-30 16:04:06 -0700222 private void performDestructiveAction(final int id) {
Vikram Aggarwal531488e2012-05-29 16:36:52 -0700223 final DestructiveAction action = mUpdater.getBatchAction(id);
Vikram Aggarwal7d816002012-04-17 17:06:41 -0700224 final Settings settings = mActivity.getSettings();
Mindy Pereiraefe3d252012-03-01 14:20:44 -0800225 final Collection<Conversation> conversations = mSelectionSet.values();
Vikram Aggarwal7d816002012-04-17 17:06:41 -0700226 final boolean showDialog = (settings != null
227 && (id == R.id.delete) ? settings.confirmDelete : settings.confirmArchive);
Mindy Pereiraefe3d252012-03-01 14:20:44 -0800228 if (showDialog) {
229 int resId = id == R.id.delete ? R.plurals.confirm_delete_conversation
230 : R.plurals.confirm_archive_conversation;
231 CharSequence message = Utils.formatPlural(mContext, resId, conversations.size());
232 new AlertDialog.Builder(mContext).setMessage(message)
233 .setPositiveButton(R.string.ok, new AlertDialog.OnClickListener() {
234 @Override
235 public void onClick(DialogInterface dialog, int which) {
Vikram Aggarwal09a4bfe2012-04-23 13:07:50 -0700236 destroy(id, conversations, action);
Mindy Pereiraefe3d252012-03-01 14:20:44 -0800237 }
Mindy Pereiraefe3d252012-03-01 14:20:44 -0800238 }).setNegativeButton(R.string.cancel, null).create().show();
239 } else {
Vikram Aggarwal09a4bfe2012-04-23 13:07:50 -0700240 destroy(id, conversations, action);
Mindy Pereira07118a02012-04-02 16:35:01 -0700241 }
242 }
243
Vikram Aggarwal7f602f72012-04-30 16:04:06 -0700244 private void destroy(int id, final Collection<Conversation> conversations,
245 final DestructiveAction listener) {
Mindy Pereira07118a02012-04-02 16:35:01 -0700246 if (id == R.id.archive) {
247 ArrayList<ConversationItemView> views = new ArrayList<ConversationItemView>();
248 for (ConversationItemView view : mSelectionSet.views()) {
249 views.add(view);
250 }
251 mListView.archiveItems(views, listener);
252 } else {
Vikram Aggarwal4f4782b2012-05-30 08:39:09 -0700253 mUpdater.delete(conversations, listener);
Mindy Pereiraefe3d252012-03-01 14:20:44 -0800254 }
255 }
256
Vikram Aggarwal0e091c52012-05-30 15:07:15 -0700257 /**
258 * Marks the read state of currently selected conversations (<b>and</b> the backing storage)
259 * to the value provided here.
260 * @param read is true if the conversations are to be marked as read, false if they are to be
261 * marked unread.
262 */
Mindy Pereirafebeb5f2012-02-14 15:08:13 -0800263 private void markConversationsRead(boolean read) {
Mindy Pereira6c2663d2012-07-20 15:37:29 -0700264 final Collection<Conversation> targets = mSelectionSet.values();
265 ContentValues values;
266 ConversationInfo info;
267 for (Conversation target : targets) {
268 values = new ContentValues();
269 values.put(ConversationColumns.READ, read);
270 info = target.conversationInfo;
271 if (info != null) {
272 try {
273 info.markRead(read);
274 values.put(ConversationColumns.CONVERSATION_INFO,
275 ConversationInfo.toString(info));
276 } catch (JSONException e) {
277 LogUtils.e(LOG_TAG, e, "Error updating conversation info");
278 }
279 }
280 mUpdater.updateConversation(Conversation.listOf(target), values);
281 }
Vikram Aggarwal0e091c52012-05-30 15:07:15 -0700282 // Update the conversations in the selection too.
Mindy Pereira6c2663d2012-07-20 15:37:29 -0700283 for (final Conversation c : targets) {
Vikram Aggarwal0e091c52012-05-30 15:07:15 -0700284 c.read = read;
285 }
Vikram Aggarwal04dc8192012-04-09 13:07:19 -0700286 updateSelection();
Mindy Pereira7f0a9622012-02-29 15:00:34 -0800287 }
288
Vikram Aggarwal04dc8192012-04-09 13:07:19 -0700289 /**
Vikram Aggarwal0e091c52012-05-30 15:07:15 -0700290 * Marks the important state of currently selected conversations (<b>and</b> the backing
291 * storage) to the value provided here.
292 * @param important is true if the conversations are to be marked as important, false if they
293 * are to be marked not important.
294 */
295 private void markConversationsImportant(boolean important) {
296 final Collection<Conversation> target = mSelectionSet.values();
297 final int priority = important ? UIProvider.ConversationPriority.HIGH
298 : UIProvider.ConversationPriority.LOW;
299 mUpdater.updateConversation(target, ConversationColumns.PRIORITY, priority);
300 // Update the conversations in the selection too.
301 for (final Conversation c : target) {
302 c.priority = priority;
303 }
304 updateSelection();
305 }
306
307 /**
308 * Marks the selected conversations with the star setting provided here.
Vikram Aggarwal04dc8192012-04-09 13:07:19 -0700309 * @param star true if you want all the conversations to have stars, false if you want to remove
310 * stars from all conversations
311 */
Mindy Pereirafebeb5f2012-02-14 15:08:13 -0800312 private void starConversations(boolean star) {
Vikram Aggarwal0e091c52012-05-30 15:07:15 -0700313 final Collection<Conversation> target = mSelectionSet.values();
314 mUpdater.updateConversation(target, ConversationColumns.STARRED, star);
315 // Update the conversations in the selection too.
316 for (final Conversation c : target) {
317 c.starred = star;
318 }
Vikram Aggarwal04dc8192012-04-09 13:07:19 -0700319 updateSelection();
Mindy Pereirafebeb5f2012-02-14 15:08:13 -0800320 }
321
Mindy Pereira11b0bbd2012-01-24 10:06:17 -0800322 @Override
323 public boolean onCreateActionMode(ActionMode mode, Menu menu) {
324 mSelectionSet.addObserver(this);
Vikram Aggarwal7f602f72012-04-30 16:04:06 -0700325 final MenuInflater inflater = mActivity.getMenuInflater();
Mindy Pereira11b0bbd2012-01-24 10:06:17 -0800326 inflater.inflate(R.menu.conversation_list_selection_actions_menu, menu);
327 mActionMode = mode;
328 mMenu = menu;
329 updateCount();
330 return true;
331 }
332
333 @Override
334 public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
Mindy Pereirafebeb5f2012-02-14 15:08:13 -0800335 // Determine read/ unread
336 // Star/ unstar
Vikram Aggarwal04dc8192012-04-09 13:07:19 -0700337 final Collection<Conversation> conversations = mSelectionSet.values();
Mindy Pereirafebeb5f2012-02-14 15:08:13 -0800338 boolean showStar = false;
339 boolean showMarkUnread = false;
Mindy Pereira7f0a9622012-02-29 15:00:34 -0800340 boolean showMarkImportant = false;
Paul Westbrook77eee622012-07-10 13:41:57 -0700341 boolean showMarkNotSpam = false;
Paul Westbrook76b20622012-07-12 11:45:43 -0700342 boolean showMarkAsPhishing = false;
Mindy Pereira7f0a9622012-02-29 15:00:34 -0800343
Mindy Pereirafebeb5f2012-02-14 15:08:13 -0800344 for (Conversation conversation : conversations) {
345 if (!conversation.starred) {
346 showStar = true;
347 }
348 if (conversation.read) {
349 showMarkUnread = true;
350 }
Mindy Pereira7f0a9622012-02-29 15:00:34 -0800351 if (!conversation.isImportant()) {
352 showMarkImportant = true;
353 }
Paul Westbrook77eee622012-07-10 13:41:57 -0700354 if (conversation.spam) {
355 showMarkNotSpam = true;
356 }
Paul Westbrook76b20622012-07-12 11:45:43 -0700357 if (!conversation.phishing) {
358 showMarkAsPhishing = true;
359 }
360 if (showStar && showMarkUnread && showMarkImportant && showMarkNotSpam &&
361 showMarkAsPhishing) {
Mindy Pereirafebeb5f2012-02-14 15:08:13 -0800362 break;
363 }
364 }
Paul Westbrook334e64a2012-02-23 13:26:35 -0800365 final MenuItem star = menu.findItem(R.id.star);
Mindy Pereirafebeb5f2012-02-14 15:08:13 -0800366 star.setVisible(showStar);
Paul Westbrook334e64a2012-02-23 13:26:35 -0800367 final MenuItem unstar = menu.findItem(R.id.remove_star);
Mindy Pereirafebeb5f2012-02-14 15:08:13 -0800368 unstar.setVisible(!showStar);
Paul Westbrook334e64a2012-02-23 13:26:35 -0800369 final MenuItem read = menu.findItem(R.id.read);
Mindy Pereirafebeb5f2012-02-14 15:08:13 -0800370 read.setVisible(!showMarkUnread);
Paul Westbrook334e64a2012-02-23 13:26:35 -0800371 final MenuItem unread = menu.findItem(R.id.unread);
Mindy Pereirafebeb5f2012-02-14 15:08:13 -0800372 unread.setVisible(showMarkUnread);
Paul Westbrook334e64a2012-02-23 13:26:35 -0800373 final MenuItem archive = menu.findItem(R.id.archive);
374 archive.setVisible(mAccount.supportsCapability(UIProvider.AccountCapabilities.ARCHIVE) &&
375 mFolder.supportsCapability(FolderCapabilities.ARCHIVE));
376 final MenuItem spam = menu.findItem(R.id.report_spam);
377 spam.setVisible(mAccount.supportsCapability(UIProvider.AccountCapabilities.REPORT_SPAM) &&
Paul Westbrook77eee622012-07-10 13:41:57 -0700378 mFolder.supportsCapability(FolderCapabilities.REPORT_SPAM));
379 final MenuItem notSpam = menu.findItem(R.id.mark_not_spam);
380 notSpam.setVisible(showMarkNotSpam &&
381 mAccount.supportsCapability(UIProvider.AccountCapabilities.REPORT_SPAM) &&
382 mFolder.supportsCapability(FolderCapabilities.MARK_NOT_SPAM));
Paul Westbrook76b20622012-07-12 11:45:43 -0700383 final MenuItem phishing = menu.findItem(R.id.report_phishing);
384 phishing.setVisible(showMarkAsPhishing &&
385 mAccount.supportsCapability(UIProvider.AccountCapabilities.REPORT_PHISHING) &&
386 mFolder.supportsCapability(FolderCapabilities.REPORT_PHISHING));
387
Paul Westbrook334e64a2012-02-23 13:26:35 -0800388 final MenuItem mute = menu.findItem(R.id.mute);
Mindy Pereira830c00f2012-02-22 11:43:49 -0800389 mute.setVisible(mAccount.supportsCapability(UIProvider.AccountCapabilities.MUTE));
Mindy Pereira7f0a9622012-02-29 15:00:34 -0800390 final MenuItem markImportant = menu.findItem(R.id.mark_important);
391 markImportant.setVisible(showMarkImportant
392 && mAccount.supportsCapability(UIProvider.AccountCapabilities.MARK_IMPORTANT));
393 final MenuItem markNotImportant = menu.findItem(R.id.mark_not_important);
394 markNotImportant.setVisible(!showMarkImportant
395 && mAccount.supportsCapability(UIProvider.AccountCapabilities.MARK_IMPORTANT));
396
Mindy Pereira11b0bbd2012-01-24 10:06:17 -0800397 return true;
398 }
399
Mindy Pereira11b0bbd2012-01-24 10:06:17 -0800400 @Override
401 public void onDestroyActionMode(ActionMode mode) {
402 mActionMode = null;
403 // The action mode may have been destroyed due to this menu being deactivated, in which
404 // case resources need not be cleaned up. However, if it was destroyed while this menu is
405 // active, that implies the user hit "Done" in the top right, and resources need cleaning.
406 if (mActivated) {
407 destroy();
Mindy Pereira11b0bbd2012-01-24 10:06:17 -0800408 }
409 mMenu = null;
410 }
411
412 @Override
Vikram Aggarwal1ddcf0f2012-01-13 11:45:02 -0800413 public void onSetPopulated(ConversationSelectionSet set) {
Mindy Pereira11b0bbd2012-01-24 10:06:17 -0800414 // Noop. This object can only exist while the set is non-empty.
415 }
416
417 @Override
Vikram Aggarwal1ddcf0f2012-01-13 11:45:02 -0800418 public void onSetEmpty() {
Vikram Aggarwalad6d6282012-03-28 09:16:14 -0700419 LogUtils.d(LOG_TAG, "onSetEmpty called.");
Mindy Pereira11b0bbd2012-01-24 10:06:17 -0800420 destroy();
421 }
422
423 @Override
424 public void onSetChanged(ConversationSelectionSet set) {
425 // If the set is empty, the menu buttons are invalid and most like the menu will be cleaned
426 // up. Avoid making any changes to stop flickering ("Add Star" -> "Remove Star") just
427 // before hiding the menu.
428 if (set.isEmpty()) {
429 return;
430 }
Mindy Pereira11b0bbd2012-01-24 10:06:17 -0800431 updateCount();
432 }
433
434 /**
435 * Updates the visible count of how many conversations are selected.
436 */
437 private void updateCount() {
438 if (mActionMode != null) {
439 mActionMode.setTitle(mContext.getString(R.string.num_selected, mSelectionSet.size()));
440 }
441 }
442
443 /**
Vikram Aggarwale128fc22012-04-04 12:33:34 -0700444 * Activates and shows this menu (essentially starting an {@link ActionMode}) if the selected
445 * set is non-empty.
Mindy Pereira11b0bbd2012-01-24 10:06:17 -0800446 */
447 public void activate() {
Vikram Aggarwale128fc22012-04-04 12:33:34 -0700448 if (mSelectionSet.isEmpty()) {
449 // We have nothing to do since there is no conversation selected.
450 return;
451 }
Mindy Pereira11b0bbd2012-01-24 10:06:17 -0800452 mActivated = true;
453 if (mActionMode == null) {
454 mActivity.startActionMode(this);
455 }
456 }
457
458 /**
459 * De-activates and hides the menu (essentially disabling the {@link ActionMode}), but maintains
460 * the selection conversation set, and internally updates state as necessary.
461 */
462 public void deactivate() {
463 if (mActionMode != null) {
464 mActivated = false;
465 mActionMode.finish();
466 }
467 }
468
469 @VisibleForTesting
470 public boolean isActivated() {
471 return mActivated;
472 }
473
474 /**
475 * Destroys and cleans up the resources associated with this menu.
476 */
Vikram Aggarwalad6d6282012-03-28 09:16:14 -0700477 private void destroy() {
Mindy Pereira11b0bbd2012-01-24 10:06:17 -0800478 deactivate();
Mindy Pereira11b0bbd2012-01-24 10:06:17 -0800479 mSelectionSet.removeObserver(this);
Vikram Aggarwalad6d6282012-03-28 09:16:14 -0700480 clearSelection();
Vikram Aggarwal4f4782b2012-05-30 08:39:09 -0700481 mUpdater.refreshConversationList();
Mindy Pereira11b0bbd2012-01-24 10:06:17 -0800482 }
483
484 /**
485 * Disable the selected conversations menu item associated with a command
486 * id.
487 */
488 public void disableCommand(int id) {
489 enableMenuItem(id, false);
490 }
491
492 /**
493 * Enable the selected conversations menu item associated with a command
494 * id.
495 */
496 public void enableCommand(int id) {
497 enableMenuItem(id, true);
498 }
499
500 private void enableMenuItem(int id, boolean enable) {
501 if (mActivated) {
502 MenuItem item = mMenu.findItem(id);
503 if (item != null) {
504 item.setEnabled(enable);
505 }
506 }
507 }
Mindy Pereira11b0bbd2012-01-24 10:06:17 -0800508}