1 /* 2 * Copyright (C) 2017 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; 18 19 import static android.app.Notification.CarExtender.UnreadConversation.KEY_ON_READ; 20 import static android.app.Notification.CarExtender.UnreadConversation.KEY_ON_REPLY; 21 import static android.app.Notification.CarExtender.UnreadConversation.KEY_REMOTE_INPUT; 22 import static android.app.Notification.EXTRA_ANSWER_INTENT; 23 import static android.app.Notification.EXTRA_BUILDER_APPLICATION_INFO; 24 import static android.app.Notification.EXTRA_CALL_PERSON; 25 import static android.app.Notification.EXTRA_CONVERSATION_ICON; 26 import static android.app.Notification.EXTRA_DECLINE_INTENT; 27 import static android.app.Notification.EXTRA_HANG_UP_INTENT; 28 import static android.app.Notification.EXTRA_LARGE_ICON; 29 import static android.app.Notification.EXTRA_LARGE_ICON_BIG; 30 import static android.app.Notification.EXTRA_MEDIA_REMOTE_INTENT; 31 import static android.app.Notification.EXTRA_MEDIA_SESSION; 32 import static android.app.Notification.EXTRA_MESSAGING_PERSON; 33 import static android.app.Notification.EXTRA_PEOPLE_LIST; 34 import static android.app.Notification.EXTRA_PICTURE; 35 import static android.app.Notification.EXTRA_PICTURE_ICON; 36 import static android.app.Notification.EXTRA_SUMMARY_TEXT; 37 import static android.app.Notification.EXTRA_TITLE; 38 import static android.app.Notification.MessagingStyle.Message.KEY_DATA_URI; 39 import static android.app.Notification.MessagingStyle.Message.KEY_SENDER_PERSON; 40 import static android.app.Notification.MessagingStyle.Message.KEY_TEXT; 41 import static android.app.Notification.MessagingStyle.Message.KEY_TIMESTAMP; 42 import static android.app.Notification.TvExtender.EXTRA_CONTENT_INTENT; 43 import static android.app.Notification.TvExtender.EXTRA_DELETE_INTENT; 44 import static android.app.Notification.WearableExtender.KEY_BACKGROUND; 45 import static android.app.Notification.WearableExtender.KEY_DISPLAY_INTENT; 46 47 import static com.android.compatibility.common.util.SystemUtil.runShellCommand; 48 import static com.android.internal.util.ContrastColorUtilTest.assertContrastIsAtLeast; 49 import static com.android.internal.util.ContrastColorUtilTest.assertContrastIsWithinRange; 50 51 import static com.google.common.truth.Truth.assertThat; 52 53 import static junit.framework.Assert.assertNotNull; 54 import static junit.framework.Assert.fail; 55 56 import static org.junit.Assert.assertEquals; 57 import static org.junit.Assert.assertFalse; 58 import static org.junit.Assert.assertNotSame; 59 import static org.junit.Assert.assertNull; 60 import static org.junit.Assert.assertSame; 61 import static org.junit.Assert.assertTrue; 62 import static org.mockito.Mockito.mock; 63 import static org.mockito.Mockito.spy; 64 import static org.mockito.Mockito.when; 65 66 import android.annotation.Nullable; 67 import android.content.Context; 68 import android.content.Intent; 69 import android.content.LocusId; 70 import android.content.res.Configuration; 71 import android.graphics.Bitmap; 72 import android.graphics.BitmapFactory; 73 import android.graphics.Color; 74 import android.graphics.Typeface; 75 import android.graphics.drawable.Icon; 76 import android.net.Uri; 77 import android.os.Build; 78 import android.os.Bundle; 79 import android.os.Parcel; 80 import android.os.Parcelable; 81 import android.os.SystemProperties; 82 import android.text.Spannable; 83 import android.text.SpannableString; 84 import android.text.SpannableStringBuilder; 85 import android.text.Spanned; 86 import android.text.style.ForegroundColorSpan; 87 import android.text.style.StyleSpan; 88 import android.text.style.TextAppearanceSpan; 89 import android.util.Pair; 90 import android.widget.RemoteViews; 91 92 import androidx.test.InstrumentationRegistry; 93 import androidx.test.filters.SmallTest; 94 import androidx.test.runner.AndroidJUnit4; 95 96 import com.android.internal.R; 97 import com.android.internal.util.ContrastColorUtil; 98 99 import junit.framework.Assert; 100 101 import org.junit.Before; 102 import org.junit.Test; 103 import org.junit.runner.RunWith; 104 105 import java.util.List; 106 import java.util.function.Consumer; 107 108 @RunWith(AndroidJUnit4.class) 109 @SmallTest 110 public class NotificationTest { 111 112 private Context mContext; 113 114 @Before setUp()115 public void setUp() { 116 mContext = InstrumentationRegistry.getContext(); 117 // TODO(b/169435530): remove this flag set once resolved. 118 SystemProperties.set("persist.sysui.notification.builder_extras_override", 119 Boolean.toString(false)); 120 } 121 122 @Test testColorizedByPermission()123 public void testColorizedByPermission() { 124 Notification n = new Notification.Builder(mContext, "test") 125 .setFlag(Notification.FLAG_CAN_COLORIZE, true) 126 .setColorized(true).setColor(Color.WHITE) 127 .build(); 128 assertTrue(n.isColorized()); 129 130 n = new Notification.Builder(mContext, "test") 131 .setFlag(Notification.FLAG_CAN_COLORIZE, true) 132 .build(); 133 assertFalse(n.isColorized()); 134 135 n = new Notification.Builder(mContext, "test") 136 .setFlag(Notification.FLAG_CAN_COLORIZE, false) 137 .setColorized(true).setColor(Color.WHITE) 138 .build(); 139 assertFalse(n.isColorized()); 140 } 141 142 @Test testColorizedByForeground()143 public void testColorizedByForeground() { 144 Notification n = new Notification.Builder(mContext, "test") 145 .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true) 146 .setColorized(true).setColor(Color.WHITE) 147 .build(); 148 assertTrue(n.isColorized()); 149 150 n = new Notification.Builder(mContext, "test") 151 .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true) 152 .build(); 153 assertFalse(n.isColorized()); 154 155 n = new Notification.Builder(mContext, "test") 156 .setFlag(Notification.FLAG_FOREGROUND_SERVICE, false) 157 .setColorized(true).setColor(Color.WHITE) 158 .build(); 159 assertFalse(n.isColorized()); 160 } 161 162 @Test testHasCompletedProgress_noProgress()163 public void testHasCompletedProgress_noProgress() { 164 Notification n = new Notification.Builder(mContext).build(); 165 166 assertFalse(n.hasCompletedProgress()); 167 } 168 169 @Test testHasCompletedProgress_complete()170 public void testHasCompletedProgress_complete() { 171 Notification n = new Notification.Builder(mContext) 172 .setProgress(100, 100, true) 173 .build(); 174 Notification n2 = new Notification.Builder(mContext) 175 .setProgress(10, 10, false) 176 .build(); 177 assertTrue(n.hasCompletedProgress()); 178 assertTrue(n2.hasCompletedProgress()); 179 } 180 181 @Test testHasCompletedProgress_notComplete()182 public void testHasCompletedProgress_notComplete() { 183 Notification n = new Notification.Builder(mContext) 184 .setProgress(100, 99, true) 185 .build(); 186 Notification n2 = new Notification.Builder(mContext) 187 .setProgress(10, 4, false) 188 .build(); 189 assertFalse(n.hasCompletedProgress()); 190 assertFalse(n2.hasCompletedProgress()); 191 } 192 193 @Test testHasCompletedProgress_zeroMax()194 public void testHasCompletedProgress_zeroMax() { 195 Notification n = new Notification.Builder(mContext) 196 .setProgress(0, 0, true) 197 .build(); 198 assertFalse(n.hasCompletedProgress()); 199 } 200 201 @Test largeIconMultipleReferences_keptAfterParcelling()202 public void largeIconMultipleReferences_keptAfterParcelling() { 203 Icon originalIcon = Icon.createWithBitmap(BitmapFactory.decodeResource( 204 mContext.getResources(), com.android.frameworks.coretests.R.drawable.test128x96)); 205 206 Notification n = new Notification.Builder(mContext).setLargeIcon(originalIcon).build(); 207 assertSame(n.getLargeIcon(), originalIcon); 208 209 Notification q = writeAndReadParcelable(n); 210 assertNotSame(q.getLargeIcon(), n.getLargeIcon()); 211 212 assertTrue(q.getLargeIcon().getBitmap().sameAs(n.getLargeIcon().getBitmap())); 213 assertSame(q.getLargeIcon(), q.extras.getParcelable(EXTRA_LARGE_ICON)); 214 } 215 216 @Test largeIconReferenceInExtrasOnly_keptAfterParcelling()217 public void largeIconReferenceInExtrasOnly_keptAfterParcelling() { 218 Icon originalIcon = Icon.createWithBitmap(BitmapFactory.decodeResource( 219 mContext.getResources(), com.android.frameworks.coretests.R.drawable.test128x96)); 220 221 Notification n = new Notification.Builder(mContext).build(); 222 n.extras.putParcelable(EXTRA_LARGE_ICON, originalIcon); 223 assertSame(n.getLargeIcon(), null); 224 225 Notification q = writeAndReadParcelable(n); 226 assertSame(q.getLargeIcon(), null); 227 assertTrue(((Icon) q.extras.getParcelable(EXTRA_LARGE_ICON)).getBitmap() 228 .sameAs(originalIcon.getBitmap())); 229 } 230 231 @Test allPendingIntents_recollectedAfterReusingBuilder()232 public void allPendingIntents_recollectedAfterReusingBuilder() { 233 PendingIntent intent1 = PendingIntent.getActivity( 234 mContext, 0, new Intent("test1"), PendingIntent.FLAG_IMMUTABLE); 235 PendingIntent intent2 = PendingIntent.getActivity( 236 mContext, 0, new Intent("test2"), PendingIntent.FLAG_IMMUTABLE); 237 238 Notification.Builder builder = new Notification.Builder(mContext, "channel"); 239 builder.setContentIntent(intent1); 240 241 Parcel p = Parcel.obtain(); 242 243 Notification n1 = builder.build(); 244 n1.writeToParcel(p, 0); 245 246 builder.setContentIntent(intent2); 247 Notification n2 = builder.build(); 248 n2.writeToParcel(p, 0); 249 250 assertTrue(n2.allPendingIntents.contains(intent2)); 251 } 252 253 @Test allPendingIntents_containsCustomRemoteViews()254 public void allPendingIntents_containsCustomRemoteViews() { 255 PendingIntent intent = PendingIntent.getActivity(mContext, 0, 256 new Intent("test").setPackage(mContext.getPackageName()), 257 PendingIntent.FLAG_MUTABLE); 258 259 RemoteViews contentView = new RemoteViews(mContext.getPackageName(), 0 /* layoutId */); 260 contentView.setOnClickPendingIntent(1 /* id */, intent); 261 262 Notification.Builder builder = new Notification.Builder(mContext, "channel"); 263 builder.setCustomContentView(contentView); 264 265 Parcel p = Parcel.obtain(); 266 267 Notification n = builder.build(); 268 n.writeToParcel(p, 0); 269 270 assertTrue(n.allPendingIntents.contains(intent)); 271 } 272 273 @Test allPendingIntents_resilientToAnotherNotificationInExtras()274 public void allPendingIntents_resilientToAnotherNotificationInExtras() { 275 PendingIntent contentIntent = createPendingIntent("content"); 276 PendingIntent actionIntent = createPendingIntent("action"); 277 Notification another = new Notification.Builder(mContext, "channel").build(); 278 Bundle bundleContainingAnotherNotification = new Bundle(); 279 bundleContainingAnotherNotification.putParcelable(null, another); 280 Notification source = new Notification.Builder(mContext, "channel") 281 .setContentIntent(contentIntent) 282 .addAction(new Notification.Action.Builder(null, "action", actionIntent).build()) 283 .setExtras(bundleContainingAnotherNotification) 284 .build(); 285 286 Parcel p = Parcel.obtain(); 287 source.writeToParcel(p, 0); 288 p.setDataPosition(0); 289 Notification unparceled = new Notification(p); 290 291 assertThat(unparceled.allPendingIntents).containsExactly(contentIntent, actionIntent); 292 } 293 294 @Test allPendingIntents_alsoInPublicVersion()295 public void allPendingIntents_alsoInPublicVersion() { 296 PendingIntent contentIntent = createPendingIntent("content"); 297 PendingIntent actionIntent = createPendingIntent("action"); 298 PendingIntent publicContentIntent = createPendingIntent("publicContent"); 299 PendingIntent publicActionIntent = createPendingIntent("publicAction"); 300 Notification source = new Notification.Builder(mContext, "channel") 301 .setContentIntent(contentIntent) 302 .addAction(new Notification.Action.Builder(null, "action", actionIntent).build()) 303 .setPublicVersion(new Notification.Builder(mContext, "channel") 304 .setContentIntent(publicContentIntent) 305 .addAction(new Notification.Action.Builder( 306 null, "publicAction", publicActionIntent).build()) 307 .build()) 308 .build(); 309 310 Parcel p = Parcel.obtain(); 311 source.writeToParcel(p, 0); 312 p.setDataPosition(0); 313 Notification unparceled = new Notification(p); 314 315 assertThat(unparceled.allPendingIntents).containsExactly(contentIntent, actionIntent, 316 publicContentIntent, publicActionIntent); 317 assertThat(unparceled.publicVersion.allPendingIntents).containsExactly(publicContentIntent, 318 publicActionIntent); 319 } 320 321 @Test messagingStyle_isGroupConversation()322 public void messagingStyle_isGroupConversation() { 323 mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.P; 324 Notification.MessagingStyle messagingStyle = new Notification.MessagingStyle("self name") 325 .setGroupConversation(true) 326 .setConversationTitle("test conversation title"); 327 Notification notification = new Notification.Builder(mContext, "test id") 328 .setSmallIcon(1) 329 .setContentTitle("test title") 330 .setStyle(messagingStyle) 331 .build(); 332 333 assertTrue(messagingStyle.isGroupConversation()); 334 assertTrue(notification.extras.getBoolean(Notification.EXTRA_IS_GROUP_CONVERSATION)); 335 } 336 337 @Test messagingStyle_isGroupConversation_noConversationTitle()338 public void messagingStyle_isGroupConversation_noConversationTitle() { 339 mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.P; 340 Notification.MessagingStyle messagingStyle = new Notification.MessagingStyle("self name") 341 .setGroupConversation(true) 342 .setConversationTitle(null); 343 Notification notification = new Notification.Builder(mContext, "test id") 344 .setSmallIcon(1) 345 .setContentTitle("test title") 346 .setStyle(messagingStyle) 347 .build(); 348 349 assertTrue(messagingStyle.isGroupConversation()); 350 assertTrue(notification.extras.getBoolean(Notification.EXTRA_IS_GROUP_CONVERSATION)); 351 } 352 353 @Test messagingStyle_isGroupConversation_withConversationTitle_legacy()354 public void messagingStyle_isGroupConversation_withConversationTitle_legacy() { 355 // In legacy (version < P), isGroupConversation is controlled by conversationTitle. 356 mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.O; 357 Notification.MessagingStyle messagingStyle = new Notification.MessagingStyle("self name") 358 .setGroupConversation(false) 359 .setConversationTitle("test conversation title"); 360 Notification notification = new Notification.Builder(mContext, "test id") 361 .setSmallIcon(1) 362 .setContentTitle("test title") 363 .setStyle(messagingStyle) 364 .build(); 365 366 assertTrue(messagingStyle.isGroupConversation()); 367 assertFalse(notification.extras.getBoolean(Notification.EXTRA_IS_GROUP_CONVERSATION)); 368 } 369 370 @Test messagingStyle_isGroupConversation_withoutConversationTitle_legacy()371 public void messagingStyle_isGroupConversation_withoutConversationTitle_legacy() { 372 // In legacy (version < P), isGroupConversation is controlled by conversationTitle. 373 mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.O; 374 Notification.MessagingStyle messagingStyle = new Notification.MessagingStyle("self name") 375 .setGroupConversation(true) 376 .setConversationTitle(null); 377 Notification notification = new Notification.Builder(mContext, "test id") 378 .setSmallIcon(1) 379 .setContentTitle("test title") 380 .setStyle(messagingStyle) 381 .build(); 382 383 assertFalse(messagingStyle.isGroupConversation()); 384 assertTrue(notification.extras.getBoolean(Notification.EXTRA_IS_GROUP_CONVERSATION)); 385 } 386 387 @Test action_builder_hasDefault()388 public void action_builder_hasDefault() { 389 Notification.Action action = makeNotificationAction(null); 390 assertEquals(Notification.Action.SEMANTIC_ACTION_NONE, action.getSemanticAction()); 391 } 392 393 @Test action_builder_setSemanticAction()394 public void action_builder_setSemanticAction() { 395 Notification.Action action = makeNotificationAction( 396 builder -> builder.setSemanticAction(Notification.Action.SEMANTIC_ACTION_REPLY)); 397 assertEquals(Notification.Action.SEMANTIC_ACTION_REPLY, action.getSemanticAction()); 398 } 399 400 @Test action_parcel()401 public void action_parcel() { 402 Notification.Action action = writeAndReadParcelable( 403 makeNotificationAction(builder -> { 404 builder.setSemanticAction(Notification.Action.SEMANTIC_ACTION_ARCHIVE); 405 builder.setAllowGeneratedReplies(true); 406 })); 407 408 assertEquals(Notification.Action.SEMANTIC_ACTION_ARCHIVE, action.getSemanticAction()); 409 assertTrue(action.getAllowGeneratedReplies()); 410 } 411 412 @Test action_clone()413 public void action_clone() { 414 Notification.Action action = makeNotificationAction( 415 builder -> builder.setSemanticAction(Notification.Action.SEMANTIC_ACTION_DELETE)); 416 assertEquals( 417 Notification.Action.SEMANTIC_ACTION_DELETE, 418 action.clone().getSemanticAction()); 419 } 420 421 @Test testBuilder_setLocusId()422 public void testBuilder_setLocusId() { 423 LocusId locusId = new LocusId("4815162342"); 424 Notification notification = new Notification.Builder(mContext, "whatever") 425 .setLocusId(locusId).build(); 426 assertEquals(locusId, notification.getLocusId()); 427 428 Notification clone = writeAndReadParcelable(notification); 429 assertEquals(locusId, clone.getLocusId()); 430 } 431 432 @Test testBuilder_setLocusId_null()433 public void testBuilder_setLocusId_null() { 434 Notification notification = new Notification.Builder(mContext, "whatever") 435 .setLocusId(null).build(); 436 assertNull(notification.getLocusId()); 437 438 Notification clone = writeAndReadParcelable(notification); 439 assertNull(clone.getLocusId()); 440 } 441 442 @Test testBuilder_getFullLengthSpanColor_returnsNullForString()443 public void testBuilder_getFullLengthSpanColor_returnsNullForString() { 444 assertThat(Notification.Builder.getFullLengthSpanColor("String")).isNull(); 445 } 446 447 @Test testBuilder_getFullLengthSpanColor_returnsNullWithPartialSpan()448 public void testBuilder_getFullLengthSpanColor_returnsNullWithPartialSpan() { 449 CharSequence text = new SpannableStringBuilder() 450 .append("text with ") 451 .append("some red", new ForegroundColorSpan(Color.RED), 452 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 453 assertThat(Notification.Builder.getFullLengthSpanColor(text)).isNull(); 454 } 455 456 @Test testBuilder_getFullLengthSpanColor_worksWithSingleSpan()457 public void testBuilder_getFullLengthSpanColor_worksWithSingleSpan() { 458 CharSequence text = new SpannableStringBuilder() 459 .append("text that is all red", new ForegroundColorSpan(Color.RED), 460 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 461 assertThat(Notification.Builder.getFullLengthSpanColor(text)).isEqualTo(Color.RED); 462 } 463 464 @Test testBuilder_getFullLengthSpanColor_worksWithFullAndPartialSpans()465 public void testBuilder_getFullLengthSpanColor_worksWithFullAndPartialSpans() { 466 Spannable text = new SpannableString("blue text with yellow and green"); 467 text.setSpan(new ForegroundColorSpan(Color.YELLOW), 15, 21, 468 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 469 text.setSpan(new ForegroundColorSpan(Color.BLUE), 0, text.length(), 470 Spanned.SPAN_INCLUSIVE_INCLUSIVE); 471 text.setSpan(new ForegroundColorSpan(Color.GREEN), 26, 31, 472 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 473 assertThat(Notification.Builder.getFullLengthSpanColor(text)).isEqualTo(Color.BLUE); 474 } 475 476 @Test testBuilder_getFullLengthSpanColor_worksWithTextAppearance()477 public void testBuilder_getFullLengthSpanColor_worksWithTextAppearance() { 478 Spannable text = new SpannableString("title text with yellow and green"); 479 text.setSpan(new ForegroundColorSpan(Color.YELLOW), 15, 21, 480 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 481 TextAppearanceSpan textAppearanceSpan = new TextAppearanceSpan(mContext, 482 R.style.TextAppearance_DeviceDefault_Notification_Title); 483 int expectedTextColor = textAppearanceSpan.getTextColor().getDefaultColor(); 484 text.setSpan(textAppearanceSpan, 0, text.length(), 485 Spanned.SPAN_INCLUSIVE_INCLUSIVE); 486 text.setSpan(new ForegroundColorSpan(Color.GREEN), 26, 31, 487 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 488 assertThat(Notification.Builder.getFullLengthSpanColor(text)).isEqualTo(expectedTextColor); 489 } 490 491 492 493 @Test testBuilder_ensureButtonFillContrast_adjustsDarker()494 public void testBuilder_ensureButtonFillContrast_adjustsDarker() { 495 int background = Color.LTGRAY; 496 int foreground = Color.LTGRAY; 497 int result = Notification.Builder.ensureButtonFillContrast(foreground, background); 498 assertContrastIsWithinRange(result, background, 1.3, 1.5); 499 assertThat(ContrastColorUtil.calculateLuminance(result)) 500 .isLessThan(ContrastColorUtil.calculateLuminance(background)); 501 } 502 503 @Test testBuilder_ensureButtonFillContrast_adjustsLighter()504 public void testBuilder_ensureButtonFillContrast_adjustsLighter() { 505 int background = Color.DKGRAY; 506 int foreground = Color.DKGRAY; 507 int result = Notification.Builder.ensureButtonFillContrast(foreground, background); 508 assertContrastIsWithinRange(result, background, 1.3, 1.5); 509 assertThat(ContrastColorUtil.calculateLuminance(result)) 510 .isGreaterThan(ContrastColorUtil.calculateLuminance(background)); 511 } 512 513 @Test testCallStyle_getSystemActions_forIncomingCall()514 public void testCallStyle_getSystemActions_forIncomingCall() { 515 PendingIntent answerIntent = createPendingIntent("answer"); 516 PendingIntent declineIntent = createPendingIntent("decline"); 517 Notification.CallStyle style = Notification.CallStyle.forIncomingCall( 518 new Person.Builder().setName("A Caller").build(), 519 declineIntent, 520 answerIntent 521 ); 522 style.setBuilder(new Notification.Builder(mContext, "Channel")); 523 524 List<Notification.Action> actions = style.getActionsListWithSystemActions(); 525 526 assertEquals(2, actions.size()); 527 assertEquals(declineIntent, actions.get(0).actionIntent); 528 assertEquals(answerIntent, actions.get(1).actionIntent); 529 } 530 531 @Test testCallStyle_getSystemActions_forOngoingCall()532 public void testCallStyle_getSystemActions_forOngoingCall() { 533 PendingIntent hangUpIntent = createPendingIntent("hangUp"); 534 Notification.CallStyle style = Notification.CallStyle.forOngoingCall( 535 new Person.Builder().setName("A Caller").build(), 536 hangUpIntent 537 ); 538 style.setBuilder(new Notification.Builder(mContext, "Channel")); 539 540 List<Notification.Action> actions = style.getActionsListWithSystemActions(); 541 542 assertEquals(1, actions.size()); 543 assertEquals(hangUpIntent, actions.get(0).actionIntent); 544 } 545 546 @Test testCallStyle_getSystemActions_forIncomingCallWithOtherActions()547 public void testCallStyle_getSystemActions_forIncomingCallWithOtherActions() { 548 PendingIntent answerIntent = createPendingIntent("answer"); 549 PendingIntent declineIntent = createPendingIntent("decline"); 550 Notification.CallStyle style = Notification.CallStyle.forIncomingCall( 551 new Person.Builder().setName("A Caller").build(), 552 declineIntent, 553 answerIntent 554 ); 555 Notification.Action actionToKeep = makeNotificationAction(null); 556 Notification.Action actionToDrop = makeNotificationAction(null); 557 Notification.Builder notifBuilder = new Notification.Builder(mContext, "Channel") 558 .addAction(actionToKeep) 559 .addAction(actionToDrop); //expect to move this action to the end 560 style.setBuilder(notifBuilder); //add a builder with actions 561 562 List<Notification.Action> actions = style.getActionsListWithSystemActions(); 563 564 assertEquals(4, actions.size()); 565 assertEquals(declineIntent, actions.get(0).actionIntent); 566 assertEquals(actionToKeep, actions.get(1)); 567 assertEquals(answerIntent, actions.get(2).actionIntent); 568 assertEquals(actionToDrop, actions.get(3)); 569 } 570 571 @Test testCallStyle_getSystemActions_forOngoingCallWithOtherActions()572 public void testCallStyle_getSystemActions_forOngoingCallWithOtherActions() { 573 PendingIntent hangUpIntent = createPendingIntent("hangUp"); 574 Notification.CallStyle style = Notification.CallStyle.forOngoingCall( 575 new Person.Builder().setName("A Caller").build(), 576 hangUpIntent 577 ); 578 Notification.Action firstAction = makeNotificationAction(null); 579 Notification.Action secondAction = makeNotificationAction(null); 580 Notification.Builder notifBuilder = new Notification.Builder(mContext, "Channel") 581 .addAction(firstAction) 582 .addAction(secondAction); 583 style.setBuilder(notifBuilder); //add a builder with actions 584 585 List<Notification.Action> actions = style.getActionsListWithSystemActions(); 586 587 assertEquals(3, actions.size()); 588 assertEquals(hangUpIntent, actions.get(0).actionIntent); 589 assertEquals(firstAction, actions.get(1)); 590 assertEquals(secondAction, actions.get(2)); 591 } 592 593 @Test testCallStyle_getSystemActions_dropsOldSystemActions()594 public void testCallStyle_getSystemActions_dropsOldSystemActions() { 595 PendingIntent hangUpIntent = createPendingIntent("decline"); 596 Notification.CallStyle style = Notification.CallStyle.forOngoingCall( 597 new Person.Builder().setName("A Caller").build(), 598 hangUpIntent 599 ); 600 Bundle actionExtras = new Bundle(); 601 actionExtras.putBoolean("key_action_priority", true); 602 Notification.Action oldSystemAction = makeNotificationAction( 603 builder -> builder.addExtras(actionExtras) 604 ); 605 Notification.Builder notifBuilder = new Notification.Builder(mContext, "Channel") 606 .addAction(oldSystemAction); 607 style.setBuilder(notifBuilder); //add a builder with actions 608 609 List<Notification.Action> actions = style.getActionsListWithSystemActions(); 610 611 assertFalse("Old versions of system actions should be dropped.", 612 actions.contains(oldSystemAction)); 613 } 614 615 @Test testBuild_ensureSmallIconIsNotTooBig_resizesIcon()616 public void testBuild_ensureSmallIconIsNotTooBig_resizesIcon() { 617 Icon hugeIcon = Icon.createWithBitmap( 618 Bitmap.createBitmap(3000, 3000, Bitmap.Config.ARGB_8888)); 619 Notification notification = new Notification.Builder(mContext, "Channel").setSmallIcon( 620 hugeIcon).build(); 621 622 Bitmap smallNotificationIcon = notification.getSmallIcon().getBitmap(); 623 assertThat(smallNotificationIcon.getWidth()).isEqualTo( 624 mContext.getResources().getDimensionPixelSize( 625 R.dimen.notification_small_icon_size)); 626 assertThat(smallNotificationIcon.getHeight()).isEqualTo( 627 mContext.getResources().getDimensionPixelSize( 628 R.dimen.notification_small_icon_size)); 629 } 630 631 @Test testBuild_ensureMessagingUserIsNotTooBig_resizesIcon()632 public void testBuild_ensureMessagingUserIsNotTooBig_resizesIcon() { 633 Icon hugeIcon = Icon.createWithBitmap( 634 Bitmap.createBitmap(3000, 3000, Bitmap.Config.ARGB_8888)); 635 Icon hugeMessageAvatar = Icon.createWithBitmap( 636 Bitmap.createBitmap(3000, 3000, Bitmap.Config.ARGB_8888)); 637 Icon hugeHistoricMessageAvatar = Icon.createWithBitmap( 638 Bitmap.createBitmap(3000, 3000, Bitmap.Config.ARGB_8888)); 639 640 Notification.MessagingStyle style = new Notification.MessagingStyle( 641 new Person.Builder().setIcon(hugeIcon).setName("A User").build()); 642 style.addMessage(new Notification.MessagingStyle.Message("A message", 123456, 643 new Person.Builder().setIcon(hugeMessageAvatar).setName("A Sender").build())); 644 style.addHistoricMessage(new Notification.MessagingStyle.Message("A message", 123456, 645 new Person.Builder().setIcon(hugeHistoricMessageAvatar).setName( 646 "A Historic Sender").build())); 647 Notification notification = new Notification.Builder(mContext, "Channel").setStyle( 648 style).build(); 649 650 int targetSize = mContext.getResources().getDimensionPixelSize( 651 ActivityManager.isLowRamDeviceStatic() 652 ? R.dimen.notification_person_icon_max_size_low_ram 653 : R.dimen.notification_person_icon_max_size); 654 655 Bitmap personIcon = style.getUser().getIcon().getBitmap(); 656 assertThat(personIcon.getWidth()).isEqualTo(targetSize); 657 assertThat(personIcon.getHeight()).isEqualTo(targetSize); 658 659 Bitmap avatarIcon = style.getMessages().get(0).getSenderPerson().getIcon().getBitmap(); 660 assertThat(avatarIcon.getWidth()).isEqualTo(targetSize); 661 assertThat(avatarIcon.getHeight()).isEqualTo(targetSize); 662 663 Bitmap historicAvatarIcon = style.getHistoricMessages().get( 664 0).getSenderPerson().getIcon().getBitmap(); 665 assertThat(historicAvatarIcon.getWidth()).isEqualTo(targetSize); 666 assertThat(historicAvatarIcon.getHeight()).isEqualTo(targetSize); 667 } 668 669 @Test testBuild_ensureMessagingShortcutIconIsNotTooBig_resizesIcon()670 public void testBuild_ensureMessagingShortcutIconIsNotTooBig_resizesIcon() { 671 Icon hugeIcon = Icon.createWithBitmap( 672 Bitmap.createBitmap(3000, 3000, Bitmap.Config.ARGB_8888)); 673 Notification.MessagingStyle style = new Notification.MessagingStyle( 674 new Person.Builder().setName("A User").build()).setShortcutIcon(hugeIcon); 675 676 Notification notification = new Notification.Builder(mContext, "Channel").setStyle( 677 style).build(); 678 Bitmap shortcutIcon = style.getShortcutIcon().getBitmap(); 679 680 assertThat(shortcutIcon.getWidth()).isEqualTo( 681 mContext.getResources().getDimensionPixelSize( 682 R.dimen.notification_small_icon_size)); 683 assertThat(shortcutIcon.getHeight()).isEqualTo( 684 mContext.getResources().getDimensionPixelSize( 685 R.dimen.notification_small_icon_size)); 686 } 687 688 @Test testColors_ensureColors_dayMode_producesValidPalette()689 public void testColors_ensureColors_dayMode_producesValidPalette() { 690 Notification.Colors c = new Notification.Colors(); 691 boolean colorized = false; 692 boolean nightMode = false; 693 resolveColorsInNightMode(nightMode, c, Color.BLUE, colorized); 694 assertValid(c); 695 } 696 697 @Test testColors_ensureColors_nightMode_producesValidPalette()698 public void testColors_ensureColors_nightMode_producesValidPalette() { 699 Notification.Colors c = new Notification.Colors(); 700 boolean colorized = false; 701 boolean nightMode = true; 702 resolveColorsInNightMode(nightMode, c, Color.BLUE, colorized); 703 assertValid(c); 704 } 705 706 @Test testColors_ensureColors_colorized_producesValidPalette_default()707 public void testColors_ensureColors_colorized_producesValidPalette_default() { 708 validateColorizedPaletteForColor(Notification.COLOR_DEFAULT); 709 } 710 711 @Test testColors_ensureColors_colorized_producesValidPalette_blue()712 public void testColors_ensureColors_colorized_producesValidPalette_blue() { 713 validateColorizedPaletteForColor(Color.BLUE); 714 } 715 716 @Test testColors_ensureColors_colorized_producesValidPalette_red()717 public void testColors_ensureColors_colorized_producesValidPalette_red() { 718 validateColorizedPaletteForColor(Color.RED); 719 } 720 721 @Test testColors_ensureColors_colorized_producesValidPalette_white()722 public void testColors_ensureColors_colorized_producesValidPalette_white() { 723 validateColorizedPaletteForColor(Color.WHITE); 724 } 725 726 @Test testColors_ensureColors_colorized_producesValidPalette_black()727 public void testColors_ensureColors_colorized_producesValidPalette_black() { 728 validateColorizedPaletteForColor(Color.BLACK); 729 } 730 731 @Test testIsMediaNotification_nullSession_returnsFalse()732 public void testIsMediaNotification_nullSession_returnsFalse() { 733 // Null media session 734 Notification.MediaStyle mediaStyle = new Notification.MediaStyle(); 735 Notification notification = new Notification.Builder(mContext, "test id") 736 .setStyle(mediaStyle) 737 .build(); 738 assertFalse(notification.isMediaNotification()); 739 } 740 741 @Test testIsMediaNotification_invalidSession_returnsFalse()742 public void testIsMediaNotification_invalidSession_returnsFalse() { 743 // Extra was set manually to an invalid type 744 Bundle extras = new Bundle(); 745 extras.putParcelable(EXTRA_MEDIA_SESSION, new Intent()); 746 Notification.MediaStyle mediaStyle = new Notification.MediaStyle(); 747 Notification notification = new Notification.Builder(mContext, "test id") 748 .setStyle(mediaStyle) 749 .addExtras(extras) 750 .build(); 751 assertFalse(notification.isMediaNotification()); 752 } 753 validateColorizedPaletteForColor(int rawColor)754 public void validateColorizedPaletteForColor(int rawColor) { 755 Notification.Colors cDay = new Notification.Colors(); 756 Notification.Colors cNight = new Notification.Colors(); 757 boolean colorized = true; 758 759 resolveColorsInNightMode(false, cDay, rawColor, colorized); 760 resolveColorsInNightMode(true, cNight, rawColor, colorized); 761 762 if (rawColor != Notification.COLOR_DEFAULT) { 763 assertEquals(rawColor, cDay.getBackgroundColor()); 764 assertEquals(rawColor, cNight.getBackgroundColor()); 765 } 766 767 assertValid(cDay); 768 assertValid(cNight); 769 770 if (rawColor != Notification.COLOR_DEFAULT) { 771 // When a color is provided, night mode should have no effect on the notification 772 assertEquals(cDay.getBackgroundColor(), cNight.getBackgroundColor()); 773 assertEquals(cDay.getPrimaryTextColor(), cNight.getPrimaryTextColor()); 774 assertEquals(cDay.getSecondaryTextColor(), cNight.getSecondaryTextColor()); 775 assertEquals(cDay.getPrimaryAccentColor(), cNight.getPrimaryAccentColor()); 776 assertEquals(cDay.getSecondaryAccentColor(), cNight.getSecondaryAccentColor()); 777 assertEquals(cDay.getTertiaryAccentColor(), cNight.getTertiaryAccentColor()); 778 assertEquals(cDay.getOnAccentTextColor(), cNight.getOnAccentTextColor()); 779 assertEquals(cDay.getProtectionColor(), cNight.getProtectionColor()); 780 assertEquals(cDay.getContrastColor(), cNight.getContrastColor()); 781 assertEquals(cDay.getRippleAlpha(), cNight.getRippleAlpha()); 782 } 783 } 784 785 @Test testRecoverBuilder_nullExtraPeopleList_noCrash()786 public void testRecoverBuilder_nullExtraPeopleList_noCrash() { 787 Bundle extras = new Bundle(); 788 extras.putParcelable(EXTRA_PEOPLE_LIST, null); 789 790 Notification n = new Notification.Builder(mContext, "test") 791 .setSmallIcon(0) 792 .addExtras(extras) 793 .build(); 794 Bundle fakeTypes = new Bundle(); 795 fakeTypes.putParcelable(EXTRA_BUILDER_APPLICATION_INFO, new Bundle()); 796 797 Notification.Builder.recoverBuilder(mContext, n); 798 799 // no crash, good 800 } 801 802 @Test testVisitUris_invalidExtra_noCrash()803 public void testVisitUris_invalidExtra_noCrash() { 804 Notification n = new Notification.Builder(mContext, "test") 805 .setSmallIcon(0) 806 .build(); 807 Bundle fakeTypes = new Bundle(); 808 fakeTypes.putParcelable(EXTRA_LARGE_ICON_BIG, new Bundle()); 809 fakeTypes.putParcelable(EXTRA_PICTURE_ICON, new Bundle()); 810 fakeTypes.putParcelable(EXTRA_MESSAGING_PERSON, new Bundle()); 811 812 Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class); 813 n.visitUris(visitor); 814 815 // no crash, good 816 } 817 818 @Test testRecoverBuilder_invalidExtra_noCrash()819 public void testRecoverBuilder_invalidExtra_noCrash() { 820 Notification n = new Notification.Builder(mContext, "test") 821 .setSmallIcon(0) 822 .build(); 823 Bundle fakeTypes = new Bundle(); 824 fakeTypes.putParcelable(EXTRA_BUILDER_APPLICATION_INFO, new Bundle()); 825 826 Notification.Builder.recoverBuilder(mContext, n); 827 828 // no crash, good 829 } 830 831 @Test testIsMediaNotification_invalidExtra_noCrash()832 public void testIsMediaNotification_invalidExtra_noCrash() { 833 Notification n = new Notification.Builder(mContext, "test") 834 .setSmallIcon(0) 835 .setStyle(new Notification.MediaStyle()) 836 .build(); 837 Bundle fakeTypes = new Bundle(); 838 fakeTypes.putParcelable(EXTRA_MEDIA_SESSION, new Bundle()); 839 840 n.isMediaNotification(); 841 842 // no crash, good 843 } 844 845 @Test testRestoreFromExtras_BigText_invalidExtra_noCrash()846 public void testRestoreFromExtras_BigText_invalidExtra_noCrash() { 847 Notification.Style style = new Notification.BigTextStyle(); 848 Bundle fakeTypes = new Bundle(); 849 fakeTypes.putParcelable(EXTRA_LARGE_ICON_BIG, new Bundle()); 850 851 852 // no crash, good 853 } 854 855 @Test testRestoreFromExtras_Messaging_invalidExtra_noCrash()856 public void testRestoreFromExtras_Messaging_invalidExtra_noCrash() { 857 Notification.Style style = new Notification.MessagingStyle("test"); 858 Bundle fakeTypes = new Bundle(); 859 fakeTypes.putParcelable(EXTRA_MESSAGING_PERSON, new Bundle()); 860 fakeTypes.putParcelable(EXTRA_CONVERSATION_ICON, new Bundle()); 861 862 Notification n = new Notification.Builder(mContext, "test") 863 .setStyle(style) 864 .setExtras(fakeTypes) 865 .build(); 866 Notification.Builder.recoverBuilder(mContext, n); 867 868 // no crash, good 869 } 870 871 @Test testRestoreFromExtras_Media_invalidExtra_noCrash()872 public void testRestoreFromExtras_Media_invalidExtra_noCrash() { 873 Notification.Style style = new Notification.MediaStyle(); 874 Bundle fakeTypes = new Bundle(); 875 fakeTypes.putParcelable(EXTRA_MEDIA_SESSION, new Bundle()); 876 fakeTypes.putParcelable(EXTRA_MEDIA_REMOTE_INTENT, new Bundle()); 877 878 Notification n = new Notification.Builder(mContext, "test") 879 .setStyle(style) 880 .setExtras(fakeTypes) 881 .build(); 882 Notification.Builder.recoverBuilder(mContext, n); 883 884 // no crash, good 885 } 886 887 @Test testRestoreFromExtras_Call_invalidExtra_noCrash()888 public void testRestoreFromExtras_Call_invalidExtra_noCrash() { 889 PendingIntent intent1 = PendingIntent.getActivity( 890 mContext, 0, new Intent("test1"), PendingIntent.FLAG_IMMUTABLE); 891 Notification.Style style = Notification.CallStyle.forIncomingCall( 892 new Person.Builder().setName("hi").build(), intent1, intent1); 893 894 Bundle fakeTypes = new Bundle(); 895 fakeTypes.putParcelable(EXTRA_CALL_PERSON, new Bundle()); 896 fakeTypes.putParcelable(EXTRA_ANSWER_INTENT, new Bundle()); 897 fakeTypes.putParcelable(EXTRA_DECLINE_INTENT, new Bundle()); 898 fakeTypes.putParcelable(EXTRA_HANG_UP_INTENT, new Bundle()); 899 900 Notification n = new Notification.Builder(mContext, "test") 901 .setStyle(style) 902 .setExtras(fakeTypes) 903 .build(); 904 Notification.Builder.recoverBuilder(mContext, n); 905 // no crash, good 906 } 907 908 @Test testGetPictureIcon_invalidExtra_noCrash()909 public void testGetPictureIcon_invalidExtra_noCrash() { 910 Bundle fakeTypes = new Bundle(); 911 fakeTypes.putParcelable(EXTRA_PICTURE, new Bundle()); 912 fakeTypes.putParcelable(EXTRA_PICTURE_ICON, new Bundle()); 913 914 Notification.BigPictureStyle.getPictureIcon(fakeTypes); 915 916 // no crash, good 917 } 918 919 @Test testWearableExtender_invalidExtra_noCrash()920 public void testWearableExtender_invalidExtra_noCrash() { 921 Notification n = new Notification.Builder(mContext, "test") 922 .setSmallIcon(0) 923 .setStyle(new Notification.MediaStyle()) 924 .build(); 925 Bundle fakeTypes = new Bundle(); 926 fakeTypes.putParcelable(KEY_DISPLAY_INTENT, new Bundle()); 927 fakeTypes.putParcelable(KEY_BACKGROUND, new Bundle()); 928 Notification.WearableExtender extender = new Notification.WearableExtender(n); 929 930 // no crash, good 931 } 932 933 @Test testCarExtender_invalidExtra_noCrash()934 public void testCarExtender_invalidExtra_noCrash() { 935 Notification n = new Notification.Builder(mContext, "test") 936 .setSmallIcon(0) 937 .setStyle(new Notification.MediaStyle()) 938 .build(); 939 Bundle fakeTypes = new Bundle(); 940 fakeTypes.putParcelable(EXTRA_LARGE_ICON, new Bundle()); 941 Notification.CarExtender extender = new Notification.CarExtender(n); 942 943 // no crash, good 944 } 945 946 @Test testTvExtender_invalidExtra_noCrash()947 public void testTvExtender_invalidExtra_noCrash() { 948 Notification n = new Notification.Builder(mContext, "test") 949 .setSmallIcon(0) 950 .setStyle(new Notification.MediaStyle()) 951 .build(); 952 Bundle fakeTypes = new Bundle(); 953 fakeTypes.putParcelable(EXTRA_CONTENT_INTENT, new Bundle()); 954 fakeTypes.putParcelable(EXTRA_DELETE_INTENT, new Bundle()); 955 Notification.TvExtender extender = new Notification.TvExtender(n); 956 957 // no crash, good 958 } 959 960 @Test testGetUnreadConversationFromBundle_invalidExtra_noCrash()961 public void testGetUnreadConversationFromBundle_invalidExtra_noCrash() { 962 Bundle fakeTypes = new Bundle(); 963 fakeTypes.putParcelable(KEY_ON_READ, new Bundle()); 964 fakeTypes.putParcelable(KEY_ON_REPLY, new Bundle()); 965 fakeTypes.putParcelable(KEY_REMOTE_INPUT, new Bundle()); 966 967 Notification n = new Notification.Builder(mContext, "test") 968 .setExtras(fakeTypes) 969 .build(); 970 Notification.CarExtender extender = new Notification.CarExtender(n); 971 972 // no crash, good 973 } 974 975 @Test testGetMessageFromBundle_invalidExtra_noCrash()976 public void testGetMessageFromBundle_invalidExtra_noCrash() { 977 Bundle fakeTypes = new Bundle(); 978 fakeTypes.putParcelable(KEY_SENDER_PERSON, new Bundle()); 979 fakeTypes.putString(KEY_TEXT, "text"); 980 fakeTypes.putLong(KEY_TIMESTAMP, 0); 981 fakeTypes.putParcelable(KEY_REMOTE_INPUT, new Bundle()); 982 fakeTypes.putParcelable(KEY_DATA_URI, new Bundle()); 983 Notification.MessagingStyle.Message.getMessageFromBundle(fakeTypes); 984 985 // no crash, good 986 } 987 988 989 @Test testDoesNotStripsExtenders()990 public void testDoesNotStripsExtenders() { 991 Notification.Builder nb = new Notification.Builder(mContext, "channel"); 992 nb.extend(new Notification.CarExtender().setColor(Color.RED)); 993 nb.extend(new Notification.TvExtender().setChannelId("different channel")); 994 nb.extend(new Notification.WearableExtender().setDismissalId("dismiss")); 995 Notification before = nb.build(); 996 Notification after = Notification.Builder.maybeCloneStrippedForDelivery(before); 997 998 assertTrue(before == after); 999 1000 Assert.assertEquals("different channel", 1001 new Notification.TvExtender(before).getChannelId()); 1002 Assert.assertEquals(Color.RED, new Notification.CarExtender(before).getColor()); 1003 Assert.assertEquals("dismiss", new Notification.WearableExtender(before).getDismissalId()); 1004 } 1005 1006 @Test areIconsDifferent_sameSmallIcon_false()1007 public void areIconsDifferent_sameSmallIcon_false() { 1008 Notification n1 = new Notification.Builder(mContext, "test").setSmallIcon(1).build(); 1009 Notification n2 = new Notification.Builder(mContext, "test").setSmallIcon(1).build(); 1010 1011 assertThat(Notification.areIconsDifferent(n1, n2)).isFalse(); 1012 } 1013 1014 @Test areIconsDifferent_differentSmallIcon_true()1015 public void areIconsDifferent_differentSmallIcon_true() { 1016 Notification n1 = new Notification.Builder(mContext, "test").setSmallIcon(1).build(); 1017 Notification n2 = new Notification.Builder(mContext, "test").setSmallIcon(2).build(); 1018 1019 assertThat(Notification.areIconsDifferent(n1, n2)).isTrue(); 1020 } 1021 1022 @Test areIconsDifferent_sameLargeIcon_false()1023 public void areIconsDifferent_sameLargeIcon_false() { 1024 Icon icon1 = Icon.createWithContentUri("uri"); 1025 Icon icon2 = Icon.createWithContentUri("uri"); 1026 Notification n1 = new Notification.Builder(mContext, "test") 1027 .setSmallIcon(1).setLargeIcon(icon1).build(); 1028 Notification n2 = new Notification.Builder(mContext, "test") 1029 .setSmallIcon(1).setLargeIcon(icon2).build(); 1030 1031 // Note that this will almost certainly not happen for Icons created from Bitmaps, since 1032 // their serialization/deserialization of Bitmaps (app -> system_process) results in a 1033 // different getGenerationId() value. :( 1034 assertThat(Notification.areIconsDifferent(n1, n2)).isFalse(); 1035 } 1036 1037 @Test areIconsDifferent_differentLargeIcon_true()1038 public void areIconsDifferent_differentLargeIcon_true() { 1039 Icon icon1 = Icon.createWithContentUri("uri1"); 1040 Icon icon2 = Icon.createWithContentUri("uri2"); 1041 Notification n1 = new Notification.Builder(mContext, "test") 1042 .setSmallIcon(1).setLargeIcon(icon1).build(); 1043 Notification n2 = new Notification.Builder(mContext, "test") 1044 .setSmallIcon(2).setLargeIcon(icon2).build(); 1045 1046 assertThat(Notification.areIconsDifferent(n1, n2)).isTrue(); 1047 } 1048 1049 @Test areIconsDifferent_addedLargeIcon_true()1050 public void areIconsDifferent_addedLargeIcon_true() { 1051 Icon icon = Icon.createWithContentUri("uri"); 1052 Notification n1 = new Notification.Builder(mContext, "test").setSmallIcon(1).build(); 1053 Notification n2 = new Notification.Builder(mContext, "test") 1054 .setSmallIcon(2).setLargeIcon(icon).build(); 1055 1056 assertThat(Notification.areIconsDifferent(n1, n2)).isTrue(); 1057 } 1058 1059 @Test areIconsDifferent_removedLargeIcon_true()1060 public void areIconsDifferent_removedLargeIcon_true() { 1061 Icon icon = Icon.createWithContentUri("uri"); 1062 Notification n1 = new Notification.Builder(mContext, "test") 1063 .setSmallIcon(1).setLargeIcon(icon).build(); 1064 Notification n2 = new Notification.Builder(mContext, "test").setSmallIcon(2).build(); 1065 1066 assertThat(Notification.areIconsDifferent(n1, n2)).isTrue(); 1067 } 1068 1069 @Test testStyleChangeVisiblyDifferent_noStyles()1070 public void testStyleChangeVisiblyDifferent_noStyles() { 1071 Notification.Builder n1 = new Notification.Builder(mContext, "test"); 1072 Notification.Builder n2 = new Notification.Builder(mContext, "test"); 1073 1074 assertFalse(Notification.areStyledNotificationsVisiblyDifferent(n1, n2)); 1075 } 1076 1077 @Test testStyleChangeVisiblyDifferent_noStyleToStyle()1078 public void testStyleChangeVisiblyDifferent_noStyleToStyle() { 1079 Notification.Builder n1 = new Notification.Builder(mContext, "test"); 1080 Notification.Builder n2 = new Notification.Builder(mContext, "test") 1081 .setStyle(new Notification.BigTextStyle()); 1082 1083 assertTrue(Notification.areStyledNotificationsVisiblyDifferent(n1, n2)); 1084 } 1085 1086 @Test testStyleChangeVisiblyDifferent_styleToNoStyle()1087 public void testStyleChangeVisiblyDifferent_styleToNoStyle() { 1088 Notification.Builder n2 = new Notification.Builder(mContext, "test"); 1089 Notification.Builder n1 = new Notification.Builder(mContext, "test") 1090 .setStyle(new Notification.BigTextStyle()); 1091 1092 assertTrue(Notification.areStyledNotificationsVisiblyDifferent(n1, n2)); 1093 } 1094 1095 @Test testStyleChangeVisiblyDifferent_changeStyle()1096 public void testStyleChangeVisiblyDifferent_changeStyle() { 1097 Notification.Builder n1 = new Notification.Builder(mContext, "test") 1098 .setStyle(new Notification.InboxStyle()); 1099 Notification.Builder n2 = new Notification.Builder(mContext, "test") 1100 .setStyle(new Notification.BigTextStyle()); 1101 1102 assertTrue(Notification.areStyledNotificationsVisiblyDifferent(n1, n2)); 1103 } 1104 1105 @Test testInboxTextChange()1106 public void testInboxTextChange() { 1107 Notification.Builder nInbox1 = new Notification.Builder(mContext, "test") 1108 .setStyle(new Notification.InboxStyle().addLine("a").addLine("b")); 1109 Notification.Builder nInbox2 = new Notification.Builder(mContext, "test") 1110 .setStyle(new Notification.InboxStyle().addLine("b").addLine("c")); 1111 1112 assertTrue(Notification.areStyledNotificationsVisiblyDifferent(nInbox1, nInbox2)); 1113 } 1114 1115 @Test testBigTextTextChange()1116 public void testBigTextTextChange() { 1117 Notification.Builder nBigText1 = new Notification.Builder(mContext, "test") 1118 .setStyle(new Notification.BigTextStyle().bigText("something")); 1119 Notification.Builder nBigText2 = new Notification.Builder(mContext, "test") 1120 .setStyle(new Notification.BigTextStyle().bigText("else")); 1121 1122 assertTrue(Notification.areStyledNotificationsVisiblyDifferent(nBigText1, nBigText2)); 1123 } 1124 1125 @Test testBigPictureChange()1126 public void testBigPictureChange() { 1127 Bitmap bitA = Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888); 1128 Bitmap bitB = Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888); 1129 1130 Notification.Builder nBigPic1 = new Notification.Builder(mContext, "test") 1131 .setStyle(new Notification.BigPictureStyle().bigPicture(bitA)); 1132 Notification.Builder nBigPic2 = new Notification.Builder(mContext, "test") 1133 .setStyle(new Notification.BigPictureStyle().bigPicture(bitB)); 1134 1135 assertTrue(Notification.areStyledNotificationsVisiblyDifferent(nBigPic1, nBigPic2)); 1136 } 1137 1138 @Test testMessagingChange_text()1139 public void testMessagingChange_text() { 1140 Notification.Builder nM1 = new Notification.Builder(mContext, "test") 1141 .setStyle(new Notification.MessagingStyle("") 1142 .addMessage(new Notification.MessagingStyle.Message( 1143 "a", 100, new Person.Builder().setName("hi").build()))); 1144 Notification.Builder nM2 = new Notification.Builder(mContext, "test") 1145 .setStyle(new Notification.MessagingStyle("") 1146 .addMessage(new Notification.MessagingStyle.Message( 1147 "a", 100, new Person.Builder().setName("hi").build())) 1148 .addMessage(new Notification.MessagingStyle.Message( 1149 "b", 100, new Person.Builder().setName("hi").build())) 1150 ); 1151 1152 assertTrue(Notification.areStyledNotificationsVisiblyDifferent(nM1, nM2)); 1153 } 1154 1155 @Test testMessagingChange_data()1156 public void testMessagingChange_data() { 1157 Notification.Builder nM1 = new Notification.Builder(mContext, "test") 1158 .setStyle(new Notification.MessagingStyle("") 1159 .addMessage(new Notification.MessagingStyle.Message( 1160 "a", 100, new Person.Builder().setName("hi").build()) 1161 .setData("text", mock(Uri.class)))); 1162 Notification.Builder nM2 = new Notification.Builder(mContext, "test") 1163 .setStyle(new Notification.MessagingStyle("") 1164 .addMessage(new Notification.MessagingStyle.Message( 1165 "a", 100, new Person.Builder().setName("hi").build()))); 1166 1167 assertTrue(Notification.areStyledNotificationsVisiblyDifferent(nM1, nM2)); 1168 } 1169 1170 @Test testMessagingChange_sender()1171 public void testMessagingChange_sender() { 1172 Person a = new Person.Builder().setName("A").build(); 1173 Person b = new Person.Builder().setName("b").build(); 1174 Notification.Builder nM1 = new Notification.Builder(mContext, "test") 1175 .setStyle(new Notification.MessagingStyle("") 1176 .addMessage(new Notification.MessagingStyle.Message("a", 100, b))); 1177 Notification.Builder nM2 = new Notification.Builder(mContext, "test") 1178 .setStyle(new Notification.MessagingStyle("") 1179 .addMessage(new Notification.MessagingStyle.Message("a", 100, a))); 1180 1181 assertTrue(Notification.areStyledNotificationsVisiblyDifferent(nM1, nM2)); 1182 } 1183 1184 @Test testMessagingChange_key()1185 public void testMessagingChange_key() { 1186 Person a = new Person.Builder().setName("hi").setKey("A").build(); 1187 Person b = new Person.Builder().setName("hi").setKey("b").build(); 1188 Notification.Builder nM1 = new Notification.Builder(mContext, "test") 1189 .setStyle(new Notification.MessagingStyle("") 1190 .addMessage(new Notification.MessagingStyle.Message("a", 100, a))); 1191 Notification.Builder nM2 = new Notification.Builder(mContext, "test") 1192 .setStyle(new Notification.MessagingStyle("") 1193 .addMessage(new Notification.MessagingStyle.Message("a", 100, b))); 1194 1195 assertTrue(Notification.areStyledNotificationsVisiblyDifferent(nM1, nM2)); 1196 } 1197 1198 @Test testMessagingChange_ignoreTimeChange()1199 public void testMessagingChange_ignoreTimeChange() { 1200 Notification.Builder nM1 = new Notification.Builder(mContext, "test") 1201 .setStyle(new Notification.MessagingStyle("") 1202 .addMessage(new Notification.MessagingStyle.Message( 1203 "a", 100, new Person.Builder().setName("hi").build()))); 1204 Notification.Builder nM2 = new Notification.Builder(mContext, "test") 1205 .setStyle(new Notification.MessagingStyle("") 1206 .addMessage(new Notification.MessagingStyle.Message( 1207 "a", 1000, new Person.Builder().setName("hi").build())) 1208 ); 1209 1210 assertFalse(Notification.areStyledNotificationsVisiblyDifferent(nM1, nM2)); 1211 } 1212 1213 @Test testRemoteViews_nullChange()1214 public void testRemoteViews_nullChange() { 1215 Notification.Builder n1 = new Notification.Builder(mContext, "test") 1216 .setContent(mock(RemoteViews.class)); 1217 Notification.Builder n2 = new Notification.Builder(mContext, "test"); 1218 assertTrue(Notification.areRemoteViewsChanged(n1, n2)); 1219 1220 n1 = new Notification.Builder(mContext, "test"); 1221 n2 = new Notification.Builder(mContext, "test") 1222 .setContent(mock(RemoteViews.class)); 1223 assertTrue(Notification.areRemoteViewsChanged(n1, n2)); 1224 1225 n1 = new Notification.Builder(mContext, "test") 1226 .setCustomBigContentView(mock(RemoteViews.class)); 1227 n2 = new Notification.Builder(mContext, "test"); 1228 assertTrue(Notification.areRemoteViewsChanged(n1, n2)); 1229 1230 n1 = new Notification.Builder(mContext, "test"); 1231 n2 = new Notification.Builder(mContext, "test") 1232 .setCustomBigContentView(mock(RemoteViews.class)); 1233 assertTrue(Notification.areRemoteViewsChanged(n1, n2)); 1234 1235 n1 = new Notification.Builder(mContext, "test"); 1236 n2 = new Notification.Builder(mContext, "test"); 1237 assertFalse(Notification.areRemoteViewsChanged(n1, n2)); 1238 } 1239 1240 @Test testRemoteViews_layoutChange()1241 public void testRemoteViews_layoutChange() { 1242 RemoteViews a = mock(RemoteViews.class); 1243 when(a.getLayoutId()).thenReturn(234); 1244 RemoteViews b = mock(RemoteViews.class); 1245 when(b.getLayoutId()).thenReturn(189); 1246 1247 Notification.Builder n1 = new Notification.Builder(mContext, "test").setContent(a); 1248 Notification.Builder n2 = new Notification.Builder(mContext, "test").setContent(b); 1249 assertTrue(Notification.areRemoteViewsChanged(n1, n2)); 1250 1251 n1 = new Notification.Builder(mContext, "test").setCustomBigContentView(a); 1252 n2 = new Notification.Builder(mContext, "test").setCustomBigContentView(b); 1253 assertTrue(Notification.areRemoteViewsChanged(n1, n2)); 1254 1255 n1 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(a); 1256 n2 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(b); 1257 assertTrue(Notification.areRemoteViewsChanged(n1, n2)); 1258 } 1259 1260 @Test testRemoteViews_layoutSame()1261 public void testRemoteViews_layoutSame() { 1262 RemoteViews a = mock(RemoteViews.class); 1263 when(a.getLayoutId()).thenReturn(234); 1264 RemoteViews b = mock(RemoteViews.class); 1265 when(b.getLayoutId()).thenReturn(234); 1266 1267 Notification.Builder n1 = new Notification.Builder(mContext, "test").setContent(a); 1268 Notification.Builder n2 = new Notification.Builder(mContext, "test").setContent(b); 1269 assertFalse(Notification.areRemoteViewsChanged(n1, n2)); 1270 1271 n1 = new Notification.Builder(mContext, "test").setCustomBigContentView(a); 1272 n2 = new Notification.Builder(mContext, "test").setCustomBigContentView(b); 1273 assertFalse(Notification.areRemoteViewsChanged(n1, n2)); 1274 1275 n1 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(a); 1276 n2 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(b); 1277 assertFalse(Notification.areRemoteViewsChanged(n1, n2)); 1278 } 1279 1280 @Test testRemoteViews_sequenceChange()1281 public void testRemoteViews_sequenceChange() { 1282 RemoteViews a = mock(RemoteViews.class); 1283 when(a.getLayoutId()).thenReturn(234); 1284 when(a.getSequenceNumber()).thenReturn(1); 1285 RemoteViews b = mock(RemoteViews.class); 1286 when(b.getLayoutId()).thenReturn(234); 1287 when(b.getSequenceNumber()).thenReturn(2); 1288 1289 Notification.Builder n1 = new Notification.Builder(mContext, "test").setContent(a); 1290 Notification.Builder n2 = new Notification.Builder(mContext, "test").setContent(b); 1291 assertTrue(Notification.areRemoteViewsChanged(n1, n2)); 1292 1293 n1 = new Notification.Builder(mContext, "test").setCustomBigContentView(a); 1294 n2 = new Notification.Builder(mContext, "test").setCustomBigContentView(b); 1295 assertTrue(Notification.areRemoteViewsChanged(n1, n2)); 1296 1297 n1 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(a); 1298 n2 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(b); 1299 assertTrue(Notification.areRemoteViewsChanged(n1, n2)); 1300 } 1301 1302 @Test testRemoteViews_sequenceSame()1303 public void testRemoteViews_sequenceSame() { 1304 RemoteViews a = mock(RemoteViews.class); 1305 when(a.getLayoutId()).thenReturn(234); 1306 when(a.getSequenceNumber()).thenReturn(1); 1307 RemoteViews b = mock(RemoteViews.class); 1308 when(b.getLayoutId()).thenReturn(234); 1309 when(b.getSequenceNumber()).thenReturn(1); 1310 1311 Notification.Builder n1 = new Notification.Builder(mContext, "test").setContent(a); 1312 Notification.Builder n2 = new Notification.Builder(mContext, "test").setContent(b); 1313 assertFalse(Notification.areRemoteViewsChanged(n1, n2)); 1314 1315 n1 = new Notification.Builder(mContext, "test").setCustomBigContentView(a); 1316 n2 = new Notification.Builder(mContext, "test").setCustomBigContentView(b); 1317 assertFalse(Notification.areRemoteViewsChanged(n1, n2)); 1318 1319 n1 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(a); 1320 n2 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(b); 1321 assertFalse(Notification.areRemoteViewsChanged(n1, n2)); 1322 } 1323 1324 @Test testActionsDifferent_null()1325 public void testActionsDifferent_null() { 1326 Notification n1 = new Notification.Builder(mContext, "test") 1327 .build(); 1328 Notification n2 = new Notification.Builder(mContext, "test") 1329 .build(); 1330 1331 assertFalse(Notification.areActionsVisiblyDifferent(n1, n2)); 1332 } 1333 1334 @Test testActionsDifferentSame()1335 public void testActionsDifferentSame() { 1336 PendingIntent intent = PendingIntent.getActivity( 1337 mContext, 0, new Intent("test1"), PendingIntent.FLAG_IMMUTABLE);; 1338 Icon icon = Icon.createWithBitmap(Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888)); 1339 1340 Notification n1 = new Notification.Builder(mContext, "test") 1341 .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent).build()) 1342 .build(); 1343 Notification n2 = new Notification.Builder(mContext, "test") 1344 .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent).build()) 1345 .build(); 1346 1347 assertFalse(Notification.areActionsVisiblyDifferent(n1, n2)); 1348 } 1349 1350 @Test testActionsDifferentText()1351 public void testActionsDifferentText() { 1352 PendingIntent intent = PendingIntent.getActivity( 1353 mContext, 0, new Intent("test1"), PendingIntent.FLAG_IMMUTABLE);; 1354 Icon icon = Icon.createWithBitmap(Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888)); 1355 1356 Notification n1 = new Notification.Builder(mContext, "test") 1357 .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent).build()) 1358 .build(); 1359 Notification n2 = new Notification.Builder(mContext, "test") 1360 .addAction(new Notification.Action.Builder(icon, "TEXT 2", intent).build()) 1361 .build(); 1362 1363 assertTrue(Notification.areActionsVisiblyDifferent(n1, n2)); 1364 } 1365 1366 @Test testActionsDifferentSpannables()1367 public void testActionsDifferentSpannables() { 1368 PendingIntent intent = PendingIntent.getActivity( 1369 mContext, 0, new Intent("test1"), PendingIntent.FLAG_IMMUTABLE);; 1370 Icon icon = Icon.createWithBitmap(Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888)); 1371 1372 Notification n1 = new Notification.Builder(mContext, "test") 1373 .addAction(new Notification.Action.Builder(icon, 1374 new SpannableStringBuilder().append("test1", 1375 new StyleSpan(Typeface.BOLD), 1376 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE), 1377 intent).build()) 1378 .build(); 1379 Notification n2 = new Notification.Builder(mContext, "test") 1380 .addAction(new Notification.Action.Builder(icon, "test1", intent).build()) 1381 .build(); 1382 1383 assertFalse(Notification.areActionsVisiblyDifferent(n1, n2)); 1384 } 1385 1386 @Test testActionsDifferentNumber()1387 public void testActionsDifferentNumber() { 1388 PendingIntent intent = PendingIntent.getActivity( 1389 mContext, 0, new Intent("test1"), PendingIntent.FLAG_IMMUTABLE); 1390 Icon icon = Icon.createWithBitmap(Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888)); 1391 1392 Notification n1 = new Notification.Builder(mContext, "test") 1393 .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent).build()) 1394 .build(); 1395 Notification n2 = new Notification.Builder(mContext, "test") 1396 .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent).build()) 1397 .addAction(new Notification.Action.Builder(icon, "TEXT 2", intent).build()) 1398 .build(); 1399 1400 assertTrue(Notification.areActionsVisiblyDifferent(n1, n2)); 1401 } 1402 1403 @Test testActionsDifferentIntent()1404 public void testActionsDifferentIntent() { 1405 PendingIntent intent1 = PendingIntent.getActivity( 1406 mContext, 0, new Intent("test1"), PendingIntent.FLAG_IMMUTABLE); 1407 PendingIntent intent2 = PendingIntent.getActivity( 1408 mContext, 0, new Intent("test1"), PendingIntent.FLAG_IMMUTABLE); 1409 Icon icon = Icon.createWithBitmap(Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888)); 1410 1411 Notification n1 = new Notification.Builder(mContext, "test") 1412 .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent1).build()) 1413 .build(); 1414 Notification n2 = new Notification.Builder(mContext, "test") 1415 .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent2).build()) 1416 .build(); 1417 1418 assertFalse(Notification.areActionsVisiblyDifferent(n1, n2)); 1419 } 1420 1421 @Test testActionsIgnoresRemoteInputs()1422 public void testActionsIgnoresRemoteInputs() { 1423 PendingIntent intent = PendingIntent.getActivity( 1424 mContext, 0, new Intent("test1"), PendingIntent.FLAG_IMMUTABLE);; 1425 Icon icon = Icon.createWithBitmap(Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888)); 1426 1427 Notification n1 = new Notification.Builder(mContext, "test") 1428 .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent) 1429 .addRemoteInput(new RemoteInput.Builder("a") 1430 .setChoices(new CharSequence[] {"i", "m"}) 1431 .build()) 1432 .build()) 1433 .build(); 1434 Notification n2 = new Notification.Builder(mContext, "test") 1435 .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent) 1436 .addRemoteInput(new RemoteInput.Builder("a") 1437 .setChoices(new CharSequence[] {"t", "m"}) 1438 .build()) 1439 .build()) 1440 .build(); 1441 1442 assertFalse(Notification.areActionsVisiblyDifferent(n1, n2)); 1443 } 1444 1445 @Test testFreeformRemoteInputActionPair_noRemoteInput()1446 public void testFreeformRemoteInputActionPair_noRemoteInput() { 1447 PendingIntent intent = PendingIntent.getActivity( 1448 mContext, 0, new Intent("test1"), PendingIntent.FLAG_IMMUTABLE);; 1449 Icon icon = Icon.createWithBitmap(Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888)); 1450 Notification notification = new Notification.Builder(mContext, "test") 1451 .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent) 1452 .build()) 1453 .build(); 1454 Assert.assertNull(notification.findRemoteInputActionPair(false)); 1455 } 1456 1457 @Test testFreeformRemoteInputActionPair_hasRemoteInput()1458 public void testFreeformRemoteInputActionPair_hasRemoteInput() { 1459 PendingIntent intent = PendingIntent.getActivity( 1460 mContext, 0, new Intent("test1"), PendingIntent.FLAG_IMMUTABLE);; 1461 Icon icon = Icon.createWithBitmap(Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888)); 1462 1463 RemoteInput remoteInput = new RemoteInput.Builder("a").build(); 1464 1465 Notification.Action actionWithRemoteInput = 1466 new Notification.Action.Builder(icon, "TEXT 1", intent) 1467 .addRemoteInput(remoteInput) 1468 .addRemoteInput(remoteInput) 1469 .build(); 1470 1471 Notification.Action actionWithoutRemoteInput = 1472 new Notification.Action.Builder(icon, "TEXT 2", intent) 1473 .build(); 1474 1475 Notification notification = new Notification.Builder(mContext, "test") 1476 .addAction(actionWithoutRemoteInput) 1477 .addAction(actionWithRemoteInput) 1478 .build(); 1479 1480 Pair<RemoteInput, Notification.Action> remoteInputActionPair = 1481 notification.findRemoteInputActionPair(false); 1482 1483 assertNotNull(remoteInputActionPair); 1484 Assert.assertEquals(remoteInput, remoteInputActionPair.first); 1485 Assert.assertEquals(actionWithRemoteInput, remoteInputActionPair.second); 1486 } 1487 1488 @Test testFreeformRemoteInputActionPair_requestFreeform_noFreeformRemoteInput()1489 public void testFreeformRemoteInputActionPair_requestFreeform_noFreeformRemoteInput() { 1490 PendingIntent intent = PendingIntent.getActivity( 1491 mContext, 0, new Intent("test1"), PendingIntent.FLAG_IMMUTABLE);; 1492 Icon icon = Icon.createWithBitmap(Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888)); 1493 Notification notification = new Notification.Builder(mContext, "test") 1494 .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent) 1495 .addRemoteInput( 1496 new RemoteInput.Builder("a") 1497 .setAllowFreeFormInput(false).build()) 1498 .build()) 1499 .build(); 1500 Assert.assertNull(notification.findRemoteInputActionPair(true)); 1501 } 1502 1503 @Test testFreeformRemoteInputActionPair_requestFreeform_hasFreeformRemoteInput()1504 public void testFreeformRemoteInputActionPair_requestFreeform_hasFreeformRemoteInput() { 1505 PendingIntent intent = PendingIntent.getActivity( 1506 mContext, 0, new Intent("test1"), PendingIntent.FLAG_IMMUTABLE);; 1507 Icon icon = Icon.createWithBitmap(Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888)); 1508 1509 RemoteInput remoteInput = 1510 new RemoteInput.Builder("a").setAllowFreeFormInput(false).build(); 1511 RemoteInput freeformRemoteInput = 1512 new RemoteInput.Builder("b").setAllowFreeFormInput(true).build(); 1513 1514 Notification.Action actionWithFreeformRemoteInput = 1515 new Notification.Action.Builder(icon, "TEXT 1", intent) 1516 .addRemoteInput(remoteInput) 1517 .addRemoteInput(freeformRemoteInput) 1518 .build(); 1519 1520 Notification.Action actionWithoutFreeformRemoteInput = 1521 new Notification.Action.Builder(icon, "TEXT 2", intent) 1522 .addRemoteInput(remoteInput) 1523 .build(); 1524 1525 Notification notification = new Notification.Builder(mContext, "test") 1526 .addAction(actionWithoutFreeformRemoteInput) 1527 .addAction(actionWithFreeformRemoteInput) 1528 .build(); 1529 1530 Pair<RemoteInput, Notification.Action> remoteInputActionPair = 1531 notification.findRemoteInputActionPair(true); 1532 1533 assertNotNull(remoteInputActionPair); 1534 Assert.assertEquals(freeformRemoteInput, remoteInputActionPair.first); 1535 Assert.assertEquals(actionWithFreeformRemoteInput, remoteInputActionPair.second); 1536 } 1537 1538 // Ensures that extras in a Notification Builder can be updated. 1539 @Test testExtras_cachedExtrasOverwrittenByUserProvided()1540 public void testExtras_cachedExtrasOverwrittenByUserProvided() { 1541 // Sets the flag to new state. 1542 // TODO(b/169435530): remove this set value once resolved. 1543 SystemProperties.set("persist.sysui.notification.builder_extras_override", 1544 Boolean.toString(true)); 1545 Bundle extras = new Bundle(); 1546 extras.putCharSequence(EXTRA_TITLE, "test title"); 1547 extras.putCharSequence(EXTRA_SUMMARY_TEXT, "summary text"); 1548 1549 Notification.Builder builder = new Notification.Builder(mContext, "test id") 1550 .addExtras(extras); 1551 1552 Notification notification = builder.build(); 1553 assertThat(notification.extras.getCharSequence(EXTRA_TITLE).toString()).isEqualTo( 1554 "test title"); 1555 assertThat(notification.extras.getCharSequence(EXTRA_SUMMARY_TEXT).toString()).isEqualTo( 1556 "summary text"); 1557 1558 extras.putCharSequence(EXTRA_TITLE, "new title"); 1559 builder.addExtras(extras); 1560 notification = builder.build(); 1561 assertThat(notification.extras.getCharSequence(EXTRA_TITLE).toString()).isEqualTo( 1562 "new title"); 1563 assertThat(notification.extras.getCharSequence(EXTRA_SUMMARY_TEXT).toString()).isEqualTo( 1564 "summary text"); 1565 } 1566 1567 // Ensures that extras in a Notification Builder can be updated by an extender. 1568 @Test testExtras_cachedExtrasOverwrittenByExtender()1569 public void testExtras_cachedExtrasOverwrittenByExtender() { 1570 // Sets the flag to new state. 1571 // TODO(b/169435530): remove this set value once resolved. 1572 SystemProperties.set("persist.sysui.notification.builder_extras_override", 1573 Boolean.toString(true)); 1574 Notification.CarExtender extender = new Notification.CarExtender().setColor(1234); 1575 1576 Notification notification = new Notification.Builder(mContext, "test id") 1577 .extend(extender).build(); 1578 1579 extender.setColor(5678); 1580 1581 Notification.Builder.recoverBuilder(mContext, notification).extend(extender).build(); 1582 1583 Notification.CarExtender recoveredExtender = new Notification.CarExtender(notification); 1584 assertThat(recoveredExtender.getColor()).isEqualTo(5678); 1585 } 1586 1587 // Validates pre-flag flip behavior, that extras in a Notification Builder cannot be updated. 1588 // TODO(b/169435530): remove this test once resolved. 1589 @Test testExtras_cachedExtrasOverwrittenByUserProvidedOld()1590 public void testExtras_cachedExtrasOverwrittenByUserProvidedOld() { 1591 // Sets the flag to old state. 1592 SystemProperties.set("persist.sysui.notification.builder_extras_override", 1593 Boolean.toString(false)); 1594 1595 Bundle extras = new Bundle(); 1596 extras.putCharSequence(EXTRA_TITLE, "test title"); 1597 extras.putCharSequence(EXTRA_SUMMARY_TEXT, "summary text"); 1598 1599 Notification.Builder builder = new Notification.Builder(mContext, "test id") 1600 .addExtras(extras); 1601 1602 Notification notification = builder.build(); 1603 assertThat(notification.extras.getCharSequence(EXTRA_TITLE).toString()).isEqualTo( 1604 "test title"); 1605 assertThat(notification.extras.getCharSequence(EXTRA_SUMMARY_TEXT).toString()).isEqualTo( 1606 "summary text"); 1607 1608 extras.putCharSequence(EXTRA_TITLE, "new title"); 1609 builder.addExtras(extras); 1610 notification = builder.build(); 1611 assertThat(notification.extras.getCharSequence(EXTRA_TITLE).toString()).isEqualTo( 1612 "test title"); 1613 assertThat(notification.extras.getCharSequence(EXTRA_SUMMARY_TEXT).toString()).isEqualTo( 1614 "summary text"); 1615 } 1616 1617 // Validates pre-flag flip behavior, that extras in a Notification Builder cannot be updated 1618 // by an extender. 1619 // TODO(b/169435530): remove this test once resolved. 1620 @Test testExtras_cachedExtrasOverwrittenByExtenderOld()1621 public void testExtras_cachedExtrasOverwrittenByExtenderOld() { 1622 // Sets the flag to old state. 1623 SystemProperties.set("persist.sysui.notification.builder_extras_override", 1624 Boolean.toString(false)); 1625 1626 Notification.CarExtender extender = new Notification.CarExtender().setColor(1234); 1627 1628 Notification notification = new Notification.Builder(mContext, "test id") 1629 .extend(extender).build(); 1630 1631 extender.setColor(5678); 1632 1633 Notification.Builder.recoverBuilder(mContext, notification).extend(extender).build(); 1634 1635 Notification.CarExtender recoveredExtender = new Notification.CarExtender(notification); 1636 assertThat(recoveredExtender.getColor()).isEqualTo(1234); 1637 } 1638 assertValid(Notification.Colors c)1639 private void assertValid(Notification.Colors c) { 1640 // Assert that all colors are populated 1641 assertThat(c.getBackgroundColor()).isNotEqualTo(Notification.COLOR_INVALID); 1642 assertThat(c.getProtectionColor()).isNotEqualTo(Notification.COLOR_INVALID); 1643 assertThat(c.getPrimaryTextColor()).isNotEqualTo(Notification.COLOR_INVALID); 1644 assertThat(c.getSecondaryTextColor()).isNotEqualTo(Notification.COLOR_INVALID); 1645 assertThat(c.getPrimaryAccentColor()).isNotEqualTo(Notification.COLOR_INVALID); 1646 assertThat(c.getSecondaryAccentColor()).isNotEqualTo(Notification.COLOR_INVALID); 1647 assertThat(c.getTertiaryAccentColor()).isNotEqualTo(Notification.COLOR_INVALID); 1648 assertThat(c.getOnAccentTextColor()).isNotEqualTo(Notification.COLOR_INVALID); 1649 assertThat(c.getErrorColor()).isNotEqualTo(Notification.COLOR_INVALID); 1650 assertThat(c.getContrastColor()).isNotEqualTo(Notification.COLOR_INVALID); 1651 assertThat(c.getRippleAlpha()).isAtLeast(0x00); 1652 assertThat(c.getRippleAlpha()).isAtMost(0xff); 1653 1654 // Assert that various colors have sufficient contrast with the background 1655 assertContrastIsAtLeast(c.getPrimaryTextColor(), c.getBackgroundColor(), 4.5); 1656 assertContrastIsAtLeast(c.getSecondaryTextColor(), c.getBackgroundColor(), 4.5); 1657 assertContrastIsAtLeast(c.getPrimaryAccentColor(), c.getBackgroundColor(), 4.5); 1658 assertContrastIsAtLeast(c.getErrorColor(), c.getBackgroundColor(), 4.5); 1659 assertContrastIsAtLeast(c.getContrastColor(), c.getBackgroundColor(), 4.5); 1660 1661 // These colors are only used for emphasized buttons; they do not need contrast 1662 assertContrastIsAtLeast(c.getSecondaryAccentColor(), c.getBackgroundColor(), 1); 1663 assertContrastIsAtLeast(c.getTertiaryAccentColor(), c.getBackgroundColor(), 1); 1664 1665 // The text that is used within the accent color DOES need to have contrast 1666 assertContrastIsAtLeast(c.getOnAccentTextColor(), c.getTertiaryAccentColor(), 4.5); 1667 } 1668 resolveColorsInNightMode(boolean nightMode, Notification.Colors c, int rawColor, boolean colorized)1669 private void resolveColorsInNightMode(boolean nightMode, Notification.Colors c, int rawColor, 1670 boolean colorized) { 1671 runInNightMode(nightMode, 1672 () -> c.resolvePalette(mContext, rawColor, colorized, nightMode)); 1673 } 1674 runInNightMode(boolean nightMode, Runnable task)1675 private void runInNightMode(boolean nightMode, Runnable task) { 1676 final String initialNightMode = changeNightMode(nightMode); 1677 try { 1678 Configuration currentConfig = mContext.getResources().getConfiguration(); 1679 boolean isNightMode = (currentConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK) 1680 == Configuration.UI_MODE_NIGHT_YES; 1681 assertEquals(nightMode, isNightMode); 1682 task.run(); 1683 } finally { 1684 runShellCommand("cmd uimode night " + initialNightMode); 1685 } 1686 } 1687 1688 1689 // Change the night mode and return the previous mode changeNightMode(boolean nightMode)1690 private String changeNightMode(boolean nightMode) { 1691 final String nightModeText = runShellCommand("cmd uimode night"); 1692 final String[] nightModeSplit = nightModeText.split(":"); 1693 if (nightModeSplit.length != 2) { 1694 fail("Failed to get initial night mode value from " + nightModeText); 1695 } 1696 String previousMode = nightModeSplit[1].trim(); 1697 runShellCommand("cmd uimode night " + (nightMode ? "yes" : "no")); 1698 return previousMode; 1699 } 1700 1701 /** 1702 * Writes an arbitrary {@link Parcelable} into a {@link Parcel} using its writeToParcel 1703 * method before reading it out again to check that it was sent properly. 1704 */ writeAndReadParcelable(T original)1705 private static <T extends Parcelable> T writeAndReadParcelable(T original) { 1706 Parcel p = Parcel.obtain(); 1707 p.writeParcelable(original, /* flags */ 0); 1708 p.setDataPosition(0); 1709 return p.readParcelable(/* classLoader */ null); 1710 } 1711 1712 /** 1713 * Creates a Notification.Action by mocking initial dependencies and then applying 1714 * transformations if they're defined. 1715 */ makeNotificationAction( @ullable Consumer<Notification.Action.Builder> transformation)1716 private Notification.Action makeNotificationAction( 1717 @Nullable Consumer<Notification.Action.Builder> transformation) { 1718 Notification.Action.Builder actionBuilder = 1719 new Notification.Action.Builder(null, "Test Title", null); 1720 if (transformation != null) { 1721 transformation.accept(actionBuilder); 1722 } 1723 return actionBuilder.build(); 1724 } 1725 1726 /** 1727 * Creates a PendingIntent with the given action. 1728 */ createPendingIntent(String action)1729 private PendingIntent createPendingIntent(String action) { 1730 return PendingIntent.getActivity(mContext, 0, 1731 new Intent(action).setPackage(mContext.getPackageName()), 1732 PendingIntent.FLAG_MUTABLE); 1733 } 1734 } 1735