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