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