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;
32439aa5d7d9226de4682c3697c68c0703b8847518Alan Lauimport android.support.v4.app.RemoteInput;
333168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport android.support.v4.app.TaskStackBuilder;
343168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport android.widget.RemoteViews;
353168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
36f2566a42b5dec4e846391ee0d7ecae0891356653Scott Kennedyimport com.android.mail.MailIntentService;
373168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport com.android.mail.NotificationActionIntentService;
383168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport com.android.mail.R;
393168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport com.android.mail.compose.ComposeActivity;
403168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport com.android.mail.providers.Account;
413168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport com.android.mail.providers.Conversation;
423168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport com.android.mail.providers.Folder;
433168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport com.android.mail.providers.Message;
443168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport com.android.mail.providers.UIProvider;
45143eb6ca9acb2d41e56efa5b3ceb2d82dfedf755Scott Kennedyimport com.android.mail.providers.UIProvider.ConversationOperations;
463168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport com.google.common.collect.ImmutableMap;
47828bc86ffcb1274fb461fbb25cdc2a07ae76b6c8Andrew Sappersteinimport com.google.common.collect.Sets;
483168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
493168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport java.util.ArrayList;
50d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedyimport java.util.Collection;
513168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport java.util.List;
523168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport java.util.Map;
533168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedyimport java.util.Set;
543168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
553168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedypublic class NotificationActionUtils {
56781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy    private static final String LOG_TAG = "NotifActionUtils";
57781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy
5815490239c82cdb4765e87e926c8c1945adedd1edAlan Lau    public static final String WEAR_REPLY_INPUT = "wear_reply";
5915490239c82cdb4765e87e926c8c1945adedd1edAlan Lau
60a61f99847d48938589bc7f7740e2385eee5626abScott Kennedy    private static long sUndoTimeoutMillis = -1;
613168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
623168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    /**
633168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     * If an {@link NotificationAction} exists here for a given notification key, then we should
643168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     * display this undo notification rather than an email notification.
653168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     */
6608a079c3d2857e365736432b2691187767eb116fScott Kennedy    public static final ObservableSparseArrayCompat<NotificationAction> sUndoNotifications =
6708a079c3d2857e365736432b2691187767eb116fScott Kennedy            new ObservableSparseArrayCompat<NotificationAction>();
683168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
693168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    /**
70828bc86ffcb1274fb461fbb25cdc2a07ae76b6c8Andrew Sapperstein     * If a {@link Conversation} exists in this set, then the undo notification for this
71828bc86ffcb1274fb461fbb25cdc2a07ae76b6c8Andrew Sapperstein     * {@link Conversation} was tapped by the user in the notification drawer.
72828bc86ffcb1274fb461fbb25cdc2a07ae76b6c8Andrew Sapperstein     * We need to properly handle notification actions for this case.
73828bc86ffcb1274fb461fbb25cdc2a07ae76b6c8Andrew Sapperstein     */
74828bc86ffcb1274fb461fbb25cdc2a07ae76b6c8Andrew Sapperstein    public static final Set<Conversation> sUndoneConversations = Sets.newHashSet();
75828bc86ffcb1274fb461fbb25cdc2a07ae76b6c8Andrew Sapperstein
76828bc86ffcb1274fb461fbb25cdc2a07ae76b6c8Andrew Sapperstein    /**
773168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     * If an undo notification is displayed, its timestamp
783168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     * ({@link android.app.Notification.Builder#setWhen(long)}) is stored here so we can use it for
793168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     * the original notification if the action is undone.
803168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     */
813168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    public static final SparseLongArray sNotificationTimestamps = new SparseLongArray();
823168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
833168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    public enum NotificationActionType {
847750adb207c55d61ba4693a461ba1e133940f39fAndrew Sapperstein        ARCHIVE_REMOVE_LABEL("archive", true, R.drawable.ic_archive_wht_24dp,
85d90a3bb006296443ea35ec3062cad11092ac2f95Andrew Sapperstein                R.drawable.ic_remove_label_wht_24dp, R.string.notification_action_archive,
863168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                R.string.notification_action_remove_label, new ActionToggler() {
873168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            @Override
883168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            public boolean shouldDisplayPrimary(final Folder folder,
893168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                    final Conversation conversation, final Message message) {
90962a6922af499db189ace88ed3ba518946764197Scott Kennedy                return folder == null || folder.isInbox();
913168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            }
923168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        }),
937750adb207c55d61ba4693a461ba1e133940f39fAndrew Sapperstein        DELETE("delete", true, R.drawable.ic_delete_wht_24dp,
9408a079c3d2857e365736432b2691187767eb116fScott Kennedy                R.string.notification_action_delete),
95d90a3bb006296443ea35ec3062cad11092ac2f95Andrew Sapperstein        REPLY("reply", false, R.drawable.ic_reply_wht_24dp, R.string.notification_action_reply),
96d90a3bb006296443ea35ec3062cad11092ac2f95Andrew Sapperstein        REPLY_ALL("reply_all", false, R.drawable.ic_reply_all_wht_24dp,
9721934896faadf6e740ec87797a9b0d1092c6bc6bScott Kennedy                R.string.notification_action_reply_all);
983168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
993168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        private final String mPersistedValue;
10008a079c3d2857e365736432b2691187767eb116fScott Kennedy        private final boolean mIsDestructive;
1013168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
1023168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        private final int mActionIcon;
1033168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        private final int mActionIcon2;
1043168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
1053168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        private final int mDisplayString;
1063168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        private final int mDisplayString2;
1073168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
1083168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        private final ActionToggler mActionToggler;
1093168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
1103168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        private static final Map<String, NotificationActionType> sPersistedMapping;
1113168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
1123168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        private interface ActionToggler {
1133168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            /**
1143168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy             * Determines if we should display the primary or secondary text/icon.
1153168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy             *
1163168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy             * @return <code>true</code> to display primary, <code>false</code> to display secondary
1173168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy             */
1183168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            boolean shouldDisplayPrimary(Folder folder, Conversation conversation, Message message);
1193168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        }
1203168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
1213168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        static {
1223168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            final NotificationActionType[] values = values();
1233168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            final ImmutableMap.Builder<String, NotificationActionType> mapBuilder =
1243168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                    new ImmutableMap.Builder<String, NotificationActionType>();
1253168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
1263168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            for (int i = 0; i < values.length; i++) {
1273168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                mapBuilder.put(values[i].getPersistedValue(), values[i]);
1283168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            }
1293168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
1303168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            sPersistedMapping = mapBuilder.build();
1313168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        }
1323168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
13308a079c3d2857e365736432b2691187767eb116fScott Kennedy        private NotificationActionType(final String persistedValue, final boolean isDestructive,
13408a079c3d2857e365736432b2691187767eb116fScott Kennedy                final int actionIcon, final int displayString) {
1353168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            mPersistedValue = persistedValue;
13608a079c3d2857e365736432b2691187767eb116fScott Kennedy            mIsDestructive = isDestructive;
1373168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            mActionIcon = actionIcon;
1383168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            mActionIcon2 = -1;
1393168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            mDisplayString = displayString;
1403168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            mDisplayString2 = -1;
1413168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            mActionToggler = null;
1423168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        }
1433168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
14408a079c3d2857e365736432b2691187767eb116fScott Kennedy        private NotificationActionType(final String persistedValue, final boolean isDestructive,
14508a079c3d2857e365736432b2691187767eb116fScott Kennedy                final int actionIcon, final int actionIcon2, final int displayString,
14608a079c3d2857e365736432b2691187767eb116fScott Kennedy                final int displayString2, final ActionToggler actionToggler) {
1473168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            mPersistedValue = persistedValue;
14808a079c3d2857e365736432b2691187767eb116fScott Kennedy            mIsDestructive = isDestructive;
1493168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            mActionIcon = actionIcon;
1503168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            mActionIcon2 = actionIcon2;
1513168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            mDisplayString = displayString;
1523168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            mDisplayString2 = displayString2;
1533168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            mActionToggler = actionToggler;
1543168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        }
1553168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
1563168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        public static NotificationActionType getActionType(final String persistedValue) {
1573168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            return sPersistedMapping.get(persistedValue);
1583168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        }
1593168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
1603168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        public String getPersistedValue() {
1613168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            return mPersistedValue;
1623168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        }
1633168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
16408a079c3d2857e365736432b2691187767eb116fScott Kennedy        public boolean getIsDestructive() {
16508a079c3d2857e365736432b2691187767eb116fScott Kennedy            return mIsDestructive;
16608a079c3d2857e365736432b2691187767eb116fScott Kennedy        }
16708a079c3d2857e365736432b2691187767eb116fScott Kennedy
1683168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        public int getActionIconResId(final Folder folder, final Conversation conversation,
1693168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                final Message message) {
1703168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            if (mActionToggler == null || mActionToggler.shouldDisplayPrimary(folder, conversation,
1713168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                    message)) {
1723168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                return mActionIcon;
1733168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            }
1743168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
1753168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            return mActionIcon2;
1763168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        }
1773168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
1783168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        public int getDisplayStringResId(final Folder folder, final Conversation conversation,
1793168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                final Message message) {
1803168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            if (mActionToggler == null || mActionToggler.shouldDisplayPrimary(folder, conversation,
1813168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                    message)) {
1823168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                return mDisplayString;
1833168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            }
1843168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
1853168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            return mDisplayString2;
1863168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        }
1873168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    }
1883168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
1893168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    /**
1903168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     * Adds the appropriate notification actions to the specified
191d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy     * {@link android.support.v4.app.NotificationCompat.Builder}
1923168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     *
1933168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     * @param notificationIntent The {@link Intent} used when the notification is clicked
1943168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     * @param when The value passed into {@link android.app.Notification.Builder#setWhen(long)}.
1953168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     *        This is used for maintaining notification ordering with the undo bar
196d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy     * @param notificationActions A {@link Set} set of the actions to display
1973168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     */
1983168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    public static void addNotificationActions(final Context context,
199d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy            final Intent notificationIntent, final NotificationCompat.Builder notification,
200439aa5d7d9226de4682c3697c68c0703b8847518Alan Lau            NotificationCompat.WearableExtender wearExtender, final Account account,
20115490239c82cdb4765e87e926c8c1945adedd1edAlan Lau            final Conversation conversation, final Message message,
2023168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            final Folder folder, final int notificationId, final long when,
203d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy            final Set<String> notificationActions) {
204d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy        final List<NotificationActionType> sortedActions =
205d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy                getSortedNotificationActions(folder, notificationActions);
2063168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
207d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy        for (final NotificationActionType notificationAction : sortedActions) {
208e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau            final PendingIntent pendingIntent = getNotificationActionPendingIntent(
20915490239c82cdb4765e87e926c8c1945adedd1edAlan Lau                    context, account, conversation, message,
21015490239c82cdb4765e87e926c8c1945adedd1edAlan Lau                    folder, notificationIntent, notificationAction, notificationId, when);
211e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau            final int actionIconResId = notificationAction.getActionIconResId(folder, conversation,
21215490239c82cdb4765e87e926c8c1945adedd1edAlan Lau                    message);
213e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau            final String title = context.getString(notificationAction.getDisplayStringResId(
21415490239c82cdb4765e87e926c8c1945adedd1edAlan Lau                    folder, conversation, message));
21515490239c82cdb4765e87e926c8c1945adedd1edAlan Lau
216ecb8ce46f50042c9b67362e57349d3eae39f6182Alan Lau            // Always add all actions to both standard and wearable notifications.
217ecb8ce46f50042c9b67362e57349d3eae39f6182Alan Lau            notification.addAction(actionIconResId, title, pendingIntent);
218ecb8ce46f50042c9b67362e57349d3eae39f6182Alan Lau
219e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau            // Use a different intent for wear because it triggers different set of behavior:
220e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau            // no undo for archive/delete, and mark conversation as read after reply.
221e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau            final PendingIntent wearPendingIntent = getWearNotificationActionPendingIntent(
222e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau                    context, account, conversation, message,
223e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau                    folder, notificationIntent, notificationAction, notificationId, when);
224e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau
225e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau            final NotificationCompat.Action.Builder wearableActionBuilder =
226781d1b0449ecdf74064f42df07e24c7e962c88ebAlan Lau                    new NotificationCompat.Action.Builder(
227781d1b0449ecdf74064f42df07e24c7e962c88ebAlan Lau                            mapWearActionResId(notificationAction, actionIconResId), title,
228e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau                            wearPendingIntent);
229781d1b0449ecdf74064f42df07e24c7e962c88ebAlan Lau
230ecb8ce46f50042c9b67362e57349d3eae39f6182Alan Lau            if (notificationAction == NotificationActionType.REPLY
231ecb8ce46f50042c9b67362e57349d3eae39f6182Alan Lau                    || notificationAction == NotificationActionType.REPLY_ALL) {
232e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau                final String[] choices = context.getResources().getStringArray(
233e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau                        R.array.reply_choices);
234ecb8ce46f50042c9b67362e57349d3eae39f6182Alan Lau                wearableActionBuilder.addRemoteInput(
235dbf09e5f9614abe2cf672463b1da3993093694a0Alan Lau                        new RemoteInput.Builder(WEAR_REPLY_INPUT)
236dbf09e5f9614abe2cf672463b1da3993093694a0Alan Lau                                .setLabel(title)
237dbf09e5f9614abe2cf672463b1da3993093694a0Alan Lau                                .setChoices(choices)
238781d1b0449ecdf74064f42df07e24c7e962c88ebAlan Lau                                .build());
23915490239c82cdb4765e87e926c8c1945adedd1edAlan Lau            }
240ecb8ce46f50042c9b67362e57349d3eae39f6182Alan Lau
241439aa5d7d9226de4682c3697c68c0703b8847518Alan Lau            wearExtender.addAction(wearableActionBuilder.build());
242781d1b0449ecdf74064f42df07e24c7e962c88ebAlan Lau            LogUtils.d(LOG_TAG, "Adding wearable action!!");
243781d1b0449ecdf74064f42df07e24c7e962c88ebAlan Lau        }
244781d1b0449ecdf74064f42df07e24c7e962c88ebAlan Lau    }
245781d1b0449ecdf74064f42df07e24c7e962c88ebAlan Lau
246781d1b0449ecdf74064f42df07e24c7e962c88ebAlan Lau    private static int mapWearActionResId(NotificationActionType notificationAction,
247781d1b0449ecdf74064f42df07e24c7e962c88ebAlan Lau            int defActionIconResId) {
248781d1b0449ecdf74064f42df07e24c7e962c88ebAlan Lau        switch (notificationAction) {
249781d1b0449ecdf74064f42df07e24c7e962c88ebAlan Lau            case REPLY:
250781d1b0449ecdf74064f42df07e24c7e962c88ebAlan Lau                return R.drawable.ic_wear_full_reply;
251781d1b0449ecdf74064f42df07e24c7e962c88ebAlan Lau            case REPLY_ALL:
252781d1b0449ecdf74064f42df07e24c7e962c88ebAlan Lau                return R.drawable.ic_wear_full_reply_all;
253781d1b0449ecdf74064f42df07e24c7e962c88ebAlan Lau            case ARCHIVE_REMOVE_LABEL:
254781d1b0449ecdf74064f42df07e24c7e962c88ebAlan Lau                return R.drawable.ic_wear_full_archive;
255781d1b0449ecdf74064f42df07e24c7e962c88ebAlan Lau            case DELETE:
256781d1b0449ecdf74064f42df07e24c7e962c88ebAlan Lau                return R.drawable.ic_wear_full_delete;
257781d1b0449ecdf74064f42df07e24c7e962c88ebAlan Lau            default:
258781d1b0449ecdf74064f42df07e24c7e962c88ebAlan Lau                return defActionIconResId;
2593168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        }
2603168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    }
2613168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
2623168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    /**
2633168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     * Sorts the notification actions into the appropriate order, based on current label
2643168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     *
2653168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     * @param folder The {@link Folder} being notified
266d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy     * @param notificationActionStrings The action strings to sort
2673168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     */
268d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy    private static List<NotificationActionType> getSortedNotificationActions(
269d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy            final Folder folder, final Collection<String> notificationActionStrings) {
270d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy        final List<NotificationActionType> unsortedActions =
271d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy                new ArrayList<NotificationActionType>(notificationActionStrings.size());
272d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy        for (final String action : notificationActionStrings) {
273d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy            unsortedActions.add(NotificationActionType.getActionType(action));
274d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy        }
275d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy
276d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy        final List<NotificationActionType> sortedActions =
277d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy                new ArrayList<NotificationActionType>(unsortedActions.size());
2783168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
2798c1058ee75ec4a5824a68c3c5275bc48d56bbad8Scott Kennedy        if (folder.isInbox()) {
2803168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            // Inbox
2813168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            /*
2823168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy             * Action 1: Archive, Delete, Mute, Mark read, Add star, Mark important, Reply, Reply
2833168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy             * all, Forward
2843168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy             */
2853168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            /*
2863168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy             * Action 2: Reply, Reply all, Forward, Mark important, Add star, Mark read, Mute,
2873168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy             * Delete, Archive
2883168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy             */
289d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy            if (unsortedActions.contains(NotificationActionType.ARCHIVE_REMOVE_LABEL)) {
290d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy                sortedActions.add(NotificationActionType.ARCHIVE_REMOVE_LABEL);
2913168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            }
292d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy            if (unsortedActions.contains(NotificationActionType.DELETE)) {
293d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy                sortedActions.add(NotificationActionType.DELETE);
2943168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            }
295d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy            if (unsortedActions.contains(NotificationActionType.REPLY)) {
296d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy                sortedActions.add(NotificationActionType.REPLY);
2973168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            }
298d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy            if (unsortedActions.contains(NotificationActionType.REPLY_ALL)) {
299d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy                sortedActions.add(NotificationActionType.REPLY_ALL);
3003168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            }
3013168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        } else if (folder.isProviderFolder()) {
3023168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            // Gmail system labels
3033168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            /*
3043168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy             * Action 1: Delete, Mute, Mark read, Add star, Mark important, Reply, Reply all,
3053168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy             * Forward
3063168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy             */
3073168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            /*
3083168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy             * Action 2: Reply, Reply all, Forward, Mark important, Add star, Mark read, Mute,
3093168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy             * Delete
3103168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy             */
311d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy            if (unsortedActions.contains(NotificationActionType.DELETE)) {
312d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy                sortedActions.add(NotificationActionType.DELETE);
3133168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            }
314d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy            if (unsortedActions.contains(NotificationActionType.REPLY)) {
315d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy                sortedActions.add(NotificationActionType.REPLY);
3163168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            }
317d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy            if (unsortedActions.contains(NotificationActionType.REPLY_ALL)) {
318d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy                sortedActions.add(NotificationActionType.REPLY_ALL);
3193168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            }
3203168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        } else {
3213168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            // Gmail user created labels
3223168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            /*
3233168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy             * Action 1: Remove label, Delete, Mark read, Add star, Mark important, Reply, Reply
3243168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy             * all, Forward
3253168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy             */
3263168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            /*
3273168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy             * Action 2: Reply, Reply all, Forward, Mark important, Add star, Mark read, Delete
3283168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy             */
329d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy            if (unsortedActions.contains(NotificationActionType.ARCHIVE_REMOVE_LABEL)) {
330d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy                sortedActions.add(NotificationActionType.ARCHIVE_REMOVE_LABEL);
3313168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            }
332d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy            if (unsortedActions.contains(NotificationActionType.DELETE)) {
333d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy                sortedActions.add(NotificationActionType.DELETE);
3343168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            }
335d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy            if (unsortedActions.contains(NotificationActionType.REPLY)) {
336d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy                sortedActions.add(NotificationActionType.REPLY);
3373168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            }
338d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy            if (unsortedActions.contains(NotificationActionType.REPLY_ALL)) {
339d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy                sortedActions.add(NotificationActionType.REPLY_ALL);
3403168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            }
3413168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        }
342d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy
343d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy        return sortedActions;
3443168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    }
3453168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
3463168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    /**
3473168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     * Creates a {@link PendingIntent} for the specified notification action.
3483168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     */
3493168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    private static PendingIntent getNotificationActionPendingIntent(final Context context,
3503168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            final Account account, final Conversation conversation, final Message message,
3513168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            final Folder folder, final Intent notificationIntent,
3523168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            final NotificationActionType action, final int notificationId, final long when) {
3533168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        final Uri messageUri = message.uri;
3543168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
3553168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        final NotificationAction notificationAction = new NotificationAction(action, account,
356e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau                conversation, message, folder, conversation.id, message.serverId, message.id, when,
3573806cb53f880094d811ced050342fd6ee7c4bf99Alan Lau                NotificationAction.SOURCE_LOCAL, notificationId);
3583168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
3593168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        switch (action) {
3603168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            case REPLY: {
3613168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                // Build a task stack that forces the conversation view on the stack before the
3623168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                // reply activity.
3633168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                final TaskStackBuilder taskStackBuilder = TaskStackBuilder.create(context);
36407342eff9ca95b9db665f1453565ea895f3b125fScott Kennedy
365d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy                final Intent intent = createReplyIntent(context, account, messageUri, false);
366d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy                intent.setPackage(context.getPackageName());
367804490c46d54741018917cc7f033acb7e6b7e824Alan Lau                intent.setData(conversation.uri);
368d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy                intent.putExtra(ComposeActivity.EXTRA_NOTIFICATION_FOLDER, folder);
36907342eff9ca95b9db665f1453565ea895f3b125fScott Kennedy
370d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy                taskStackBuilder.addNextIntent(notificationIntent).addNextIntent(intent);
37107342eff9ca95b9db665f1453565ea895f3b125fScott Kennedy
3725680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy                return taskStackBuilder.getPendingIntent(
3733168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                        notificationId, PendingIntent.FLAG_UPDATE_CURRENT);
3743168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            } case REPLY_ALL: {
3753168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                // Build a task stack that forces the conversation view on the stack before the
3763168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                // reply activity.
3773168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                final TaskStackBuilder taskStackBuilder = TaskStackBuilder.create(context);
37807342eff9ca95b9db665f1453565ea895f3b125fScott Kennedy
379d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy                final Intent intent = createReplyIntent(context, account, messageUri, true);
380d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy                intent.setPackage(context.getPackageName());
381804490c46d54741018917cc7f033acb7e6b7e824Alan Lau                intent.setData(conversation.uri);
382d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy                intent.putExtra(ComposeActivity.EXTRA_NOTIFICATION_FOLDER, folder);
38307342eff9ca95b9db665f1453565ea895f3b125fScott Kennedy
384d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy                taskStackBuilder.addNextIntent(notificationIntent).addNextIntent(intent);
38507342eff9ca95b9db665f1453565ea895f3b125fScott Kennedy
3865680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy                return taskStackBuilder.getPendingIntent(
3873168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                        notificationId, PendingIntent.FLAG_UPDATE_CURRENT);
3883168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            } case ARCHIVE_REMOVE_LABEL: {
3893168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                final String intentAction =
3903168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                        NotificationActionIntentService.ACTION_ARCHIVE_REMOVE_LABEL;
39107342eff9ca95b9db665f1453565ea895f3b125fScott Kennedy
3923168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                final Intent intent = new Intent(intentAction);
393d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy                intent.setPackage(context.getPackageName());
394804490c46d54741018917cc7f033acb7e6b7e824Alan Lau                intent.setData(conversation.uri);
395621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy                putNotificationActionExtra(intent, notificationAction);
39607342eff9ca95b9db665f1453565ea895f3b125fScott Kennedy
3973168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                return PendingIntent.getService(
3983168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                        context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
3993168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            } case DELETE: {
4003168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                final String intentAction = NotificationActionIntentService.ACTION_DELETE;
40107342eff9ca95b9db665f1453565ea895f3b125fScott Kennedy
4023168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                final Intent intent = new Intent(intentAction);
403d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy                intent.setPackage(context.getPackageName());
404804490c46d54741018917cc7f033acb7e6b7e824Alan Lau                intent.setData(conversation.uri);
405621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy                putNotificationActionExtra(intent, notificationAction);
40607342eff9ca95b9db665f1453565ea895f3b125fScott Kennedy
4073168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                return PendingIntent.getService(
4083168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                        context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
4093168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            }
4103168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        }
4113168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
4123168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        throw new IllegalArgumentException("Invalid NotificationActionType");
4133168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    }
4143168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
4153168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    /**
416e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau     * Creates a {@link PendingIntent} for the specified Wear notification action.
417e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau     */
418e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau    private static PendingIntent getWearNotificationActionPendingIntent(final Context context,
419e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau            final Account account, final Conversation conversation, final Message message,
420e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau            final Folder folder, final Intent notificationIntent,
421e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau            final NotificationActionType action, final int notificationId, final long when) {
422e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau        final Uri messageUri = message.uri;
423e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau
424e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau        final NotificationAction notificationAction = new NotificationAction(action, account,
425e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau                conversation, message, folder, conversation.id, message.serverId, message.id, when,
4263806cb53f880094d811ced050342fd6ee7c4bf99Alan Lau                NotificationAction.SOURCE_REMOTE, notificationId);
427e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau
428e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau        switch (action) {
429e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau            case REPLY:
430e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau            case REPLY_ALL: {
431e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau                // Build a task stack that forces the conversation view on the stack before the
432e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau                // reply activity.
433e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau                final TaskStackBuilder taskStackBuilder = TaskStackBuilder.create(context);
434e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau
435e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau                final Intent intent = createReplyIntent(context, account, messageUri,
436e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau                        (action == NotificationActionType.REPLY_ALL));
437e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau                intent.setPackage(context.getPackageName());
438e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau                intent.setData(buildWearUri(conversation.uri));
439e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau                intent.putExtra(ComposeActivity.EXTRA_NOTIFICATION_FOLDER, folder);
440e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau                intent.putExtra(ComposeActivity.EXTRA_NOTIFICATION_CONVERSATION, conversation.uri);
441e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau
442e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau                taskStackBuilder.addNextIntent(notificationIntent).addNextIntent(intent);
443e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau
444e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau                return taskStackBuilder.getPendingIntent(notificationId,
445e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau                        PendingIntent.FLAG_UPDATE_CURRENT);
446e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau            }
447e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau            case ARCHIVE_REMOVE_LABEL:
448e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau            case DELETE: {
449e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau                final String intentAction = (action == NotificationActionType.ARCHIVE_REMOVE_LABEL)
450e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau                        ? NotificationActionIntentService.ACTION_ARCHIVE_REMOVE_LABEL
451e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau                        : NotificationActionIntentService.ACTION_DELETE;
452e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau
453e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau                final Intent intent = new Intent(intentAction);
454e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau                intent.setPackage(context.getPackageName());
455e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau                intent.setData(buildWearUri(conversation.uri));
456e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau                putNotificationActionExtra(intent, notificationAction);
457e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau
458e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau                return PendingIntent.getService(context, notificationId, intent,
459e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau                        PendingIntent.FLAG_UPDATE_CURRENT);
460e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau            }
461e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau        }
462e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau
463e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau        throw new IllegalArgumentException("Invalid NotificationActionType");
464e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau    }
465e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau
466e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau    private static Uri buildWearUri(Uri uri) {
467e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau        return uri.buildUpon().appendQueryParameter("type", "wear").build();
468e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau    }
469e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau
470e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau    /**
4713168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     * @return an intent which, if launched, will reply to the conversation
4723168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     */
4733168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    public static Intent createReplyIntent(final Context context, final Account account,
4743168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            final Uri messageUri, final boolean isReplyAll) {
4753168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        final Intent intent = ComposeActivity.createReplyIntent(context, account, messageUri,
4763168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                isReplyAll);
4774fe0af81874976a1995191321e35c844b2229811Andy Huang        intent.putExtra(Utils.EXTRA_FROM_NOTIFICATION, true);
4783168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        return intent;
4793168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    }
4803168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
4813168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    public static class NotificationAction implements Parcelable {
482e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau        public static final int SOURCE_LOCAL = 0;
483e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau        public static final int SOURCE_REMOTE = 1;
484e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau
4853168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        private final NotificationActionType mNotificationActionType;
4863168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        private final Account mAccount;
4873168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        private final Conversation mConversation;
4883168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        private final Message mMessage;
4893168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        private final Folder mFolder;
4903168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        private final long mConversationId;
4913168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        private final String mMessageId;
4923168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        private final long mLocalMessageId;
4933168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        private final long mWhen;
494e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau        private final int mSource;
4953806cb53f880094d811ced050342fd6ee7c4bf99Alan Lau        private final int mNotificationId;
4963168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
4973168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        public NotificationAction(final NotificationActionType notificationActionType,
4983168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                final Account account, final Conversation conversation, final Message message,
4993168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                final Folder folder, final long conversationId, final String messageId,
5003806cb53f880094d811ced050342fd6ee7c4bf99Alan Lau                final long localMessageId, final long when, final int source,
5013806cb53f880094d811ced050342fd6ee7c4bf99Alan Lau                final int notificationId) {
5023168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            mNotificationActionType = notificationActionType;
5033168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            mAccount = account;
5043168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            mConversation = conversation;
5053168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            mMessage = message;
5063168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            mFolder = folder;
5073168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            mConversationId = conversationId;
5083168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            mMessageId = messageId;
5093168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            mLocalMessageId = localMessageId;
5103168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            mWhen = when;
511e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau            mSource = source;
5123806cb53f880094d811ced050342fd6ee7c4bf99Alan Lau            mNotificationId = notificationId;
5133168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        }
5143168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
5153168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        public NotificationActionType getNotificationActionType() {
5163168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            return mNotificationActionType;
5173168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        }
5183168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
5193168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        public Account getAccount() {
5203168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            return mAccount;
5213168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        }
5223168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
5233168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        public Conversation getConversation() {
5243168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            return mConversation;
5253168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        }
5263168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
5273168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        public Message getMessage() {
5283168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            return mMessage;
5293168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        }
5303168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
5313168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        public Folder getFolder() {
5323168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            return mFolder;
5333168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        }
5343168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
5353168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        public long getConversationId() {
5363168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            return mConversationId;
5373168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        }
5383168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
5393168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        public String getMessageId() {
5403168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            return mMessageId;
5413168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        }
5423168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
5433168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        public long getLocalMessageId() {
5443168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            return mLocalMessageId;
5453168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        }
5463168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
5473168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        public long getWhen() {
5483168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            return mWhen;
5493168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        }
5503168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
551e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau        public int getSource() {
552e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau            return mSource;
553e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau        }
554e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau
5553806cb53f880094d811ced050342fd6ee7c4bf99Alan Lau        public int getNotificationId() {
5563806cb53f880094d811ced050342fd6ee7c4bf99Alan Lau            return mNotificationId;
5573806cb53f880094d811ced050342fd6ee7c4bf99Alan Lau        }
5583806cb53f880094d811ced050342fd6ee7c4bf99Alan Lau
5593168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        public int getActionTextResId() {
5603168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            switch (mNotificationActionType) {
5613168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                case ARCHIVE_REMOVE_LABEL:
5628c1058ee75ec4a5824a68c3c5275bc48d56bbad8Scott Kennedy                    if (mFolder.isInbox()) {
5633168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                        return R.string.notification_action_undo_archive;
5643168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                    } else {
5653168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                        return R.string.notification_action_undo_remove_label;
5663168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                    }
5673168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                case DELETE:
5683168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                    return R.string.notification_action_undo_delete;
5693168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                default:
5703168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                    throw new IllegalStateException(
5713168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                            "There is no action text for this NotificationActionType.");
5723168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            }
5733168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        }
5743168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
5753168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        @Override
5763168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        public int describeContents() {
5773168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            return 0;
5783168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        }
5793168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
5803168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        @Override
5813168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        public void writeToParcel(final Parcel out, final int flags) {
5823168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            out.writeInt(mNotificationActionType.ordinal());
5833168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            out.writeParcelable(mAccount, 0);
5843168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            out.writeParcelable(mConversation, 0);
5853168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            out.writeParcelable(mMessage, 0);
5863168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            out.writeParcelable(mFolder, 0);
5873168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            out.writeLong(mConversationId);
5883168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            out.writeString(mMessageId);
5893168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            out.writeLong(mLocalMessageId);
5903168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            out.writeLong(mWhen);
591e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau            out.writeInt(mSource);
5923806cb53f880094d811ced050342fd6ee7c4bf99Alan Lau            out.writeInt(mNotificationId);
5933168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        }
5943168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
595b2ce334a6109aa79e8e6b5a4e74e4f011e8eae1dScott Kennedy        public static final Parcelable.ClassLoaderCreator<NotificationAction> CREATOR =
596b2ce334a6109aa79e8e6b5a4e74e4f011e8eae1dScott Kennedy                new Parcelable.ClassLoaderCreator<NotificationAction>() {
5973168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                    @Override
5983168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                    public NotificationAction createFromParcel(final Parcel in) {
599b2ce334a6109aa79e8e6b5a4e74e4f011e8eae1dScott Kennedy                        return new NotificationAction(in, null);
6003168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                    }
6013168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
6023168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                    @Override
6033168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                    public NotificationAction[] newArray(final int size) {
6043168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                        return new NotificationAction[size];
6053168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                    }
606b2ce334a6109aa79e8e6b5a4e74e4f011e8eae1dScott Kennedy
607b2ce334a6109aa79e8e6b5a4e74e4f011e8eae1dScott Kennedy                    @Override
608b2ce334a6109aa79e8e6b5a4e74e4f011e8eae1dScott Kennedy                    public NotificationAction createFromParcel(
609b2ce334a6109aa79e8e6b5a4e74e4f011e8eae1dScott Kennedy                            final Parcel in, final ClassLoader loader) {
610b2ce334a6109aa79e8e6b5a4e74e4f011e8eae1dScott Kennedy                        return new NotificationAction(in, loader);
611b2ce334a6109aa79e8e6b5a4e74e4f011e8eae1dScott Kennedy                    }
6123168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                };
6133168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
614b2ce334a6109aa79e8e6b5a4e74e4f011e8eae1dScott Kennedy        private NotificationAction(final Parcel in, final ClassLoader loader) {
6153168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            mNotificationActionType = NotificationActionType.values()[in.readInt()];
616b2ce334a6109aa79e8e6b5a4e74e4f011e8eae1dScott Kennedy            mAccount = in.readParcelable(loader);
617b2ce334a6109aa79e8e6b5a4e74e4f011e8eae1dScott Kennedy            mConversation = in.readParcelable(loader);
618b2ce334a6109aa79e8e6b5a4e74e4f011e8eae1dScott Kennedy            mMessage = in.readParcelable(loader);
619b2ce334a6109aa79e8e6b5a4e74e4f011e8eae1dScott Kennedy            mFolder = in.readParcelable(loader);
6203168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            mConversationId = in.readLong();
6213168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            mMessageId = in.readString();
6223168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            mLocalMessageId = in.readLong();
6233168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            mWhen = in.readLong();
624e806c9447c7137d2a7a828e7ccdc1f8961aa1c2aAlan Lau            mSource = in.readInt();
6253806cb53f880094d811ced050342fd6ee7c4bf99Alan Lau            mNotificationId = in.readInt();
6263168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        }
6273168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    }
6283168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
6293168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    public static Notification createUndoNotification(final Context context,
6303168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            final NotificationAction notificationAction, final int notificationId) {
631781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy        LogUtils.i(LOG_TAG, "createUndoNotification for %s",
632781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy                notificationAction.getNotificationActionType());
633781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy
6343168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        final NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
6353168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
636722c8c8e9797a021178c9feb7f2902a2a095ab36Rohan Shah        builder.setSmallIcon(R.drawable.ic_notification_mail_24dp);
6373168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        builder.setWhen(notificationAction.getWhen());
63876fb85a30a41254537c0ad26cabec06030fcdbbaPaul Westbrook        builder.setCategory(NotificationCompat.CATEGORY_EMAIL);
6393168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
6403168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        final RemoteViews undoView =
6413168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                new RemoteViews(context.getPackageName(), R.layout.undo_notification);
6423168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        undoView.setTextViewText(
6433168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                R.id.description_text, context.getString(notificationAction.getActionTextResId()));
6443168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
645d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy        final String packageName = context.getPackageName();
646d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy
6473168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        final Intent clickIntent = new Intent(NotificationActionIntentService.ACTION_UNDO);
648d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy        clickIntent.setPackage(packageName);
649804490c46d54741018917cc7f033acb7e6b7e824Alan Lau        clickIntent.setData(notificationAction.mConversation.uri);
650621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy        putNotificationActionExtra(clickIntent, notificationAction);
6513168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        final PendingIntent clickPendingIntent = PendingIntent.getService(context, notificationId,
6523168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                clickIntent, PendingIntent.FLAG_CANCEL_CURRENT);
6533168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
6543168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        undoView.setOnClickPendingIntent(R.id.status_bar_latest_event_content, clickPendingIntent);
6553168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
6563168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        builder.setContent(undoView);
6573168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
6583168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        // When the notification is cleared, we perform the destructive action
6593168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        final Intent deleteIntent = new Intent(NotificationActionIntentService.ACTION_DESTRUCT);
660d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy        deleteIntent.setPackage(packageName);
661735cbbd8a4676c1d36a25c061c8697668786227fAlan Lau        deleteIntent.setData(notificationAction.mConversation.uri);
662621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy        putNotificationActionExtra(deleteIntent, notificationAction);
6633168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        final PendingIntent deletePendingIntent = PendingIntent.getService(context,
6643168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                notificationId, deleteIntent, PendingIntent.FLAG_CANCEL_CURRENT);
6653168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        builder.setDeleteIntent(deletePendingIntent);
6663168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
6673168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        final Notification notification = builder.build();
6683168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
6693168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        return notification;
6703168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    }
6713168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
6723168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    /**
6733168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     * Registers a timeout for the undo notification such that when it expires, the undo bar will
6743168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     * disappear, and the action will be performed.
6753168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     */
6763168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    public static void registerUndoTimeout(
6773168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            final Context context, final NotificationAction notificationAction) {
678781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy        LogUtils.i(LOG_TAG, "registerUndoTimeout for %s",
679781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy                notificationAction.getNotificationActionType());
680781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy
681a61f99847d48938589bc7f7740e2385eee5626abScott Kennedy        if (sUndoTimeoutMillis == -1) {
682a61f99847d48938589bc7f7740e2385eee5626abScott Kennedy            sUndoTimeoutMillis =
683a61f99847d48938589bc7f7740e2385eee5626abScott Kennedy                    context.getResources().getInteger(R.integer.undo_notification_timeout);
684a61f99847d48938589bc7f7740e2385eee5626abScott Kennedy        }
685a61f99847d48938589bc7f7740e2385eee5626abScott Kennedy
6863168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        final AlarmManager alarmManager =
6873168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
6883168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
689a61f99847d48938589bc7f7740e2385eee5626abScott Kennedy        final long triggerAtMills = SystemClock.elapsedRealtime() + sUndoTimeoutMillis;
6903168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
6913168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        final PendingIntent pendingIntent =
6923168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                createUndoTimeoutPendingIntent(context, notificationAction);
6933168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
6943168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        alarmManager.set(AlarmManager.ELAPSED_REALTIME, triggerAtMills, pendingIntent);
6953168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    }
6963168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
6973168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    /**
6983168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     * Cancels the undo timeout for a notification action. This should be called if the undo
6993168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     * notification is clicked (to prevent the action from being performed anyway) or cleared (since
7003168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     * we have already performed the action).
7013168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     */
7023168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    public static void cancelUndoTimeout(
7033168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            final Context context, final NotificationAction notificationAction) {
704781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy        LogUtils.i(LOG_TAG, "cancelUndoTimeout for %s",
705781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy                notificationAction.getNotificationActionType());
706781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy
7073168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        final AlarmManager alarmManager =
7083168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
7093168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
7103168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        final PendingIntent pendingIntent =
7113168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                createUndoTimeoutPendingIntent(context, notificationAction);
7123168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
7133168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        alarmManager.cancel(pendingIntent);
7143168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    }
7153168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
7163168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    /**
7173168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     * Creates a {@link PendingIntent} to be used for creating and canceling the undo timeout
7183168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     * alarm.
7193168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     */
7203168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    private static PendingIntent createUndoTimeoutPendingIntent(
7213168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            final Context context, final NotificationAction notificationAction) {
7223168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        final Intent intent = new Intent(NotificationActionIntentService.ACTION_UNDO_TIMEOUT);
7232d8f3094d69b7ebbd9376dde7f61eb4334e86075Scott Kennedy        intent.setPackage(context.getPackageName());
724804490c46d54741018917cc7f033acb7e6b7e824Alan Lau        intent.setData(notificationAction.mConversation.uri);
725621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy        putNotificationActionExtra(intent, notificationAction);
7263168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
7273168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        final int requestCode = notificationAction.getAccount().hashCode()
7283168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                ^ notificationAction.getFolder().hashCode();
7293168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        final PendingIntent pendingIntent =
7303168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                PendingIntent.getService(context, requestCode, intent, 0);
7313168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
7323168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        return pendingIntent;
7333168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    }
7343168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
7353168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    /**
7363168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     * Processes the specified destructive action (archive, delete, mute) on the message.
7373168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     */
7383168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    public static void processDestructiveAction(
7393168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            final Context context, final NotificationAction notificationAction) {
740781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy        LogUtils.i(LOG_TAG, "processDestructiveAction: %s",
741781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy                notificationAction.getNotificationActionType());
742781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy
7433168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        final NotificationActionType destructAction =
7443168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                notificationAction.getNotificationActionType();
7453168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        final Conversation conversation = notificationAction.getConversation();
7463168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        final Folder folder = notificationAction.getFolder();
7473168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
7483168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        final ContentResolver contentResolver = context.getContentResolver();
7491007e70b1abad47c84d19890809e2b3727419607Scott Kennedy        final Uri uri = conversation.uri.buildUpon().appendQueryParameter(
7501007e70b1abad47c84d19890809e2b3727419607Scott Kennedy                UIProvider.FORCE_UI_NOTIFICATIONS_QUERY_PARAMETER, Boolean.TRUE.toString()).build();
7513168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
7523168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        switch (destructAction) {
7533168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            case ARCHIVE_REMOVE_LABEL: {
7548c1058ee75ec4a5824a68c3c5275bc48d56bbad8Scott Kennedy                if (folder.isInbox()) {
7553168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                    // Inbox, so archive
7563168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                    final ContentValues values = new ContentValues(1);
7573168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                    values.put(UIProvider.ConversationOperations.OPERATION_KEY,
7583168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                            UIProvider.ConversationOperations.ARCHIVE);
7593168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
7603168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                    contentResolver.update(uri, values, null, null);
7613168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                } else {
7623168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                    // Not inbox, so remove label
7633168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                    final ContentValues values = new ContentValues(1);
764143eb6ca9acb2d41e56efa5b3ceb2d82dfedf755Scott Kennedy
765259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedy                    final String removeFolderUri = folder.folderUri.fullUri.buildUpon()
766259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedy                            .appendPath(Boolean.FALSE.toString()).toString();
767143eb6ca9acb2d41e56efa5b3ceb2d82dfedf755Scott Kennedy                    values.put(ConversationOperations.FOLDERS_UPDATED, removeFolderUri);
7683168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
7693168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                    contentResolver.update(uri, values, null, null);
7703168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                }
7713168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                break;
7723168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            }
7733168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            case DELETE: {
7743168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                contentResolver.delete(uri, null, null);
7753168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                break;
7763168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            }
7773168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            default:
7783168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                throw new IllegalArgumentException(
7793168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                        "The specified NotificationActionType is not a destructive action.");
7803168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        }
7813168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    }
7823168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
7833168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    /**
7843168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     * Creates and displays an Undo notification for the specified {@link NotificationAction}.
7853168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     */
7863168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    public static void createUndoNotification(final Context context,
7873168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            final NotificationAction notificationAction) {
788781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy        LogUtils.i(LOG_TAG, "createUndoNotification for %s",
789781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy                notificationAction.getNotificationActionType());
790781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy
791d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy        final int notificationId = NotificationUtils.getNotificationId(
792b90a813b107d8f43236e2d3fe12f299d94c82ce8Tony Mantler                notificationAction.getAccount().getAccountManagerAccount(),
793b90a813b107d8f43236e2d3fe12f299d94c82ce8Tony Mantler                notificationAction.getFolder());
7943168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
7953168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        final Notification notification =
7963168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                createUndoNotification(context, notificationAction, notificationId);
7973168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
7983168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        final NotificationManager notificationManager =
7993168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy                (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
8003168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        notificationManager.notify(notificationId, notification);
8013168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
8023168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        sUndoNotifications.put(notificationId, notificationAction);
8033168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        sNotificationTimestamps.put(notificationId, notificationAction.getWhen());
8043168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    }
8053168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
806828bc86ffcb1274fb461fbb25cdc2a07ae76b6c8Andrew Sapperstein    /**
807828bc86ffcb1274fb461fbb25cdc2a07ae76b6c8Andrew Sapperstein     * Called when an Undo notification has been tapped.
808828bc86ffcb1274fb461fbb25cdc2a07ae76b6c8Andrew Sapperstein     */
8093168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    public static void cancelUndoNotification(final Context context,
8103168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            final NotificationAction notificationAction) {
811781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy        LogUtils.i(LOG_TAG, "cancelUndoNotification for %s",
812781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy                notificationAction.getNotificationActionType());
813781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy
814ddd17bc2963b67ba07dfd1e2d9b1f17abf8c8e4aAndrew Sapperstein        final Account account = notificationAction.getAccount();
815ddd17bc2963b67ba07dfd1e2d9b1f17abf8c8e4aAndrew Sapperstein        final Folder folder = notificationAction.getFolder();
816828bc86ffcb1274fb461fbb25cdc2a07ae76b6c8Andrew Sapperstein        final Conversation conversation = notificationAction.getConversation();
817b90a813b107d8f43236e2d3fe12f299d94c82ce8Tony Mantler        final int notificationId =
818b90a813b107d8f43236e2d3fe12f299d94c82ce8Tony Mantler                NotificationUtils.getNotificationId(account.getAccountManagerAccount(), folder);
819828bc86ffcb1274fb461fbb25cdc2a07ae76b6c8Andrew Sapperstein
820828bc86ffcb1274fb461fbb25cdc2a07ae76b6c8Andrew Sapperstein        // Note: we must add the conversation before removing the undo notification
821828bc86ffcb1274fb461fbb25cdc2a07ae76b6c8Andrew Sapperstein        // Otherwise, the observer for sUndoNotifications gets called, which calls
822828bc86ffcb1274fb461fbb25cdc2a07ae76b6c8Andrew Sapperstein        // handleNotificationActions before the undone conversation has been added to the set.
823828bc86ffcb1274fb461fbb25cdc2a07ae76b6c8Andrew Sapperstein        sUndoneConversations.add(conversation);
824caa952b4074b3d8a9f9d869355c4a98fcb904dd1Scott Kennedy        removeUndoNotification(context, notificationId, false);
825ddd17bc2963b67ba07dfd1e2d9b1f17abf8c8e4aAndrew Sapperstein        resendNotifications(context, account, folder);
8263168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    }
8273168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
8283168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    /**
8293168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     * If an undo notification is left alone for a long enough time, it will disappear, this method
8303168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     * will be called, and the action will be finalized.
8313168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     */
8323168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    public static void processUndoNotification(final Context context,
8333168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy            final NotificationAction notificationAction) {
834781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy        LogUtils.i(LOG_TAG, "processUndoNotification, %s",
835781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy                notificationAction.getNotificationActionType());
836781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy
837ddd17bc2963b67ba07dfd1e2d9b1f17abf8c8e4aAndrew Sapperstein        final Account account = notificationAction.getAccount();
838ddd17bc2963b67ba07dfd1e2d9b1f17abf8c8e4aAndrew Sapperstein        final Folder folder = notificationAction.getFolder();
839d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy        final int notificationId = NotificationUtils.getNotificationId(
840b90a813b107d8f43236e2d3fe12f299d94c82ce8Tony Mantler                account.getAccountManagerAccount(), folder);
841caa952b4074b3d8a9f9d869355c4a98fcb904dd1Scott Kennedy        removeUndoNotification(context, notificationId, true);
8423168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        sNotificationTimestamps.delete(notificationId);
8433168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        processDestructiveAction(context, notificationAction);
8443168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    }
8453168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy
846606893390dcb49a88833aa17955dbe96fa41ae4aScott Kennedy    /**
847606893390dcb49a88833aa17955dbe96fa41ae4aScott Kennedy     * Removes the undo notification.
848caa952b4074b3d8a9f9d869355c4a98fcb904dd1Scott Kennedy     *
849caa952b4074b3d8a9f9d869355c4a98fcb904dd1Scott Kennedy     * @param removeNow <code>true</code> to remove it from the drawer right away,
850caa952b4074b3d8a9f9d869355c4a98fcb904dd1Scott Kennedy     *        <code>false</code> to just remove the reference to it
851606893390dcb49a88833aa17955dbe96fa41ae4aScott Kennedy     */
852caa952b4074b3d8a9f9d869355c4a98fcb904dd1Scott Kennedy    private static void removeUndoNotification(
853caa952b4074b3d8a9f9d869355c4a98fcb904dd1Scott Kennedy            final Context context, final int notificationId, final boolean removeNow) {
854606893390dcb49a88833aa17955dbe96fa41ae4aScott Kennedy        sUndoNotifications.delete(notificationId);
855606893390dcb49a88833aa17955dbe96fa41ae4aScott Kennedy
856caa952b4074b3d8a9f9d869355c4a98fcb904dd1Scott Kennedy        if (removeNow) {
857caa952b4074b3d8a9f9d869355c4a98fcb904dd1Scott Kennedy            final NotificationManager notificationManager =
858caa952b4074b3d8a9f9d869355c4a98fcb904dd1Scott Kennedy                    (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
859caa952b4074b3d8a9f9d869355c4a98fcb904dd1Scott Kennedy            notificationManager.cancel(notificationId);
860caa952b4074b3d8a9f9d869355c4a98fcb904dd1Scott Kennedy        }
861606893390dcb49a88833aa17955dbe96fa41ae4aScott Kennedy    }
862606893390dcb49a88833aa17955dbe96fa41ae4aScott Kennedy
8633168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    /**
8643168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     * Broadcasts an {@link Intent} to inform the app to resend its notifications.
8653168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy     */
866ddd17bc2963b67ba07dfd1e2d9b1f17abf8c8e4aAndrew Sapperstein    public static void resendNotifications(final Context context, final Account account,
867ddd17bc2963b67ba07dfd1e2d9b1f17abf8c8e4aAndrew Sapperstein            final Folder folder) {
868781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy        LogUtils.i(LOG_TAG, "resendNotifications account: %s, folder: %s",
869de56df00df1f02977a0013b3c474794b5264fe9fRégis Décamps                account == null ? null : LogUtils.sanitizeName(LOG_TAG, account.getEmailAddress()),
870de56df00df1f02977a0013b3c474794b5264fe9fRégis Décamps                folder == null ? null : LogUtils.sanitizeName(LOG_TAG, folder.name));
871781f7e322283229483b048776fcb6857c38a72b5Scott Kennedy
872f2566a42b5dec4e846391ee0d7ecae0891356653Scott Kennedy        final Intent intent = new Intent(MailIntentService.ACTION_RESEND_NOTIFICATIONS);
873612eb3287c1261952f16dff7bdf5715b9b92b8daRégis Décamps        intent.setPackage(context.getPackageName()); // Make sure we only deliver this to ourselves
874612eb3287c1261952f16dff7bdf5715b9b92b8daRégis Décamps        if (account != null) {
875612eb3287c1261952f16dff7bdf5715b9b92b8daRégis Décamps            intent.putExtra(Utils.EXTRA_ACCOUNT_URI, account.uri);
876612eb3287c1261952f16dff7bdf5715b9b92b8daRégis Décamps        }
877612eb3287c1261952f16dff7bdf5715b9b92b8daRégis Décamps        if (folder != null) {
878612eb3287c1261952f16dff7bdf5715b9b92b8daRégis Décamps            intent.putExtra(Utils.EXTRA_FOLDER_URI, folder.folderUri.fullUri);
879612eb3287c1261952f16dff7bdf5715b9b92b8daRégis Décamps        }
8803168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy        context.startService(intent);
8813168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy    }
88208a079c3d2857e365736432b2691187767eb116fScott Kennedy
88308a079c3d2857e365736432b2691187767eb116fScott Kennedy    public static void registerUndoNotificationObserver(final DataSetObserver observer) {
88408a079c3d2857e365736432b2691187767eb116fScott Kennedy        sUndoNotifications.getDataSetObservable().registerObserver(observer);
88508a079c3d2857e365736432b2691187767eb116fScott Kennedy    }
88608a079c3d2857e365736432b2691187767eb116fScott Kennedy
88708a079c3d2857e365736432b2691187767eb116fScott Kennedy    public static void unregisterUndoNotificationObserver(final DataSetObserver observer) {
88808a079c3d2857e365736432b2691187767eb116fScott Kennedy        sUndoNotifications.getDataSetObservable().unregisterObserver(observer);
88908a079c3d2857e365736432b2691187767eb116fScott Kennedy    }
890621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy
891621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy    /**
892621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy     * <p>
893621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy     * This is a slight hack to avoid an exception in the remote AlarmManagerService process. The
894621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy     * AlarmManager adds extra data to this Intent which causes it to inflate. Since the remote
895621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy     * process does not know about the NotificationAction class, it throws a ClassNotFoundException.
896621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy     * </p>
897621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy     * <p>
898621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy     * To avoid this, we marshall the data ourselves and then parcel a plain byte[] array. The
899621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy     * NotificationActionIntentService class knows to build the NotificationAction object from the
900621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy     * byte[] array.
901621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy     * </p>
902621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy     */
903621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy    private static void putNotificationActionExtra(final Intent intent,
904621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy            final NotificationAction notificationAction) {
905621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy        final Parcel out = Parcel.obtain();
906621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy        notificationAction.writeToParcel(out, 0);
907621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy        out.setDataPosition(0);
908621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy        intent.putExtra(NotificationActionIntentService.EXTRA_NOTIFICATION_ACTION, out.marshall());
909621981ca3fb5f7b461edeac7ac4df765fe72f582Scott Kennedy    }
9103168c2a75edbf597932ab9edfd96037ceba99b35Scott Kennedy}
911