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.Bundle; 24 import android.support.v4.app.NotificationCompat.BigPictureStyle; 25 import android.support.v4.app.NotificationManagerCompat; 26 import android.support.v4.app.RemoteInput; 27 import android.support.v7.app.NotificationCompat; 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.wearnotifications.mock.MockDatabase; 34 35 /** 36 * Asynchronously handles updating social app posts (and active Notification) with comments from 37 * user. Notification for social app use BigPictureStyle. 38 */ 39 public class BigPictureSocialIntentService extends IntentService { 40 41 private static final String TAG = "BigPictureService"; 42 43 public static final String ACTION_COMMENT = 44 "com.example.android.wearable.wear.wearnotifications.handlers.action.COMMENT"; 45 46 public static final String EXTRA_COMMENT = 47 "com.example.android.wearable.wear.wearnotifications.handlers.extra.COMMENT"; 48 BigPictureSocialIntentService()49 public BigPictureSocialIntentService() { 50 super("BigPictureSocialIntentService"); 51 } 52 53 @Override onHandleIntent(Intent intent)54 protected void onHandleIntent(Intent intent) { 55 Log.d(TAG, "onHandleIntent(): " + intent); 56 57 if (intent != null) { 58 final String action = intent.getAction(); 59 if (ACTION_COMMENT.equals(action)) { 60 handleActionComment(getMessage(intent)); 61 } 62 } 63 } 64 65 /** 66 * Handles action for adding a comment from the notification. 67 */ handleActionComment(CharSequence comment)68 private void handleActionComment(CharSequence comment) { 69 Log.d(TAG, "handleActionComment(): " + comment); 70 71 if (comment != null) { 72 73 // TODO: Asynchronously save your message to Database and servers. 74 75 /* 76 * You have two options for updating your notification (this class uses approach #2): 77 * 78 * 1. Use a new NotificationCompatBuilder to create the Notification. This approach 79 * requires you to get *ALL* the information that existed in the previous 80 * Notification (and updates) and pass it to the builder. This is the approach used in 81 * the MainActivity. 82 * 83 * 2. Use the original NotificationCompatBuilder to create the Notification. This 84 * approach requires you to store a reference to the original builder. The benefit is 85 * you only need the new/updated information. In our case, the comment from the user 86 * regarding the post (which we already have here). 87 * 88 * IMPORTANT NOTE: You shouldn't save/modify the resulting Notification object using 89 * its member variables and/or legacy APIs. If you want to retain anything from update 90 * to update, retain the Builder as option 2 outlines. 91 */ 92 93 // Retrieves NotificationCompat.Builder used to create initial Notification 94 NotificationCompat.Builder notificationCompatBuilder = 95 GlobalNotificationBuilder.getNotificationCompatBuilderInstance(); 96 97 // Recreate builder from persistent state if app process is killed 98 if (notificationCompatBuilder == null) { 99 // Note: New builder set globally in the method 100 notificationCompatBuilder = recreateBuilderWithBigPictureStyle(); 101 } 102 103 // Updates active Notification 104 Notification updatedNotification = notificationCompatBuilder 105 // Adds a line and comment below content in Notification 106 .setRemoteInputHistory(new CharSequence[]{comment}) 107 .build(); 108 109 // Pushes out the updated Notification 110 NotificationManagerCompat notificationManagerCompat = 111 NotificationManagerCompat.from(getApplicationContext()); 112 notificationManagerCompat.notify( 113 StandaloneMainActivity.NOTIFICATION_ID, 114 updatedNotification); 115 } 116 } 117 118 /* 119 * Extracts CharSequence created from the RemoteInput associated with the Notification. 120 */ getMessage(Intent intent)121 private CharSequence getMessage(Intent intent) { 122 Bundle remoteInput = RemoteInput.getResultsFromIntent(intent); 123 if (remoteInput != null) { 124 return remoteInput.getCharSequence(EXTRA_COMMENT); 125 } 126 return null; 127 } 128 129 /* 130 * This recreates the notification from the persistent state in case the app process was killed. 131 * It is basically the same code for creating the Notification from StandaloneMainActivity. 132 */ recreateBuilderWithBigPictureStyle()133 private NotificationCompat.Builder recreateBuilderWithBigPictureStyle() { 134 135 // Main steps for building a BIG_PICTURE_STYLE notification (for more detailed comments on 136 // building this notification, check StandaloneMainActivity.java): 137 // 0. Get your data 138 // 1. Build the BIG_PICTURE_STYLE 139 // 2. Set up main Intent for notification 140 // 3. Set up RemoteInput, so users can input (keyboard and voice) from notification 141 // 4. Build and issue the notification 142 143 // 0. Get your data (everything unique per Notification) 144 MockDatabase.BigPictureStyleSocialAppData bigPictureStyleSocialAppData = 145 MockDatabase.getBigPictureStyleData(); 146 147 // 1. Build the BIG_PICTURE_STYLE 148 BigPictureStyle bigPictureStyle = new NotificationCompat.BigPictureStyle() 149 .bigPicture( 150 BitmapFactory.decodeResource( 151 getResources(), 152 bigPictureStyleSocialAppData.getBigImage())) 153 .setBigContentTitle(bigPictureStyleSocialAppData.getBigContentTitle()) 154 .setSummaryText(bigPictureStyleSocialAppData.getSummaryText()); 155 156 // 2. Set up main Intent for notification 157 Intent mainIntent = new Intent(this, BigPictureSocialMainActivity.class); 158 159 PendingIntent mainPendingIntent = 160 PendingIntent.getActivity( 161 this, 162 0, 163 mainIntent, 164 PendingIntent.FLAG_UPDATE_CURRENT 165 ); 166 167 // 3. Set up a RemoteInput Action, so users can input (keyboard, drawing, voice) directly 168 // from the notification without entering the app. 169 String replyLabel = getString(R.string.reply_label); 170 RemoteInput remoteInput = 171 new RemoteInput.Builder(BigPictureSocialIntentService.EXTRA_COMMENT) 172 .setLabel(replyLabel) 173 .setChoices(bigPictureStyleSocialAppData.getPossiblePostResponses()) 174 .build(); 175 176 Intent replyIntent = new Intent(this, BigPictureSocialIntentService.class); 177 replyIntent.setAction(BigPictureSocialIntentService.ACTION_COMMENT); 178 PendingIntent replyActionPendingIntent = PendingIntent.getService(this, 0, replyIntent, 0); 179 180 // Enable action to appear inline on Wear 2.0 (24+). This means it will appear over the 181 // lower portion of the Notification for easy action (only possible for one action). 182 final NotificationCompat.Action.WearableExtender inlineActionForWear2 = 183 new NotificationCompat.Action.WearableExtender() 184 .setHintDisplayActionInline(true) 185 .setHintLaunchesActivity(false); 186 187 NotificationCompat.Action replyAction = 188 new NotificationCompat.Action.Builder( 189 R.drawable.ic_reply_white_18dp, 190 replyLabel, 191 replyActionPendingIntent) 192 .addRemoteInput(remoteInput) 193 // Add WearableExtender to enable inline actions 194 .extend(inlineActionForWear2) 195 .build(); 196 197 // 4. Build and issue the notification 198 NotificationCompat.Builder notificationCompatBuilder = 199 new NotificationCompat.Builder(getApplicationContext()); 200 201 GlobalNotificationBuilder.setNotificationCompatBuilderInstance(notificationCompatBuilder); 202 203 // Build notification 204 notificationCompatBuilder 205 .setStyle(bigPictureStyle) 206 .setContentTitle(bigPictureStyleSocialAppData.getContentTitle()) 207 .setContentText(bigPictureStyleSocialAppData.getContentText()) 208 .setSmallIcon(R.drawable.ic_launcher) 209 .setLargeIcon(BitmapFactory.decodeResource( 210 getResources(), 211 R.drawable.ic_person_black_48dp)) 212 .setContentIntent(mainPendingIntent) 213 .setColor(getResources().getColor(R.color.colorPrimary)) 214 .setSubText(Integer.toString(1)) 215 .addAction(replyAction) 216 .setCategory(Notification.CATEGORY_SOCIAL) 217 .setPriority(Notification.PRIORITY_HIGH) 218 .setVisibility(Notification.VISIBILITY_PRIVATE) 219 .extend(new NotificationCompat.WearableExtender() 220 .setHintContentIntentLaunchesActivity(true)); 221 222 for (String name : bigPictureStyleSocialAppData.getParticipants()) { 223 notificationCompatBuilder.addPerson(name); 224 } 225 226 return notificationCompatBuilder; 227 } 228 }