13168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy/* 23168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * Copyright (C) 2012 The Android Open Source Project 33168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * 43168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * Licensed under the Apache License, Version 2.0 (the "License"); 53168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * you may not use this file except in compliance with the License. 63168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * You may obtain a copy of the License at 73168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * 83168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * http://www.apache.org/licenses/LICENSE-2.0 93168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * 103168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * Unless required by applicable law or agreed to in writing, software 113168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * distributed under the License is distributed on an "AS IS" BASIS, 123168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * See the License for the specific language governing permissions and 143168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * limitations under the License. 153168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy */ 163168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedypackage com.android.mail.utils; 173168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 183168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport android.app.AlarmManager; 193168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport android.app.Notification; 203168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport android.app.NotificationManager; 213168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport android.app.PendingIntent; 223168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport android.content.ContentResolver; 233168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport android.content.ContentValues; 243168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport android.content.Context; 253168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport android.content.Intent; 2608a079c3d2857e365736432b2691187767eb116fScott Kennedyimport android.database.DataSetObserver; 273168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport android.net.Uri; 283168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport android.os.Parcel; 293168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport android.os.Parcelable; 303168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport android.os.SystemClock; 313168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport android.support.v4.app.NotificationCompat; 323168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport android.support.v4.app.TaskStackBuilder; 333168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport android.widget.RemoteViews; 343168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 35f2566a42b5dec4e846391ee0d7ecae0891356653Scott Kennedyimport com.android.mail.MailIntentService; 363168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport com.android.mail.NotificationActionIntentService; 373168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport com.android.mail.R; 383168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport com.android.mail.compose.ComposeActivity; 393168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport com.android.mail.providers.Account; 403168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport com.android.mail.providers.Conversation; 413168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport com.android.mail.providers.Folder; 423168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport com.android.mail.providers.Message; 433168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport com.android.mail.providers.UIProvider; 44143eb6ca9acb2d41e56efa5b3ceb2d82dfedf755Scott Kennedyimport com.android.mail.providers.UIProvider.ConversationOperations; 453168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport com.google.common.collect.ImmutableMap; 46828bc86ffcb1274fb461fbb25cdc2a07ae76b6c8Andrew Sappersteinimport com.google.common.collect.Sets; 473168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 483168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport java.util.ArrayList; 49d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedyimport java.util.Collection; 503168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport java.util.List; 513168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport java.util.Map; 523168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport java.util.Set; 533168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 543168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedypublic class NotificationActionUtils { 55781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy private static final String LOG_TAG = "NotifActionUtils"; 56781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy 57a61f99847d48938589bc7f7740e2385eee5626abScott Kennedy private static long sUndoTimeoutMillis = -1; 583168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 593168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy /** 603168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * If an {@link NotificationAction} exists here for a given notification key, then we should 613168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * display this undo notification rather than an email notification. 623168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy */ 6308a079c3d2857e365736432b2691187767eb116fScott Kennedy public static final ObservableSparseArrayCompat<NotificationAction> sUndoNotifications = 6408a079c3d2857e365736432b2691187767eb116fScott Kennedy new ObservableSparseArrayCompat<NotificationAction>(); 653168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 663168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy /** 67828bc86ffcb1274fb461fbb25cdc2a07ae76b6c8Andrew Sapperstein * If a {@link Conversation} exists in this set, then the undo notification for this 68828bc86ffcb1274fb461fbb25cdc2a07ae76b6c8Andrew Sapperstein * {@link Conversation} was tapped by the user in the notification drawer. 69828bc86ffcb1274fb461fbb25cdc2a07ae76b6c8Andrew Sapperstein * We need to properly handle notification actions for this case. 70828bc86ffcb1274fb461fbb25cdc2a07ae76b6c8Andrew Sapperstein */ 71828bc86ffcb1274fb461fbb25cdc2a07ae76b6c8Andrew Sapperstein public static final Set<Conversation> sUndoneConversations = Sets.newHashSet(); 72828bc86ffcb1274fb461fbb25cdc2a07ae76b6c8Andrew Sapperstein 73828bc86ffcb1274fb461fbb25cdc2a07ae76b6c8Andrew Sapperstein /** 743168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * If an undo notification is displayed, its timestamp 753168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * ({@link android.app.Notification.Builder#setWhen(long)}) is stored here so we can use it for 763168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * the original notification if the action is undone. 773168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy */ 783168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy public static final SparseLongArray sNotificationTimestamps = new SparseLongArray(); 793168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 803168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy public enum NotificationActionType { 8108a079c3d2857e365736432b2691187767eb116fScott Kennedy ARCHIVE_REMOVE_LABEL("archive", true, R.drawable.ic_menu_archive_holo_dark, 8263e1ca51511c6d3f76f7504c186258ec4b27260bScott Kennedy R.drawable.ic_menu_remove_label_holo_dark, R.string.notification_action_archive, 833168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy R.string.notification_action_remove_label, new ActionToggler() { 843168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy @Override 853168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy public boolean shouldDisplayPrimary(final Folder folder, 863168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final Conversation conversation, final Message message) { 87962a6922af499db189ace88ed3ba518946764197Scott Kennedy return folder == null || folder.isInbox(); 883168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 893168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy }), 9008a079c3d2857e365736432b2691187767eb116fScott Kennedy DELETE("delete", true, R.drawable.ic_menu_delete_holo_dark, 9108a079c3d2857e365736432b2691187767eb116fScott Kennedy R.string.notification_action_delete), 9208a079c3d2857e365736432b2691187767eb116fScott Kennedy REPLY("reply", false, R.drawable.ic_reply_holo_dark, R.string.notification_action_reply), 9308a079c3d2857e365736432b2691187767eb116fScott Kennedy REPLY_ALL("reply_all", false, R.drawable.ic_reply_all_holo_dark, 9421934896faadf6e740ec87797a9b0d1092c6bc6bScott Kennedy R.string.notification_action_reply_all); 953168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 963168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy private final String mPersistedValue; 9708a079c3d2857e365736432b2691187767eb116fScott Kennedy private final boolean mIsDestructive; 983168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 993168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy private final int mActionIcon; 1003168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy private final int mActionIcon2; 1013168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 1023168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy private final int mDisplayString; 1033168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy private final int mDisplayString2; 1043168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 1053168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy private final ActionToggler mActionToggler; 1063168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 1073168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy private static final Map<String, NotificationActionType> sPersistedMapping; 1083168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 1093168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy private interface ActionToggler { 1103168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy /** 1113168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * Determines if we should display the primary or secondary text/icon. 1123168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * 1133168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * @return <code>true</code> to display primary, <code>false</code> to display secondary 1143168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy */ 1153168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy boolean shouldDisplayPrimary(Folder folder, Conversation conversation, Message message); 1163168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 1173168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 1183168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy static { 1193168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final NotificationActionType[] values = values(); 1203168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final ImmutableMap.Builder<String, NotificationActionType> mapBuilder = 1213168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy new ImmutableMap.Builder<String, NotificationActionType>(); 1223168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 1233168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy for (int i = 0; i < values.length; i++) { 1243168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy mapBuilder.put(values[i].getPersistedValue(), values[i]); 1253168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 1263168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 1273168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy sPersistedMapping = mapBuilder.build(); 1283168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 1293168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 13008a079c3d2857e365736432b2691187767eb116fScott Kennedy private NotificationActionType(final String persistedValue, final boolean isDestructive, 13108a079c3d2857e365736432b2691187767eb116fScott Kennedy final int actionIcon, final int displayString) { 1323168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy mPersistedValue = persistedValue; 13308a079c3d2857e365736432b2691187767eb116fScott Kennedy mIsDestructive = isDestructive; 1343168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy mActionIcon = actionIcon; 1353168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy mActionIcon2 = -1; 1363168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy mDisplayString = displayString; 1373168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy mDisplayString2 = -1; 1383168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy mActionToggler = null; 1393168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 1403168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 14108a079c3d2857e365736432b2691187767eb116fScott Kennedy private NotificationActionType(final String persistedValue, final boolean isDestructive, 14208a079c3d2857e365736432b2691187767eb116fScott Kennedy final int actionIcon, final int actionIcon2, final int displayString, 14308a079c3d2857e365736432b2691187767eb116fScott Kennedy final int displayString2, final ActionToggler actionToggler) { 1443168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy mPersistedValue = persistedValue; 14508a079c3d2857e365736432b2691187767eb116fScott Kennedy mIsDestructive = isDestructive; 1463168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy mActionIcon = actionIcon; 1473168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy mActionIcon2 = actionIcon2; 1483168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy mDisplayString = displayString; 1493168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy mDisplayString2 = displayString2; 1503168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy mActionToggler = actionToggler; 1513168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 1523168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 1533168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy public static NotificationActionType getActionType(final String persistedValue) { 1543168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy return sPersistedMapping.get(persistedValue); 1553168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 1563168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 1573168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy public String getPersistedValue() { 1583168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy return mPersistedValue; 1593168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 1603168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 16108a079c3d2857e365736432b2691187767eb116fScott Kennedy public boolean getIsDestructive() { 16208a079c3d2857e365736432b2691187767eb116fScott Kennedy return mIsDestructive; 16308a079c3d2857e365736432b2691187767eb116fScott Kennedy } 16408a079c3d2857e365736432b2691187767eb116fScott Kennedy 1653168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy public int getActionIconResId(final Folder folder, final Conversation conversation, 1663168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final Message message) { 1673168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy if (mActionToggler == null || mActionToggler.shouldDisplayPrimary(folder, conversation, 1683168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy message)) { 1693168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy return mActionIcon; 1703168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 1713168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 1723168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy return mActionIcon2; 1733168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 1743168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 1753168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy public int getDisplayStringResId(final Folder folder, final Conversation conversation, 1763168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final Message message) { 1773168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy if (mActionToggler == null || mActionToggler.shouldDisplayPrimary(folder, conversation, 1783168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy message)) { 1793168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy return mDisplayString; 1803168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 1813168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 1823168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy return mDisplayString2; 1833168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 1843168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 1853168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 1863168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy /** 1873168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * Adds the appropriate notification actions to the specified 188d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy * {@link android.support.v4.app.NotificationCompat.Builder} 1893168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * 1903168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * @param notificationIntent The {@link Intent} used when the notification is clicked 1913168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * @param when The value passed into {@link android.app.Notification.Builder#setWhen(long)}. 1923168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * This is used for maintaining notification ordering with the undo bar 193d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy * @param notificationActions A {@link Set} set of the actions to display 1943168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy */ 1953168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy public static void addNotificationActions(final Context context, 196d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy final Intent notificationIntent, final NotificationCompat.Builder notification, 1973168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final Account account, final Conversation conversation, final Message message, 1983168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final Folder folder, final int notificationId, final long when, 199d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy final Set<String> notificationActions) { 200d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy final List<NotificationActionType> sortedActions = 201d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy getSortedNotificationActions(folder, notificationActions); 2023168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 203d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy for (final NotificationActionType notificationAction : sortedActions) { 2043168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy notification.addAction(notificationAction.getActionIconResId( 2053168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy folder, conversation, message), context.getString(notificationAction 2063168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy .getDisplayStringResId(folder, conversation, message)), 2073168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy getNotificationActionPendingIntent(context, account, conversation, message, 2083168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy folder, notificationIntent, notificationAction, notificationId, when)); 2093168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 2103168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 2113168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 2123168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy /** 2133168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * Sorts the notification actions into the appropriate order, based on current label 2143168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * 2153168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * @param folder The {@link Folder} being notified 216d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy * @param notificationActionStrings The action strings to sort 2173168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy */ 218d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy private static List<NotificationActionType> getSortedNotificationActions( 219d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy final Folder folder, final Collection<String> notificationActionStrings) { 220d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy final List<NotificationActionType> unsortedActions = 221d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy new ArrayList<NotificationActionType>(notificationActionStrings.size()); 222d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy for (final String action : notificationActionStrings) { 223d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy unsortedActions.add(NotificationActionType.getActionType(action)); 224d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy } 225d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy 226d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy final List<NotificationActionType> sortedActions = 227d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy new ArrayList<NotificationActionType>(unsortedActions.size()); 2283168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 2298c1058ee75ec4a5824a68c3c5275bc48d56bbad8Scott Kennedy if (folder.isInbox()) { 2303168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy // Inbox 2313168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy /* 2323168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * Action 1: Archive, Delete, Mute, Mark read, Add star, Mark important, Reply, Reply 2333168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * all, Forward 2343168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy */ 2353168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy /* 2363168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * Action 2: Reply, Reply all, Forward, Mark important, Add star, Mark read, Mute, 2373168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * Delete, Archive 2383168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy */ 239d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy if (unsortedActions.contains(NotificationActionType.ARCHIVE_REMOVE_LABEL)) { 240d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy sortedActions.add(NotificationActionType.ARCHIVE_REMOVE_LABEL); 2413168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 242d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy if (unsortedActions.contains(NotificationActionType.DELETE)) { 243d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy sortedActions.add(NotificationActionType.DELETE); 2443168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 245d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy if (unsortedActions.contains(NotificationActionType.REPLY)) { 246d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy sortedActions.add(NotificationActionType.REPLY); 2473168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 248d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy if (unsortedActions.contains(NotificationActionType.REPLY_ALL)) { 249d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy sortedActions.add(NotificationActionType.REPLY_ALL); 2503168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 2513168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } else if (folder.isProviderFolder()) { 2523168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy // Gmail system labels 2533168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy /* 2543168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * Action 1: Delete, Mute, Mark read, Add star, Mark important, Reply, Reply all, 2553168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * Forward 2563168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy */ 2573168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy /* 2583168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * Action 2: Reply, Reply all, Forward, Mark important, Add star, Mark read, Mute, 2593168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * Delete 2603168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy */ 261d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy if (unsortedActions.contains(NotificationActionType.DELETE)) { 262d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy sortedActions.add(NotificationActionType.DELETE); 2633168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 264d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy if (unsortedActions.contains(NotificationActionType.REPLY)) { 265d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy sortedActions.add(NotificationActionType.REPLY); 2663168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 267d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy if (unsortedActions.contains(NotificationActionType.REPLY_ALL)) { 268d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy sortedActions.add(NotificationActionType.REPLY_ALL); 2693168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 2703168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } else { 2713168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy // Gmail user created labels 2723168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy /* 2733168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * Action 1: Remove label, Delete, Mark read, Add star, Mark important, Reply, Reply 2743168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * all, Forward 2753168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy */ 2763168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy /* 2773168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * Action 2: Reply, Reply all, Forward, Mark important, Add star, Mark read, Delete 2783168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy */ 279d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy if (unsortedActions.contains(NotificationActionType.ARCHIVE_REMOVE_LABEL)) { 280d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy sortedActions.add(NotificationActionType.ARCHIVE_REMOVE_LABEL); 2813168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 282d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy if (unsortedActions.contains(NotificationActionType.DELETE)) { 283d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy sortedActions.add(NotificationActionType.DELETE); 2843168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 285d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy if (unsortedActions.contains(NotificationActionType.REPLY)) { 286d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy sortedActions.add(NotificationActionType.REPLY); 2873168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 288d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy if (unsortedActions.contains(NotificationActionType.REPLY_ALL)) { 289d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy sortedActions.add(NotificationActionType.REPLY_ALL); 2903168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 2913168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 292d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy 293d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy return sortedActions; 2943168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 2953168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 2963168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy /** 2973168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * Creates a {@link PendingIntent} for the specified notification action. 2983168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy */ 2993168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy private static PendingIntent getNotificationActionPendingIntent(final Context context, 3003168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final Account account, final Conversation conversation, final Message message, 3013168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final Folder folder, final Intent notificationIntent, 3023168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final NotificationActionType action, final int notificationId, final long when) { 3033168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final Uri messageUri = message.uri; 3043168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 3053168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final NotificationAction notificationAction = new NotificationAction(action, account, 3063168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy conversation, message, folder, conversation.id, message.serverId, message.id, when); 3073168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 3083168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy switch (action) { 3093168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy case REPLY: { 3103168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy // Build a task stack that forces the conversation view on the stack before the 3113168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy // reply activity. 3123168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final TaskStackBuilder taskStackBuilder = TaskStackBuilder.create(context); 31307342eff9ca95b9db665f1453565ea895f3b125fScott Kennedy 314d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy final Intent intent = createReplyIntent(context, account, messageUri, false); 315d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy intent.setPackage(context.getPackageName()); 316d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy intent.putExtra(ComposeActivity.EXTRA_NOTIFICATION_FOLDER, folder); 3173168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy // To make sure that the reply intents one notification don't clobber over 3183168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy // intents for other notification, force a data uri on the intent 3193168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final Uri notificationUri = 320d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy Uri.parse("mailfrom://mail/account/" + "reply/" + notificationId); 321d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy intent.setData(notificationUri); 32207342eff9ca95b9db665f1453565ea895f3b125fScott Kennedy 323d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy taskStackBuilder.addNextIntent(notificationIntent).addNextIntent(intent); 32407342eff9ca95b9db665f1453565ea895f3b125fScott Kennedy 3255680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy return taskStackBuilder.getPendingIntent( 3263168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy notificationId, PendingIntent.FLAG_UPDATE_CURRENT); 3273168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } case REPLY_ALL: { 3283168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy // Build a task stack that forces the conversation view on the stack before the 3293168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy // reply activity. 3303168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final TaskStackBuilder taskStackBuilder = TaskStackBuilder.create(context); 33107342eff9ca95b9db665f1453565ea895f3b125fScott Kennedy 332d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy final Intent intent = createReplyIntent(context, account, messageUri, true); 333d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy intent.setPackage(context.getPackageName()); 334d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy intent.putExtra(ComposeActivity.EXTRA_NOTIFICATION_FOLDER, folder); 3353168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy // To make sure that the reply intents one notification don't clobber over 3363168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy // intents for other notification, force a data uri on the intent 3373168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final Uri notificationUri = 338d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy Uri.parse("mailfrom://mail/account/" + "replyall/" + notificationId); 339d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy intent.setData(notificationUri); 34007342eff9ca95b9db665f1453565ea895f3b125fScott Kennedy 341d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy taskStackBuilder.addNextIntent(notificationIntent).addNextIntent(intent); 34207342eff9ca95b9db665f1453565ea895f3b125fScott Kennedy 3435680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy return taskStackBuilder.getPendingIntent( 3443168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy notificationId, PendingIntent.FLAG_UPDATE_CURRENT); 3453168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } case ARCHIVE_REMOVE_LABEL: { 3463168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final String intentAction = 3473168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy NotificationActionIntentService.ACTION_ARCHIVE_REMOVE_LABEL; 34807342eff9ca95b9db665f1453565ea895f3b125fScott Kennedy 3493168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final Intent intent = new Intent(intentAction); 350d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy intent.setPackage(context.getPackageName()); 351621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy putNotificationActionExtra(intent, notificationAction); 35207342eff9ca95b9db665f1453565ea895f3b125fScott Kennedy 3533168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy return PendingIntent.getService( 3543168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT); 3553168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } case DELETE: { 3563168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final String intentAction = NotificationActionIntentService.ACTION_DELETE; 35707342eff9ca95b9db665f1453565ea895f3b125fScott Kennedy 3583168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final Intent intent = new Intent(intentAction); 359d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy intent.setPackage(context.getPackageName()); 360621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy putNotificationActionExtra(intent, notificationAction); 36107342eff9ca95b9db665f1453565ea895f3b125fScott Kennedy 3623168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy return PendingIntent.getService( 3633168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT); 3643168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 3653168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 3663168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 3673168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy throw new IllegalArgumentException("Invalid NotificationActionType"); 3683168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 3693168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 3703168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy /** 3713168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * @return an intent which, if launched, will reply to the conversation 3723168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy */ 3733168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy public static Intent createReplyIntent(final Context context, final Account account, 3743168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final Uri messageUri, final boolean isReplyAll) { 3753168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final Intent intent = ComposeActivity.createReplyIntent(context, account, messageUri, 3763168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy isReplyAll); 3774fe0af81874976a1995191321e35c844b2229811Andy Huang intent.putExtra(Utils.EXTRA_FROM_NOTIFICATION, true); 3783168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy return intent; 3793168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 3803168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 3813168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy /** 3823168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * @return an intent which, if launched, will forward the conversation 3833168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy */ 3843168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy public static Intent createForwardIntent( 3853168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final Context context, final Account account, final Uri messageUri) { 3863168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final Intent intent = ComposeActivity.createForwardIntent(context, account, messageUri); 3874fe0af81874976a1995191321e35c844b2229811Andy Huang intent.putExtra(Utils.EXTRA_FROM_NOTIFICATION, true); 3883168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy return intent; 3893168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 3903168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 3913168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy public static class NotificationAction implements Parcelable { 3923168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy private final NotificationActionType mNotificationActionType; 3933168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy private final Account mAccount; 3943168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy private final Conversation mConversation; 3953168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy private final Message mMessage; 3963168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy private final Folder mFolder; 3973168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy private final long mConversationId; 3983168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy private final String mMessageId; 3993168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy private final long mLocalMessageId; 4003168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy private final long mWhen; 4013168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 4023168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy public NotificationAction(final NotificationActionType notificationActionType, 4033168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final Account account, final Conversation conversation, final Message message, 4043168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final Folder folder, final long conversationId, final String messageId, 4053168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final long localMessageId, final long when) { 4063168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy mNotificationActionType = notificationActionType; 4073168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy mAccount = account; 4083168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy mConversation = conversation; 4093168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy mMessage = message; 4103168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy mFolder = folder; 4113168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy mConversationId = conversationId; 4123168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy mMessageId = messageId; 4133168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy mLocalMessageId = localMessageId; 4143168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy mWhen = when; 4153168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 4163168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 4173168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy public NotificationActionType getNotificationActionType() { 4183168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy return mNotificationActionType; 4193168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 4203168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 4213168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy public Account getAccount() { 4223168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy return mAccount; 4233168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 4243168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 4253168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy public Conversation getConversation() { 4263168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy return mConversation; 4273168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 4283168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 4293168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy public Message getMessage() { 4303168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy return mMessage; 4313168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 4323168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 4333168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy public Folder getFolder() { 4343168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy return mFolder; 4353168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 4363168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 4373168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy public long getConversationId() { 4383168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy return mConversationId; 4393168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 4403168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 4413168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy public String getMessageId() { 4423168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy return mMessageId; 4433168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 4443168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 4453168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy public long getLocalMessageId() { 4463168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy return mLocalMessageId; 4473168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 4483168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 4493168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy public long getWhen() { 4503168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy return mWhen; 4513168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 4523168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 4533168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy public int getActionTextResId() { 4543168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy switch (mNotificationActionType) { 4553168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy case ARCHIVE_REMOVE_LABEL: 4568c1058ee75ec4a5824a68c3c5275bc48d56bbad8Scott Kennedy if (mFolder.isInbox()) { 4573168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy return R.string.notification_action_undo_archive; 4583168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } else { 4593168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy return R.string.notification_action_undo_remove_label; 4603168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 4613168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy case DELETE: 4623168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy return R.string.notification_action_undo_delete; 4633168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy default: 4643168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy throw new IllegalStateException( 4653168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy "There is no action text for this NotificationActionType."); 4663168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 4673168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 4683168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 4693168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy @Override 4703168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy public int describeContents() { 4713168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy return 0; 4723168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 4733168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 4743168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy @Override 4753168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy public void writeToParcel(final Parcel out, final int flags) { 4763168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy out.writeInt(mNotificationActionType.ordinal()); 4773168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy out.writeParcelable(mAccount, 0); 4783168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy out.writeParcelable(mConversation, 0); 4793168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy out.writeParcelable(mMessage, 0); 4803168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy out.writeParcelable(mFolder, 0); 4813168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy out.writeLong(mConversationId); 4823168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy out.writeString(mMessageId); 4833168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy out.writeLong(mLocalMessageId); 4843168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy out.writeLong(mWhen); 4853168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 4863168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 487b2ce334a6109aa79e8e6b5a4e74e4f011e8eae1dScott Kennedy public static final Parcelable.ClassLoaderCreator<NotificationAction> CREATOR = 488b2ce334a6109aa79e8e6b5a4e74e4f011e8eae1dScott Kennedy new Parcelable.ClassLoaderCreator<NotificationAction>() { 4893168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy @Override 4903168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy public NotificationAction createFromParcel(final Parcel in) { 491b2ce334a6109aa79e8e6b5a4e74e4f011e8eae1dScott Kennedy return new NotificationAction(in, null); 4923168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 4933168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 4943168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy @Override 4953168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy public NotificationAction[] newArray(final int size) { 4963168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy return new NotificationAction[size]; 4973168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 498b2ce334a6109aa79e8e6b5a4e74e4f011e8eae1dScott Kennedy 499b2ce334a6109aa79e8e6b5a4e74e4f011e8eae1dScott Kennedy @Override 500b2ce334a6109aa79e8e6b5a4e74e4f011e8eae1dScott Kennedy public NotificationAction createFromParcel( 501b2ce334a6109aa79e8e6b5a4e74e4f011e8eae1dScott Kennedy final Parcel in, final ClassLoader loader) { 502b2ce334a6109aa79e8e6b5a4e74e4f011e8eae1dScott Kennedy return new NotificationAction(in, loader); 503b2ce334a6109aa79e8e6b5a4e74e4f011e8eae1dScott Kennedy } 5043168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy }; 5053168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 506b2ce334a6109aa79e8e6b5a4e74e4f011e8eae1dScott Kennedy private NotificationAction(final Parcel in, final ClassLoader loader) { 5073168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy mNotificationActionType = NotificationActionType.values()[in.readInt()]; 508b2ce334a6109aa79e8e6b5a4e74e4f011e8eae1dScott Kennedy mAccount = in.readParcelable(loader); 509b2ce334a6109aa79e8e6b5a4e74e4f011e8eae1dScott Kennedy mConversation = in.readParcelable(loader); 510b2ce334a6109aa79e8e6b5a4e74e4f011e8eae1dScott Kennedy mMessage = in.readParcelable(loader); 511b2ce334a6109aa79e8e6b5a4e74e4f011e8eae1dScott Kennedy mFolder = in.readParcelable(loader); 5123168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy mConversationId = in.readLong(); 5133168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy mMessageId = in.readString(); 5143168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy mLocalMessageId = in.readLong(); 5153168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy mWhen = in.readLong(); 5163168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 5173168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 5183168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 5193168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy public static Notification createUndoNotification(final Context context, 5203168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final NotificationAction notificationAction, final int notificationId) { 521781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy LogUtils.i(LOG_TAG, "createUndoNotification for %s", 522781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy notificationAction.getNotificationActionType()); 523781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy 5243168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final NotificationCompat.Builder builder = new NotificationCompat.Builder(context); 5253168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 5263168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy builder.setSmallIcon(R.drawable.stat_notify_email); 5273168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy builder.setWhen(notificationAction.getWhen()); 5283168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 5293168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final RemoteViews undoView = 5303168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy new RemoteViews(context.getPackageName(), R.layout.undo_notification); 5313168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy undoView.setTextViewText( 5323168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy R.id.description_text, context.getString(notificationAction.getActionTextResId())); 5333168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 534d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy final String packageName = context.getPackageName(); 535d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy 5363168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final Intent clickIntent = new Intent(NotificationActionIntentService.ACTION_UNDO); 537d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy clickIntent.setPackage(packageName); 538621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy putNotificationActionExtra(clickIntent, notificationAction); 5393168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final PendingIntent clickPendingIntent = PendingIntent.getService(context, notificationId, 5403168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy clickIntent, PendingIntent.FLAG_CANCEL_CURRENT); 5413168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 5423168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy undoView.setOnClickPendingIntent(R.id.status_bar_latest_event_content, clickPendingIntent); 5433168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 5443168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy builder.setContent(undoView); 5453168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 5463168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy // When the notification is cleared, we perform the destructive action 5473168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final Intent deleteIntent = new Intent(NotificationActionIntentService.ACTION_DESTRUCT); 548d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy deleteIntent.setPackage(packageName); 549621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy putNotificationActionExtra(deleteIntent, notificationAction); 5503168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final PendingIntent deletePendingIntent = PendingIntent.getService(context, 5513168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy notificationId, deleteIntent, PendingIntent.FLAG_CANCEL_CURRENT); 5523168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy builder.setDeleteIntent(deletePendingIntent); 5533168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 5543168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final Notification notification = builder.build(); 5553168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 5563168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy return notification; 5573168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 5583168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 5593168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy /** 5603168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * Registers a timeout for the undo notification such that when it expires, the undo bar will 5613168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * disappear, and the action will be performed. 5623168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy */ 5633168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy public static void registerUndoTimeout( 5643168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final Context context, final NotificationAction notificationAction) { 565781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy LogUtils.i(LOG_TAG, "registerUndoTimeout for %s", 566781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy notificationAction.getNotificationActionType()); 567781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy 568a61f99847d48938589bc7f7740e2385eee5626abScott Kennedy if (sUndoTimeoutMillis == -1) { 569a61f99847d48938589bc7f7740e2385eee5626abScott Kennedy sUndoTimeoutMillis = 570a61f99847d48938589bc7f7740e2385eee5626abScott Kennedy context.getResources().getInteger(R.integer.undo_notification_timeout); 571a61f99847d48938589bc7f7740e2385eee5626abScott Kennedy } 572a61f99847d48938589bc7f7740e2385eee5626abScott Kennedy 5733168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final AlarmManager alarmManager = 5743168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 5753168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 576a61f99847d48938589bc7f7740e2385eee5626abScott Kennedy final long triggerAtMills = SystemClock.elapsedRealtime() + sUndoTimeoutMillis; 5773168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 5783168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final PendingIntent pendingIntent = 5793168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy createUndoTimeoutPendingIntent(context, notificationAction); 5803168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 5813168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy alarmManager.set(AlarmManager.ELAPSED_REALTIME, triggerAtMills, pendingIntent); 5823168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 5833168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 5843168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy /** 5853168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * Cancels the undo timeout for a notification action. This should be called if the undo 5863168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * notification is clicked (to prevent the action from being performed anyway) or cleared (since 5873168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * we have already performed the action). 5883168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy */ 5893168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy public static void cancelUndoTimeout( 5903168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final Context context, final NotificationAction notificationAction) { 591781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy LogUtils.i(LOG_TAG, "cancelUndoTimeout for %s", 592781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy notificationAction.getNotificationActionType()); 593781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy 5943168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final AlarmManager alarmManager = 5953168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 5963168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 5973168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final PendingIntent pendingIntent = 5983168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy createUndoTimeoutPendingIntent(context, notificationAction); 5993168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 6003168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy alarmManager.cancel(pendingIntent); 6013168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 6023168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 6033168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy /** 6043168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * Creates a {@link PendingIntent} to be used for creating and canceling the undo timeout 6053168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * alarm. 6063168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy */ 6073168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy private static PendingIntent createUndoTimeoutPendingIntent( 6083168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final Context context, final NotificationAction notificationAction) { 6093168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final Intent intent = new Intent(NotificationActionIntentService.ACTION_UNDO_TIMEOUT); 6102d8f3094d69b7ebbd9376dde7f61eb4334e86075Scott Kennedy intent.setPackage(context.getPackageName()); 611621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy putNotificationActionExtra(intent, notificationAction); 6123168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 6133168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final int requestCode = notificationAction.getAccount().hashCode() 6143168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy ^ notificationAction.getFolder().hashCode(); 6153168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final PendingIntent pendingIntent = 6163168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy PendingIntent.getService(context, requestCode, intent, 0); 6173168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 6183168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy return pendingIntent; 6193168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 6203168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 6213168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy /** 6223168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * Processes the specified destructive action (archive, delete, mute) on the message. 6233168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy */ 6243168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy public static void processDestructiveAction( 6253168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final Context context, final NotificationAction notificationAction) { 626781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy LogUtils.i(LOG_TAG, "processDestructiveAction: %s", 627781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy notificationAction.getNotificationActionType()); 628781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy 6293168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final NotificationActionType destructAction = 6303168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy notificationAction.getNotificationActionType(); 6313168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final Conversation conversation = notificationAction.getConversation(); 6323168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final Folder folder = notificationAction.getFolder(); 6333168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 6343168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final ContentResolver contentResolver = context.getContentResolver(); 6351007e70b1abad47c84d19890809e2b3727419607Scott Kennedy final Uri uri = conversation.uri.buildUpon().appendQueryParameter( 6361007e70b1abad47c84d19890809e2b3727419607Scott Kennedy UIProvider.FORCE_UI_NOTIFICATIONS_QUERY_PARAMETER, Boolean.TRUE.toString()).build(); 6373168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 6383168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy switch (destructAction) { 6393168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy case ARCHIVE_REMOVE_LABEL: { 6408c1058ee75ec4a5824a68c3c5275bc48d56bbad8Scott Kennedy if (folder.isInbox()) { 6413168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy // Inbox, so archive 6423168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final ContentValues values = new ContentValues(1); 6433168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy values.put(UIProvider.ConversationOperations.OPERATION_KEY, 6443168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy UIProvider.ConversationOperations.ARCHIVE); 6453168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 6463168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy contentResolver.update(uri, values, null, null); 6473168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } else { 6483168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy // Not inbox, so remove label 6493168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final ContentValues values = new ContentValues(1); 650143eb6ca9acb2d41e56efa5b3ceb2d82dfedf755Scott Kennedy 651259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedy final String removeFolderUri = folder.folderUri.fullUri.buildUpon() 652259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedy .appendPath(Boolean.FALSE.toString()).toString(); 653143eb6ca9acb2d41e56efa5b3ceb2d82dfedf755Scott Kennedy values.put(ConversationOperations.FOLDERS_UPDATED, removeFolderUri); 6543168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 6553168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy contentResolver.update(uri, values, null, null); 6563168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 6573168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy break; 6583168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 6593168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy case DELETE: { 6603168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy contentResolver.delete(uri, null, null); 6613168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy break; 6623168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 6633168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy default: 6643168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy throw new IllegalArgumentException( 6653168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy "The specified NotificationActionType is not a destructive action."); 6663168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 6673168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 6683168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 6693168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy /** 6703168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * Creates and displays an Undo notification for the specified {@link NotificationAction}. 6713168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy */ 6723168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy public static void createUndoNotification(final Context context, 6733168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final NotificationAction notificationAction) { 674781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy LogUtils.i(LOG_TAG, "createUndoNotification for %s", 675781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy notificationAction.getNotificationActionType()); 676781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy 677d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy final int notificationId = NotificationUtils.getNotificationId( 678b90a813b107d8f43236e2d3fe12f299d94c82ce8Tony Mantler notificationAction.getAccount().getAccountManagerAccount(), 679b90a813b107d8f43236e2d3fe12f299d94c82ce8Tony Mantler notificationAction.getFolder()); 6803168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 6813168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final Notification notification = 6823168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy createUndoNotification(context, notificationAction, notificationId); 6833168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 6843168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final NotificationManager notificationManager = 6853168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); 6863168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy notificationManager.notify(notificationId, notification); 6873168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 6883168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy sUndoNotifications.put(notificationId, notificationAction); 6893168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy sNotificationTimestamps.put(notificationId, notificationAction.getWhen()); 6903168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 6913168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 692828bc86ffcb1274fb461fbb25cdc2a07ae76b6c8Andrew Sapperstein /** 693828bc86ffcb1274fb461fbb25cdc2a07ae76b6c8Andrew Sapperstein * Called when an Undo notification has been tapped. 694828bc86ffcb1274fb461fbb25cdc2a07ae76b6c8Andrew Sapperstein */ 6953168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy public static void cancelUndoNotification(final Context context, 6963168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final NotificationAction notificationAction) { 697781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy LogUtils.i(LOG_TAG, "cancelUndoNotification for %s", 698781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy notificationAction.getNotificationActionType()); 699781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy 700ddd17bc2963b67ba07dfd1e2d9b1f17abf8c8e4aAndrew Sapperstein final Account account = notificationAction.getAccount(); 701ddd17bc2963b67ba07dfd1e2d9b1f17abf8c8e4aAndrew Sapperstein final Folder folder = notificationAction.getFolder(); 702828bc86ffcb1274fb461fbb25cdc2a07ae76b6c8Andrew Sapperstein final Conversation conversation = notificationAction.getConversation(); 703b90a813b107d8f43236e2d3fe12f299d94c82ce8Tony Mantler final int notificationId = 704b90a813b107d8f43236e2d3fe12f299d94c82ce8Tony Mantler NotificationUtils.getNotificationId(account.getAccountManagerAccount(), folder); 705828bc86ffcb1274fb461fbb25cdc2a07ae76b6c8Andrew Sapperstein 706828bc86ffcb1274fb461fbb25cdc2a07ae76b6c8Andrew Sapperstein // Note: we must add the conversation before removing the undo notification 707828bc86ffcb1274fb461fbb25cdc2a07ae76b6c8Andrew Sapperstein // Otherwise, the observer for sUndoNotifications gets called, which calls 708828bc86ffcb1274fb461fbb25cdc2a07ae76b6c8Andrew Sapperstein // handleNotificationActions before the undone conversation has been added to the set. 709828bc86ffcb1274fb461fbb25cdc2a07ae76b6c8Andrew Sapperstein sUndoneConversations.add(conversation); 710caa952b4074b3d8a9f9d869355c4a98fcb904dd1Scott Kennedy removeUndoNotification(context, notificationId, false); 711ddd17bc2963b67ba07dfd1e2d9b1f17abf8c8e4aAndrew Sapperstein resendNotifications(context, account, folder); 7123168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 7133168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 7143168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy /** 7153168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * If an undo notification is left alone for a long enough time, it will disappear, this method 7163168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * will be called, and the action will be finalized. 7173168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy */ 7183168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy public static void processUndoNotification(final Context context, 7193168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy final NotificationAction notificationAction) { 720781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy LogUtils.i(LOG_TAG, "processUndoNotification, %s", 721781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy notificationAction.getNotificationActionType()); 722781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy 723ddd17bc2963b67ba07dfd1e2d9b1f17abf8c8e4aAndrew Sapperstein final Account account = notificationAction.getAccount(); 724ddd17bc2963b67ba07dfd1e2d9b1f17abf8c8e4aAndrew Sapperstein final Folder folder = notificationAction.getFolder(); 725d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy final int notificationId = NotificationUtils.getNotificationId( 726b90a813b107d8f43236e2d3fe12f299d94c82ce8Tony Mantler account.getAccountManagerAccount(), folder); 727caa952b4074b3d8a9f9d869355c4a98fcb904dd1Scott Kennedy removeUndoNotification(context, notificationId, true); 7283168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy sNotificationTimestamps.delete(notificationId); 7293168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy processDestructiveAction(context, notificationAction); 730606893390dcb49a88833aa17955dbe96fa41ae4aScott Kennedy 731ddd17bc2963b67ba07dfd1e2d9b1f17abf8c8e4aAndrew Sapperstein resendNotifications(context, account, folder); 7323168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 7333168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy 734606893390dcb49a88833aa17955dbe96fa41ae4aScott Kennedy /** 735606893390dcb49a88833aa17955dbe96fa41ae4aScott Kennedy * Removes the undo notification. 736caa952b4074b3d8a9f9d869355c4a98fcb904dd1Scott Kennedy * 737caa952b4074b3d8a9f9d869355c4a98fcb904dd1Scott Kennedy * @param removeNow <code>true</code> to remove it from the drawer right away, 738caa952b4074b3d8a9f9d869355c4a98fcb904dd1Scott Kennedy * <code>false</code> to just remove the reference to it 739606893390dcb49a88833aa17955dbe96fa41ae4aScott Kennedy */ 740caa952b4074b3d8a9f9d869355c4a98fcb904dd1Scott Kennedy private static void removeUndoNotification( 741caa952b4074b3d8a9f9d869355c4a98fcb904dd1Scott Kennedy final Context context, final int notificationId, final boolean removeNow) { 742606893390dcb49a88833aa17955dbe96fa41ae4aScott Kennedy sUndoNotifications.delete(notificationId); 743606893390dcb49a88833aa17955dbe96fa41ae4aScott Kennedy 744caa952b4074b3d8a9f9d869355c4a98fcb904dd1Scott Kennedy if (removeNow) { 745caa952b4074b3d8a9f9d869355c4a98fcb904dd1Scott Kennedy final NotificationManager notificationManager = 746caa952b4074b3d8a9f9d869355c4a98fcb904dd1Scott Kennedy (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); 747caa952b4074b3d8a9f9d869355c4a98fcb904dd1Scott Kennedy notificationManager.cancel(notificationId); 748caa952b4074b3d8a9f9d869355c4a98fcb904dd1Scott Kennedy } 749606893390dcb49a88833aa17955dbe96fa41ae4aScott Kennedy } 750606893390dcb49a88833aa17955dbe96fa41ae4aScott Kennedy 7513168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy /** 7523168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy * Broadcasts an {@link Intent} to inform the app to resend its notifications. 7533168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy */ 754ddd17bc2963b67ba07dfd1e2d9b1f17abf8c8e4aAndrew Sapperstein public static void resendNotifications(final Context context, final Account account, 755ddd17bc2963b67ba07dfd1e2d9b1f17abf8c8e4aAndrew Sapperstein final Folder folder) { 756781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy LogUtils.i(LOG_TAG, "resendNotifications account: %s, folder: %s", 757781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy LogUtils.sanitizeName(LOG_TAG, account.name), 758781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy LogUtils.sanitizeName(LOG_TAG, folder.name)); 759781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy 760f2566a42b5dec4e846391ee0d7ecae0891356653Scott Kennedy final Intent intent = new Intent(MailIntentService.ACTION_RESEND_NOTIFICATIONS); 7613168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy intent.setPackage(context.getPackageName()); // Make sure we only deliver this to ourself 762ddd17bc2963b67ba07dfd1e2d9b1f17abf8c8e4aAndrew Sapperstein intent.putExtra(Utils.EXTRA_ACCOUNT_URI, account.uri); 763259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedy intent.putExtra(Utils.EXTRA_FOLDER_URI, folder.folderUri.fullUri); 7643168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy context.startService(intent); 7653168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy } 76608a079c3d2857e365736432b2691187767eb116fScott Kennedy 76708a079c3d2857e365736432b2691187767eb116fScott Kennedy public static void registerUndoNotificationObserver(final DataSetObserver observer) { 76808a079c3d2857e365736432b2691187767eb116fScott Kennedy sUndoNotifications.getDataSetObservable().registerObserver(observer); 76908a079c3d2857e365736432b2691187767eb116fScott Kennedy } 77008a079c3d2857e365736432b2691187767eb116fScott Kennedy 77108a079c3d2857e365736432b2691187767eb116fScott Kennedy public static void unregisterUndoNotificationObserver(final DataSetObserver observer) { 77208a079c3d2857e365736432b2691187767eb116fScott Kennedy sUndoNotifications.getDataSetObservable().unregisterObserver(observer); 77308a079c3d2857e365736432b2691187767eb116fScott Kennedy } 774621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy 775621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy /** 776621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy * <p> 777621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy * This is a slight hack to avoid an exception in the remote AlarmManagerService process. The 778621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy * AlarmManager adds extra data to this Intent which causes it to inflate. Since the remote 779621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy * process does not know about the NotificationAction class, it throws a ClassNotFoundException. 780621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy * </p> 781621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy * <p> 782621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy * To avoid this, we marshall the data ourselves and then parcel a plain byte[] array. The 783621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy * NotificationActionIntentService class knows to build the NotificationAction object from the 784621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy * byte[] array. 785621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy * </p> 786621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy */ 787621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy private static void putNotificationActionExtra(final Intent intent, 788621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy final NotificationAction notificationAction) { 789621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy final Parcel out = Parcel.obtain(); 790621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy notificationAction.writeToParcel(out, 0); 791621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy out.setDataPosition(0); 792621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy intent.putExtra(NotificationActionIntentService.EXTRA_NOTIFICATION_ACTION, out.marshall()); 793621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy } 7943168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy} 795