1 /*
2  * Copyright (C) 2014 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 
17 package com.example.android.support.wearable.notifications;
18 
19 import android.app.Notification;
20 import android.content.Context;
21 import android.graphics.BitmapFactory;
22 import android.graphics.Color;
23 import android.graphics.Typeface;
24 import android.support.v4.app.NotificationCompat;
25 import android.text.SpannableStringBuilder;
26 import android.text.style.ForegroundColorSpan;
27 import android.text.style.RelativeSizeSpan;
28 import android.text.style.StrikethroughSpan;
29 import android.text.style.StyleSpan;
30 import android.text.style.SubscriptSpan;
31 import android.text.style.SuperscriptSpan;
32 import android.text.style.TypefaceSpan;
33 import android.text.style.UnderlineSpan;
34 import android.view.Gravity;
35 
36 /**
37  * Collection of notification builder presets.
38  */
39 public class NotificationPresets {
40     private static final String EXAMPLE_GROUP_KEY = "example";
41 
42     public static final NotificationPreset BASIC = new BasicNotificationPreset();
43     public static final NotificationPreset STYLIZED_TEXT = new StylizedTextNotificationPreset();
44     public static final NotificationPreset INBOX = new InboxNotificationPreset();
45     public static final NotificationPreset BIG_PICTURE = new BigPictureNotificationPreset();
46     public static final NotificationPreset BIG_TEXT = new BigTextNotificationPreset();
47     public static final NotificationPreset BOTTOM_ALIGNED = new BottomAlignedNotificationPreset();
48     public static final NotificationPreset GRAVITY = new GravityNotificationPreset();
49     public static final NotificationPreset CONTENT_ACTION = new ContentActionNotificationPreset();
50     public static final NotificationPreset CONTENT_ICON = new ContentIconNotificationPreset();
51     public static final NotificationPreset MULTIPLE_PAGE = new MultiplePageNotificationPreset();
52     public static final NotificationPreset BUNDLE = new NotificationBundlePreset();
53     public static final NotificationPreset BARCODE = new NotificationBarcodePreset();
54 
55     public static final NotificationPreset[] PRESETS = new NotificationPreset[] {
56             BASIC,
57             STYLIZED_TEXT,
58             INBOX,
59             BIG_PICTURE,
60             BIG_TEXT,
61             BOTTOM_ALIGNED,
62             GRAVITY,
63             CONTENT_ACTION,
64             CONTENT_ICON,
65             MULTIPLE_PAGE,
66             BUNDLE,
67             BARCODE
68     };
69 
applyBasicOptions(Context context, NotificationCompat.Builder builder, NotificationCompat.WearableExtender wearableOptions, NotificationPreset.BuildOptions options)70     private static NotificationCompat.Builder applyBasicOptions(Context context,
71             NotificationCompat.Builder builder, NotificationCompat.WearableExtender wearableOptions,
72             NotificationPreset.BuildOptions options) {
73         builder.setContentTitle(options.titlePreset)
74                 .setContentText(options.textPreset)
75                 .setSmallIcon(R.mipmap.ic_launcher)
76                 .setDeleteIntent(NotificationUtil.getExamplePendingIntent(
77                         context, R.string.example_notification_deleted));
78         options.actionsPreset.apply(context, builder, wearableOptions);
79         options.priorityPreset.apply(builder, wearableOptions);
80         if (options.includeLargeIcon) {
81             builder.setLargeIcon(BitmapFactory.decodeResource(
82                     context.getResources(), R.drawable.example_large_icon));
83         }
84         if (options.isLocalOnly) {
85             builder.setLocalOnly(true);
86         }
87         if (options.hasContentIntent) {
88             builder.setContentIntent(NotificationUtil.getExamplePendingIntent(context,
89                     R.string.content_intent_clicked));
90         }
91         if (options.vibrate) {
92             builder.setVibrate(new long[] {0, 100, 50, 100} );
93         }
94         return builder;
95     }
96 
97     private static class BasicNotificationPreset extends NotificationPreset {
BasicNotificationPreset()98         public BasicNotificationPreset() {
99             super(R.string.basic_example, R.string.example_content_title,
100                 R.string.example_content_text);
101         }
102 
103         @Override
buildNotifications(Context context, BuildOptions options)104         public Notification[] buildNotifications(Context context, BuildOptions options) {
105             NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
106             NotificationCompat.WearableExtender wearableOptions =
107                     new NotificationCompat.WearableExtender();
108             applyBasicOptions(context, builder, wearableOptions, options);
109             builder.extend(wearableOptions);
110             return new Notification[] { builder.build() };
111         }
112     }
113 
114     private static class StylizedTextNotificationPreset extends NotificationPreset {
StylizedTextNotificationPreset()115         public StylizedTextNotificationPreset() {
116             super(R.string.stylized_text_example, R.string.example_content_title,
117                     R.string.example_content_text);
118         }
119 
120         @Override
buildNotifications(Context context, BuildOptions options)121         public Notification[] buildNotifications(Context context, BuildOptions options) {
122             NotificationCompat.BigTextStyle style = new NotificationCompat.BigTextStyle();
123 
124             SpannableStringBuilder title = new SpannableStringBuilder();
125             appendStyled(title, "Stylized", new StyleSpan(Typeface.BOLD_ITALIC));
126             title.append(" title");
127             SpannableStringBuilder text = new SpannableStringBuilder("Stylized text: ");
128             appendStyled(text, "C", new ForegroundColorSpan(Color.RED));
129             appendStyled(text, "O", new ForegroundColorSpan(Color.GREEN));
130             appendStyled(text, "L", new ForegroundColorSpan(Color.BLUE));
131             appendStyled(text, "O", new ForegroundColorSpan(Color.YELLOW));
132             appendStyled(text, "R", new ForegroundColorSpan(Color.MAGENTA));
133             appendStyled(text, "S", new ForegroundColorSpan(Color.CYAN));
134             text.append("; ");
135             appendStyled(text, "1.25x size", new RelativeSizeSpan(1.25f));
136             text.append("; ");
137             appendStyled(text, "0.75x size", new RelativeSizeSpan(0.75f));
138             text.append("; ");
139             appendStyled(text, "underline", new UnderlineSpan());
140             text.append("; ");
141             appendStyled(text, "strikethrough", new StrikethroughSpan());
142             text.append("; ");
143             appendStyled(text, "bold", new StyleSpan(Typeface.BOLD));
144             text.append("; ");
145             appendStyled(text, "italic", new StyleSpan(Typeface.ITALIC));
146             text.append("; ");
147             appendStyled(text, "sans-serif-thin", new TypefaceSpan("sans-serif-thin"));
148             text.append("; ");
149             appendStyled(text, "monospace", new TypefaceSpan("monospace"));
150             text.append("; ");
151             appendStyled(text, "sub", new SubscriptSpan());
152             text.append("script");
153             appendStyled(text, "super", new SuperscriptSpan());
154 
155             style.setBigContentTitle(title);
156             style.bigText(text);
157 
158             NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
159                     .setStyle(style);
160             NotificationCompat.WearableExtender wearableOptions =
161                     new NotificationCompat.WearableExtender();
162             applyBasicOptions(context, builder, wearableOptions, options);
163             builder.extend(wearableOptions);
164             return new Notification[] { builder.build() };
165         }
166 
appendStyled(SpannableStringBuilder builder, String str, Object... spans)167         private void appendStyled(SpannableStringBuilder builder, String str, Object... spans) {
168             builder.append(str);
169             for (Object span : spans) {
170                 builder.setSpan(span, builder.length() - str.length(), builder.length(), 0);
171             }
172         }
173     }
174 
175     private static class InboxNotificationPreset extends NotificationPreset {
InboxNotificationPreset()176         public InboxNotificationPreset() {
177             super(R.string.inbox_example, R.string.example_content_title,
178                 R.string.example_content_text);
179         }
180 
181         @Override
buildNotifications(Context context, BuildOptions options)182         public Notification[] buildNotifications(Context context, BuildOptions options) {
183             NotificationCompat.InboxStyle style = new NotificationCompat.InboxStyle();
184             style.addLine(context.getString(R.string.inbox_style_example_line1));
185             style.addLine(context.getString(R.string.inbox_style_example_line2));
186             style.addLine(context.getString(R.string.inbox_style_example_line3));
187             style.setBigContentTitle(context.getString(R.string.inbox_style_example_title));
188             style.setSummaryText(context.getString(R.string.inbox_style_example_summary_text));
189 
190             NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
191                     .setStyle(style);
192             NotificationCompat.WearableExtender wearableOptions =
193                     new NotificationCompat.WearableExtender();
194             applyBasicOptions(context, builder, wearableOptions, options);
195             builder.extend(wearableOptions);
196             return new Notification[] { builder.build() };
197         }
198     }
199 
200     private static class BigPictureNotificationPreset extends NotificationPreset {
BigPictureNotificationPreset()201         public BigPictureNotificationPreset() {
202             super(R.string.big_picture_example, R.string.example_content_title,
203                 R.string.example_content_text);
204         }
205 
206         @Override
buildNotifications(Context context, BuildOptions options)207         public Notification[] buildNotifications(Context context, BuildOptions options) {
208             NotificationCompat.BigPictureStyle style = new NotificationCompat.BigPictureStyle();
209             style.bigPicture(BitmapFactory.decodeResource(context.getResources(),
210                     R.drawable.example_big_picture));
211             style.setBigContentTitle(context.getString(R.string.big_picture_style_example_title));
212             style.setSummaryText(context.getString(
213                     R.string.big_picture_style_example_summary_text));
214 
215             NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
216                     .setStyle(style);
217             NotificationCompat.WearableExtender wearableOptions =
218                     new NotificationCompat.WearableExtender();
219             applyBasicOptions(context, builder, wearableOptions, options);
220             builder.extend(wearableOptions);
221             return new Notification[] { builder.build() };
222         }
223     }
224 
225     private static class BigTextNotificationPreset extends NotificationPreset {
BigTextNotificationPreset()226         public BigTextNotificationPreset() {
227             super(R.string.big_text_example, R.string.example_content_title,
228                 R.string.example_content_text);
229         }
230 
231         @Override
buildNotifications(Context context, BuildOptions options)232         public Notification[] buildNotifications(Context context, BuildOptions options) {
233             NotificationCompat.BigTextStyle style = new NotificationCompat.BigTextStyle();
234             style.bigText(context.getString(R.string.big_text_example_big_text));
235             style.setBigContentTitle(context.getString(R.string.big_text_example_title));
236             style.setSummaryText(context.getString(R.string.big_text_example_summary_text));
237 
238             NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
239                     .setStyle(style);
240             NotificationCompat.WearableExtender wearableOptions =
241                     new NotificationCompat.WearableExtender();
242             applyBasicOptions(context, builder, wearableOptions, options);
243             builder.extend(wearableOptions);
244             return new Notification[] { builder.build() };
245         }
246     }
247 
248     private static class BottomAlignedNotificationPreset extends NotificationPreset {
BottomAlignedNotificationPreset()249         public BottomAlignedNotificationPreset() {
250             super(R.string.bottom_aligned_example, R.string.example_content_title,
251                 R.string.example_content_text);
252         }
253 
254         @Override
buildNotifications(Context context, BuildOptions options)255         public Notification[] buildNotifications(Context context, BuildOptions options) {
256             NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
257             NotificationCompat.WearableExtender wearableOptions =
258                     new NotificationCompat.WearableExtender();
259             applyBasicOptions(context, builder, wearableOptions, options);
260 
261             NotificationCompat.Builder secondPageBuilder = new NotificationCompat.Builder(context);
262             secondPageBuilder.setContentTitle(
263                     context.getString(R.string.second_page_content_title));
264             secondPageBuilder.setContentText(context.getString(R.string.big_text_example_big_text));
265             secondPageBuilder.extend(new NotificationCompat.WearableExtender()
266                             .setStartScrollBottom(true));
267 
268             wearableOptions.addPage(secondPageBuilder.build());
269             builder.extend(wearableOptions);
270             return new Notification[] { builder.build() };
271         }
272     }
273 
274     private static class GravityNotificationPreset extends NotificationPreset {
GravityNotificationPreset()275         public GravityNotificationPreset() {
276             super(R.string.gravity_example, R.string.example_content_title,
277                 R.string.example_content_text);
278         }
279 
280         @Override
buildNotifications(Context context, BuildOptions options)281         public Notification[] buildNotifications(Context context, BuildOptions options) {
282             NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
283             NotificationCompat.WearableExtender wearableOptions =
284                     new NotificationCompat.WearableExtender();
285             applyBasicOptions(context, builder, wearableOptions, options);
286 
287             NotificationCompat.Builder secondPageBuilder = new NotificationCompat.Builder(context)
288                     .setContentTitle(options.titlePreset)
289                     .setContentText(options.textPreset)
290                     .extend(new NotificationCompat.WearableExtender()
291                             .setGravity(Gravity.CENTER_VERTICAL));
292             wearableOptions.addPage(secondPageBuilder.build());
293 
294             NotificationCompat.Builder thirdPageBuilder = new NotificationCompat.Builder(context)
295                     .setContentTitle(options.titlePreset)
296                     .setContentText(options.textPreset)
297                     .extend(new NotificationCompat.WearableExtender()
298                             .setGravity(Gravity.TOP));
299             wearableOptions.addPage(thirdPageBuilder.build());
300 
301             wearableOptions.setGravity(Gravity.BOTTOM);
302             builder.extend(wearableOptions);
303             return new Notification[] { builder.build() };
304         }
305     }
306 
307     private static class ContentActionNotificationPreset extends NotificationPreset {
ContentActionNotificationPreset()308         public ContentActionNotificationPreset() {
309             super(R.string.content_action_example, R.string.example_content_title,
310                 R.string.example_content_text);
311         }
312 
313         @Override
buildNotifications(Context context, BuildOptions options)314         public Notification[] buildNotifications(Context context, BuildOptions options) {
315             Notification secondPage = new NotificationCompat.Builder(context)
316                     .setContentTitle(context.getString(R.string.second_page_content_title))
317                     .setContentText(context.getString(R.string.second_page_content_text))
318                     .extend(new NotificationCompat.WearableExtender()
319                             .setContentAction(1))
320                     .build();
321 
322             NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
323             NotificationCompat.Action action = new NotificationCompat.Action.Builder(
324                     R.drawable.ic_result_open, null, NotificationUtil.getExamplePendingIntent(
325                             context, R.string.example_content_action_clicked)).build();
326             NotificationCompat.Action action2 = new NotificationCompat.Action.Builder(
327                     R.drawable.ic_result_open, null, NotificationUtil.getExamplePendingIntent(
328                             context, R.string.example_content_action2_clicked)).build();
329             NotificationCompat.WearableExtender wearableOptions =
330                     new NotificationCompat.WearableExtender()
331                             .addAction(action)
332                             .addAction(action2)
333                             .addPage(secondPage)
334                             .setContentAction(0)
335                             .setHintHideIcon(true);
336             applyBasicOptions(context, builder, wearableOptions, options);
337             builder.extend(wearableOptions);
338             return new Notification[] { builder.build() };
339         }
340 
341         @Override
actionsRequired()342         public boolean actionsRequired() {
343             return true;
344         }
345     }
346 
347     private static class ContentIconNotificationPreset extends NotificationPreset {
ContentIconNotificationPreset()348         public ContentIconNotificationPreset() {
349             super(R.string.content_icon_example, R.string.example_content_title,
350                     R.string.example_content_text);
351         }
352 
353         @Override
buildNotifications(Context context, BuildOptions options)354         public Notification[] buildNotifications(Context context, BuildOptions options) {
355             Notification secondPage = new NotificationCompat.Builder(context)
356                     .setContentTitle(context.getString(R.string.second_page_content_title))
357                     .setContentText(context.getString(R.string.second_page_content_text))
358                     .extend(new NotificationCompat.WearableExtender()
359                             .setContentIcon(R.drawable.content_icon_small)
360                             .setContentIconGravity(Gravity.START))
361                     .build();
362 
363             Notification thirdPage = new NotificationCompat.Builder(context)
364                     .setContentTitle(context.getString(R.string.third_page_content_title))
365                     .setContentText(context.getString(R.string.third_page_content_text))
366                     .extend(new NotificationCompat.WearableExtender()
367                             .setContentIcon(R.drawable.content_icon_large))
368                     .build();
369 
370             Notification fourthPage = new NotificationCompat.Builder(context)
371                     .setContentTitle(context.getString(R.string.fourth_page_content_title))
372                     .setContentText(context.getString(R.string.fourth_page_content_text))
373                     .extend(new NotificationCompat.WearableExtender()
374                             .setContentIcon(R.drawable.content_icon_large)
375                             .setContentIconGravity(Gravity.START))
376                     .build();
377 
378             NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
379             NotificationCompat.WearableExtender wearableOptions =
380                     new NotificationCompat.WearableExtender()
381                             .setHintHideIcon(true)
382                             .setContentIcon(R.drawable.content_icon_small)
383                             .addPage(secondPage)
384                             .addPage(thirdPage)
385                             .addPage(fourthPage);
386             applyBasicOptions(context, builder, wearableOptions, options);
387             builder.extend(wearableOptions);
388             return new Notification[] { builder.build() };
389         }
390     }
391 
392     private static class MultiplePageNotificationPreset extends NotificationPreset {
MultiplePageNotificationPreset()393         public MultiplePageNotificationPreset() {
394             super(R.string.multiple_page_example, R.string.example_content_title,
395                 R.string.example_content_text);
396         }
397 
398         @Override
buildNotifications(Context context, BuildOptions options)399         public Notification[] buildNotifications(Context context, BuildOptions options) {
400             NotificationCompat.Builder secondPageBuilder = new NotificationCompat.Builder(context)
401                     .setContentTitle(context.getString(R.string.second_page_content_title))
402                     .setContentText(context.getString(R.string.second_page_content_text));
403 
404             NotificationCompat.Builder firstPageBuilder = new NotificationCompat.Builder(context);
405             NotificationCompat.WearableExtender firstPageWearableOptions =
406                     new NotificationCompat.WearableExtender();
407             applyBasicOptions(context, firstPageBuilder, firstPageWearableOptions, options);
408 
409             Integer firstBackground = options.backgroundIds == null
410                     ? null : options.backgroundIds[0];
411             if (firstBackground != null) {
412                 NotificationCompat.BigPictureStyle style =
413                         new NotificationCompat.BigPictureStyle();
414                 style.bigPicture(BitmapFactory.decodeResource(context.getResources(),
415                         firstBackground));
416                 firstPageBuilder.setStyle(style);
417             }
418 
419             Integer secondBackground = options.backgroundIds == null
420                     ? null : options.backgroundIds[1];
421             if (secondBackground != null) {
422                 NotificationCompat.BigPictureStyle style = new NotificationCompat.BigPictureStyle();
423                 style.bigPicture(BitmapFactory.decodeResource(context.getResources(),
424                         secondBackground));
425                 secondPageBuilder.setStyle(style);
426             }
427 
428             firstPageBuilder.extend(
429                     firstPageWearableOptions.addPage(secondPageBuilder.build()));
430 
431             return new Notification[]{ firstPageBuilder.build() };
432         }
433 
434         @Override
countBackgroundPickersRequired()435         public int countBackgroundPickersRequired() {
436             return 2; // This sample does 2 pages notifications.
437         }
438     }
439 
440     private static class NotificationBundlePreset extends NotificationPreset {
NotificationBundlePreset()441         public NotificationBundlePreset() {
442             super(R.string.bundle_example, R.string.example_content_title,
443                 R.string.example_content_text);
444         }
445 
446         @Override
buildNotifications(Context context, BuildOptions options)447         public Notification[] buildNotifications(Context context, BuildOptions options) {
448             NotificationCompat.Builder childBuilder1 = new NotificationCompat.Builder(context)
449                     .setContentTitle(context.getString(R.string.first_child_content_title))
450                     .setContentText(context.getString(R.string.first_child_content_text))
451                     .setSmallIcon(R.mipmap.ic_launcher)
452                     .setLocalOnly(options.isLocalOnly)
453                     .setGroup(EXAMPLE_GROUP_KEY)
454                     .setSortKey("0");
455 
456             NotificationCompat.Builder childBuilder2 = new NotificationCompat.Builder(context)
457                     .setContentTitle(context.getString(R.string.second_child_content_title))
458                     .setContentText(context.getString(R.string.second_child_content_text))
459                     .setSmallIcon(R.mipmap.ic_launcher)
460                     .addAction(R.mipmap.ic_launcher,
461                             context.getString(R.string.second_child_action),
462                             NotificationUtil.getExamplePendingIntent(
463                                     context, R.string.second_child_action_clicked))
464                     .setLocalOnly(options.isLocalOnly)
465                     .setGroup(EXAMPLE_GROUP_KEY)
466                     .setSortKey("1");
467 
468             NotificationCompat.Builder summaryBuilder = new NotificationCompat.Builder(context)
469                     .setGroup(EXAMPLE_GROUP_KEY)
470                     .setGroupSummary(true);
471 
472             NotificationCompat.WearableExtender summaryWearableOptions =
473                     new NotificationCompat.WearableExtender();
474             applyBasicOptions(context, summaryBuilder, summaryWearableOptions, options);
475             summaryBuilder.extend(summaryWearableOptions);
476 
477             return new Notification[] { summaryBuilder.build(), childBuilder1.build(),
478                     childBuilder2.build() };
479         }
480     }
481 
482     private static class NotificationBarcodePreset extends NotificationPreset {
NotificationBarcodePreset()483         public NotificationBarcodePreset() {
484             super(R.string.barcode_example, R.string.barcode_content_title,
485                     R.string.barcode_content_text);
486         }
487 
488         @Override
buildNotifications(Context context, BuildOptions options)489         public Notification[] buildNotifications(Context context, BuildOptions options) {
490             NotificationCompat.Builder secondPageBuilder = new NotificationCompat.Builder(context)
491                     .extend(new NotificationCompat.WearableExtender()
492                             .setHintShowBackgroundOnly(true)
493                             .setBackground(BitmapFactory.decodeResource(context.getResources(),
494                                     R.drawable.qr_code))
495                             .setHintAvoidBackgroundClipping(true)
496                             .setHintScreenTimeout(
497                                     NotificationCompat.WearableExtender.SCREEN_TIMEOUT_LONG));
498 
499             NotificationCompat.Builder firstPageBuilder = new NotificationCompat.Builder(context);
500             NotificationCompat.WearableExtender firstPageWearableOptions =
501                     new NotificationCompat.WearableExtender();
502             applyBasicOptions(context, firstPageBuilder, firstPageWearableOptions, options);
503 
504             firstPageBuilder.extend(
505                     firstPageWearableOptions.addPage(secondPageBuilder.build()));
506 
507             return new Notification[]{ firstPageBuilder.build() };
508         }
509     }
510 }
511