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