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