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 }