1 /* 2 * Copyright (C) 2008 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 android.app.cts; 18 19 import android.app.Notification; 20 import android.app.Notification.Action.Builder; 21 import android.app.Notification.MessagingStyle; 22 import android.app.Notification.MessagingStyle.Message; 23 import android.app.NotificationChannel; 24 import android.app.NotificationManager; 25 import android.app.PendingIntent; 26 import android.app.Person; 27 import android.app.RemoteInput; 28 import android.app.stubs.R; 29 import android.content.Context; 30 import android.content.Intent; 31 import android.graphics.drawable.Icon; 32 import android.net.Uri; 33 import android.os.Build; 34 import android.os.Parcel; 35 import android.os.Parcelable; 36 import androidx.annotation.Nullable; 37 38 import android.os.StrictMode; 39 import android.test.AndroidTestCase; 40 import android.widget.RemoteViews; 41 42 import java.util.ArrayList; 43 import java.util.function.Consumer; 44 45 public class NotificationTest extends AndroidTestCase { 46 private static final String TEXT_RESULT_KEY = "text"; 47 private static final String DATA_RESULT_KEY = "data"; 48 private static final String DATA_AND_TEXT_RESULT_KEY = "data and text"; 49 50 private Notification.Action mAction; 51 private Notification mNotification; 52 private Context mContext; 53 54 private static final String TICKER_TEXT = "tickerText"; 55 private static final String CONTENT_TITLE = "contentTitle"; 56 private static final String CONTENT_TEXT = "contentText"; 57 private static final String URI_STRING = "uriString"; 58 private static final String ACTION_TITLE = "actionTitle"; 59 private static final int TOLERANCE = 200; 60 private static final long TIMEOUT = 4000; 61 private static final NotificationChannel CHANNEL = new NotificationChannel("id", "name", 62 NotificationManager.IMPORTANCE_HIGH); 63 private static final String SHORTCUT_ID = "shortcutId"; 64 private static final String SETTING_TEXT = "work chats"; 65 66 @Override 67 protected void setUp() throws Exception { 68 super.setUp(); 69 mContext = getContext(); 70 mNotification = new Notification(); 71 } 72 73 public void testConstructor() { 74 mNotification = null; 75 mNotification = new Notification(); 76 assertNotNull(mNotification); 77 assertTrue(System.currentTimeMillis() - mNotification.when < TOLERANCE); 78 79 mNotification = null; 80 final int notificationTime = 200; 81 mNotification = new Notification(0, TICKER_TEXT, notificationTime); 82 assertEquals(notificationTime, mNotification.when); 83 assertEquals(0, mNotification.icon); 84 assertEquals(TICKER_TEXT, mNotification.tickerText); 85 assertEquals(0, mNotification.number); 86 } 87 88 public void testBuilderConstructor() { 89 mNotification = new Notification.Builder(mContext, CHANNEL.getId()).build(); 90 assertEquals(CHANNEL.getId(), mNotification.getChannelId()); 91 assertEquals(Notification.BADGE_ICON_NONE, mNotification.getBadgeIconType()); 92 assertNull(mNotification.getShortcutId()); 93 assertEquals(Notification.GROUP_ALERT_ALL, mNotification.getGroupAlertBehavior()); 94 assertEquals((long) 0, mNotification.getTimeoutAfter()); 95 } 96 97 public void testDescribeContents() { 98 final int expected = 0; 99 mNotification = new Notification(); 100 assertEquals(expected, mNotification.describeContents()); 101 } 102 103 public void testCategories() { 104 assertNotNull(Notification.CATEGORY_ALARM); 105 assertNotNull(Notification.CATEGORY_CALL); 106 assertNotNull(Notification.CATEGORY_EMAIL); 107 assertNotNull(Notification.CATEGORY_ERROR); 108 assertNotNull(Notification.CATEGORY_EVENT); 109 assertNotNull(Notification.CATEGORY_MESSAGE); 110 assertNotNull(Notification.CATEGORY_NAVIGATION); 111 assertNotNull(Notification.CATEGORY_PROGRESS); 112 assertNotNull(Notification.CATEGORY_PROMO); 113 assertNotNull(Notification.CATEGORY_RECOMMENDATION); 114 assertNotNull(Notification.CATEGORY_REMINDER); 115 assertNotNull(Notification.CATEGORY_SERVICE); 116 assertNotNull(Notification.CATEGORY_SOCIAL); 117 assertNotNull(Notification.CATEGORY_STATUS); 118 assertNotNull(Notification.CATEGORY_SYSTEM); 119 assertNotNull(Notification.CATEGORY_TRANSPORT); 120 } 121 122 public void testWriteToParcel() { 123 124 mNotification = new Notification.Builder(mContext, CHANNEL.getId()) 125 .setBadgeIconType(Notification.BADGE_ICON_SMALL) 126 .setShortcutId(SHORTCUT_ID) 127 .setTimeoutAfter(TIMEOUT) 128 .setSettingsText(SETTING_TEXT) 129 .setGroupAlertBehavior(Notification.GROUP_ALERT_CHILDREN) 130 .build(); 131 mNotification.icon = 0; 132 mNotification.number = 1; 133 final Intent intent = new Intent(); 134 final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0); 135 mNotification.contentIntent = pendingIntent; 136 final Intent deleteIntent = new Intent(); 137 final PendingIntent delPendingIntent = PendingIntent.getBroadcast( 138 mContext, 0, deleteIntent, 0); 139 mNotification.deleteIntent = delPendingIntent; 140 mNotification.tickerText = TICKER_TEXT; 141 142 final RemoteViews contentView = new RemoteViews(mContext.getPackageName(), 143 android.R.layout.simple_list_item_1); 144 mNotification.contentView = contentView; 145 mNotification.defaults = 0; 146 mNotification.flags = 0; 147 final Uri uri = Uri.parse(URI_STRING); 148 mNotification.sound = uri; 149 mNotification.audioStreamType = 0; 150 final long[] longArray = { 1l, 2l, 3l }; 151 mNotification.vibrate = longArray; 152 mNotification.ledARGB = 0; 153 mNotification.ledOnMS = 0; 154 mNotification.ledOffMS = 0; 155 mNotification.iconLevel = 0; 156 157 Parcel parcel = Parcel.obtain(); 158 mNotification.writeToParcel(parcel, 0); 159 parcel.setDataPosition(0); 160 // Test Notification(Parcel) 161 Notification result = new Notification(parcel); 162 assertEquals(mNotification.icon, result.icon); 163 assertEquals(mNotification.when, result.when); 164 assertEquals(mNotification.number, result.number); 165 assertNotNull(result.contentIntent); 166 assertNotNull(result.deleteIntent); 167 assertEquals(mNotification.tickerText, result.tickerText); 168 assertNotNull(result.contentView); 169 assertEquals(mNotification.defaults, result.defaults); 170 assertEquals(mNotification.flags, result.flags); 171 assertNotNull(result.sound); 172 assertEquals(mNotification.audioStreamType, result.audioStreamType); 173 assertEquals(mNotification.vibrate[0], result.vibrate[0]); 174 assertEquals(mNotification.vibrate[1], result.vibrate[1]); 175 assertEquals(mNotification.vibrate[2], result.vibrate[2]); 176 assertEquals(mNotification.ledARGB, result.ledARGB); 177 assertEquals(mNotification.ledOnMS, result.ledOnMS); 178 assertEquals(mNotification.ledOffMS, result.ledOffMS); 179 assertEquals(mNotification.iconLevel, result.iconLevel); 180 assertEquals(mNotification.getShortcutId(), result.getShortcutId()); 181 assertEquals(mNotification.getBadgeIconType(), result.getBadgeIconType()); 182 assertEquals(mNotification.getTimeoutAfter(), result.getTimeoutAfter()); 183 assertEquals(mNotification.getChannelId(), result.getChannelId()); 184 assertEquals(mNotification.getSettingsText(), result.getSettingsText()); 185 assertEquals(mNotification.getGroupAlertBehavior(), result.getGroupAlertBehavior()); 186 187 mNotification.contentIntent = null; 188 parcel = Parcel.obtain(); 189 mNotification.writeToParcel(parcel, 0); 190 parcel.setDataPosition(0); 191 result = new Notification(parcel); 192 assertNull(result.contentIntent); 193 194 mNotification.deleteIntent = null; 195 parcel = Parcel.obtain(); 196 mNotification.writeToParcel(parcel, 0); 197 parcel.setDataPosition(0); 198 result = new Notification(parcel); 199 assertNull(result.deleteIntent); 200 201 mNotification.tickerText = null; 202 parcel = Parcel.obtain(); 203 mNotification.writeToParcel(parcel, 0); 204 parcel.setDataPosition(0); 205 result = new Notification(parcel); 206 assertNull(result.tickerText); 207 208 mNotification.contentView = null; 209 parcel = Parcel.obtain(); 210 mNotification.writeToParcel(parcel, 0); 211 parcel.setDataPosition(0); 212 result = new Notification(parcel); 213 assertNull(result.contentView); 214 215 mNotification.sound = null; 216 parcel = Parcel.obtain(); 217 mNotification.writeToParcel(parcel, 0); 218 parcel.setDataPosition(0); 219 result = new Notification(parcel); 220 assertNull(result.sound); 221 } 222 223 public void testColorizeNotification() { 224 mNotification = new Notification.Builder(mContext, "channel_id") 225 .setSmallIcon(1) 226 .setContentTitle(CONTENT_TITLE) 227 .setColorized(true) 228 .build(); 229 230 assertTrue(mNotification.extras.getBoolean(Notification.EXTRA_COLORIZED)); 231 } 232 233 public void testBuilder() { 234 final Intent intent = new Intent(); 235 final PendingIntent contentIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0); 236 mNotification = new Notification.Builder(mContext, CHANNEL.getId()) 237 .setSmallIcon(1) 238 .setContentTitle(CONTENT_TITLE) 239 .setContentText(CONTENT_TEXT) 240 .setContentIntent(contentIntent) 241 .setBadgeIconType(Notification.BADGE_ICON_SMALL) 242 .setShortcutId(SHORTCUT_ID) 243 .setTimeoutAfter(TIMEOUT) 244 .setSettingsText(SETTING_TEXT) 245 .setGroupAlertBehavior(Notification.GROUP_ALERT_SUMMARY) 246 .build(); 247 assertEquals(CONTENT_TEXT, mNotification.extras.getString(Notification.EXTRA_TEXT)); 248 assertEquals(CONTENT_TITLE, mNotification.extras.getString(Notification.EXTRA_TITLE)); 249 assertEquals(1, mNotification.icon); 250 assertEquals(contentIntent, mNotification.contentIntent); 251 assertEquals(CHANNEL.getId(), mNotification.getChannelId()); 252 assertEquals(Notification.BADGE_ICON_SMALL, mNotification.getBadgeIconType()); 253 assertEquals(SHORTCUT_ID, mNotification.getShortcutId()); 254 assertEquals(TIMEOUT, mNotification.getTimeoutAfter()); 255 assertEquals(SETTING_TEXT, mNotification.getSettingsText()); 256 assertEquals(Notification.GROUP_ALERT_SUMMARY, mNotification.getGroupAlertBehavior()); 257 } 258 259 public void testBuilder_getStyle() { 260 MessagingStyle ms = new MessagingStyle(new Person.Builder().setName("Test name").build()); 261 Notification.Builder builder = new Notification.Builder(mContext, CHANNEL.getId()); 262 263 builder.setStyle(ms); 264 265 assertEquals(ms, builder.getStyle()); 266 } 267 268 public void testActionBuilder() { 269 final Intent intent = new Intent(); 270 final PendingIntent actionIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0); 271 mAction = null; 272 mAction = new Notification.Action.Builder(0, ACTION_TITLE, actionIntent).build(); 273 assertEquals(ACTION_TITLE, mAction.title); 274 assertEquals(actionIntent, mAction.actionIntent); 275 assertEquals(true, mAction.getAllowGeneratedReplies()); 276 } 277 278 public void testNotification_addPerson() { 279 String name = "name"; 280 String key = "key"; 281 String uri = "name:name"; 282 Person person = new Person.Builder() 283 .setName(name) 284 .setIcon(Icon.createWithResource(mContext, 1)) 285 .setKey(key) 286 .setUri(uri) 287 .build(); 288 mNotification = new Notification.Builder(mContext, CHANNEL.getId()) 289 .setSmallIcon(1) 290 .setContentTitle(CONTENT_TITLE) 291 .addPerson(person) 292 .build(); 293 294 ArrayList<Person> restoredPeople = mNotification.extras.getParcelableArrayList( 295 Notification.EXTRA_PEOPLE_LIST); 296 assertNotNull(restoredPeople); 297 Person restoredPerson = restoredPeople.get(0); 298 assertNotNull(restoredPerson); 299 assertNotNull(restoredPerson.getIcon()); 300 assertEquals(name, restoredPerson.getName()); 301 assertEquals(key, restoredPerson.getKey()); 302 assertEquals(uri, restoredPerson.getUri()); 303 } 304 305 public void testNotification_MessagingStyle_people() { 306 String name = "name"; 307 String key = "key"; 308 String uri = "name:name"; 309 Person user = new Person.Builder() 310 .setName(name) 311 .setIcon(Icon.createWithResource(mContext, 1)) 312 .setKey(key) 313 .setUri(uri) 314 .build(); 315 Person participant = new Person.Builder().setName("sender").build(); 316 Notification.MessagingStyle messagingStyle = new Notification.MessagingStyle(user) 317 .addMessage("text", 0, participant) 318 .addMessage(new Message("text 2", 0, participant)); 319 mNotification = new Notification.Builder(mContext, CHANNEL.getId()) 320 .setSmallIcon(1) 321 .setStyle(messagingStyle) 322 .build(); 323 324 Person restoredPerson = mNotification.extras.getParcelable( 325 Notification.EXTRA_MESSAGING_PERSON); 326 assertNotNull(restoredPerson); 327 assertNotNull(restoredPerson.getIcon()); 328 assertEquals(name, restoredPerson.getName()); 329 assertEquals(key, restoredPerson.getKey()); 330 assertEquals(uri, restoredPerson.getUri()); 331 assertNotNull(mNotification.extras.getParcelableArray(Notification.EXTRA_MESSAGES)); 332 } 333 334 335 public void testMessagingStyle_historicMessages() { 336 mNotification = new Notification.Builder(mContext, CHANNEL.getId()) 337 .setSmallIcon(1) 338 .setContentTitle(CONTENT_TITLE) 339 .setStyle(new Notification.MessagingStyle("self name") 340 .addMessage("text", 0, "sender") 341 .addMessage(new Message("image", 0, "sender") 342 .setData("image/png", Uri.parse("http://example.com/image.png"))) 343 .addHistoricMessage(new Message("historic text", 0, "historic sender")) 344 .setConversationTitle("title") 345 ).build(); 346 347 assertNotNull( 348 mNotification.extras.getParcelableArray(Notification.EXTRA_HISTORIC_MESSAGES)); 349 } 350 351 public void testMessagingStyle_isGroupConversation() { 352 mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.P; 353 Notification.MessagingStyle messagingStyle = new Notification.MessagingStyle("self name") 354 .setGroupConversation(true) 355 .setConversationTitle("test conversation title"); 356 Notification notification = new Notification.Builder(mContext, "test id") 357 .setSmallIcon(1) 358 .setContentTitle("test title") 359 .setStyle(messagingStyle) 360 .build(); 361 362 assertTrue(messagingStyle.isGroupConversation()); 363 assertTrue(notification.extras.getBoolean(Notification.EXTRA_IS_GROUP_CONVERSATION)); 364 } 365 366 public void testMessagingStyle_isGroupConversation_noConversationTitle() { 367 mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.P; 368 Notification.MessagingStyle messagingStyle = new Notification.MessagingStyle("self name") 369 .setGroupConversation(true) 370 .setConversationTitle(null); 371 Notification notification = new Notification.Builder(mContext, "test id") 372 .setSmallIcon(1) 373 .setContentTitle("test title") 374 .setStyle(messagingStyle) 375 .build(); 376 377 assertTrue(messagingStyle.isGroupConversation()); 378 assertTrue(notification.extras.getBoolean(Notification.EXTRA_IS_GROUP_CONVERSATION)); 379 } 380 381 public void testMessagingStyle_isGroupConversation_withConversationTitle_legacy() { 382 // In legacy (version < P), isGroupConversation is controlled by conversationTitle. 383 mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.O; 384 Notification.MessagingStyle messagingStyle = new Notification.MessagingStyle("self name") 385 .setGroupConversation(false) 386 .setConversationTitle("test conversation title"); 387 Notification notification = new Notification.Builder(mContext, "test id") 388 .setSmallIcon(1) 389 .setContentTitle("test title") 390 .setStyle(messagingStyle) 391 .build(); 392 393 assertTrue(messagingStyle.isGroupConversation()); 394 assertFalse(notification.extras.getBoolean(Notification.EXTRA_IS_GROUP_CONVERSATION)); 395 } 396 397 public void testMessagingStyle_isGroupConversation_withoutConversationTitle_legacy() { 398 // In legacy (version < P), isGroupConversation is controlled by conversationTitle. 399 mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.O; 400 Notification.MessagingStyle messagingStyle = new Notification.MessagingStyle("self name") 401 .setGroupConversation(true) 402 .setConversationTitle(null); 403 Notification notification = new Notification.Builder(mContext, "test id") 404 .setSmallIcon(1) 405 .setContentTitle("test title") 406 .setStyle(messagingStyle) 407 .build(); 408 409 assertFalse(messagingStyle.isGroupConversation()); 410 assertTrue(notification.extras.getBoolean(Notification.EXTRA_IS_GROUP_CONVERSATION)); 411 } 412 413 public void testMessagingStyle_getUser() { 414 Person user = new Person.Builder().setName("Test name").build(); 415 416 MessagingStyle messagingStyle = new MessagingStyle(user); 417 418 assertEquals(user, messagingStyle.getUser()); 419 } 420 421 public void testMessage() { 422 Person sender = new Person.Builder().setName("Test name").build(); 423 String text = "Test message"; 424 long timestamp = 400; 425 426 Message message = new Message(text, timestamp, sender); 427 428 assertEquals(text, message.getText()); 429 assertEquals(timestamp, message.getTimestamp()); 430 assertEquals(sender, message.getSenderPerson()); 431 } 432 433 public void testToString() { 434 mNotification = new Notification(); 435 assertNotNull(mNotification.toString()); 436 mNotification = null; 437 } 438 439 public void testNotificationActionBuilder_setDataOnlyRemoteInput() throws Throwable { 440 Notification.Action a = newActionBuilder() 441 .addRemoteInput(newDataOnlyRemoteInput()).build(); 442 RemoteInput[] textInputs = a.getRemoteInputs(); 443 assertTrue(textInputs == null || textInputs.length == 0); 444 verifyRemoteInputArrayHasSingleResult(a.getDataOnlyRemoteInputs(), DATA_RESULT_KEY); 445 } 446 447 public void testNotificationActionBuilder_setTextAndDataOnlyRemoteInput() throws Throwable { 448 Notification.Action a = newActionBuilder() 449 .addRemoteInput(newDataOnlyRemoteInput()) 450 .addRemoteInput(newTextRemoteInput()) 451 .build(); 452 453 verifyRemoteInputArrayHasSingleResult(a.getRemoteInputs(), TEXT_RESULT_KEY); 454 verifyRemoteInputArrayHasSingleResult(a.getDataOnlyRemoteInputs(), DATA_RESULT_KEY); 455 } 456 457 public void testNotificationActionBuilder_setTextAndDataOnlyAndBothRemoteInput() 458 throws Throwable { 459 Notification.Action a = newActionBuilder() 460 .addRemoteInput(newDataOnlyRemoteInput()) 461 .addRemoteInput(newTextRemoteInput()) 462 .addRemoteInput(newTextAndDataRemoteInput()) 463 .build(); 464 465 assertTrue(a.getRemoteInputs() != null && a.getRemoteInputs().length == 2); 466 assertEquals(TEXT_RESULT_KEY, a.getRemoteInputs()[0].getResultKey()); 467 assertFalse(a.getRemoteInputs()[0].isDataOnly()); 468 assertEquals(DATA_AND_TEXT_RESULT_KEY, a.getRemoteInputs()[1].getResultKey()); 469 assertFalse(a.getRemoteInputs()[1].isDataOnly()); 470 471 verifyRemoteInputArrayHasSingleResult(a.getDataOnlyRemoteInputs(), DATA_RESULT_KEY); 472 assertTrue(a.getDataOnlyRemoteInputs()[0].isDataOnly()); 473 } 474 475 public void testAction_builder_hasDefault() { 476 Notification.Action action = makeNotificationAction(null); 477 assertEquals(Notification.Action.SEMANTIC_ACTION_NONE, action.getSemanticAction()); 478 } 479 480 public void testAction_builder_setSemanticAction() { 481 Notification.Action action = makeNotificationAction( 482 builder -> builder.setSemanticAction(Notification.Action.SEMANTIC_ACTION_REPLY)); 483 assertEquals(Notification.Action.SEMANTIC_ACTION_REPLY, action.getSemanticAction()); 484 } 485 486 public void testAction_parcel() { 487 Notification.Action action = writeAndReadParcelable( 488 makeNotificationAction(builder -> { 489 builder.setSemanticAction(Notification.Action.SEMANTIC_ACTION_ARCHIVE); 490 builder.setAllowGeneratedReplies(true); 491 })); 492 493 assertEquals(Notification.Action.SEMANTIC_ACTION_ARCHIVE, action.getSemanticAction()); 494 assertTrue(action.getAllowGeneratedReplies()); 495 } 496 497 public void testAction_clone() { 498 Notification.Action action = makeNotificationAction( 499 builder -> builder.setSemanticAction(Notification.Action.SEMANTIC_ACTION_DELETE)); 500 assertEquals( 501 Notification.Action.SEMANTIC_ACTION_DELETE, 502 action.clone().getSemanticAction()); 503 } 504 505 public void testBuildStrictMode() { 506 try { 507 StrictMode.setThreadPolicy( 508 new StrictMode.ThreadPolicy.Builder().detectAll().penaltyDeath().build()); 509 Notification.Action a = newActionBuilder() 510 .addRemoteInput(newDataOnlyRemoteInput()) 511 .addRemoteInput(newTextRemoteInput()) 512 .addRemoteInput(newTextAndDataRemoteInput()) 513 .build(); 514 Notification.Builder b = new Notification.Builder(mContext, "id") 515 .setStyle(new Notification.BigTextStyle().setBigContentTitle("Big content")) 516 .setContentTitle("title") 517 .setActions(a); 518 519 b.build(); 520 } finally { 521 StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().permitAll().build()); 522 } 523 } 524 525 private static RemoteInput newDataOnlyRemoteInput() { 526 return new RemoteInput.Builder(DATA_RESULT_KEY) 527 .setAllowFreeFormInput(false) 528 .setAllowDataType("mimeType", true) 529 .build(); 530 } 531 532 private static RemoteInput newTextAndDataRemoteInput() { 533 return new RemoteInput.Builder(DATA_AND_TEXT_RESULT_KEY) 534 .setAllowDataType("mimeType", true) 535 .build(); // allowFreeForm defaults to true 536 } 537 538 private static RemoteInput newTextRemoteInput() { 539 return new RemoteInput.Builder(TEXT_RESULT_KEY).build(); // allowFreeForm defaults to true 540 } 541 542 private static void verifyRemoteInputArrayHasSingleResult( 543 RemoteInput[] remoteInputs, String expectedResultKey) { 544 assertTrue(remoteInputs != null && remoteInputs.length == 1); 545 assertEquals(expectedResultKey, remoteInputs[0].getResultKey()); 546 } 547 548 private static Notification.Action.Builder newActionBuilder() { 549 return new Notification.Action.Builder(0, "title", null); 550 } 551 552 /** 553 * Writes an arbitrary {@link Parcelable} into a {@link Parcel} using its writeToParcel 554 * method before reading it out again to check that it was sent properly. 555 */ 556 private static <T extends Parcelable> T writeAndReadParcelable(T original) { 557 Parcel p = Parcel.obtain(); 558 p.writeParcelable(original, /* flags */ 0); 559 p.setDataPosition(0); 560 return p.readParcelable(/* classLoader */ null); 561 } 562 563 /** 564 * Creates a Notification.Action by mocking initial dependencies and then applying 565 * transformations if they're defined. 566 */ 567 private Notification.Action makeNotificationAction( 568 @Nullable Consumer<Builder> transformation) { 569 Notification.Action.Builder actionBuilder = 570 new Notification.Action.Builder(null, "Test Title", null); 571 if (transformation != null) { 572 transformation.accept(actionBuilder); 573 } 574 return actionBuilder.build(); 575 } 576 } 577