Home | History | Annotate | Download | only in com.example.android.wearable.wear.wearnotifications
      1 /*
      2  * Copyright (C) 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;
     17 
     18 import android.app.Notification;
     19 import android.app.PendingIntent;
     20 import android.content.Intent;
     21 import android.graphics.BitmapFactory;
     22 import android.os.Build;
     23 import android.os.Bundle;
     24 import android.support.design.widget.Snackbar;
     25 import android.support.v4.app.NotificationCompat.BigPictureStyle;
     26 import android.support.v4.app.NotificationCompat.BigTextStyle;
     27 import android.support.v4.app.NotificationCompat.InboxStyle;
     28 import android.support.v4.app.NotificationCompat.MessagingStyle;
     29 import android.support.v4.app.NotificationManagerCompat;
     30 import android.support.v4.app.RemoteInput;
     31 import android.support.v7.app.NotificationCompat;
     32 import android.support.wearable.activity.WearableActivity;
     33 import android.support.wearable.view.WearableRecyclerView;
     34 import android.util.Log;
     35 import android.view.View;
     36 import android.widget.FrameLayout;
     37 
     38 import com.example.android.wearable.wear.wearnotifications.handlers.BigPictureSocialIntentService;
     39 import com.example.android.wearable.wear.wearnotifications.handlers.BigPictureSocialMainActivity;
     40 import com.example.android.wearable.wear.wearnotifications.handlers.BigTextIntentService;
     41 import com.example.android.wearable.wear.wearnotifications.handlers.BigTextMainActivity;
     42 import com.example.android.wearable.wear.wearnotifications.handlers.InboxMainActivity;
     43 import com.example.android.wearable.wear.wearnotifications.handlers.MessagingIntentService;
     44 import com.example.android.wearable.wear.wearnotifications.handlers.MessagingMainActivity;
     45 import com.example.android.wearable.wear.wearnotifications.mock.MockDatabase;
     46 
     47 /**
     48  * Demonstrates best practice for {@link NotificationCompat} Notifications created by local
     49  * standalone Android Wear apps. All {@link NotificationCompat} examples use
     50  * {@link NotificationCompat.Style}.
     51  */
     52 public class StandaloneMainActivity extends WearableActivity {
     53 
     54     private static final String TAG = "StandaloneMainActivity";
     55 
     56     public static final int NOTIFICATION_ID = 888;
     57 
     58     /*
     59      * Used to represent each major {@link NotificationCompat.Style} in the
     60      * {@link WearableRecyclerView}. These constants are also used in a switch statement when one
     61      * of the items is selected to create the appropriate {@link Notification}.
     62      */
     63     private static final String BIG_TEXT_STYLE = "BIG_TEXT_STYLE";
     64     private static final String BIG_PICTURE_STYLE = "BIG_PICTURE_STYLE";
     65     private static final String INBOX_STYLE = "INBOX_STYLE";
     66     private static final String MESSAGING_STYLE = "MESSAGING_STYLE";
     67 
     68     /*
     69     Collection of major {@link NotificationCompat.Style} to create {@link CustomRecyclerAdapter}
     70     for {@link WearableRecyclerView}.
     71     */
     72     private static final String[] NOTIFICATION_STYLES =
     73             {BIG_TEXT_STYLE, BIG_PICTURE_STYLE, INBOX_STYLE, MESSAGING_STYLE};
     74 
     75     private NotificationManagerCompat mNotificationManagerCompat;
     76 
     77     // Needed for {@link SnackBar} to alert users when {@link Notification} are disabled for app.
     78     private FrameLayout mMainFrameLayout;
     79     private WearableRecyclerView mWearableRecyclerView;
     80     private CustomRecyclerAdapter mCustomRecyclerAdapter;
     81 
     82     @Override
     83     protected void onCreate(Bundle savedInstanceState) {
     84         super.onCreate(savedInstanceState);
     85         Log.d(TAG, "onCreate()");
     86 
     87         setContentView(R.layout.activity_main);
     88         setAmbientEnabled();
     89 
     90         mNotificationManagerCompat = NotificationManagerCompat.from(getApplicationContext());
     91 
     92         mMainFrameLayout = (FrameLayout) findViewById(R.id.mainFrameLayout);
     93         mWearableRecyclerView = (WearableRecyclerView) findViewById(R.id.recycler_view);
     94 
     95         // Aligns the first and last items on the list vertically centered on the screen.
     96         mWearableRecyclerView.setCenterEdgeItems(true);
     97 
     98         // Customizes scrolling (zoom) and offsets of WearableRecyclerView's items
     99         ScalingOffsettingHelper scalingOffsettingHelper = new ScalingOffsettingHelper();
    100         mWearableRecyclerView.setOffsettingHelper(scalingOffsettingHelper);
    101 
    102         // Improves performance because we know changes in content do not change the layout size of
    103         // the RecyclerView.
    104         mWearableRecyclerView.setHasFixedSize(true);
    105 
    106         // Specifies an adapter (see also next example).
    107         mCustomRecyclerAdapter = new CustomRecyclerAdapter(
    108                 NOTIFICATION_STYLES,
    109                 // Controller passes selected data from the Adapter out to this Activity to trigger
    110                 // updates in the UI/Notifications.
    111                 new Controller(this));
    112 
    113         mWearableRecyclerView.setAdapter(mCustomRecyclerAdapter);
    114     }
    115 
    116     // Called by WearableRecyclerView when an item is selected (check onCreate() for initialization)
    117     public void itemSelected(String data) {
    118 
    119         Log.d(TAG, "itemSelected()");
    120 
    121         boolean areNotificationsEnabled = mNotificationManagerCompat.areNotificationsEnabled();
    122 
    123         // If notifications are disabled, allow user to enable.
    124         if (!areNotificationsEnabled) {
    125             // Because the user took an action to create a notification, we create a prompt to let
    126             // the user re-enable notifications for this application again.
    127             Snackbar snackbar = Snackbar
    128                     .make(
    129                             mMainFrameLayout,
    130                             "", // Not enough space for both text and action text
    131                             Snackbar.LENGTH_LONG)
    132                     .setAction("Enable Notifications", new View.OnClickListener() {
    133                         @Override
    134                         public void onClick(View view) {
    135                             // Links to this app's notification settings
    136                             openNotificationSettingsForApp();
    137                         }
    138                     });
    139             snackbar.show();
    140             return;
    141         }
    142 
    143         String notificationStyle = data;
    144 
    145         switch (notificationStyle) {
    146             case BIG_TEXT_STYLE:
    147                 generateBigTextStyleNotification();
    148                 break;
    149 
    150             case BIG_PICTURE_STYLE:
    151                 generateBigPictureStyleNotification();
    152                 break;
    153 
    154             case INBOX_STYLE:
    155                 generateInboxStyleNotification();
    156                 break;
    157 
    158             case MESSAGING_STYLE:
    159                 generateMessagingStyleNotification();
    160                 break;
    161 
    162             default:
    163                 // continue below
    164         }
    165     }
    166 
    167     /*
    168      * Generates a BIG_TEXT_STYLE Notification that supports both Wear 1.+ and Wear 2.0.
    169      *
    170      * IMPORTANT NOTE:
    171      * This method includes extra code to replicate Notification Styles behavior from Wear 1.+ and
    172      * phones on Wear 2.0, i.e., the notification expands on click. To see the specific code in the
    173      * method, search for "REPLICATE_NOTIFICATION_STYLE_CODE".
    174      *
    175      * Notification Styles behave slightly different on Wear 2.0 when they are launched by a
    176      * native/local Wear app, i.e., they will NOT expand when the user taps them but will instead
    177      * take the user directly into the local app for the richest experience. In contrast, a bridged
    178      * Notification launched from the phone will expand with the style details (whether there is a
    179      * local app or not).
    180      *
    181      * If you want to see the new behavior, please review the generateBigPictureStyleNotification()
    182      * and generateMessagingStyleNotification() methods.
    183      */
    184     private void generateBigTextStyleNotification() {
    185 
    186         Log.d(TAG, "generateBigTextStyleNotification()");
    187 
    188         // Main steps for building a BIG_TEXT_STYLE notification:
    189         //      0. Get your data
    190         //      1. Build the BIG_TEXT_STYLE
    191         //      2. Set up main Intent for notification
    192         //      3. Create additional Actions for the Notification
    193         //      4. Build and issue the notification
    194 
    195         // 0. Get your data (everything unique per Notification)
    196         MockDatabase.BigTextStyleReminderAppData bigTextStyleReminderAppData =
    197                 MockDatabase.getBigTextStyleData();
    198 
    199         // 1. Build the BIG_TEXT_STYLE
    200         BigTextStyle bigTextStyle = new NotificationCompat.BigTextStyle()
    201                 // Overrides ContentText in the big form of the template
    202                 .bigText(bigTextStyleReminderAppData.getBigText())
    203                 // Overrides ContentTitle in the big form of the template
    204                 .setBigContentTitle(bigTextStyleReminderAppData.getBigContentTitle())
    205                 // Summary line after the detail section in the big form of the template
    206                 // Note: To improve readability, don't overload the user with info. If Summary Text
    207                 // doesn't add critical information, you should skip it.
    208                 .setSummaryText(bigTextStyleReminderAppData.getSummaryText());
    209 
    210 
    211         // 2. Set up main Intent for notification
    212         Intent mainIntent = new Intent(this, BigTextMainActivity.class);
    213 
    214         PendingIntent mainPendingIntent =
    215                 PendingIntent.getActivity(
    216                         this,
    217                         0,
    218                         mainIntent,
    219                         PendingIntent.FLAG_UPDATE_CURRENT
    220                 );
    221 
    222 
    223         // 3. Create additional Actions (Intents) for the Notification
    224 
    225         // In our case, we create two additional actions: a Snooze action and a Dismiss action.
    226 
    227         // Snooze Action
    228         Intent snoozeIntent = new Intent(this, BigTextIntentService.class);
    229         snoozeIntent.setAction(BigTextIntentService.ACTION_SNOOZE);
    230 
    231         PendingIntent snoozePendingIntent = PendingIntent.getService(this, 0, snoozeIntent, 0);
    232         NotificationCompat.Action snoozeAction =
    233                 new NotificationCompat.Action.Builder(
    234                         R.drawable.ic_alarm_white_48dp,
    235                         "Snooze",
    236                         snoozePendingIntent)
    237                         .build();
    238 
    239         // Dismiss Action
    240         Intent dismissIntent = new Intent(this, BigTextIntentService.class);
    241         dismissIntent.setAction(BigTextIntentService.ACTION_DISMISS);
    242 
    243         PendingIntent dismissPendingIntent = PendingIntent.getService(this, 0, dismissIntent, 0);
    244         NotificationCompat.Action dismissAction =
    245                 new NotificationCompat.Action.Builder(
    246                         R.drawable.ic_cancel_white_48dp,
    247                         "Dismiss",
    248                         dismissPendingIntent)
    249                         .build();
    250 
    251 
    252         // 4. Build and issue the notification
    253 
    254         // Because we want this to be a new notification (not updating a previous notification), we
    255         // create a new Builder. Later, we use the same global builder to get back the notification
    256         // we built here for the snooze action, that is, canceling the notification and relaunching
    257         // it several seconds later.
    258 
    259         NotificationCompat.Builder notificationCompatBuilder =
    260                 new NotificationCompat.Builder(getApplicationContext());
    261 
    262         GlobalNotificationBuilder.setNotificationCompatBuilderInstance(notificationCompatBuilder);
    263 
    264         notificationCompatBuilder
    265                 // BIG_TEXT_STYLE sets title and content
    266                 .setStyle(bigTextStyle)
    267                 .setContentTitle(bigTextStyleReminderAppData.getContentTitle())
    268                 .setContentText(bigTextStyleReminderAppData.getContentText())
    269                 .setSmallIcon(R.drawable.ic_launcher)
    270                 .setLargeIcon(BitmapFactory.decodeResource(
    271                         getResources(),
    272                         R.drawable.ic_alarm_white_48dp))
    273                 // Set primary color (important for Wear 2.0 Notifications)
    274                 .setColor(getResources().getColor(R.color.colorPrimary))
    275 
    276                 .setCategory(Notification.CATEGORY_REMINDER)
    277                 .setPriority(Notification.PRIORITY_HIGH)
    278 
    279                 // Shows content on the lock-screen
    280                 .setVisibility(Notification.VISIBILITY_PUBLIC)
    281 
    282                 // Adds additional actions specified above
    283                 .addAction(snoozeAction)
    284                 .addAction(dismissAction);
    285 
    286         /* REPLICATE_NOTIFICATION_STYLE_CODE:
    287          * You can replicate Notification Style functionality on Wear 2.0 (24+) by not setting the
    288          * main content intent, that is, skipping the call setContentIntent(). However, you need to
    289          * still allow the user to open the native Wear app from the Notification itself, so you
    290          * add an action to launch the app.
    291          */
    292         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    293 
    294             // Enables launching app in Wear 2.0 while keeping the old Notification Style behavior.
    295             NotificationCompat.Action mainAction = new NotificationCompat.Action.Builder(
    296                     R.drawable.ic_launcher,
    297                     "Open",
    298                     mainPendingIntent)
    299                     .build();
    300 
    301             notificationCompatBuilder.addAction(mainAction);
    302 
    303         } else {
    304             // Wear 1.+ still functions the same, so we set the main content intent.
    305             notificationCompatBuilder.setContentIntent(mainPendingIntent);
    306         }
    307 
    308 
    309         Notification notification = notificationCompatBuilder.build();
    310 
    311         mNotificationManagerCompat.notify(NOTIFICATION_ID, notification);
    312 
    313         // Close app to demonstrate notification in steam.
    314         finish();
    315     }
    316 
    317     /*
    318      * Generates a BIG_PICTURE_STYLE Notification that supports both Wear 1.+ and Wear 2.0.
    319      *
    320      * This example Notification is a social post. It allows updating the notification with
    321      * comments/responses via RemoteInput and the BigPictureSocialIntentService on 24+ (N+) and
    322      * Android Wear devices.
    323      *
    324      * IMPORTANT NOTE:
    325      * Notification Styles behave slightly different on Wear 2.0 when they are launched by a
    326      * native/local Wear app, i.e., they will NOT expand when the user taps them but will instead
    327      * take the user directly into the local app for the richest experience. In contrast, a bridged
    328      * Notification launched from the phone will expand with the style details (whether there is a
    329      * local app or not).
    330      *
    331      * If you want to enable an action on your Notification without launching the app, you can do so
    332      * with the setHintDisplayActionInline() feature (shown below), but this only allows one action.
    333      *
    334      * If you wish to replicate the original experience of a bridged notification, please review the
    335      * generateBigTextStyleNotification() method above to see how.
    336      */
    337     private void generateBigPictureStyleNotification() {
    338 
    339         Log.d(TAG, "generateBigPictureStyleNotification()");
    340 
    341         // Main steps for building a BIG_PICTURE_STYLE notification:
    342         //      0. Get your data
    343         //      1. Build the BIG_PICTURE_STYLE
    344         //      2. Set up main Intent for notification
    345         //      3. Set up RemoteInput, so users can input (keyboard and voice) from notification
    346         //      4. Build and issue the notification
    347 
    348         // 0. Get your data (everything unique per Notification)
    349         MockDatabase.BigPictureStyleSocialAppData bigPictureStyleSocialAppData =
    350                 MockDatabase.getBigPictureStyleData();
    351 
    352         // 1. Build the BIG_PICTURE_STYLE
    353         BigPictureStyle bigPictureStyle = new NotificationCompat.BigPictureStyle()
    354                 // Provides the bitmap for the BigPicture notification
    355                 .bigPicture(
    356                         BitmapFactory.decodeResource(
    357                                 getResources(),
    358                                 bigPictureStyleSocialAppData.getBigImage()))
    359                 // Overrides ContentTitle in the big form of the template
    360                 .setBigContentTitle(bigPictureStyleSocialAppData.getBigContentTitle())
    361                 // Summary line after the detail section in the big form of the template
    362                 .setSummaryText(bigPictureStyleSocialAppData.getSummaryText());
    363 
    364         // 2. Set up main Intent for notification
    365         Intent mainIntent = new Intent(this, BigPictureSocialMainActivity.class);
    366 
    367         PendingIntent mainPendingIntent =
    368                 PendingIntent.getActivity(
    369                         this,
    370                         0,
    371                         mainIntent,
    372                         PendingIntent.FLAG_UPDATE_CURRENT
    373                 );
    374 
    375         // 3. Set up a RemoteInput Action, so users can input (keyboard, drawing, voice) directly
    376         // from the notification without entering the app.
    377 
    378         // Create the RemoteInput.
    379         String replyLabel = getString(R.string.reply_label);
    380         RemoteInput remoteInput =
    381                 new RemoteInput.Builder(BigPictureSocialIntentService.EXTRA_COMMENT)
    382                         .setLabel(replyLabel)
    383                         // List of quick response choices for any wearables paired with the phone
    384                         .setChoices(bigPictureStyleSocialAppData.getPossiblePostResponses())
    385                         .build();
    386 
    387         // Create PendingIntent for service that handles input.
    388         Intent replyIntent = new Intent(this, BigPictureSocialIntentService.class);
    389         replyIntent.setAction(BigPictureSocialIntentService.ACTION_COMMENT);
    390         PendingIntent replyActionPendingIntent = PendingIntent.getService(this, 0, replyIntent, 0);
    391 
    392         // Enable action to appear inline on Wear 2.0 (24+). This means it will appear over the
    393         // lower portion of the Notification for easy action (only possible for one action).
    394         final NotificationCompat.Action.WearableExtender inlineActionForWear2 =
    395                 new NotificationCompat.Action.WearableExtender()
    396                         .setHintDisplayActionInline(true)
    397                         .setHintLaunchesActivity(false);
    398 
    399         NotificationCompat.Action replyAction =
    400                 new NotificationCompat.Action.Builder(
    401                         R.drawable.ic_reply_white_18dp,
    402                         replyLabel,
    403                         replyActionPendingIntent)
    404                         .addRemoteInput(remoteInput)
    405                         // Add WearableExtender to enable inline actions
    406                         .extend(inlineActionForWear2)
    407                         .build();
    408 
    409         // 4. Build and issue the notification
    410 
    411         // Because we want this to be a new notification (not updating a previous notification), we
    412         // create a new Builder. Later, we use the same global builder to get back the notification
    413         // we built here for a comment on the post.
    414 
    415         NotificationCompat.Builder notificationCompatBuilder =
    416                 new NotificationCompat.Builder(getApplicationContext());
    417 
    418         GlobalNotificationBuilder.setNotificationCompatBuilderInstance(notificationCompatBuilder);
    419 
    420         // Build notification
    421         notificationCompatBuilder
    422                 // BIG_PICTURE_STYLE sets title and content
    423                 .setStyle(bigPictureStyle)
    424                 .setContentTitle(bigPictureStyleSocialAppData.getContentTitle())
    425                 .setContentText(bigPictureStyleSocialAppData.getContentText())
    426                 .setSmallIcon(R.drawable.ic_launcher)
    427                 .setLargeIcon(BitmapFactory.decodeResource(
    428                         getResources(),
    429                         R.drawable.ic_person_black_48dp))
    430                 .setContentIntent(mainPendingIntent)
    431                 // Set primary color (important for Wear 2.0 Notifications)
    432                 .setColor(getResources().getColor(R.color.colorPrimary))
    433 
    434                 .setSubText(Integer.toString(1))
    435                 .addAction(replyAction)
    436                 .setCategory(Notification.CATEGORY_SOCIAL)
    437                 .setPriority(Notification.PRIORITY_HIGH)
    438 
    439                 // Hides content on the lock-screen
    440                 .setVisibility(Notification.VISIBILITY_PRIVATE)
    441                 // Notifies system that the main launch intent is an Activity.
    442                 .extend(new NotificationCompat.WearableExtender()
    443                         .setHintContentIntentLaunchesActivity(true));
    444 
    445         // If the phone is in "Do not disturb mode, the user will still be notified if
    446         // the sender(s) is starred as a favorite.
    447         for (String name : bigPictureStyleSocialAppData.getParticipants()) {
    448             notificationCompatBuilder.addPerson(name);
    449         }
    450 
    451         Notification notification = notificationCompatBuilder.build();
    452         mNotificationManagerCompat.notify(NOTIFICATION_ID, notification);
    453 
    454         // Close app to demonstrate notification in steam.
    455         finish();
    456     }
    457 
    458     /*
    459      * Generates a INBOX_STYLE Notification that supports both Wear 1.+ and Wear 2.0.
    460      */
    461     private void generateInboxStyleNotification() {
    462 
    463         Log.d(TAG, "generateInboxStyleNotification()");
    464 
    465 
    466         // Main steps for building a INBOX_STYLE notification:
    467         //      0. Get your data
    468         //      1. Build the INBOX_STYLE
    469         //      2. Set up main Intent for notification
    470         //      3. Build and issue the notification
    471 
    472         // 0. Get your data (everything unique per Notification)
    473         MockDatabase.InboxStyleEmailAppData inboxStyleEmailAppData =
    474                 MockDatabase.getInboxStyleData();
    475 
    476         // 1. Build the INBOX_STYLE
    477         InboxStyle inboxStyle = new NotificationCompat.InboxStyle()
    478                 // This title is slightly different than regular title, since I know INBOX_STYLE is
    479                 // available.
    480                 .setBigContentTitle(inboxStyleEmailAppData.getBigContentTitle())
    481                 .setSummaryText(inboxStyleEmailAppData.getSummaryText());
    482 
    483         // Add each summary line of the new emails, you can add up to 5
    484         for (String summary : inboxStyleEmailAppData.getIndividualEmailSummary()) {
    485             inboxStyle.addLine(summary);
    486         }
    487 
    488         // 2. Set up main Intent for notification
    489         Intent mainIntent = new Intent(this, InboxMainActivity.class);
    490 
    491         PendingIntent mainPendingIntent =
    492                 PendingIntent.getActivity(
    493                         this,
    494                         0,
    495                         mainIntent,
    496                         PendingIntent.FLAG_UPDATE_CURRENT
    497                 );
    498 
    499         // 3. Build and issue the notification
    500 
    501         // Because we want this to be a new notification (not updating a previous notification), we
    502         // create a new Builder. However, we don't need to update this notification later, so we
    503         // will not need to set a global builder for access to the notification later.
    504 
    505         NotificationCompat.Builder notificationCompatBuilder =
    506                 new NotificationCompat.Builder(getApplicationContext());
    507 
    508         GlobalNotificationBuilder.setNotificationCompatBuilderInstance(notificationCompatBuilder);
    509 
    510         // 4. Build and issue the notification
    511         notificationCompatBuilder
    512                 // INBOX_STYLE sets title and content
    513                 .setStyle(inboxStyle)
    514                 .setContentTitle(inboxStyleEmailAppData.getContentTitle())
    515                 .setContentText(inboxStyleEmailAppData.getContentText())
    516                 .setSmallIcon(R.drawable.ic_launcher)
    517                 .setLargeIcon(BitmapFactory.decodeResource(
    518                         getResources(),
    519                         R.drawable.ic_person_black_48dp))
    520                 .setContentIntent(mainPendingIntent)
    521                 // Set primary color (important for Wear 2.0 Notifications)
    522                 .setColor(getResources().getColor(R.color.colorPrimary))
    523 
    524                 // Sets large number at the right-hand side of the notification for Wear 1.+.
    525                 .setSubText(Integer.toString(inboxStyleEmailAppData.getNumberOfNewEmails()))
    526 
    527                 .setCategory(Notification.CATEGORY_EMAIL)
    528                 .setPriority(Notification.PRIORITY_HIGH)
    529 
    530                 // Hides content on the lock-screen
    531                 .setVisibility(Notification.VISIBILITY_PRIVATE)
    532                 // Notifies system that the main launch intent is an Activity.
    533                 .extend(new NotificationCompat.WearableExtender()
    534                         .setHintContentIntentLaunchesActivity(true));
    535 
    536         // If the phone is in "Do not disturb mode, the user will still be notified if
    537         // the sender(s) is starred as a favorite.
    538         for (String name : inboxStyleEmailAppData.getParticipants()) {
    539             notificationCompatBuilder.addPerson(name);
    540         }
    541 
    542         Notification notification = notificationCompatBuilder.build();
    543         mNotificationManagerCompat.notify(NOTIFICATION_ID, notification);
    544 
    545         // Close app to demonstrate notification in steam.
    546         finish();
    547     }
    548 
    549     /*
    550      * Generates a MESSAGING_STYLE Notification that supports both Wear 1.+ and Wear 2.0. For
    551      * devices on API level 24 (Wear 2.0) and after, displays MESSAGING_STYLE. Otherwise, displays
    552      * a basic BIG_TEXT_STYLE.
    553      *
    554      * IMPORTANT NOTE:
    555      * Notification Styles behave slightly different on Wear 2.0 when they are launched by a
    556      * native/local Wear app, i.e., they will NOT expand when the user taps them but will instead
    557      * take the user directly into the local app for the richest experience. In contrast, a bridged
    558      * Notification launched from the phone will expand with the style details (whether there is a
    559      * local app or not).
    560      *
    561      * If you want to enable an action on your Notification without launching the app, you can do so
    562      * with the setHintDisplayActionInline() feature (shown below), but this only allows one action.
    563      *
    564      * If you wish to replicate the original experience of a bridged notification, please review the
    565      * generateBigTextStyleNotification() method above to see how.
    566      */
    567     private void generateMessagingStyleNotification() {
    568 
    569         Log.d(TAG, "generateMessagingStyleNotification()");
    570 
    571         // Main steps for building a MESSAGING_STYLE notification:
    572         //      0. Get your data
    573         //      1. Build the MESSAGING_STYLE
    574         //      2. Add support for Wear 1.+
    575         //      3. Set up main Intent for notification
    576         //      4. Set up RemoteInput (users can input directly from notification)
    577         //      5. Build and issue the notification
    578 
    579         // 0. Get your data (everything unique per Notification)
    580         MockDatabase.MessagingStyleCommsAppData messagingStyleCommsAppData =
    581                 MockDatabase.getMessagingStyleData();
    582 
    583         // 1. Build the Notification.Style (MESSAGING_STYLE)
    584         String contentTitle = messagingStyleCommsAppData.getContentTitle();
    585 
    586         MessagingStyle messagingStyle =
    587                 new NotificationCompat.MessagingStyle(messagingStyleCommsAppData.getReplayName())
    588                         // You could set a different title to appear when the messaging style
    589                         // is supported on device (24+) if you wish. In our case, we use the same
    590                         // title.
    591                         .setConversationTitle(contentTitle);
    592 
    593         // Adds all Messages
    594         // Note: Messages include the text, timestamp, and sender
    595         for (MessagingStyle.Message message : messagingStyleCommsAppData.getMessages()) {
    596             messagingStyle.addMessage(message);
    597         }
    598 
    599 
    600         // 2. Add support for Wear 1.+
    601 
    602         // Since Wear 1.0 doesn't support the MESSAGING_STYLE, we use the BIG_TEXT_STYLE, so all the
    603         // text is visible.
    604 
    605         // This is basically a toString() of all the Messages above.
    606         String fullMessageForWearVersion1 = messagingStyleCommsAppData.getFullConversation();
    607 
    608         Notification chatHistoryForWearV1 = new NotificationCompat.Builder(getApplicationContext())
    609                 .setStyle(new BigTextStyle().bigText(fullMessageForWearVersion1))
    610                 .setContentTitle(contentTitle)
    611                 .setSmallIcon(R.drawable.ic_launcher)
    612                 .setContentText(fullMessageForWearVersion1)
    613                 .build();
    614 
    615         // Adds page with all text to support Wear 1.+.
    616         NotificationCompat.WearableExtender wearableExtenderForWearVersion1 =
    617                 new NotificationCompat.WearableExtender()
    618                         .setHintContentIntentLaunchesActivity(true)
    619                         .addPage(chatHistoryForWearV1);
    620 
    621         // 3. Set up main Intent for notification
    622         Intent notifyIntent = new Intent(this, MessagingMainActivity.class);
    623 
    624         PendingIntent mainPendingIntent =
    625                 PendingIntent.getActivity(
    626                         this,
    627                         0,
    628                         notifyIntent,
    629                         PendingIntent.FLAG_UPDATE_CURRENT
    630                 );
    631 
    632 
    633         // 4. Set up a RemoteInput Action, so users can input (keyboard, drawing, voice) directly
    634         // from the notification without entering the app.
    635 
    636         // Create the RemoteInput specifying this key.
    637         String replyLabel = getString(R.string.reply_label);
    638         RemoteInput remoteInput = new RemoteInput.Builder(MessagingIntentService.EXTRA_REPLY)
    639                 .setLabel(replyLabel)
    640                 .build();
    641 
    642         // Create PendingIntent for service that handles input.
    643         Intent replyIntent = new Intent(this, MessagingIntentService.class);
    644         replyIntent.setAction(MessagingIntentService.ACTION_REPLY);
    645         PendingIntent replyActionPendingIntent = PendingIntent.getService(this, 0, replyIntent, 0);
    646 
    647         // Enable action to appear inline on Wear 2.0 (24+). This means it will appear over the
    648         // lower portion of the Notification for easy action (only possible for one action).
    649         final NotificationCompat.Action.WearableExtender inlineActionForWear2 =
    650                 new NotificationCompat.Action.WearableExtender()
    651                         .setHintDisplayActionInline(true)
    652                         .setHintLaunchesActivity(false);
    653 
    654         NotificationCompat.Action replyAction =
    655                 new NotificationCompat.Action.Builder(
    656                         R.drawable.ic_reply_white_18dp,
    657                         replyLabel,
    658                         replyActionPendingIntent)
    659                         .addRemoteInput(remoteInput)
    660                         // Allows system to generate replies by context of conversation
    661                         .setAllowGeneratedReplies(true)
    662                         // Add WearableExtender to enable inline actions
    663                         .extend(inlineActionForWear2)
    664                         .build();
    665 
    666 
    667         // 5. Build and issue the notification
    668 
    669         // Because we want this to be a new notification (not updating current notification), we
    670         // create a new Builder. Later, we update this same notification, so we need to save this
    671         // Builder globally (as outlined earlier).
    672 
    673         NotificationCompat.Builder notificationCompatBuilder =
    674                 new NotificationCompat.Builder(getApplicationContext());
    675 
    676         GlobalNotificationBuilder.setNotificationCompatBuilderInstance(notificationCompatBuilder);
    677 
    678         // Builds and issues notification
    679         notificationCompatBuilder
    680                 // MESSAGING_STYLE sets title and content for API 24+ (Wear 2.0) devices
    681                 .setStyle(messagingStyle)
    682                 // Title for API <24 (Wear 1.+) devices
    683                 .setContentTitle(contentTitle)
    684                 // Content for API <24 (Wear 1.+) devices
    685                 .setContentText(messagingStyleCommsAppData.getContentText())
    686                 .setSmallIcon(R.drawable.ic_launcher)
    687                 .setLargeIcon(BitmapFactory.decodeResource(
    688                         getResources(),
    689                         R.drawable.ic_person_black_48dp))
    690                 .setContentIntent(mainPendingIntent)
    691                 // Set primary color (important for Wear 2.0 Notifications)
    692                 .setColor(getResources().getColor(R.color.colorPrimary))
    693 
    694                 // Number of new notifications for API <24 (Wear 1.+) devices
    695                 .setSubText(Integer.toString(messagingStyleCommsAppData.getNumberOfNewMessages()))
    696 
    697                 .addAction(replyAction)
    698                 .setCategory(Notification.CATEGORY_MESSAGE)
    699                 .setPriority(Notification.PRIORITY_HIGH)
    700 
    701                 // Hides content on the lock-screen
    702                 .setVisibility(Notification.VISIBILITY_PRIVATE)
    703 
    704                 // Adds multiple pages for easy consumption on a wear device.
    705                 .extend(wearableExtenderForWearVersion1);
    706 
    707         // If the phone is in "Do not disturb mode, the user will still be notified if
    708         // the sender(s) is starred as a favorite.
    709         for (String name : messagingStyleCommsAppData.getParticipants()) {
    710             notificationCompatBuilder.addPerson(name);
    711         }
    712 
    713         Notification notification = notificationCompatBuilder.build();
    714         mNotificationManagerCompat.notify(NOTIFICATION_ID, notification);
    715 
    716         // Close app to demonstrate notification in steam.
    717         finish();
    718     }
    719 
    720     /**
    721      * Helper method for the SnackBar action, i.e., if the user has this application's notifications
    722      * disabled, this opens up the dialog to turn them back on after the user requests a
    723      * Notification launch.
    724      *
    725      * IMPORTANT NOTE: You should not do this action unless the user takes an action to see your
    726      * Notifications like this sample demonstrates. Spamming users to re-enable your notifications
    727      * is a bad idea.
    728      */
    729     private void openNotificationSettingsForApp() {
    730         // Links to this app's notification settings
    731         Intent intent = new Intent();
    732         intent.setAction("android.settings.APP_NOTIFICATION_SETTINGS");
    733         intent.putExtra("app_package", getPackageName());
    734         intent.putExtra("app_uid", getApplicationInfo().uid);
    735         startActivity(intent);
    736     }
    737 }