blob: 1c6f42a1ed0e7fa91af2a6a5b80b0b6bf8322223 [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
20import com.android.mail.R;
Mindy Pereira30d2d322012-02-03 08:40:49 -080021import com.android.mail.providers.Account;
Mindy Pereira11b0bbd2012-01-24 10:06:17 -080022import com.android.mail.providers.Conversation;
Mindy Pereira4f166de2012-02-14 13:40:58 -080023import com.android.mail.providers.Folder;
Mindy Pereiraefe3d252012-03-01 14:20:44 -080024import com.android.mail.providers.Settings;
Mindy Pereiraf98b3182012-02-22 11:07:13 -080025import com.android.mail.providers.UIProvider;
Paul Westbrook334e64a2012-02-23 13:26:35 -080026import com.android.mail.providers.UIProvider.FolderCapabilities;
Marc Blank8d69d4e2012-01-25 12:04:28 -080027import com.android.mail.providers.UIProvider.ConversationColumns;
Mindy Pereirafac92d72012-02-01 10:58:33 -080028import com.android.mail.ui.AnimatedAdapter;
Mindy Pereira9879d4c2012-01-31 09:34:18 -080029import com.android.mail.ui.ActionCompleteListener;
Vikram Aggarwal1ddcf0f2012-01-13 11:45:02 -080030import com.android.mail.ui.ConversationSelectionSet;
31import com.android.mail.ui.ConversationSetObserver;
Mindy Pereiraf3dfb152012-02-06 12:55:13 -080032import com.android.mail.ui.FoldersSelectionDialog;
Vikram Aggarwald247dc92012-02-10 15:49:01 -080033import com.android.mail.ui.RestrictedActivity;
Mindy Pereirac9d59182012-03-22 16:06:46 -070034import com.android.mail.ui.FoldersSelectionDialog.FolderChangeCommitListener;
Mindy Pereira07118a02012-04-02 16:35:01 -070035import com.android.mail.ui.SwipeableListView;
Mindy Pereira7ad3b872012-02-22 09:10:46 -080036import com.android.mail.ui.UndoBarView.UndoListener;
37import com.android.mail.ui.UndoOperation;
Mindy Pereira11b0bbd2012-01-24 10:06:17 -080038import com.android.mail.utils.LogUtils;
Mindy Pereiraefe3d252012-03-01 14:20:44 -080039import com.android.mail.utils.Utils;
Mindy Pereira11b0bbd2012-01-24 10:06:17 -080040import com.google.common.annotations.VisibleForTesting;
41
Mindy Pereirad92e9f32012-02-03 09:10:58 -080042import java.util.ArrayList;
Mindy Pereira11b0bbd2012-01-24 10:06:17 -080043import java.util.Collection;
Mindy Pereira0825efd2012-02-15 17:30:32 -080044import java.util.HashSet;
Mindy Pereira11b0bbd2012-01-24 10:06:17 -080045
Mindy Pereiraefe3d252012-03-01 14:20:44 -080046import android.app.AlertDialog;
Mindy Pereira11b0bbd2012-01-24 10:06:17 -080047import android.content.Context;
Mindy Pereiraefe3d252012-03-01 14:20:44 -080048import android.content.DialogInterface;
Mindy Pereira11b0bbd2012-01-24 10:06:17 -080049import android.view.ActionMode;
50import android.view.Menu;
51import android.view.MenuInflater;
52import android.view.MenuItem;
53
54/**
55 * A component that displays a custom view for an {@code ActionBar}'s {@code
56 * ContextMode} specific to operating on a set of conversations.
57 */
58public class SelectedConversationsActionMenu implements ActionMode.Callback,
Mindy Pereirac9d59182012-03-22 16:06:46 -070059 ConversationSetObserver, FolderChangeCommitListener {
Mindy Pereira11b0bbd2012-01-24 10:06:17 -080060
61 private static final String LOG_TAG = new LogUtils().getLogTag();
62
63 /**
64 * The set of conversations to display the menu for.
65 */
66 protected final ConversationSelectionSet mSelectionSet;
Marc Blankce538182012-02-03 13:04:27 -080067 /**
68 * The set of conversations to marked for deletion
69 */
70 protected Collection<Conversation> mDeletionSet;
71 /**
72 * The new folder list (after selection)
73 */
Mindy Pereira6778f462012-03-23 18:01:55 -070074 protected ArrayList<Folder> mFolderChangeList;
Mindy Pereira11b0bbd2012-01-24 10:06:17 -080075
Vikram Aggarwald247dc92012-02-10 15:49:01 -080076 private final RestrictedActivity mActivity;
Mindy Pereira11b0bbd2012-01-24 10:06:17 -080077
Vikram Aggarwalcd8bf0a2012-02-14 13:13:18 -080078 /**
79 * Context of the activity. A dialog requires the context of an activity rather than the global
80 * root context of the process. So mContext = mActivity.getApplicationContext() will fail.
81 */
Mindy Pereira11b0bbd2012-01-24 10:06:17 -080082 private final Context mContext;
83
84 @VisibleForTesting
85 ActionMode mActionMode;
86
87 private boolean mActivated = false;
88
89 private Menu mMenu;
90
Mindy Pereirafac92d72012-02-01 10:58:33 -080091 private AnimatedAdapter mListAdapter;
Mindy Pereira9879d4c2012-01-31 09:34:18 -080092
Mindy Pereira96b5c352012-02-01 11:33:40 -080093 private ActionCompleteListener mActionCompleteListener;
94
Mindy Pereira7ad3b872012-02-22 09:10:46 -080095 private UndoListener mUndoListener;
96
Mindy Pereira30d2d322012-02-03 08:40:49 -080097 private Account mAccount;
98
Mindy Pereirad92e9f32012-02-03 09:10:58 -080099 protected int mCheckedItem = 0;
100
Mindy Pereira4f166de2012-02-14 13:40:58 -0800101 private Folder mFolder;
102
Vikram Aggarwale128fc22012-04-04 12:33:34 -0700103 private final ActionCompleteListener mDeleteListener =
104 new DestructiveActionListener(R.id.delete);
105 private final ActionCompleteListener mArchiveListener =
106 new DestructiveActionListener(R.id.archive);
107 private final ActionCompleteListener mMuteListener = new DestructiveActionListener(R.id.mute);
108 private final ActionCompleteListener mSpamListener =
109 new DestructiveActionListener(R.id.report_spam);
Mindy Pereiraf98b3182012-02-22 11:07:13 -0800110
Mindy Pereira07118a02012-04-02 16:35:01 -0700111 private SwipeableListView mListView;
112
Vikram Aggarwald247dc92012-02-10 15:49:01 -0800113 public SelectedConversationsActionMenu(RestrictedActivity activity,
Mindy Pereira96b5c352012-02-01 11:33:40 -0800114 ConversationSelectionSet selectionSet, AnimatedAdapter adapter,
Mindy Pereira7ad3b872012-02-22 09:10:46 -0800115 ActionCompleteListener listener, UndoListener undoListener, Account account,
Mindy Pereira07118a02012-04-02 16:35:01 -0700116 Folder folder, SwipeableListView list) {
Mindy Pereira11b0bbd2012-01-24 10:06:17 -0800117 mSelectionSet = selectionSet;
118 mActivity = activity;
Vikram Aggarwalcd8bf0a2012-02-14 13:13:18 -0800119 mContext = mActivity.getActivityContext();
Mindy Pereirafac92d72012-02-01 10:58:33 -0800120 mListAdapter = adapter;
Mindy Pereira96b5c352012-02-01 11:33:40 -0800121 mActionCompleteListener = listener;
Mindy Pereira7ad3b872012-02-22 09:10:46 -0800122 mUndoListener = undoListener;
Mindy Pereira30d2d322012-02-03 08:40:49 -0800123 mAccount = account;
Mindy Pereira4f166de2012-02-14 13:40:58 -0800124 mFolder = folder;
Mindy Pereira07118a02012-04-02 16:35:01 -0700125 mListView = list;
Mindy Pereira11b0bbd2012-01-24 10:06:17 -0800126 }
127
128 @Override
129 public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
130 boolean handled = true;
Marc Blank8d69d4e2012-01-25 12:04:28 -0800131 Collection<Conversation> conversations = mSelectionSet.values();
Mindy Pereira11b0bbd2012-01-24 10:06:17 -0800132 switch (item.getItemId()) {
133 case R.id.delete:
Mindy Pereiraefe3d252012-03-01 14:20:44 -0800134 performDestructiveAction(R.id.delete, mDeleteListener);
Marc Blank8d69d4e2012-01-25 12:04:28 -0800135 break;
Mindy Pereiraf98b3182012-02-22 11:07:13 -0800136 case R.id.archive:
Mindy Pereiraefe3d252012-03-01 14:20:44 -0800137 performDestructiveAction(R.id.archive, mArchiveListener);
Mindy Pereiraf98b3182012-02-22 11:07:13 -0800138 break;
Mindy Pereira830c00f2012-02-22 11:43:49 -0800139 case R.id.mute:
140 mListAdapter.delete(conversations, mMuteListener);
141 break;
142 case R.id.report_spam:
143 mListAdapter.delete(conversations, mSpamListener);
144 break;
Mindy Pereirafebeb5f2012-02-14 15:08:13 -0800145 case R.id.read:
146 markConversationsRead(true);
147 break;
148 case R.id.unread:
149 markConversationsRead(false);
Marc Blank8d69d4e2012-01-25 12:04:28 -0800150 break;
151 case R.id.star:
Mindy Pereirafebeb5f2012-02-14 15:08:13 -0800152 starConversations(true);
153 break;
154 case R.id.remove_star:
155 starConversations(false);
Mindy Pereira11b0bbd2012-01-24 10:06:17 -0800156 break;
Mindy Pereira30d2d322012-02-03 08:40:49 -0800157 case R.id.change_folder:
158 showChangeFoldersDialog();
159 break;
Mindy Pereira7f0a9622012-02-29 15:00:34 -0800160 case R.id.mark_important:
161 markConversationsImportant(true);
162 break;
163 case R.id.mark_not_important:
164 markConversationsImportant(false);
165 break;
Mindy Pereira11b0bbd2012-01-24 10:06:17 -0800166 default:
167 handled = false;
168 break;
169 }
170 return handled;
171 }
172
Vikram Aggarwalad6d6282012-03-28 09:16:14 -0700173 /**
174 * Clear the selection and perform related UI changes to keep the state consistent.
175 */
176 private void clearSelection() {
177 mSelectionSet.clear();
178 // Redraw with changes
179 mListAdapter.notifyDataSetChanged();
180 }
181
Mindy Pereira07118a02012-04-02 16:35:01 -0700182 private void performDestructiveAction(final int id, final ActionCompleteListener listener) {
Mindy Pereiraefe3d252012-03-01 14:20:44 -0800183 Settings settings = mActivity.getSettings();
184 final Collection<Conversation> conversations = mSelectionSet.values();
185 boolean showDialog = false;
186 if (settings != null) {
187 showDialog = (id == R.id.delete) ? settings.confirmDelete : settings.confirmArchive;
188 }
189 if (showDialog) {
190 int resId = id == R.id.delete ? R.plurals.confirm_delete_conversation
191 : R.plurals.confirm_archive_conversation;
192 CharSequence message = Utils.formatPlural(mContext, resId, conversations.size());
193 new AlertDialog.Builder(mContext).setMessage(message)
194 .setPositiveButton(R.string.ok, new AlertDialog.OnClickListener() {
195 @Override
196 public void onClick(DialogInterface dialog, int which) {
Mindy Pereira07118a02012-04-02 16:35:01 -0700197 destroy(id, conversations, listener);
Mindy Pereiraefe3d252012-03-01 14:20:44 -0800198 }
Mindy Pereiraefe3d252012-03-01 14:20:44 -0800199 }).setNegativeButton(R.string.cancel, null).create().show();
200 } else {
Mindy Pereira07118a02012-04-02 16:35:01 -0700201 destroy(id, conversations, listener);
202 }
203 }
204
205
206 private void destroy(int id, Collection<Conversation> conversations,
207 ActionCompleteListener listener) {
208 if (id == R.id.archive) {
209 ArrayList<ConversationItemView> views = new ArrayList<ConversationItemView>();
210 for (ConversationItemView view : mSelectionSet.views()) {
211 views.add(view);
212 }
213 mListView.archiveItems(views, listener);
214 } else {
Mindy Pereiraefe3d252012-03-01 14:20:44 -0800215 mListAdapter.delete(conversations, listener);
216 }
217 }
218
Mindy Pereirafebeb5f2012-02-14 15:08:13 -0800219 private void markConversationsRead(boolean read) {
220 Collection<Conversation> conversations = mSelectionSet.values();
Mindy Pereirafebeb5f2012-02-14 15:08:13 -0800221 Conversation.updateBoolean(mContext, conversations, ConversationColumns.READ, read);
Vikram Aggarwalad6d6282012-03-28 09:16:14 -0700222 clearSelection();
Mindy Pereirafebeb5f2012-02-14 15:08:13 -0800223 }
224
Mindy Pereira7f0a9622012-02-29 15:00:34 -0800225 private void markConversationsImportant(boolean important) {
226 Collection<Conversation> conversations = mSelectionSet.values();
227 int priority = important ? UIProvider.ConversationPriority.HIGH
228 : UIProvider.ConversationPriority.LOW;
229 Conversation.updateInt(mContext, conversations, ConversationColumns.PRIORITY, priority);
Vikram Aggarwalad6d6282012-03-28 09:16:14 -0700230 clearSelection();
Mindy Pereira7f0a9622012-02-29 15:00:34 -0800231 }
232
Mindy Pereirafebeb5f2012-02-14 15:08:13 -0800233 private void starConversations(boolean star) {
234 Collection<Conversation> conversations = mSelectionSet.values();
235 if (conversations.size() > 0) {
236 Conversation.updateBoolean(mContext, conversations,
237 ConversationColumns.STARRED, star);
238 }
Vikram Aggarwalad6d6282012-03-28 09:16:14 -0700239 clearSelection();
Mindy Pereirafebeb5f2012-02-14 15:08:13 -0800240 }
241
Mindy Pereira30d2d322012-02-03 08:40:49 -0800242 private void showChangeFoldersDialog() {
Vikram Aggarwald247dc92012-02-10 15:49:01 -0800243 new FoldersSelectionDialog(mContext, mAccount, this, mSelectionSet.values()).show();
Mindy Pereiraf3dfb152012-02-06 12:55:13 -0800244 }
Marc Blankce538182012-02-03 13:04:27 -0800245
Mindy Pereiraf3dfb152012-02-06 12:55:13 -0800246 @Override
Mindy Pereira6778f462012-03-23 18:01:55 -0700247 public void onFolderChangesCommit(ArrayList<Folder> folderChangeList) {
Mindy Pereiraf3dfb152012-02-06 12:55:13 -0800248 mFolderChangeList = folderChangeList;
Mindy Pereiraf3dfb152012-02-06 12:55:13 -0800249 // Do the change here...
Mindy Pereira4f166de2012-02-14 13:40:58 -0800250 // Get currently active folder info and compare it to the list
251 // these conversations have been given; if they no longer contain
252 // the selected folder, delete them from the list.
Mindy Pereira0825efd2012-02-15 17:30:32 -0800253 HashSet<String> folderUris = new HashSet<String>();
Mindy Pereira6778f462012-03-23 18:01:55 -0700254 if (folderChangeList != null && !folderChangeList.isEmpty()) {
255 for (Folder f : folderChangeList) {
256 folderUris.add(f.uri.toString());
257 }
Mindy Pereira0825efd2012-02-15 17:30:32 -0800258 }
Mindy Pereira6f9833a2012-03-21 13:53:12 -0700259 if (!folderUris.contains(mFolder.uri.toString())) {
Mindy Pereira4f166de2012-02-14 13:40:58 -0800260 final Collection<Conversation> conversations = mSelectionSet.values();
261 // Indicate delete on update (i.e. no longer in this folder)
262 mDeletionSet = new ArrayList<Conversation>();
263 for (Conversation conv : conversations) {
264 conv.localDeleteOnUpdate = true;
265 // For Gmail, add... if (noLongerInList(conv))...
266 mDeletionSet.add(conv);
267 }
268 // Delete the local delete items (all for now) and when done,
269 // update...
270 mListAdapter.delete(mDeletionSet, mFolderChangeListener);
271 } else {
272 mFolderChangeListener.onActionComplete();
Mindy Pereirad92e9f32012-02-03 09:10:58 -0800273 }
Mindy Pereira30d2d322012-02-03 08:40:49 -0800274 }
275
Vikram Aggarwale128fc22012-04-04 12:33:34 -0700276 private final ActionCompleteListener mFolderChangeListener = new ActionCompleteListener() {
Marc Blankce538182012-02-03 13:04:27 -0800277 @Override
278 public void onActionComplete() {
279 mActionCompleteListener.onActionComplete();
Mindy Pereiraf98b3182012-02-22 11:07:13 -0800280 Collection<Conversation> deletionSet = mDeletionSet;
Mindy Pereiraf98b3182012-02-22 11:07:13 -0800281 if (deletionSet != null && deletionSet.size() > 0) {
Vikram Aggarwal6fbc87a2012-03-15 15:24:00 -0700282 // Only show undo if this was a destructive folder change.
283 UndoOperation undoOp = new UndoOperation(deletionSet.size(), R.id.change_folder);
284 mUndoListener.onUndoAvailable(undoOp);
Mindy Pereiraf98b3182012-02-22 11:07:13 -0800285 mDeletionSet = null;
286 }
Mindy Pereira6778f462012-03-23 18:01:55 -0700287 StringBuilder foldersUrisString = new StringBuilder();
288 boolean first = true;
289 for (Folder f : mFolderChangeList) {
290 if (first) {
291 first = false;
292 } else {
293 foldersUrisString.append(',');
294 }
295 foldersUrisString.append(f.uri.toString());
296 }
Vikram Aggarwald247dc92012-02-10 15:49:01 -0800297 Conversation.updateString(mContext, mSelectionSet.values(),
Mindy Pereira6778f462012-03-23 18:01:55 -0700298 ConversationColumns.FOLDER_LIST, foldersUrisString.toString());
299 Conversation.updateString(mContext, mSelectionSet.values(),
300 ConversationColumns.RAW_FOLDERS,
Mindy Pereira5b84f412012-03-25 12:45:14 -0700301 Folder.getSerializedFolderString(mFolder, mFolderChangeList));
Vikram Aggarwalad6d6282012-03-28 09:16:14 -0700302 clearSelection();
Mindy Pereiraf98b3182012-02-22 11:07:13 -0800303 }
304 };
Marc Blankce538182012-02-03 13:04:27 -0800305
Mindy Pereira11b0bbd2012-01-24 10:06:17 -0800306 @Override
307 public boolean onCreateActionMode(ActionMode mode, Menu menu) {
308 mSelectionSet.addObserver(this);
309 MenuInflater inflater = mActivity.getMenuInflater();
310 inflater.inflate(R.menu.conversation_list_selection_actions_menu, menu);
311 mActionMode = mode;
312 mMenu = menu;
313 updateCount();
314 return true;
315 }
316
317 @Override
318 public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
Mindy Pereirafebeb5f2012-02-14 15:08:13 -0800319 // Determine read/ unread
320 // Star/ unstar
321 Collection<Conversation> conversations = mSelectionSet.values();
322 boolean showStar = false;
323 boolean showMarkUnread = false;
Mindy Pereira7f0a9622012-02-29 15:00:34 -0800324 boolean showMarkImportant = false;
325
Mindy Pereirafebeb5f2012-02-14 15:08:13 -0800326 for (Conversation conversation : conversations) {
327 if (!conversation.starred) {
328 showStar = true;
329 }
330 if (conversation.read) {
331 showMarkUnread = true;
332 }
Mindy Pereira7f0a9622012-02-29 15:00:34 -0800333 if (!conversation.isImportant()) {
334 showMarkImportant = true;
335 }
336 if (showStar && showMarkUnread && showMarkImportant) {
Mindy Pereirafebeb5f2012-02-14 15:08:13 -0800337 break;
338 }
339 }
Paul Westbrook334e64a2012-02-23 13:26:35 -0800340 final MenuItem star = menu.findItem(R.id.star);
Mindy Pereirafebeb5f2012-02-14 15:08:13 -0800341 star.setVisible(showStar);
Paul Westbrook334e64a2012-02-23 13:26:35 -0800342 final MenuItem unstar = menu.findItem(R.id.remove_star);
Mindy Pereirafebeb5f2012-02-14 15:08:13 -0800343 unstar.setVisible(!showStar);
Paul Westbrook334e64a2012-02-23 13:26:35 -0800344 final MenuItem read = menu.findItem(R.id.read);
Mindy Pereirafebeb5f2012-02-14 15:08:13 -0800345 read.setVisible(!showMarkUnread);
Paul Westbrook334e64a2012-02-23 13:26:35 -0800346 final MenuItem unread = menu.findItem(R.id.unread);
Mindy Pereirafebeb5f2012-02-14 15:08:13 -0800347 unread.setVisible(showMarkUnread);
Paul Westbrook334e64a2012-02-23 13:26:35 -0800348 final MenuItem archive = menu.findItem(R.id.archive);
349 archive.setVisible(mAccount.supportsCapability(UIProvider.AccountCapabilities.ARCHIVE) &&
350 mFolder.supportsCapability(FolderCapabilities.ARCHIVE));
351 final MenuItem spam = menu.findItem(R.id.report_spam);
352 spam.setVisible(mAccount.supportsCapability(UIProvider.AccountCapabilities.REPORT_SPAM) &&
353 mFolder.supportsCapability(FolderCapabilities.ARCHIVE));
354 final MenuItem mute = menu.findItem(R.id.mute);
Mindy Pereira830c00f2012-02-22 11:43:49 -0800355 mute.setVisible(mAccount.supportsCapability(UIProvider.AccountCapabilities.MUTE));
Mindy Pereira7f0a9622012-02-29 15:00:34 -0800356 final MenuItem markImportant = menu.findItem(R.id.mark_important);
357 markImportant.setVisible(showMarkImportant
358 && mAccount.supportsCapability(UIProvider.AccountCapabilities.MARK_IMPORTANT));
359 final MenuItem markNotImportant = menu.findItem(R.id.mark_not_important);
360 markNotImportant.setVisible(!showMarkImportant
361 && mAccount.supportsCapability(UIProvider.AccountCapabilities.MARK_IMPORTANT));
362
Mindy Pereira11b0bbd2012-01-24 10:06:17 -0800363 return true;
364 }
365
366 public void onPrepareActionMode() {
367 if (mActionMode != null) {
368 onPrepareActionMode(mActionMode, mActionMode.getMenu());
369 }
370 }
371
372 @Override
373 public void onDestroyActionMode(ActionMode mode) {
374 mActionMode = null;
375 // The action mode may have been destroyed due to this menu being deactivated, in which
376 // case resources need not be cleaned up. However, if it was destroyed while this menu is
377 // active, that implies the user hit "Done" in the top right, and resources need cleaning.
378 if (mActivated) {
379 destroy();
Mindy Pereira11b0bbd2012-01-24 10:06:17 -0800380 }
381 mMenu = null;
382 }
383
384 @Override
Vikram Aggarwal1ddcf0f2012-01-13 11:45:02 -0800385 public void onSetPopulated(ConversationSelectionSet set) {
Mindy Pereira11b0bbd2012-01-24 10:06:17 -0800386 // Noop. This object can only exist while the set is non-empty.
387 }
388
389 @Override
Vikram Aggarwal1ddcf0f2012-01-13 11:45:02 -0800390 public void onSetEmpty() {
Vikram Aggarwalad6d6282012-03-28 09:16:14 -0700391 LogUtils.d(LOG_TAG, "onSetEmpty called.");
Mindy Pereira11b0bbd2012-01-24 10:06:17 -0800392 destroy();
393 }
394
395 @Override
396 public void onSetChanged(ConversationSelectionSet set) {
397 // If the set is empty, the menu buttons are invalid and most like the menu will be cleaned
398 // up. Avoid making any changes to stop flickering ("Add Star" -> "Remove Star") just
399 // before hiding the menu.
400 if (set.isEmpty()) {
401 return;
402 }
Mindy Pereira11b0bbd2012-01-24 10:06:17 -0800403 updateCount();
404 }
405
406 /**
407 * Updates the visible count of how many conversations are selected.
408 */
409 private void updateCount() {
410 if (mActionMode != null) {
411 mActionMode.setTitle(mContext.getString(R.string.num_selected, mSelectionSet.size()));
412 }
413 }
414
415 /**
Vikram Aggarwale128fc22012-04-04 12:33:34 -0700416 * Activates and shows this menu (essentially starting an {@link ActionMode}) if the selected
417 * set is non-empty.
Mindy Pereira11b0bbd2012-01-24 10:06:17 -0800418 */
419 public void activate() {
Vikram Aggarwale128fc22012-04-04 12:33:34 -0700420 if (mSelectionSet.isEmpty()) {
421 // We have nothing to do since there is no conversation selected.
422 return;
423 }
Mindy Pereira11b0bbd2012-01-24 10:06:17 -0800424 mActivated = true;
425 if (mActionMode == null) {
426 mActivity.startActionMode(this);
427 }
428 }
429
430 /**
431 * De-activates and hides the menu (essentially disabling the {@link ActionMode}), but maintains
432 * the selection conversation set, and internally updates state as necessary.
433 */
434 public void deactivate() {
435 if (mActionMode != null) {
436 mActivated = false;
437 mActionMode.finish();
438 }
439 }
440
441 @VisibleForTesting
442 public boolean isActivated() {
443 return mActivated;
444 }
445
446 /**
447 * Destroys and cleans up the resources associated with this menu.
448 */
Vikram Aggarwalad6d6282012-03-28 09:16:14 -0700449 private void destroy() {
Mindy Pereira11b0bbd2012-01-24 10:06:17 -0800450 deactivate();
Mindy Pereira11b0bbd2012-01-24 10:06:17 -0800451 mSelectionSet.removeObserver(this);
Vikram Aggarwalad6d6282012-03-28 09:16:14 -0700452 clearSelection();
Mindy Pereira11b0bbd2012-01-24 10:06:17 -0800453 }
454
455 /**
456 * Disable the selected conversations menu item associated with a command
457 * id.
458 */
459 public void disableCommand(int id) {
460 enableMenuItem(id, false);
461 }
462
463 /**
464 * Enable the selected conversations menu item associated with a command
465 * id.
466 */
467 public void enableCommand(int id) {
468 enableMenuItem(id, true);
469 }
470
471 private void enableMenuItem(int id, boolean enable) {
472 if (mActivated) {
473 MenuItem item = mMenu.findItem(id);
474 if (item != null) {
475 item.setEnabled(enable);
476 }
477 }
478 }
Mindy Pereira830c00f2012-02-22 11:43:49 -0800479
Vikram Aggarwal54452ae2012-03-13 15:29:00 -0700480 private class DestructiveActionListener implements ActionCompleteListener {
481 private final int mAction;
Mindy Pereira830c00f2012-02-22 11:43:49 -0800482 public DestructiveActionListener(int action) {
483 mAction = action;
484 }
485
486 @Override
487 public void onActionComplete() {
488 // This is where we actually delete.
489 Collection<Conversation> conversations = mSelectionSet.values();
490 mActionCompleteListener.onActionComplete();
491 mUndoListener.onUndoAvailable(new UndoOperation(conversations.size(), mAction));
492 switch (mAction) {
493 case R.id.archive:
494 Conversation.archive(mContext, conversations);
495 break;
496 case R.id.delete:
497 Conversation.delete(mContext, conversations);
498 break;
499 case R.id.mute:
Paul Westbrook334e64a2012-02-23 13:26:35 -0800500 if (mFolder.supportsCapability(FolderCapabilities.DESTRUCTIVE_MUTE)) {
501 // Make sure to set the localDeleteOnUpdate flag for these conversatons.
502 for (Conversation conversation: conversations) {
503 conversation.localDeleteOnUpdate = true;
504 }
505 }
Mindy Pereira830c00f2012-02-22 11:43:49 -0800506 Conversation.mute(mContext, conversations);
507 break;
508 case R.id.report_spam:
509 Conversation.reportSpam(mContext, conversations);
510 break;
511 }
Vikram Aggarwalad6d6282012-03-28 09:16:14 -0700512 clearSelection();
Mindy Pereira830c00f2012-02-22 11:43:49 -0800513 }
Vikram Aggarwal54452ae2012-03-13 15:29:00 -0700514 }
Mindy Pereira11b0bbd2012-01-24 10:06:17 -0800515}