Home | History | Annotate | Download | only in mail
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package com.android.mail;
     17 
     18 import android.app.IntentService;
     19 import android.content.ContentResolver;
     20 import android.content.ContentValues;
     21 import android.content.Context;
     22 import android.content.Intent;
     23 import android.net.Uri;
     24 import android.os.Parcel;
     25 import android.support.v4.app.NotificationManagerCompat;
     26 
     27 import com.android.mail.analytics.Analytics;
     28 import com.android.mail.providers.Message;
     29 import com.android.mail.providers.UIProvider;
     30 import com.android.mail.utils.LogUtils;
     31 import com.android.mail.utils.NotificationActionUtils;
     32 import com.android.mail.utils.NotificationActionUtils.NotificationAction;
     33 
     34 /**
     35  * Processes notification action {@link Intent}s that need to run off the main thread.
     36  */
     37 public class NotificationActionIntentService extends IntentService {
     38     private static final String LOG_TAG = "NotifActionIS";
     39 
     40     // Compose actions
     41     public static final String ACTION_REPLY = "com.android.mail.action.notification.REPLY";
     42     public static final String ACTION_REPLY_ALL = "com.android.mail.action.notification.REPLY_ALL";
     43     public static final String ACTION_FORWARD = "com.android.mail.action.notification.FORWARD";
     44     // Toggle actions
     45     public static final String ACTION_MARK_READ = "com.android.mail.action.notification.MARK_READ";
     46 
     47     // Destructive actions - These just display the undo bar
     48     public static final String ACTION_ARCHIVE_REMOVE_LABEL =
     49             "com.android.mail.action.notification.ARCHIVE";
     50     public static final String ACTION_DELETE = "com.android.mail.action.notification.DELETE";
     51 
     52     /**
     53      * This action cancels the undo notification, and does not commit any changes.
     54      */
     55     public static final String ACTION_UNDO = "com.android.mail.action.notification.UNDO";
     56 
     57     /**
     58      * This action performs the actual destructive action.
     59      */
     60     public static final String ACTION_DESTRUCT = "com.android.mail.action.notification.DESTRUCT";
     61 
     62     public static final String EXTRA_NOTIFICATION_ACTION =
     63             "com.android.mail.extra.EXTRA_NOTIFICATION_ACTION";
     64     public static final String ACTION_UNDO_TIMEOUT =
     65             "com.android.mail.action.notification.UNDO_TIMEOUT";
     66 
     67     public NotificationActionIntentService() {
     68         super("NotificationActionIntentService");
     69     }
     70 
     71     private static void logNotificationAction(String intentAction, NotificationAction action) {
     72         final String eventAction;
     73         final String eventLabel;
     74 
     75         if (ACTION_ARCHIVE_REMOVE_LABEL.equals(intentAction)) {
     76             eventAction = "archive_remove_label";
     77             eventLabel = action.getFolder().getTypeDescription();
     78         } else if (ACTION_DELETE.equals(intentAction)) {
     79             eventAction = "delete";
     80             eventLabel = null;
     81         } else {
     82             eventAction = intentAction;
     83             eventLabel = null;
     84         }
     85 
     86         Analytics.getInstance().sendEvent("notification_action", eventAction, eventLabel, 0);
     87     }
     88 
     89     @Override
     90     protected void onHandleIntent(final Intent intent) {
     91         final Context context = this;
     92         final String action = intent.getAction();
     93 
     94         /*
     95          * Grab the alarm from the intent. Since the remote AlarmManagerService fills in the Intent
     96          * to add some extra data, it must unparcel the NotificationAction object. It throws a
     97          * ClassNotFoundException when unparcelling.
     98          * To avoid this, do the marshalling ourselves.
     99          */
    100         final NotificationAction notificationAction;
    101         final byte[] data = intent.getByteArrayExtra(EXTRA_NOTIFICATION_ACTION);
    102         if (data != null) {
    103             final Parcel in = Parcel.obtain();
    104             in.unmarshall(data, 0, data.length);
    105             in.setDataPosition(0);
    106             notificationAction = NotificationAction.CREATOR.createFromParcel(in,
    107                     NotificationAction.class.getClassLoader());
    108         } else {
    109             LogUtils.wtf(LOG_TAG, "data was null trying to unparcel the NotificationAction");
    110             return;
    111         }
    112 
    113         final Message message = notificationAction.getMessage();
    114 
    115         final ContentResolver contentResolver = getContentResolver();
    116 
    117         LogUtils.i(LOG_TAG, "Handling %s", action);
    118 
    119         logNotificationAction(action, notificationAction);
    120 
    121         if (notificationAction.getSource() == NotificationAction.SOURCE_REMOTE) {
    122             // Skip undo if the action is bridged from remote node.  This should be similar to the
    123             // logic after the Undo notification expires in a regular flow.
    124             LogUtils.d(LOG_TAG, "Canceling %s", notificationAction.getNotificationId());
    125             NotificationManagerCompat.from(context).cancel(notificationAction.getNotificationId());
    126             NotificationActionUtils.processDestructiveAction(this, notificationAction);
    127             NotificationActionUtils.resendNotifications(context, notificationAction.getAccount(),
    128                     notificationAction.getFolder());
    129             return;
    130         }
    131 
    132         if (ACTION_UNDO.equals(action)) {
    133             NotificationActionUtils.cancelUndoTimeout(context, notificationAction);
    134             NotificationActionUtils.cancelUndoNotification(context, notificationAction);
    135         } else if (ACTION_ARCHIVE_REMOVE_LABEL.equals(action) || ACTION_DELETE.equals(action)) {
    136             // All we need to do is switch to an Undo notification
    137             NotificationActionUtils.createUndoNotification(context, notificationAction);
    138 
    139             NotificationActionUtils.registerUndoTimeout(context, notificationAction);
    140         } else {
    141             if (ACTION_UNDO_TIMEOUT.equals(action) || ACTION_DESTRUCT.equals(action)) {
    142                 // Process the action
    143                 NotificationActionUtils.cancelUndoTimeout(this, notificationAction);
    144                 NotificationActionUtils.processUndoNotification(this, notificationAction);
    145             } else if (ACTION_MARK_READ.equals(action)) {
    146                 final Uri uri = message.uri;
    147 
    148                 final ContentValues values = new ContentValues(1);
    149                 values.put(UIProvider.MessageColumns.READ, 1);
    150 
    151                 contentResolver.update(uri, values, null, null);
    152             }
    153 
    154             NotificationActionUtils.resendNotifications(context, notificationAction.getAccount(),
    155                     notificationAction.getFolder());
    156         }
    157     }
    158 }
    159