Home | History | Annotate | Download | only in handlers
      1 /*
      2 Copyright 2016 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.example.android.wearable.wear.wearnotifications.handlers;
     17 
     18 import android.app.IntentService;
     19 import android.app.Notification;
     20 import android.app.PendingIntent;
     21 import android.content.Intent;
     22 import android.graphics.BitmapFactory;
     23 import android.os.Build;
     24 import android.support.v4.app.NotificationCompat;
     25 import android.support.v4.app.NotificationCompat.BigTextStyle;
     26 import android.support.v4.app.NotificationManagerCompat;
     27 import android.support.v4.content.ContextCompat;
     28 import android.util.Log;
     29 
     30 import com.example.android.wearable.wear.wearnotifications.GlobalNotificationBuilder;
     31 import com.example.android.wearable.wear.wearnotifications.R;
     32 import com.example.android.wearable.wear.wearnotifications.StandaloneMainActivity;
     33 import com.example.android.wearable.wear.common.mock.MockDatabase;
     34 
     35 import java.util.concurrent.TimeUnit;
     36 
     37 /**
     38  * Asynchronously handles snooze and dismiss actions for reminder app (and active Notification).
     39  * Notification for for reminder app uses BigTextStyle.
     40  */
     41 public class BigTextIntentService extends IntentService {
     42 
     43     private static final String TAG = "BigTextService";
     44 
     45     public static final String ACTION_DISMISS =
     46             "com.example.android.wearable.wear.wearnotifications.handlers.action.DISMISS";
     47     public static final String ACTION_SNOOZE =
     48             "com.example.android.wearable.wear.wearnotifications.handlers.action.SNOOZE";
     49 
     50     private static final long SNOOZE_TIME = TimeUnit.SECONDS.toMillis(5);
     51 
     52     public BigTextIntentService() {
     53         super("BigTextIntentService");
     54     }
     55 
     56     @Override
     57     protected void onHandleIntent(Intent intent) {
     58         Log.d(TAG, "onHandleIntent(): " + intent);
     59 
     60         if (intent != null) {
     61             final String action = intent.getAction();
     62             if (ACTION_DISMISS.equals(action)) {
     63                 handleActionDismiss();
     64             } else if (ACTION_SNOOZE.equals(action)) {
     65                 handleActionSnooze();
     66             }
     67         }
     68     }
     69 
     70     /**
     71      * Handles action Dismiss in the provided background thread.
     72      */
     73     private void handleActionDismiss() {
     74         Log.d(TAG, "handleActionDismiss()");
     75 
     76         NotificationManagerCompat notificationManagerCompat =
     77                 NotificationManagerCompat.from(getApplicationContext());
     78         notificationManagerCompat.cancel(StandaloneMainActivity.NOTIFICATION_ID);
     79     }
     80 
     81     /**
     82      * Handles action Snooze in the provided background thread.
     83      */
     84     private void handleActionSnooze() {
     85         Log.d(TAG, "handleActionSnooze()");
     86 
     87         // You could use NotificationManager.getActiveNotifications() if you are targeting SDK 23
     88         // and above, but we are targeting devices with lower SDK API numbers, so we saved the
     89         // builder globally and get the notification back to recreate it later.
     90 
     91         NotificationCompat.Builder notificationCompatBuilder =
     92                 GlobalNotificationBuilder.getNotificationCompatBuilderInstance();
     93 
     94         // Recreate builder from persistent state if app process is killed
     95         if (notificationCompatBuilder == null) {
     96             // Note: New builder set globally in the method
     97             notificationCompatBuilder = recreateBuilderWithBigTextStyle();
     98         }
     99 
    100         Notification notification;
    101         notification = notificationCompatBuilder.build();
    102 
    103 
    104         if (notification != null) {
    105             NotificationManagerCompat notificationManagerCompat =
    106                     NotificationManagerCompat.from(getApplicationContext());
    107 
    108             notificationManagerCompat.cancel(StandaloneMainActivity.NOTIFICATION_ID);
    109 
    110             try {
    111                 Thread.sleep(SNOOZE_TIME);
    112             } catch (InterruptedException ex) {
    113                 Thread.currentThread().interrupt();
    114             }
    115             notificationManagerCompat.notify(StandaloneMainActivity.NOTIFICATION_ID, notification);
    116         }
    117 
    118     }
    119 
    120     /*
    121      * This recreates the notification from the persistent state in case the app process was killed.
    122      * It is basically the same code for creating the Notification from StandaloneMainActivity.
    123      */
    124     private NotificationCompat.Builder recreateBuilderWithBigTextStyle() {
    125 
    126         // Main steps for building a BIG_TEXT_STYLE notification (for more detailed comments on
    127         // building this notification, check StandaloneMainActivity.java):
    128         //      0. Get your data
    129         //      1. Retrieve Notification Channel for O and beyond devices (26+)
    130         //      2. Build the BIG_TEXT_STYLE
    131         //      3. Set up main Intent for notification
    132         //      4. Create additional Actions for the Notification
    133         //      5. Build and issue the notification
    134 
    135         // 0. Get your data (everything unique per Notification).
    136         MockDatabase.BigTextStyleReminderAppData bigTextStyleReminderAppData =
    137                 MockDatabase.getBigTextStyleData();
    138 
    139         // 1. Retrieve Notification Channel for O and beyond devices (26+). We don't need to create
    140         //    the NotificationChannel, since it was created the first time this Notification was
    141         //    created.
    142         String notificationChannelId = bigTextStyleReminderAppData.getChannelId();
    143 
    144         // 2. Build the BIG_TEXT_STYLE.
    145         BigTextStyle bigTextStyle = new NotificationCompat.BigTextStyle()
    146                 .bigText(bigTextStyleReminderAppData.getBigText())
    147                 .setBigContentTitle(bigTextStyleReminderAppData.getBigContentTitle())
    148                 .setSummaryText(bigTextStyleReminderAppData.getSummaryText());
    149 
    150 
    151         // 3. Set up main Intent for notification.
    152         Intent mainIntent = new Intent(this, BigTextMainActivity.class);
    153 
    154         PendingIntent mainPendingIntent =
    155                 PendingIntent.getActivity(
    156                         this,
    157                         0,
    158                         mainIntent,
    159                         PendingIntent.FLAG_UPDATE_CURRENT
    160                 );
    161 
    162 
    163         // 4. Create additional Actions (Intents) for the Notification.
    164 
    165         // Snooze Action.
    166         Intent snoozeIntent = new Intent(this, BigTextIntentService.class);
    167         snoozeIntent.setAction(BigTextIntentService.ACTION_SNOOZE);
    168 
    169         PendingIntent snoozePendingIntent = PendingIntent.getService(this, 0, snoozeIntent, 0);
    170         NotificationCompat.Action snoozeAction =
    171                 new NotificationCompat.Action.Builder(
    172                         R.drawable.ic_alarm_white_48dp,
    173                         "Snooze",
    174                         snoozePendingIntent)
    175                         .build();
    176 
    177         // Dismiss Action
    178         Intent dismissIntent = new Intent(this, BigTextIntentService.class);
    179         dismissIntent.setAction(BigTextIntentService.ACTION_DISMISS);
    180 
    181         PendingIntent dismissPendingIntent = PendingIntent.getService(this, 0, dismissIntent, 0);
    182         NotificationCompat.Action dismissAction =
    183                 new NotificationCompat.Action.Builder(
    184                         R.drawable.ic_cancel_white_48dp,
    185                         "Dismiss",
    186                         dismissPendingIntent)
    187                         .build();
    188 
    189 
    190         // 5. Build and issue the notification.
    191 
    192         // Notification Channel Id is ignored for Android pre O (26).
    193         NotificationCompat.Builder notificationCompatBuilder =
    194                 new NotificationCompat.Builder(
    195                         getApplicationContext(), notificationChannelId);
    196 
    197         GlobalNotificationBuilder.setNotificationCompatBuilderInstance(notificationCompatBuilder);
    198 
    199         notificationCompatBuilder
    200                 .setStyle(bigTextStyle)
    201                 .setContentTitle(bigTextStyleReminderAppData.getContentTitle())
    202                 .setContentText(bigTextStyleReminderAppData.getContentText())
    203                 .setSmallIcon(R.drawable.ic_launcher)
    204                 .setLargeIcon(BitmapFactory.decodeResource(
    205                         getResources(),
    206                         R.drawable.ic_alarm_white_48dp))
    207                 .setColor(ContextCompat.getColor(getApplicationContext(), R.color.colorPrimary))
    208                 .setCategory(Notification.CATEGORY_REMINDER)
    209                 .setPriority(bigTextStyleReminderAppData.getPriority())
    210                 .setVisibility(bigTextStyleReminderAppData.getChannelLockscreenVisibility())
    211                 .addAction(snoozeAction)
    212                 .addAction(dismissAction);
    213 
    214         /* REPLICATE_NOTIFICATION_STYLE_CODE:
    215          * You can replicate Notification Style functionality on Wear 2.0 (24+) by not setting the
    216          * main content intent, that is, skipping the call setContentIntent(). However, you need to
    217          * still allow the user to open the native Wear app from the Notification itself, so you
    218          * add an action to launch the app.
    219          */
    220         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    221 
    222             // Enables launching app in Wear 2.0 while keeping the old Notification Style behavior.
    223             NotificationCompat.Action mainAction = new NotificationCompat.Action.Builder(
    224                     R.drawable.ic_launcher,
    225                     "Open",
    226                     mainPendingIntent)
    227                     .build();
    228 
    229             notificationCompatBuilder.addAction(mainAction);
    230 
    231         } else {
    232             // Wear 1.+ still functions the same, so we set the main content intent.
    233             notificationCompatBuilder.setContentIntent(mainPendingIntent);
    234         }
    235 
    236         return notificationCompatBuilder;
    237     }
    238 }