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.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 
     49     public BigPictureSocialIntentService() {
     50         super("BigPictureSocialIntentService");
     51     }
     52 
     53     @Override
     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      */
     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      */
    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      */
    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 }