• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.DEFAULT_SOUND;
23 import static android.app.Notification.DEFAULT_VIBRATE;
24 import static android.app.Notification.EXTRA_ANSWER_INTENT;
25 import static android.app.Notification.EXTRA_BUILDER_APPLICATION_INFO;
26 import static android.app.Notification.EXTRA_CALL_PERSON;
27 import static android.app.Notification.EXTRA_CONVERSATION_ICON;
28 import static android.app.Notification.EXTRA_DECLINE_INTENT;
29 import static android.app.Notification.EXTRA_HANG_UP_INTENT;
30 import static android.app.Notification.EXTRA_LARGE_ICON;
31 import static android.app.Notification.EXTRA_LARGE_ICON_BIG;
32 import static android.app.Notification.EXTRA_MEDIA_REMOTE_INTENT;
33 import static android.app.Notification.EXTRA_MEDIA_SESSION;
34 import static android.app.Notification.EXTRA_MESSAGING_PERSON;
35 import static android.app.Notification.EXTRA_PEOPLE_LIST;
36 import static android.app.Notification.EXTRA_PICTURE;
37 import static android.app.Notification.EXTRA_PICTURE_ICON;
38 import static android.app.Notification.EXTRA_SUMMARY_TEXT;
39 import static android.app.Notification.EXTRA_TITLE;
40 import static android.app.Notification.FLAG_CAN_COLORIZE;
41 import static android.app.Notification.GROUP_ALERT_CHILDREN;
42 import static android.app.Notification.GROUP_ALERT_SUMMARY;
43 import static android.app.Notification.GROUP_KEY_SILENT;
44 import static android.app.Notification.MessagingStyle.Message.KEY_DATA_URI;
45 import static android.app.Notification.MessagingStyle.Message.KEY_SENDER_PERSON;
46 import static android.app.Notification.MessagingStyle.Message.KEY_TEXT;
47 import static android.app.Notification.MessagingStyle.Message.KEY_TIMESTAMP;
48 import static android.app.Notification.TvExtender.EXTRA_CONTENT_INTENT;
49 import static android.app.Notification.TvExtender.EXTRA_DELETE_INTENT;
50 import static android.app.Notification.WearableExtender.KEY_BACKGROUND;
51 import static android.app.Notification.WearableExtender.KEY_DISPLAY_INTENT;
52 
53 import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
54 import static com.android.internal.util.ContrastColorUtilTest.assertContrastIsAtLeast;
55 import static com.android.internal.util.ContrastColorUtilTest.assertContrastIsWithinRange;
56 
57 import static com.google.common.truth.Truth.assertThat;
58 
59 import static junit.framework.Assert.assertNotNull;
60 import static junit.framework.Assert.fail;
61 
62 import static org.junit.Assert.assertEquals;
63 import static org.junit.Assert.assertFalse;
64 import static org.junit.Assert.assertNotSame;
65 import static org.junit.Assert.assertNull;
66 import static org.junit.Assert.assertSame;
67 import static org.junit.Assert.assertTrue;
68 import static org.mockito.Mockito.mock;
69 import static org.mockito.Mockito.spy;
70 import static org.mockito.Mockito.when;
71 
72 import android.annotation.Nullable;
73 import android.compat.testing.PlatformCompatChangeRule;
74 import android.content.Context;
75 import android.content.Intent;
76 import android.content.LocusId;
77 import android.content.res.Configuration;
78 import android.graphics.Bitmap;
79 import android.graphics.BitmapFactory;
80 import android.graphics.Color;
81 import android.graphics.Typeface;
82 import android.graphics.drawable.Icon;
83 import android.net.Uri;
84 import android.os.Build;
85 import android.os.Bundle;
86 import android.os.Parcel;
87 import android.os.Parcelable;
88 import android.platform.test.annotations.DisableFlags;
89 import android.platform.test.annotations.EnableFlags;
90 import android.platform.test.annotations.Presubmit;
91 import android.platform.test.flag.junit.SetFlagsRule;
92 import android.text.Spannable;
93 import android.text.SpannableString;
94 import android.text.SpannableStringBuilder;
95 import android.text.Spanned;
96 import android.text.style.ForegroundColorSpan;
97 import android.text.style.StyleSpan;
98 import android.text.style.TextAppearanceSpan;
99 import android.util.Pair;
100 import android.widget.RemoteViews;
101 
102 import androidx.test.InstrumentationRegistry;
103 import androidx.test.ext.junit.runners.AndroidJUnit4;
104 import androidx.test.filters.SmallTest;
105 
106 import com.android.internal.R;
107 import com.android.internal.util.ContrastColorUtil;
108 import com.android.internal.widget.NotificationProgressModel;
109 
110 import junit.framework.Assert;
111 
112 import libcore.junit.util.compat.CoreCompatChangeRule;
113 
114 import org.junit.Before;
115 import org.junit.Ignore;
116 import org.junit.Rule;
117 import org.junit.Test;
118 import org.junit.rules.TestRule;
119 import org.junit.runner.RunWith;
120 
121 import java.util.Collections;
122 import java.util.List;
123 import java.util.function.Consumer;
124 
125 @RunWith(AndroidJUnit4.class)
126 @SmallTest
127 @Presubmit
128 public class NotificationTest {
129 
130     private Context mContext;
131 
132     private RemoteViews mRemoteViews;
133 
134     @Rule
135     public TestRule compatChangeRule = new PlatformCompatChangeRule();
136     @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
137 
138     @Before
setUp()139     public void setUp() {
140         mContext = InstrumentationRegistry.getContext();
141         mRemoteViews = new RemoteViews(
142                 mContext.getPackageName(), R.layout.notification_template_header);
143     }
144 
145     @Test
testColorizedByPermission()146     public void testColorizedByPermission() {
147         Notification n = new Notification.Builder(mContext, "test")
148                 .setFlag(FLAG_CAN_COLORIZE, true)
149                 .setColorized(true).setColor(Color.WHITE)
150                 .build();
151         assertTrue(n.isColorized());
152 
153         n = new Notification.Builder(mContext, "test")
154                 .setFlag(FLAG_CAN_COLORIZE, true)
155                 .build();
156         assertFalse(n.isColorized());
157 
158         n = new Notification.Builder(mContext, "test")
159                 .setFlag(FLAG_CAN_COLORIZE, false)
160                 .setColorized(true).setColor(Color.WHITE)
161                 .build();
162         assertFalse(n.isColorized());
163     }
164 
165     @Test
testColorizedByForeground()166     public void testColorizedByForeground() {
167         Notification n = new Notification.Builder(mContext, "test")
168                 .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
169                 .setColorized(true).setColor(Color.WHITE)
170                 .build();
171         assertTrue(n.isColorized());
172 
173         n = new Notification.Builder(mContext, "test")
174                 .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
175                 .build();
176         assertFalse(n.isColorized());
177 
178         n = new Notification.Builder(mContext, "test")
179                 .setFlag(Notification.FLAG_FOREGROUND_SERVICE, false)
180                 .setColorized(true).setColor(Color.WHITE)
181                 .build();
182         assertFalse(n.isColorized());
183     }
184 
185     @Test
testHasCompletedProgress_noProgress()186     public void testHasCompletedProgress_noProgress() {
187         Notification n = new Notification.Builder(mContext).build();
188 
189         assertFalse(n.hasCompletedProgress());
190     }
191 
192     @Test
testHasCompletedProgress_complete()193     public void testHasCompletedProgress_complete() {
194         Notification n = new Notification.Builder(mContext)
195                 .setProgress(100, 100, true)
196                 .build();
197         Notification n2 = new Notification.Builder(mContext)
198                 .setProgress(10, 10, false)
199                 .build();
200         assertTrue(n.hasCompletedProgress());
201         assertTrue(n2.hasCompletedProgress());
202     }
203 
204     @Test
testHasCompletedProgress_notComplete()205     public void testHasCompletedProgress_notComplete() {
206         Notification n = new Notification.Builder(mContext)
207                 .setProgress(100, 99, true)
208                 .build();
209         Notification n2 = new Notification.Builder(mContext)
210                 .setProgress(10, 4, false)
211                 .build();
212         assertFalse(n.hasCompletedProgress());
213         assertFalse(n2.hasCompletedProgress());
214     }
215 
216     @Test
testHasCompletedProgress_zeroMax()217     public void testHasCompletedProgress_zeroMax() {
218         Notification n = new Notification.Builder(mContext)
219                 .setProgress(0, 0, true)
220                 .build();
221         assertFalse(n.hasCompletedProgress());
222     }
223 
224     @Test
225     @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
testHasTitle_noStyle()226     public void testHasTitle_noStyle() {
227         Notification n = new Notification.Builder(mContext, "test")
228                 .setContentTitle("TITLE")
229                 .build();
230         assertThat(n.hasTitle()).isTrue();
231     }
232 
233     @Test
234     @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
testHasTitle_bigText()235     public void testHasTitle_bigText() {
236         Notification n = new Notification.Builder(mContext, "test")
237                 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
238                 .build();
239         assertThat(n.hasTitle()).isTrue();
240     }
241 
242     @Test
243     @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
testHasTitle_noTitle()244     public void testHasTitle_noTitle() {
245         Notification n = new Notification.Builder(mContext, "test")
246                 .setContentText("text not title")
247                 .build();
248         assertThat(n.hasTitle()).isFalse();
249     }
250 
251     @Test
252     @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
testContainsCustomViews_none()253     public void testContainsCustomViews_none() {
254         Notification np = new Notification.Builder(mContext, "test")
255                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
256                 .setContentText("test")
257                 .build();
258         Notification n = new Notification.Builder(mContext, "test")
259                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
260                 .setContentText("test")
261                 .setPublicVersion(np)
262                 .build();
263         assertThat(n.containsCustomViews()).isFalse();
264     }
265 
266     @Test
267     @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
testContainsCustomViews_content()268     public void testContainsCustomViews_content() {
269         Notification np = new Notification.Builder(mContext, "test")
270                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
271                 .setContentText("test")
272                 .build();
273         Notification n = new Notification.Builder(mContext, "test")
274                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
275                 .setContentText("test")
276                 .setCustomContentView(mRemoteViews)
277                 .setPublicVersion(np)
278                 .build();
279         assertThat(n.containsCustomViews()).isTrue();
280     }
281 
282     @Test
283     @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
testContainsCustomViews_big()284     public void testContainsCustomViews_big() {
285         Notification np = new Notification.Builder(mContext, "test")
286                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
287                 .setContentText("test")
288                 .build();
289         Notification n = new Notification.Builder(mContext, "test")
290                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
291                 .setContentText("test")
292                 .setCustomBigContentView(mRemoteViews)
293                 .setPublicVersion(np)
294                 .build();
295         assertThat(n.containsCustomViews()).isTrue();
296     }
297 
298     @Test
299     @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
testContainsCustomViews_headsUp()300     public void testContainsCustomViews_headsUp() {
301         Notification np = new Notification.Builder(mContext, "test")
302                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
303                 .setContentText("test")
304                 .build();
305         Notification n = new Notification.Builder(mContext, "test")
306                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
307                 .setContentText("test")
308                 .setCustomHeadsUpContentView(mRemoteViews)
309                 .setPublicVersion(np)
310                 .build();
311         assertThat(n.containsCustomViews()).isTrue();
312     }
313 
314     @Test
315     @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
testContainsCustomViews_content_public()316     public void testContainsCustomViews_content_public() {
317         Notification np = new Notification.Builder(mContext, "test")
318                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
319                 .setContentText("public")
320                 .setCustomContentView(mRemoteViews)
321                 .build();
322         Notification n = new Notification.Builder(mContext, "test")
323                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
324                 .setContentText("test")
325                 .setPublicVersion(np)
326                 .build();
327         assertThat(n.containsCustomViews()).isTrue();
328     }
329 
330     @Test
331     @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
testContainsCustomViews_big_public()332     public void testContainsCustomViews_big_public() {
333         Notification np = new Notification.Builder(mContext, "test")
334                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
335                 .setContentText("test")
336                 .setCustomBigContentView(mRemoteViews)
337                 .build();
338         Notification n = new Notification.Builder(mContext, "test")
339                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
340                 .setContentText("test")
341                 .setPublicVersion(np)
342                 .build();
343         assertThat(n.containsCustomViews()).isTrue();
344     }
345 
346     @Test
347     @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
testContainsCustomViews_headsUp_public()348     public void testContainsCustomViews_headsUp_public() {
349         Notification np = new Notification.Builder(mContext, "test")
350                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
351                 .setContentText("test")
352                 .setCustomHeadsUpContentView(mRemoteViews)
353                 .build();
354         Notification n = new Notification.Builder(mContext, "test")
355                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
356                 .setContentText("test")
357                 .setPublicVersion(np)
358                 .build();
359         assertThat(n.containsCustomViews()).isTrue();
360     }
361 
362     @Test
363     @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
testHasPromotableStyle_noStyle()364     public void testHasPromotableStyle_noStyle() {
365         Notification n = new Notification.Builder(mContext, "test")
366                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
367                 .setContentText("test")
368                 .build();
369         assertThat(n.hasPromotableStyle()).isTrue();
370     }
371 
372     @Test
373     @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
testHasPromotableStyle_bigText()374     public void testHasPromotableStyle_bigText() {
375         Notification n = new Notification.Builder(mContext, "test")
376                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
377                 .setStyle(new Notification.BigTextStyle())
378                 .build();
379         assertThat(n.hasPromotableStyle()).isTrue();
380     }
381 
382     @Test
383     @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
testHasPromotableStyle_no_bigPictureStyle()384     public void testHasPromotableStyle_no_bigPictureStyle() {
385         Notification n = new Notification.Builder(mContext, "test")
386                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
387                 .setStyle(new Notification.BigPictureStyle())
388                 .build();
389         assertThat(n.hasPromotableStyle()).isFalse();
390     }
391 
392     @Test
393     @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
testHasPromotableStyle_no_messagingStyle()394     public void testHasPromotableStyle_no_messagingStyle() {
395         Notification.MessagingStyle style = new Notification.MessagingStyle("self name")
396                 .setGroupConversation(true)
397                 .setConversationTitle("test conversation title");
398         Notification n = new Notification.Builder(mContext, "test")
399                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
400                 .setStyle(style)
401                 .build();
402         assertThat(n.hasPromotableStyle()).isFalse();
403     }
404 
405     @Test
406     @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
testHasPromotableStyle_no_mediaStyle()407     public void testHasPromotableStyle_no_mediaStyle() {
408         Notification n = new Notification.Builder(mContext, "test")
409                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
410                 .setStyle(new Notification.MediaStyle())
411                 .build();
412         assertThat(n.hasPromotableStyle()).isFalse();
413     }
414 
415     @Test
416     @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
testHasPromotableStyle_no_inboxStyle()417     public void testHasPromotableStyle_no_inboxStyle() {
418         Notification n = new Notification.Builder(mContext, "test")
419                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
420                 .setStyle(new Notification.InboxStyle())
421                 .build();
422         assertThat(n.hasPromotableStyle()).isFalse();
423     }
424 
425     @Test
426     @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
testHasPromotableStyle_callText()427     public void testHasPromotableStyle_callText() {
428         PendingIntent answerIntent = createPendingIntent("answer");
429         PendingIntent declineIntent = createPendingIntent("decline");
430         Notification.CallStyle style = Notification.CallStyle.forIncomingCall(
431                 new Person.Builder().setName("A Caller").build(),
432                 declineIntent,
433                 answerIntent
434         );
435         Notification n = new Notification.Builder(mContext, "test")
436                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
437                 .setStyle(style)
438                 .build();
439         assertThat(n.hasPromotableStyle()).isTrue();
440     }
441 
442     @Test
443     @EnableFlags({Flags.FLAG_UI_RICH_ONGOING, Flags.FLAG_API_RICH_ONGOING})
testHasPromotableStyle_progress()444     public void testHasPromotableStyle_progress() {
445         Notification n = new Notification.Builder(mContext, "test")
446                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
447                 .setStyle(new Notification.ProgressStyle())
448                 .build();
449         assertThat(n.hasPromotableStyle()).isTrue();
450     }
451 
452     @Test
453     @EnableFlags({Flags.FLAG_UI_RICH_ONGOING})
testHasPromotableStyle_unknownStyle()454     public void testHasPromotableStyle_unknownStyle() {
455         Notification n = new Notification.Builder(mContext, "test")
456                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
457                 .setStyle(new NotAPlatformStyle())
458                 .build();
459 
460         assertThat(n.hasPromotableStyle()).isTrue();
461     }
462 
463     @Test
464     @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
testHasPromotableCharacteristics_bigText_bigTitle()465     public void testHasPromotableCharacteristics_bigText_bigTitle() {
466         Notification n = new Notification.Builder(mContext, "test")
467                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
468                 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
469                 .setColor(Color.WHITE)
470                 .setColorized(true)
471                 .setOngoing(true)
472                 .build();
473         assertThat(n.hasPromotableCharacteristics()).isTrue();
474     }
475 
476     @Test
477     @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
testHasPromotableCharacteristics_bigText_normalTitle()478     public void testHasPromotableCharacteristics_bigText_normalTitle() {
479         Notification n = new Notification.Builder(mContext, "test")
480                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
481                 .setStyle(new Notification.BigTextStyle())
482                 .setContentTitle("TITLE")
483                 .setColor(Color.WHITE)
484                 .setColorized(true)
485                 .setOngoing(true)
486                 .build();
487         assertThat(n.hasPromotableCharacteristics()).isTrue();
488     }
489 
490     @Test
491     @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
testHasPromotableCharacteristics_notOngoing()492     public void testHasPromotableCharacteristics_notOngoing() {
493         Notification n = new Notification.Builder(mContext, "test")
494                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
495                 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
496                 .setColor(Color.WHITE)
497                 .setColorized(true)
498                 .build();
499         assertThat(n.hasPromotableCharacteristics()).isFalse();
500     }
501 
502     @Test
503     @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
testHasPromotableCharacteristics_wrongStyle()504     public void testHasPromotableCharacteristics_wrongStyle() {
505         Notification n = new Notification.Builder(mContext, "test")
506                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
507                 .setStyle(new Notification.InboxStyle())
508                 .setContentTitle("TITLE")
509                 .setColor(Color.WHITE)
510                 .setColorized(true)
511                 .setOngoing(true)
512                 .build();
513         assertThat(n.hasPromotableCharacteristics()).isFalse();
514     }
515 
516     @Test
517     @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
testHasPromotableCharacteristics_notColorized()518     public void testHasPromotableCharacteristics_notColorized() {
519         Notification n = new Notification.Builder(mContext, "test")
520                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
521                 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
522                 .setColor(Color.WHITE)
523                 .setOngoing(true)
524                 .build();
525         assertThat(n.hasPromotableCharacteristics()).isFalse();
526     }
527 
528     @Test
529     @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
testHasPromotableCharacteristics_noTitle()530     public void testHasPromotableCharacteristics_noTitle() {
531         Notification n = new Notification.Builder(mContext, "test")
532                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
533                 .setStyle(new Notification.BigTextStyle())
534                 .setColor(Color.WHITE)
535                 .setColorized(true)
536                 .setOngoing(true)
537                 .build();
538         assertThat(n.hasPromotableCharacteristics()).isFalse();
539     }
540 
541     @Test
542     @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
testHasPromotableCharacteristics_noStyle_onlyBigTitle()543     public void testHasPromotableCharacteristics_noStyle_onlyBigTitle() {
544         Bundle extras = new Bundle();
545         extras.putString(Notification.EXTRA_TITLE_BIG, "BIG");
546         Notification n = new Notification.Builder(mContext, "test")
547                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
548                 .setColor(Color.WHITE)
549                 .setColorized(true)
550                 .setOngoing(true)
551                 .addExtras(extras)
552                 .build();
553         assertThat(n.hasPromotableCharacteristics()).isFalse();
554     }
555 
556     @Test
557     @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
testHasPromotableCharacteristics_ongoingCallStyle_notColorized()558     public void testHasPromotableCharacteristics_ongoingCallStyle_notColorized() {
559         PendingIntent intent = PendingIntent.getActivity(
560                 mContext, 0, new Intent("test1"), PendingIntent.FLAG_IMMUTABLE);
561         Person person = new Person.Builder().setName("Caller").build();
562         Notification n = new Notification.Builder(mContext, "test")
563                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
564                 .setStyle(Notification.CallStyle.forOngoingCall(person, intent))
565                 .setColor(Color.WHITE)
566                 .setOngoing(true)
567                 .build();
568         assertThat(n.hasPromotableCharacteristics()).isTrue();
569     }
570 
571     @Test
572     @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
testHasPromotableCharacteristics_incomingCallStyle_notColorized()573     public void testHasPromotableCharacteristics_incomingCallStyle_notColorized() {
574         PendingIntent intent = PendingIntent.getActivity(
575                 mContext, 0, new Intent("test1"), PendingIntent.FLAG_IMMUTABLE);
576         Person person = new Person.Builder().setName("Caller").build();
577         Notification n = new Notification.Builder(mContext, "test")
578                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
579                 .setStyle(Notification.CallStyle.forIncomingCall(person, intent, intent))
580                 .setColor(Color.WHITE)
581                 .setOngoing(true)
582                 .build();
583         assertThat(n.hasPromotableCharacteristics()).isFalse();
584     }
585 
586     @Test
587     @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
testHasPromotableCharacteristics_groupSummary()588     public void testHasPromotableCharacteristics_groupSummary() {
589         Notification n = new Notification.Builder(mContext, "test")
590                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
591                 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
592                 .setColor(Color.WHITE)
593                 .setColorized(true)
594                 .setOngoing(true)
595                 .setGroup("someGroup")
596                 .setGroupSummary(true)
597                 .build();
598         assertThat(n.hasPromotableCharacteristics()).isFalse();
599     }
600 
601     @Test
602     @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
testGetShortCriticalText_noneSet()603     public void testGetShortCriticalText_noneSet() {
604         Notification n = new Notification.Builder(mContext, "test")
605                 .build();
606 
607         assertSame(n.getShortCriticalText(), null);
608     }
609 
610     @Test
611     @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
testGetShortCriticalText_isSet()612     public void testGetShortCriticalText_isSet() {
613         Notification n = new Notification.Builder(mContext, "test")
614                 .setShortCriticalText("short critical text here")
615                 .build();
616 
617         assertSame(n.getShortCriticalText(), "short critical text here");
618     }
619 
620     @Test
largeIconMultipleReferences_keptAfterParcelling()621     public void largeIconMultipleReferences_keptAfterParcelling() {
622         Icon originalIcon = Icon.createWithBitmap(BitmapFactory.decodeResource(
623                 mContext.getResources(), com.android.frameworks.coretests.R.drawable.test128x96));
624 
625         Notification n = new Notification.Builder(mContext).setLargeIcon(originalIcon).build();
626         assertSame(n.getLargeIcon(), originalIcon);
627 
628         Notification q = writeAndReadParcelable(n);
629         assertNotSame(q.getLargeIcon(), n.getLargeIcon());
630 
631         assertTrue(q.getLargeIcon().getBitmap().sameAs(n.getLargeIcon().getBitmap()));
632         assertSame(q.getLargeIcon(), q.extras.getParcelable(EXTRA_LARGE_ICON));
633     }
634 
635     @Test
largeIconReferenceInExtrasOnly_keptAfterParcelling()636     public void largeIconReferenceInExtrasOnly_keptAfterParcelling() {
637         Icon originalIcon = Icon.createWithBitmap(BitmapFactory.decodeResource(
638                 mContext.getResources(), com.android.frameworks.coretests.R.drawable.test128x96));
639 
640         Notification n = new Notification.Builder(mContext).build();
641         n.extras.putParcelable(EXTRA_LARGE_ICON, originalIcon);
642         assertSame(n.getLargeIcon(), null);
643 
644         Notification q = writeAndReadParcelable(n);
645         assertSame(q.getLargeIcon(), null);
646         assertTrue(((Icon) q.extras.getParcelable(EXTRA_LARGE_ICON)).getBitmap()
647                 .sameAs(originalIcon.getBitmap()));
648     }
649 
650     @Test
allPendingIntents_recollectedAfterReusingBuilder()651     public void allPendingIntents_recollectedAfterReusingBuilder() {
652         PendingIntent intent1 = PendingIntent.getActivity(
653                 mContext, 0, new Intent("test1"), PendingIntent.FLAG_IMMUTABLE);
654         PendingIntent intent2 = PendingIntent.getActivity(
655                 mContext, 0, new Intent("test2"), PendingIntent.FLAG_IMMUTABLE);
656 
657         Notification.Builder builder = new Notification.Builder(mContext, "channel");
658         builder.setContentIntent(intent1);
659 
660         Parcel p = Parcel.obtain();
661 
662         Notification n1 = builder.build();
663         n1.writeToParcel(p, 0);
664 
665         builder.setContentIntent(intent2);
666         Notification n2 = builder.build();
667         n2.writeToParcel(p, 0);
668 
669         assertTrue(n2.allPendingIntents.contains(intent2));
670     }
671 
672     @Test
allPendingIntents_containsCustomRemoteViews()673     public void allPendingIntents_containsCustomRemoteViews() {
674         PendingIntent intent = PendingIntent.getActivity(mContext, 0,
675                 new Intent("test").setPackage(mContext.getPackageName()),
676                 PendingIntent.FLAG_MUTABLE);
677 
678         RemoteViews contentView = new RemoteViews(mContext.getPackageName(), 0 /* layoutId */);
679         contentView.setOnClickPendingIntent(1 /* id */, intent);
680 
681         Notification.Builder builder = new Notification.Builder(mContext, "channel");
682         builder.setCustomContentView(contentView);
683 
684         Parcel p = Parcel.obtain();
685 
686         Notification n = builder.build();
687         n.writeToParcel(p, 0);
688 
689         assertTrue(n.allPendingIntents.contains(intent));
690     }
691 
692     @Test
allPendingIntents_resilientToAnotherNotificationInExtras()693     public void allPendingIntents_resilientToAnotherNotificationInExtras() {
694         PendingIntent contentIntent = createPendingIntent("content");
695         PendingIntent actionIntent = createPendingIntent("action");
696         Notification another = new Notification.Builder(mContext, "channel").build();
697         Bundle bundleContainingAnotherNotification = new Bundle();
698         bundleContainingAnotherNotification.putParcelable(null, another);
699         Notification source = new Notification.Builder(mContext, "channel")
700                 .setContentIntent(contentIntent)
701                 .addAction(new Notification.Action.Builder(null, "action", actionIntent).build())
702                 .setExtras(bundleContainingAnotherNotification)
703                 .build();
704 
705         Parcel p = Parcel.obtain();
706         source.writeToParcel(p, 0);
707         p.setDataPosition(0);
708         Notification unparceled = new Notification(p);
709 
710         assertThat(unparceled.allPendingIntents).containsExactly(contentIntent, actionIntent);
711     }
712 
713     @Test
allPendingIntents_alsoInPublicVersion()714     public void allPendingIntents_alsoInPublicVersion() {
715         PendingIntent contentIntent = createPendingIntent("content");
716         PendingIntent actionIntent = createPendingIntent("action");
717         PendingIntent publicContentIntent = createPendingIntent("publicContent");
718         PendingIntent publicActionIntent = createPendingIntent("publicAction");
719         Notification source = new Notification.Builder(mContext, "channel")
720                 .setContentIntent(contentIntent)
721                 .addAction(new Notification.Action.Builder(null, "action", actionIntent).build())
722                 .setPublicVersion(new Notification.Builder(mContext, "channel")
723                         .setContentIntent(publicContentIntent)
724                         .addAction(new Notification.Action.Builder(
725                                 null, "publicAction", publicActionIntent).build())
726                         .build())
727                 .build();
728 
729         Parcel p = Parcel.obtain();
730         source.writeToParcel(p, 0);
731         p.setDataPosition(0);
732         Notification unparceled = new Notification(p);
733 
734         assertThat(unparceled.allPendingIntents).containsExactly(contentIntent, actionIntent,
735                 publicContentIntent, publicActionIntent);
736         assertThat(unparceled.publicVersion.allPendingIntents).containsExactly(publicContentIntent,
737                 publicActionIntent);
738     }
739 
740     @Test
messagingStyle_isGroupConversation()741     public void messagingStyle_isGroupConversation() {
742         mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.P;
743         Notification.MessagingStyle messagingStyle = new Notification.MessagingStyle("self name")
744                 .setGroupConversation(true)
745                 .setConversationTitle("test conversation title");
746         Notification notification = new Notification.Builder(mContext, "test id")
747                 .setSmallIcon(1)
748                 .setContentTitle("test title")
749                 .setStyle(messagingStyle)
750                 .build();
751 
752         assertTrue(messagingStyle.isGroupConversation());
753         assertTrue(notification.extras.getBoolean(Notification.EXTRA_IS_GROUP_CONVERSATION));
754     }
755 
756     @Test
messagingStyle_isGroupConversation_noConversationTitle()757     public void messagingStyle_isGroupConversation_noConversationTitle() {
758         mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.P;
759         Notification.MessagingStyle messagingStyle = new Notification.MessagingStyle("self name")
760                 .setGroupConversation(true)
761                 .setConversationTitle(null);
762         Notification notification = new Notification.Builder(mContext, "test id")
763                 .setSmallIcon(1)
764                 .setContentTitle("test title")
765                 .setStyle(messagingStyle)
766                 .build();
767 
768         assertTrue(messagingStyle.isGroupConversation());
769         assertTrue(notification.extras.getBoolean(Notification.EXTRA_IS_GROUP_CONVERSATION));
770     }
771 
772     @Test
messagingStyle_isGroupConversation_withConversationTitle_legacy()773     public void messagingStyle_isGroupConversation_withConversationTitle_legacy() {
774         // In legacy (version < P), isGroupConversation is controlled by conversationTitle.
775         mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.O;
776         Notification.MessagingStyle messagingStyle = new Notification.MessagingStyle("self name")
777                 .setGroupConversation(false)
778                 .setConversationTitle("test conversation title");
779         Notification notification = new Notification.Builder(mContext, "test id")
780                 .setSmallIcon(1)
781                 .setContentTitle("test title")
782                 .setStyle(messagingStyle)
783                 .build();
784 
785         assertTrue(messagingStyle.isGroupConversation());
786         assertFalse(notification.extras.getBoolean(Notification.EXTRA_IS_GROUP_CONVERSATION));
787     }
788 
789     @Test
messagingStyle_isGroupConversation_withoutConversationTitle_legacy()790     public void messagingStyle_isGroupConversation_withoutConversationTitle_legacy() {
791         // In legacy (version < P), isGroupConversation is controlled by conversationTitle.
792         mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.O;
793         Notification.MessagingStyle messagingStyle = new Notification.MessagingStyle("self name")
794                 .setGroupConversation(true)
795                 .setConversationTitle(null);
796         Notification notification = new Notification.Builder(mContext, "test id")
797                 .setSmallIcon(1)
798                 .setContentTitle("test title")
799                 .setStyle(messagingStyle)
800                 .build();
801 
802         assertFalse(messagingStyle.isGroupConversation());
803         assertTrue(notification.extras.getBoolean(Notification.EXTRA_IS_GROUP_CONVERSATION));
804     }
805 
806     @Test
action_builder_hasDefault()807     public void action_builder_hasDefault() {
808         Notification.Action action = makeNotificationAction(null);
809         assertEquals(Notification.Action.SEMANTIC_ACTION_NONE, action.getSemanticAction());
810     }
811 
812     @Test
action_builder_setSemanticAction()813     public void action_builder_setSemanticAction() {
814         Notification.Action action = makeNotificationAction(
815                 builder -> builder.setSemanticAction(Notification.Action.SEMANTIC_ACTION_REPLY));
816         assertEquals(Notification.Action.SEMANTIC_ACTION_REPLY, action.getSemanticAction());
817     }
818 
819     @Test
action_parcel()820     public void action_parcel() {
821         Notification.Action action = writeAndReadParcelable(
822                 makeNotificationAction(builder -> {
823                     builder.setSemanticAction(Notification.Action.SEMANTIC_ACTION_ARCHIVE);
824                     builder.setAllowGeneratedReplies(true);
825                 }));
826 
827         assertEquals(Notification.Action.SEMANTIC_ACTION_ARCHIVE, action.getSemanticAction());
828         assertTrue(action.getAllowGeneratedReplies());
829     }
830 
831     @Test
action_clone()832     public void action_clone() {
833         Notification.Action action = makeNotificationAction(
834                 builder -> builder.setSemanticAction(Notification.Action.SEMANTIC_ACTION_DELETE));
835         assertEquals(
836                 Notification.Action.SEMANTIC_ACTION_DELETE,
837                 action.clone().getSemanticAction());
838     }
839 
840     @Test
testBuilder_setLocusId()841     public void testBuilder_setLocusId() {
842         LocusId locusId = new LocusId("4815162342");
843         Notification notification = new Notification.Builder(mContext, "whatever")
844                 .setLocusId(locusId).build();
845         assertEquals(locusId, notification.getLocusId());
846 
847         Notification clone = writeAndReadParcelable(notification);
848         assertEquals(locusId, clone.getLocusId());
849     }
850 
851     @Test
testBuilder_setLocusId_null()852     public void testBuilder_setLocusId_null() {
853         Notification notification = new Notification.Builder(mContext, "whatever")
854                 .setLocusId(null).build();
855         assertNull(notification.getLocusId());
856 
857         Notification clone = writeAndReadParcelable(notification);
858         assertNull(clone.getLocusId());
859     }
860 
861     @Test
testBuilder_getFullLengthSpanColor_returnsNullForString()862     public void testBuilder_getFullLengthSpanColor_returnsNullForString() {
863         assertThat(Notification.Builder.getFullLengthSpanColor("String")).isNull();
864     }
865 
866     @Test
testBuilder_getFullLengthSpanColor_returnsNullWithPartialSpan()867     public void testBuilder_getFullLengthSpanColor_returnsNullWithPartialSpan() {
868         CharSequence text = new SpannableStringBuilder()
869                 .append("text with ")
870                 .append("some red", new ForegroundColorSpan(Color.RED),
871                         Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
872         assertThat(Notification.Builder.getFullLengthSpanColor(text)).isNull();
873     }
874 
875     @Test
testBuilder_getFullLengthSpanColor_worksWithSingleSpan()876     public void testBuilder_getFullLengthSpanColor_worksWithSingleSpan() {
877         CharSequence text = new SpannableStringBuilder()
878                 .append("text that is all red", new ForegroundColorSpan(Color.RED),
879                         Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
880         assertThat(Notification.Builder.getFullLengthSpanColor(text)).isEqualTo(Color.RED);
881     }
882 
883     @Test
testBuilder_getFullLengthSpanColor_worksWithFullAndPartialSpans()884     public void testBuilder_getFullLengthSpanColor_worksWithFullAndPartialSpans() {
885         Spannable text = new SpannableString("blue text with yellow and green");
886         text.setSpan(new ForegroundColorSpan(Color.YELLOW), 15, 21,
887                 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
888         text.setSpan(new ForegroundColorSpan(Color.BLUE), 0, text.length(),
889                 Spanned.SPAN_INCLUSIVE_INCLUSIVE);
890         text.setSpan(new ForegroundColorSpan(Color.GREEN), 26, 31,
891                 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
892         assertThat(Notification.Builder.getFullLengthSpanColor(text)).isEqualTo(Color.BLUE);
893     }
894 
895     @Test
testBuilder_getFullLengthSpanColor_worksWithTextAppearance()896     public void testBuilder_getFullLengthSpanColor_worksWithTextAppearance() {
897         Spannable text = new SpannableString("title text with yellow and green");
898         text.setSpan(new ForegroundColorSpan(Color.YELLOW), 15, 21,
899                 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
900         TextAppearanceSpan textAppearanceSpan = new TextAppearanceSpan(mContext,
901                 R.style.TextAppearance_DeviceDefault_Notification_Title);
902         int expectedTextColor = textAppearanceSpan.getTextColor().getDefaultColor();
903         text.setSpan(textAppearanceSpan, 0, text.length(),
904                 Spanned.SPAN_INCLUSIVE_INCLUSIVE);
905         text.setSpan(new ForegroundColorSpan(Color.GREEN), 26, 31,
906                 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
907         assertThat(Notification.Builder.getFullLengthSpanColor(text)).isEqualTo(expectedTextColor);
908     }
909 
910 
911 
912     @Test
testBuilder_ensureButtonFillContrast_adjustsDarker()913     public void testBuilder_ensureButtonFillContrast_adjustsDarker() {
914         int background = Color.LTGRAY;
915         int foreground = Color.LTGRAY;
916         int result = Notification.Builder.ensureButtonFillContrast(foreground, background);
917         assertContrastIsWithinRange(result, background, 1.3, 1.5);
918         assertThat(ContrastColorUtil.calculateLuminance(result))
919                 .isLessThan(ContrastColorUtil.calculateLuminance(background));
920     }
921 
922     @Test
testBuilder_ensureButtonFillContrast_adjustsLighter()923     public void testBuilder_ensureButtonFillContrast_adjustsLighter() {
924         int background = Color.DKGRAY;
925         int foreground = Color.DKGRAY;
926         int result = Notification.Builder.ensureButtonFillContrast(foreground, background);
927         assertContrastIsWithinRange(result, background, 1.3, 1.5);
928         assertThat(ContrastColorUtil.calculateLuminance(result))
929                 .isGreaterThan(ContrastColorUtil.calculateLuminance(background));
930     }
931 
932     @Test
testBuilder_setSilent_summaryBehavior_groupAlertChildren()933     public void testBuilder_setSilent_summaryBehavior_groupAlertChildren() {
934         Notification summaryNotif = new Notification.Builder(mContext, "channelId")
935                 .setGroupSummary(true)
936                 .setGroup("groupKey")
937                 .setSilent(true)
938                 .build();
939         assertEquals(GROUP_ALERT_CHILDREN, summaryNotif.getGroupAlertBehavior());
940     }
941 
942     @Test
testBuilder_setSilent_childBehavior_groupAlertSummary()943     public void testBuilder_setSilent_childBehavior_groupAlertSummary() {
944         Notification childNotif = new Notification.Builder(mContext, "channelId")
945                 .setGroupSummary(false)
946                 .setGroup("groupKey")
947                 .setSilent(true)
948                 .build();
949         assertEquals(GROUP_ALERT_SUMMARY, childNotif.getGroupAlertBehavior());
950     }
951 
952     @Test
953     @DisableFlags(android.service.notification.Flags.FLAG_NOTIFICATION_SILENT_FLAG)
testBuilder_setSilent_emptyGroupKey_groupKeySilent()954     public void testBuilder_setSilent_emptyGroupKey_groupKeySilent() {
955         Notification emptyGroupKeyNotif = new Notification.Builder(mContext, "channelId")
956                 .setGroup("")
957                 .setSilent(true)
958                 .build();
959         assertThat(emptyGroupKeyNotif.getGroup()).isEqualTo(GROUP_KEY_SILENT);
960         assertThat(emptyGroupKeyNotif.isSilent()).isTrue();
961     }
962 
963     @Test
964     @EnableFlags(android.service.notification.Flags.FLAG_NOTIFICATION_SILENT_FLAG)
testBuilder_setSilent_flagSilent()965     public void testBuilder_setSilent_flagSilent() {
966         final String groupKey = "groupKey";
967         Notification emptyGroupKeyNotif = new Notification.Builder(mContext, "channelId")
968             .setGroup(groupKey)
969             .setSilent(true)
970             .build();
971         assertThat(emptyGroupKeyNotif.getGroup()).isEqualTo(groupKey);
972         assertThat(emptyGroupKeyNotif.isSilent()).isTrue();
973     }
974 
975     @Test
testBuilder_setSilent_vibrateNull()976     public void testBuilder_setSilent_vibrateNull() {
977         Notification silentNotif = new Notification.Builder(mContext, "channelId")
978                 .setGroup("")
979                 .setSilent(true)
980                 .build();
981 
982         assertNull(silentNotif.vibrate);
983     }
984 
985     @Test
testBuilder_setSilent_soundNull()986     public void testBuilder_setSilent_soundNull() {
987         Notification silentNotif = new Notification.Builder(mContext, "channelId")
988                 .setGroup("")
989                 .setSilent(true)
990                 .build();
991 
992         assertNull(silentNotif.sound);
993     }
994 
995     @Test
testBuilder_setSilent_noDefaultSound()996     public void testBuilder_setSilent_noDefaultSound() {
997         Notification silentNotif = new Notification.Builder(mContext, "channelId")
998                 .setGroup("")
999                 .setSilent(true)
1000                 .build();
1001 
1002         assertEquals(0, (silentNotif.defaults & DEFAULT_SOUND));
1003     }
1004 
1005     @Test
testBuilder_setSilent_noDefaultVibrate()1006     public void testBuilder_setSilent_noDefaultVibrate() {
1007         Notification silentNotif = new Notification.Builder(mContext, "channelId")
1008                 .setGroup("")
1009                 .setSilent(true)
1010                 .build();
1011 
1012         assertEquals(0, (silentNotif.defaults & DEFAULT_VIBRATE));
1013     }
1014 
1015     @Test
testCallStyle_getSystemActions_forIncomingCall()1016     public void testCallStyle_getSystemActions_forIncomingCall() {
1017         PendingIntent answerIntent = createPendingIntent("answer");
1018         PendingIntent declineIntent = createPendingIntent("decline");
1019         Notification.CallStyle style = Notification.CallStyle.forIncomingCall(
1020                 new Person.Builder().setName("A Caller").build(),
1021                 declineIntent,
1022                 answerIntent
1023         );
1024         style.setBuilder(new Notification.Builder(mContext, "Channel"));
1025 
1026         List<Notification.Action> actions = style.getActionsListWithSystemActions();
1027 
1028         assertEquals(2, actions.size());
1029         assertEquals(declineIntent, actions.get(0).actionIntent);
1030         assertEquals(answerIntent, actions.get(1).actionIntent);
1031     }
1032 
1033     @Test
testCallStyle_getSystemActions_forOngoingCall()1034     public void testCallStyle_getSystemActions_forOngoingCall() {
1035         PendingIntent hangUpIntent = createPendingIntent("hangUp");
1036         Notification.CallStyle style = Notification.CallStyle.forOngoingCall(
1037                 new Person.Builder().setName("A Caller").build(),
1038                 hangUpIntent
1039         );
1040         style.setBuilder(new Notification.Builder(mContext, "Channel"));
1041 
1042         List<Notification.Action> actions = style.getActionsListWithSystemActions();
1043 
1044         assertEquals(1, actions.size());
1045         assertEquals(hangUpIntent, actions.get(0).actionIntent);
1046     }
1047 
1048     @Test
testCallStyle_getSystemActions_forIncomingCallWithOtherActions()1049     public void testCallStyle_getSystemActions_forIncomingCallWithOtherActions() {
1050         PendingIntent answerIntent = createPendingIntent("answer");
1051         PendingIntent declineIntent = createPendingIntent("decline");
1052         Notification.CallStyle style = Notification.CallStyle.forIncomingCall(
1053                 new Person.Builder().setName("A Caller").build(),
1054                 declineIntent,
1055                 answerIntent
1056         );
1057         Notification.Action actionToKeep = makeNotificationAction(null);
1058         Notification.Action actionToDrop = makeNotificationAction(null);
1059         Notification.Builder notifBuilder = new Notification.Builder(mContext, "Channel")
1060                 .addAction(actionToKeep)
1061                 .addAction(actionToDrop); //expect to move this action to the end
1062         style.setBuilder(notifBuilder); //add a builder with actions
1063 
1064         List<Notification.Action> actions = style.getActionsListWithSystemActions();
1065 
1066         assertEquals(4, actions.size());
1067         assertEquals(declineIntent, actions.get(0).actionIntent);
1068         assertEquals(actionToKeep, actions.get(1));
1069         assertEquals(answerIntent, actions.get(2).actionIntent);
1070         assertEquals(actionToDrop, actions.get(3));
1071     }
1072 
1073     @Test
testCallStyle_getSystemActions_forOngoingCallWithOtherActions()1074     public void testCallStyle_getSystemActions_forOngoingCallWithOtherActions() {
1075         PendingIntent hangUpIntent = createPendingIntent("hangUp");
1076         Notification.CallStyle style = Notification.CallStyle.forOngoingCall(
1077                 new Person.Builder().setName("A Caller").build(),
1078                 hangUpIntent
1079         );
1080         Notification.Action firstAction = makeNotificationAction(null);
1081         Notification.Action secondAction = makeNotificationAction(null);
1082         Notification.Builder notifBuilder = new Notification.Builder(mContext, "Channel")
1083                 .addAction(firstAction)
1084                 .addAction(secondAction);
1085         style.setBuilder(notifBuilder); //add a builder with actions
1086 
1087         List<Notification.Action> actions = style.getActionsListWithSystemActions();
1088 
1089         assertEquals(3, actions.size());
1090         assertEquals(hangUpIntent, actions.get(0).actionIntent);
1091         assertEquals(firstAction, actions.get(1));
1092         assertEquals(secondAction, actions.get(2));
1093     }
1094 
1095     @Test
testCallStyle_getSystemActions_dropsOldSystemActions()1096     public void testCallStyle_getSystemActions_dropsOldSystemActions() {
1097         PendingIntent hangUpIntent = createPendingIntent("decline");
1098         Notification.CallStyle style = Notification.CallStyle.forOngoingCall(
1099                 new Person.Builder().setName("A Caller").build(),
1100                 hangUpIntent
1101         );
1102         Bundle actionExtras = new Bundle();
1103         actionExtras.putBoolean("key_action_priority", true);
1104         Notification.Action oldSystemAction = makeNotificationAction(
1105                 builder -> builder.addExtras(actionExtras)
1106         );
1107         Notification.Builder notifBuilder = new Notification.Builder(mContext, "Channel")
1108                 .addAction(oldSystemAction);
1109         style.setBuilder(notifBuilder); //add a builder with actions
1110 
1111         List<Notification.Action> actions = style.getActionsListWithSystemActions();
1112 
1113         assertFalse("Old versions of system actions should be dropped.",
1114                 actions.contains(oldSystemAction));
1115     }
1116 
1117     @Test
testBuild_ensureSmallIconIsNotTooBig_resizesIcon()1118     public void testBuild_ensureSmallIconIsNotTooBig_resizesIcon() {
1119         Icon hugeIcon = Icon.createWithBitmap(
1120                 Bitmap.createBitmap(3000, 3000, Bitmap.Config.ARGB_8888));
1121         Notification notification = new Notification.Builder(mContext, "Channel").setSmallIcon(
1122                 hugeIcon).build();
1123 
1124         Bitmap smallNotificationIcon = notification.getSmallIcon().getBitmap();
1125         assertThat((float) smallNotificationIcon.getWidth()).isWithin(3f).of(
1126                 mContext.getResources().getDimensionPixelSize(
1127                         R.dimen.notification_small_icon_size));
1128         assertThat((float) smallNotificationIcon.getHeight()).isWithin(3f).of(
1129                 mContext.getResources().getDimensionPixelSize(
1130                         R.dimen.notification_small_icon_size));
1131     }
1132 
1133     @Test
testBuild_ensureMessagingUserIsNotTooBig_resizesIcon()1134     public void testBuild_ensureMessagingUserIsNotTooBig_resizesIcon() {
1135         Icon hugeIcon = Icon.createWithBitmap(
1136                 Bitmap.createBitmap(3000, 3000, Bitmap.Config.ARGB_8888));
1137         Icon hugeMessageAvatar = Icon.createWithBitmap(
1138                 Bitmap.createBitmap(3000, 3000, Bitmap.Config.ARGB_8888));
1139         Icon hugeHistoricMessageAvatar = Icon.createWithBitmap(
1140                 Bitmap.createBitmap(3000, 3000, Bitmap.Config.ARGB_8888));
1141 
1142         Notification.MessagingStyle style = new Notification.MessagingStyle(
1143                 new Person.Builder().setIcon(hugeIcon).setName("A User").build());
1144         style.addMessage(new Notification.MessagingStyle.Message("A message", 123456,
1145                 new Person.Builder().setIcon(hugeMessageAvatar).setName("A Sender").build()));
1146         style.addHistoricMessage(new Notification.MessagingStyle.Message("A message", 123456,
1147                 new Person.Builder().setIcon(hugeHistoricMessageAvatar).setName(
1148                         "A Historic Sender").build()));
1149         Notification notification = new Notification.Builder(mContext, "Channel").setStyle(
1150                 style).build();
1151 
1152         float targetSize = mContext.getResources().getDimensionPixelSize(
1153                 ActivityManager.isLowRamDeviceStatic()
1154                         ? R.dimen.notification_person_icon_max_size_low_ram
1155                         : R.dimen.notification_person_icon_max_size);
1156 
1157         Bitmap personIcon = style.getUser().getIcon().getBitmap();
1158         assertThat((float) personIcon.getWidth()).isWithin(3f).of(targetSize);
1159         assertThat((float) personIcon.getHeight()).isWithin(3f).of(targetSize);
1160 
1161         Bitmap avatarIcon = style.getMessages().get(0).getSenderPerson().getIcon().getBitmap();
1162         assertThat((float) avatarIcon.getWidth()).isWithin(3f).of(targetSize);
1163         assertThat((float) avatarIcon.getHeight()).isWithin(3f).of(targetSize);
1164 
1165         Bitmap historicAvatarIcon = style.getHistoricMessages().get(
1166                 0).getSenderPerson().getIcon().getBitmap();
1167         assertThat((float) historicAvatarIcon.getWidth()).isWithin(3f).of(targetSize);
1168         assertThat((float) historicAvatarIcon.getHeight()).isWithin(3f).of(targetSize);
1169     }
1170 
1171     @Test
testBuild_ensureMessagingShortcutIconIsNotTooBig_resizesIcon()1172     public void testBuild_ensureMessagingShortcutIconIsNotTooBig_resizesIcon() {
1173         Icon hugeIcon = Icon.createWithBitmap(
1174                 Bitmap.createBitmap(3000, 3000, Bitmap.Config.ARGB_8888));
1175         Notification.MessagingStyle style = new Notification.MessagingStyle(
1176                 new Person.Builder().setName("A User").build()).setShortcutIcon(hugeIcon);
1177 
1178         Notification notification = new Notification.Builder(mContext, "Channel").setStyle(
1179                 style).build();
1180         Bitmap shortcutIcon = style.getShortcutIcon().getBitmap();
1181 
1182         assertThat((float) shortcutIcon.getWidth()).isWithin(3f).of(
1183                 mContext.getResources().getDimensionPixelSize(
1184                         R.dimen.notification_small_icon_size));
1185         assertThat((float) shortcutIcon.getHeight()).isWithin(3f).of(
1186                 mContext.getResources().getDimensionPixelSize(
1187                         R.dimen.notification_small_icon_size));
1188     }
1189 
1190     @Test
1191     @Ignore // TODO: b/329389261 - Restore or delete
testColors_ensureColors_dayMode_producesValidPalette()1192     public void testColors_ensureColors_dayMode_producesValidPalette() {
1193         Notification.Colors c = new Notification.Colors();
1194         boolean colorized = false;
1195         boolean nightMode = false;
1196         resolveColorsInNightMode(nightMode, c, Color.BLUE, colorized);
1197         assertValid(c);
1198     }
1199 
1200     @Test
testColors_ensureColors_nightMode_producesValidPalette()1201     public void testColors_ensureColors_nightMode_producesValidPalette() {
1202         Notification.Colors c = new Notification.Colors();
1203         boolean colorized = false;
1204         boolean nightMode = true;
1205         resolveColorsInNightMode(nightMode, c, Color.BLUE, colorized);
1206         assertValid(c);
1207     }
1208 
1209     @Test
testColors_ensureColors_colorized_producesValidPalette_default()1210     public void testColors_ensureColors_colorized_producesValidPalette_default() {
1211         validateColorizedPaletteForColor(Notification.COLOR_DEFAULT);
1212     }
1213 
1214     @Test
testColors_ensureColors_colorized_producesValidPalette_blue()1215     public void testColors_ensureColors_colorized_producesValidPalette_blue() {
1216         validateColorizedPaletteForColor(Color.BLUE);
1217     }
1218 
1219     @Test
1220     @Ignore // TODO: b/329389261 - Restore or delete
testColors_ensureColors_colorized_producesValidPalette_red()1221     public void testColors_ensureColors_colorized_producesValidPalette_red() {
1222         validateColorizedPaletteForColor(Color.RED);
1223     }
1224 
1225     @Test
1226     @Ignore // b/347089000 - Restore or delete
testColors_ensureColors_colorized_producesValidPalette_white()1227     public void testColors_ensureColors_colorized_producesValidPalette_white() {
1228         validateColorizedPaletteForColor(Color.WHITE);
1229     }
1230 
1231     @Test
testColors_ensureColors_colorized_producesValidPalette_black()1232     public void testColors_ensureColors_colorized_producesValidPalette_black() {
1233         validateColorizedPaletteForColor(Color.BLACK);
1234     }
1235 
1236     @Test
testIsMediaNotification_nullSession_returnsFalse()1237     public void testIsMediaNotification_nullSession_returnsFalse() {
1238         // Null media session
1239         Notification.MediaStyle mediaStyle = new Notification.MediaStyle();
1240         Notification notification = new Notification.Builder(mContext, "test id")
1241                 .setStyle(mediaStyle)
1242                 .build();
1243         assertFalse(notification.isMediaNotification());
1244     }
1245 
1246     @Test
testIsMediaNotification_invalidSession_returnsFalse()1247     public void testIsMediaNotification_invalidSession_returnsFalse() {
1248         // Extra was set manually to an invalid type
1249         Bundle extras = new Bundle();
1250         extras.putParcelable(EXTRA_MEDIA_SESSION, new Intent());
1251         Notification.MediaStyle mediaStyle = new Notification.MediaStyle();
1252         Notification notification = new Notification.Builder(mContext, "test id")
1253                 .setStyle(mediaStyle)
1254                 .addExtras(extras)
1255                 .build();
1256         assertFalse(notification.isMediaNotification());
1257     }
1258 
validateColorizedPaletteForColor(int rawColor)1259     public void validateColorizedPaletteForColor(int rawColor) {
1260         Notification.Colors cDay = new Notification.Colors();
1261         Notification.Colors cNight = new Notification.Colors();
1262         boolean colorized = true;
1263 
1264         resolveColorsInNightMode(false, cDay, rawColor, colorized);
1265         resolveColorsInNightMode(true, cNight, rawColor, colorized);
1266 
1267         if (rawColor != Notification.COLOR_DEFAULT) {
1268             assertEquals(rawColor, cDay.getBackgroundColor());
1269             assertEquals(rawColor, cNight.getBackgroundColor());
1270         }
1271 
1272         assertValid(cDay);
1273         assertValid(cNight);
1274 
1275         if (rawColor != Notification.COLOR_DEFAULT) {
1276             // When a color is provided, night mode should have no effect on the notification
1277             assertEquals(cDay.getBackgroundColor(), cNight.getBackgroundColor());
1278             assertEquals(cDay.getPrimaryTextColor(), cNight.getPrimaryTextColor());
1279             assertEquals(cDay.getSecondaryTextColor(), cNight.getSecondaryTextColor());
1280             assertEquals(cDay.getPrimaryAccentColor(), cNight.getPrimaryAccentColor());
1281             assertEquals(cDay.getSecondaryAccentColor(), cNight.getSecondaryAccentColor());
1282             assertEquals(cDay.getTertiaryAccentColor(), cNight.getTertiaryAccentColor());
1283             assertEquals(cDay.getOnTertiaryAccentTextColor(),
1284                     cNight.getOnTertiaryAccentTextColor());
1285             assertEquals(cDay.getTertiaryFixedDimAccentColor(),
1286                     cNight.getTertiaryFixedDimAccentColor());
1287             assertEquals(cDay.getOnTertiaryFixedAccentTextColor(),
1288                     cNight.getOnTertiaryFixedAccentTextColor());
1289             assertEquals(cDay.getProtectionColor(), cNight.getProtectionColor());
1290             assertEquals(cDay.getContrastColor(), cNight.getContrastColor());
1291             assertEquals(cDay.getRippleAlpha(), cNight.getRippleAlpha());
1292         }
1293     }
1294 
1295     @Test
testRecoverBuilder_nullExtraPeopleList_noCrash()1296     public void testRecoverBuilder_nullExtraPeopleList_noCrash() {
1297         Bundle extras = new Bundle();
1298         extras.putParcelable(EXTRA_PEOPLE_LIST, null);
1299 
1300         Notification n = new Notification.Builder(mContext, "test")
1301                 .setSmallIcon(0)
1302                 .addExtras(extras)
1303                 .build();
1304         Bundle fakeTypes = new Bundle();
1305         fakeTypes.putParcelable(EXTRA_BUILDER_APPLICATION_INFO, new Bundle());
1306 
1307         Notification.Builder.recoverBuilder(mContext, n);
1308 
1309         // no crash, good
1310     }
1311 
1312     @Test
testVisitUris_invalidExtra_noCrash()1313     public void testVisitUris_invalidExtra_noCrash() {
1314         Notification n = new Notification.Builder(mContext, "test")
1315                 .setSmallIcon(0)
1316                 .build();
1317         Bundle fakeTypes = new Bundle();
1318         fakeTypes.putParcelable(EXTRA_LARGE_ICON_BIG, new Bundle());
1319         fakeTypes.putParcelable(EXTRA_PICTURE_ICON, new Bundle());
1320         fakeTypes.putParcelable(EXTRA_MESSAGING_PERSON, new Bundle());
1321 
1322         Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
1323         n.visitUris(visitor);
1324 
1325         // no crash, good
1326     }
1327 
1328     @Test
testRecoverBuilder_invalidExtra_noCrash()1329     public void testRecoverBuilder_invalidExtra_noCrash() {
1330         Notification n = new Notification.Builder(mContext, "test")
1331                 .setSmallIcon(0)
1332                 .build();
1333         Bundle fakeTypes = new Bundle();
1334         fakeTypes.putParcelable(EXTRA_BUILDER_APPLICATION_INFO, new Bundle());
1335 
1336         Notification.Builder.recoverBuilder(mContext, n);
1337 
1338         // no crash, good
1339     }
1340 
1341     @Test
testIsMediaNotification_invalidExtra_noCrash()1342     public void testIsMediaNotification_invalidExtra_noCrash() {
1343         Notification n = new Notification.Builder(mContext, "test")
1344                 .setSmallIcon(0)
1345                 .setStyle(new Notification.MediaStyle())
1346                 .build();
1347         Bundle fakeTypes = new Bundle();
1348         fakeTypes.putParcelable(EXTRA_MEDIA_SESSION, new Bundle());
1349 
1350         n.isMediaNotification();
1351 
1352         // no crash, good
1353     }
1354 
1355     @Test
testRestoreFromExtras_BigText_invalidExtra_noCrash()1356     public void testRestoreFromExtras_BigText_invalidExtra_noCrash() {
1357         Notification.Style style = new Notification.BigTextStyle();
1358         Bundle fakeTypes = new Bundle();
1359         fakeTypes.putParcelable(EXTRA_LARGE_ICON_BIG, new Bundle());
1360 
1361 
1362         // no crash, good
1363     }
1364 
1365     @Test
testRestoreFromExtras_Messaging_invalidExtra_noCrash()1366     public void testRestoreFromExtras_Messaging_invalidExtra_noCrash() {
1367         Notification.Style style = new Notification.MessagingStyle("test");
1368         Bundle fakeTypes = new Bundle();
1369         fakeTypes.putParcelable(EXTRA_MESSAGING_PERSON, new Bundle());
1370         fakeTypes.putParcelable(EXTRA_CONVERSATION_ICON, new Bundle());
1371 
1372         Notification n = new Notification.Builder(mContext, "test")
1373                 .setStyle(style)
1374                 .setExtras(fakeTypes)
1375                 .build();
1376         Notification.Builder.recoverBuilder(mContext, n);
1377 
1378         // no crash, good
1379     }
1380 
1381     @Test
testRestoreFromExtras_Media_invalidExtra_noCrash()1382     public void testRestoreFromExtras_Media_invalidExtra_noCrash() {
1383         Notification.Style style = new Notification.MediaStyle();
1384         Bundle fakeTypes = new Bundle();
1385         fakeTypes.putParcelable(EXTRA_MEDIA_SESSION, new Bundle());
1386         fakeTypes.putParcelable(EXTRA_MEDIA_REMOTE_INTENT, new Bundle());
1387 
1388         Notification n = new Notification.Builder(mContext, "test")
1389                 .setStyle(style)
1390                 .setExtras(fakeTypes)
1391                 .build();
1392         Notification.Builder.recoverBuilder(mContext, n);
1393 
1394         // no crash, good
1395     }
1396 
1397     @Test
testRestoreFromExtras_Call_invalidExtra_noCrash()1398     public void testRestoreFromExtras_Call_invalidExtra_noCrash() {
1399         PendingIntent intent1 = PendingIntent.getActivity(
1400                 mContext, 0, new Intent("test1"), PendingIntent.FLAG_IMMUTABLE);
1401         Notification.Style style = Notification.CallStyle.forIncomingCall(
1402                 new Person.Builder().setName("hi").build(), intent1, intent1);
1403 
1404         Bundle fakeTypes = new Bundle();
1405         fakeTypes.putParcelable(EXTRA_CALL_PERSON, new Bundle());
1406         fakeTypes.putParcelable(EXTRA_ANSWER_INTENT, new Bundle());
1407         fakeTypes.putParcelable(EXTRA_DECLINE_INTENT, new Bundle());
1408         fakeTypes.putParcelable(EXTRA_HANG_UP_INTENT, new Bundle());
1409 
1410         Notification n = new Notification.Builder(mContext, "test")
1411                 .setStyle(style)
1412                 .setExtras(fakeTypes)
1413                 .build();
1414         Notification.Builder.recoverBuilder(mContext, n);
1415         // no crash, good
1416     }
1417 
1418     @Test
testGetPictureIcon_invalidExtra_noCrash()1419     public void testGetPictureIcon_invalidExtra_noCrash() {
1420         Bundle fakeTypes = new Bundle();
1421         fakeTypes.putParcelable(EXTRA_PICTURE, new Bundle());
1422         fakeTypes.putParcelable(EXTRA_PICTURE_ICON, new Bundle());
1423 
1424         Notification.BigPictureStyle.getPictureIcon(fakeTypes);
1425 
1426         // no crash, good
1427     }
1428 
1429     @Test
testWearableExtender_invalidExtra_noCrash()1430     public void testWearableExtender_invalidExtra_noCrash() {
1431         Notification n = new Notification.Builder(mContext, "test")
1432                 .setSmallIcon(0)
1433                 .setStyle(new Notification.MediaStyle())
1434                 .build();
1435         Bundle fakeTypes = new Bundle();
1436         fakeTypes.putParcelable(KEY_DISPLAY_INTENT, new Bundle());
1437         fakeTypes.putParcelable(KEY_BACKGROUND, new Bundle());
1438         Notification.WearableExtender extender = new Notification.WearableExtender(n);
1439 
1440         // no crash, good
1441     }
1442 
1443     @Test
testCarExtender_invalidExtra_noCrash()1444     public void testCarExtender_invalidExtra_noCrash() {
1445         Notification n = new Notification.Builder(mContext, "test")
1446                 .setSmallIcon(0)
1447                 .setStyle(new Notification.MediaStyle())
1448                 .build();
1449         Bundle fakeTypes = new Bundle();
1450         fakeTypes.putParcelable(EXTRA_LARGE_ICON, new Bundle());
1451         Notification.CarExtender extender = new Notification.CarExtender(n);
1452 
1453         // no crash, good
1454     }
1455 
1456     @Test
testTvExtender_invalidExtra_noCrash()1457     public void testTvExtender_invalidExtra_noCrash() {
1458         Notification n = new Notification.Builder(mContext, "test")
1459                 .setSmallIcon(0)
1460                 .setStyle(new Notification.MediaStyle())
1461                 .build();
1462         Bundle fakeTypes = new Bundle();
1463         fakeTypes.putParcelable(EXTRA_CONTENT_INTENT, new Bundle());
1464         fakeTypes.putParcelable(EXTRA_DELETE_INTENT, new Bundle());
1465         Notification.TvExtender extender = new Notification.TvExtender(n);
1466 
1467         // no crash, good
1468     }
1469 
1470     @Test
testGetUnreadConversationFromBundle_invalidExtra_noCrash()1471     public void testGetUnreadConversationFromBundle_invalidExtra_noCrash() {
1472         Bundle fakeTypes = new Bundle();
1473         fakeTypes.putParcelable(KEY_ON_READ, new Bundle());
1474         fakeTypes.putParcelable(KEY_ON_REPLY, new Bundle());
1475         fakeTypes.putParcelable(KEY_REMOTE_INPUT, new Bundle());
1476 
1477         Notification n = new Notification.Builder(mContext, "test")
1478                 .setExtras(fakeTypes)
1479                 .build();
1480         Notification.CarExtender extender = new Notification.CarExtender(n);
1481 
1482         // no crash, good
1483     }
1484 
1485     @Test
testGetMessageFromBundle_invalidExtra_noCrash()1486     public void testGetMessageFromBundle_invalidExtra_noCrash() {
1487         Bundle fakeTypes = new Bundle();
1488         fakeTypes.putParcelable(KEY_SENDER_PERSON, new Bundle());
1489         fakeTypes.putString(KEY_TEXT, "text");
1490         fakeTypes.putLong(KEY_TIMESTAMP, 0);
1491         fakeTypes.putParcelable(KEY_REMOTE_INPUT, new Bundle());
1492         fakeTypes.putParcelable(KEY_DATA_URI, new Bundle());
1493         Notification.MessagingStyle.Message.getMessageFromBundle(fakeTypes);
1494 
1495         // no crash, good
1496     }
1497 
1498     @Test
testToBundle_getMessageFromBundle_returnsSameData()1499     public void testToBundle_getMessageFromBundle_returnsSameData() {
1500         Notification.MessagingStyle.Message message =
1501                 new Notification.MessagingStyle.Message(
1502                         "a", 100, new Person.Builder().setName("hi").build());
1503         message.setData("text", Uri.parse("http://test/uri"));
1504 
1505         Notification.MessagingStyle.Message convertedMessage =
1506                 Notification.MessagingStyle.Message.getMessageFromBundle(message.toBundle());
1507 
1508         assertThat(convertedMessage).isNotNull();
1509         assertThat(message.getText()).isEqualTo(convertedMessage.getText());
1510         assertThat(message.getTimestamp()).isEqualTo(convertedMessage.getTimestamp());
1511         assertThat(message.getExtras().size()).isEqualTo(convertedMessage.getExtras().size());
1512         assertThat(message.getSender()).isEqualTo(convertedMessage.getSender());
1513         assertThat(message.getSenderPerson()).isEqualTo(convertedMessage.getSenderPerson());
1514         assertThat(message.getDataMimeType()).isEqualTo(convertedMessage.getDataMimeType());
1515         assertThat(message.getDataUri()).isEqualTo(convertedMessage.getDataUri());
1516         assertThat(message.isRemoteInputHistory())
1517                 .isEqualTo(convertedMessage.isRemoteInputHistory());
1518     }
1519 
1520     @Test
testDoesNotStripsExtenders()1521     public void testDoesNotStripsExtenders() {
1522         Notification.Builder nb = new Notification.Builder(mContext, "channel");
1523         nb.extend(new Notification.CarExtender().setColor(Color.RED));
1524         nb.extend(new Notification.TvExtender().setChannelId("different channel"));
1525         nb.extend(new Notification.WearableExtender().setDismissalId("dismiss"));
1526         Notification before = nb.build();
1527         Notification after = Notification.Builder.maybeCloneStrippedForDelivery(before);
1528 
1529         assertTrue(before == after);
1530 
1531         Assert.assertEquals("different channel",
1532                 new Notification.TvExtender(before).getChannelId());
1533         Assert.assertEquals(Color.RED, new Notification.CarExtender(before).getColor());
1534         Assert.assertEquals("dismiss", new Notification.WearableExtender(before).getDismissalId());
1535     }
1536 
1537     @Test
areIconsDifferent_sameSmallIcon_false()1538     public void areIconsDifferent_sameSmallIcon_false() {
1539         Notification n1 = new Notification.Builder(mContext, "test").setSmallIcon(1).build();
1540         Notification n2 = new Notification.Builder(mContext, "test").setSmallIcon(1).build();
1541 
1542         assertThat(Notification.areIconsDifferent(n1, n2)).isFalse();
1543     }
1544 
1545     @Test
areIconsDifferent_differentSmallIcon_true()1546     public void areIconsDifferent_differentSmallIcon_true() {
1547         Notification n1 = new Notification.Builder(mContext, "test").setSmallIcon(1).build();
1548         Notification n2 = new Notification.Builder(mContext, "test").setSmallIcon(2).build();
1549 
1550         assertThat(Notification.areIconsDifferent(n1, n2)).isTrue();
1551     }
1552 
1553     @Test
areIconsDifferent_sameLargeIcon_false()1554     public void areIconsDifferent_sameLargeIcon_false() {
1555         Icon icon1 = Icon.createWithContentUri("uri");
1556         Icon icon2 = Icon.createWithContentUri("uri");
1557         Notification n1 = new Notification.Builder(mContext, "test")
1558                 .setSmallIcon(1).setLargeIcon(icon1).build();
1559         Notification n2 = new Notification.Builder(mContext, "test")
1560                 .setSmallIcon(1).setLargeIcon(icon2).build();
1561 
1562         // Note that this will almost certainly not happen for Icons created from Bitmaps, since
1563         // their serialization/deserialization of Bitmaps (app -> system_process) results in a
1564         // different getGenerationId() value. :(
1565         assertThat(Notification.areIconsDifferent(n1, n2)).isFalse();
1566     }
1567 
1568     @Test
areIconsDifferent_differentLargeIcon_true()1569     public void areIconsDifferent_differentLargeIcon_true() {
1570         Icon icon1 = Icon.createWithContentUri("uri1");
1571         Icon icon2 = Icon.createWithContentUri("uri2");
1572         Notification n1 = new Notification.Builder(mContext, "test")
1573                 .setSmallIcon(1).setLargeIcon(icon1).build();
1574         Notification n2 = new Notification.Builder(mContext, "test")
1575                 .setSmallIcon(2).setLargeIcon(icon2).build();
1576 
1577         assertThat(Notification.areIconsDifferent(n1, n2)).isTrue();
1578     }
1579 
1580     @Test
areIconsDifferent_addedLargeIcon_true()1581     public void areIconsDifferent_addedLargeIcon_true() {
1582         Icon icon = Icon.createWithContentUri("uri");
1583         Notification n1 = new Notification.Builder(mContext, "test").setSmallIcon(1).build();
1584         Notification n2 = new Notification.Builder(mContext, "test")
1585                 .setSmallIcon(2).setLargeIcon(icon).build();
1586 
1587         assertThat(Notification.areIconsDifferent(n1, n2)).isTrue();
1588     }
1589 
1590     @Test
areIconsDifferent_removedLargeIcon_true()1591     public void areIconsDifferent_removedLargeIcon_true() {
1592         Icon icon = Icon.createWithContentUri("uri");
1593         Notification n1 = new Notification.Builder(mContext, "test")
1594                 .setSmallIcon(1).setLargeIcon(icon).build();
1595         Notification n2 = new Notification.Builder(mContext, "test").setSmallIcon(2).build();
1596 
1597         assertThat(Notification.areIconsDifferent(n1, n2)).isTrue();
1598     }
1599 
1600     @Test
testStyleChangeVisiblyDifferent_noStyles()1601     public void testStyleChangeVisiblyDifferent_noStyles() {
1602         Notification.Builder n1 = new Notification.Builder(mContext, "test");
1603         Notification.Builder n2 = new Notification.Builder(mContext, "test");
1604 
1605         assertFalse(Notification.areStyledNotificationsVisiblyDifferent(n1, n2));
1606     }
1607 
1608     @Test
testStyleChangeVisiblyDifferent_noStyleToStyle()1609     public void testStyleChangeVisiblyDifferent_noStyleToStyle() {
1610         Notification.Builder n1 = new Notification.Builder(mContext, "test");
1611         Notification.Builder n2 = new Notification.Builder(mContext, "test")
1612                 .setStyle(new Notification.BigTextStyle());
1613 
1614         assertTrue(Notification.areStyledNotificationsVisiblyDifferent(n1, n2));
1615     }
1616 
1617     @Test
testStyleChangeVisiblyDifferent_styleToNoStyle()1618     public void testStyleChangeVisiblyDifferent_styleToNoStyle() {
1619         Notification.Builder n2 = new Notification.Builder(mContext, "test");
1620         Notification.Builder n1 = new Notification.Builder(mContext, "test")
1621                 .setStyle(new Notification.BigTextStyle());
1622 
1623         assertTrue(Notification.areStyledNotificationsVisiblyDifferent(n1, n2));
1624     }
1625 
1626     @Test
testStyleChangeVisiblyDifferent_changeStyle()1627     public void testStyleChangeVisiblyDifferent_changeStyle() {
1628         Notification.Builder n1 = new Notification.Builder(mContext, "test")
1629                 .setStyle(new Notification.InboxStyle());
1630         Notification.Builder n2 = new Notification.Builder(mContext, "test")
1631                 .setStyle(new Notification.BigTextStyle());
1632 
1633         assertTrue(Notification.areStyledNotificationsVisiblyDifferent(n1, n2));
1634     }
1635 
1636     @Test
testInboxTextChange()1637     public void testInboxTextChange() {
1638         Notification.Builder nInbox1 = new Notification.Builder(mContext, "test")
1639                 .setStyle(new Notification.InboxStyle().addLine("a").addLine("b"));
1640         Notification.Builder nInbox2 = new Notification.Builder(mContext, "test")
1641                 .setStyle(new Notification.InboxStyle().addLine("b").addLine("c"));
1642 
1643         assertTrue(Notification.areStyledNotificationsVisiblyDifferent(nInbox1, nInbox2));
1644     }
1645 
1646     @Test
testBigTextTextChange()1647     public void testBigTextTextChange() {
1648         Notification.Builder nBigText1 = new Notification.Builder(mContext, "test")
1649                 .setStyle(new Notification.BigTextStyle().bigText("something"));
1650         Notification.Builder nBigText2 = new Notification.Builder(mContext, "test")
1651                 .setStyle(new Notification.BigTextStyle().bigText("else"));
1652 
1653         assertTrue(Notification.areStyledNotificationsVisiblyDifferent(nBigText1, nBigText2));
1654     }
1655 
1656     @Test
testBigPictureChange()1657     public void testBigPictureChange() {
1658         Bitmap bitA = Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888);
1659         Bitmap bitB = Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888);
1660 
1661         Notification.Builder nBigPic1 = new Notification.Builder(mContext, "test")
1662                 .setStyle(new Notification.BigPictureStyle().bigPicture(bitA));
1663         Notification.Builder nBigPic2 = new Notification.Builder(mContext, "test")
1664                 .setStyle(new Notification.BigPictureStyle().bigPicture(bitB));
1665 
1666         assertTrue(Notification.areStyledNotificationsVisiblyDifferent(nBigPic1, nBigPic2));
1667     }
1668 
1669     @Test
testBigPictureStyle_setExtras_pictureIconNull_noPictureIconKey()1670     public void testBigPictureStyle_setExtras_pictureIconNull_noPictureIconKey() {
1671         Notification.BigPictureStyle bpStyle = new Notification.BigPictureStyle();
1672         bpStyle.bigPicture((Bitmap) null);
1673 
1674         Bundle extras = new Bundle();
1675         bpStyle.addExtras(extras);
1676 
1677         assertThat(extras.containsKey(EXTRA_PICTURE_ICON)).isFalse();
1678     }
1679 
1680     @Test
testBigPictureStyle_setExtras_pictureIconNull_noPictureKey()1681     public void testBigPictureStyle_setExtras_pictureIconNull_noPictureKey() {
1682         Notification.BigPictureStyle bpStyle = new Notification.BigPictureStyle();
1683         bpStyle.bigPicture((Bitmap) null);
1684 
1685         Bundle extras = new Bundle();
1686         bpStyle.addExtras(extras);
1687 
1688         assertThat(extras.containsKey(EXTRA_PICTURE)).isFalse();
1689     }
1690 
1691     @Test
testBigPictureStyle_setExtras_pictureIconTypeBitmap_pictureIconKeyNull()1692     public void testBigPictureStyle_setExtras_pictureIconTypeBitmap_pictureIconKeyNull() {
1693         Bitmap bitmap = Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888);
1694         Notification.BigPictureStyle bpStyle = new Notification.BigPictureStyle();
1695         bpStyle.bigPicture(bitmap);
1696 
1697         Bundle extras = new Bundle();
1698         bpStyle.addExtras(extras);
1699 
1700         assertThat(extras.containsKey(EXTRA_PICTURE_ICON)).isTrue();
1701         final Parcelable pictureIcon = extras.getParcelable(EXTRA_PICTURE_ICON);
1702         assertThat(pictureIcon).isNull();
1703     }
1704 
1705     @Test
testBigPictureStyle_setExtras_pictureIconTypeIcon_pictureKeyNull()1706     public void testBigPictureStyle_setExtras_pictureIconTypeIcon_pictureKeyNull() {
1707         Icon icon = Icon.createWithResource(mContext, R.drawable.btn_plus);
1708         Notification.BigPictureStyle bpStyle = new Notification.BigPictureStyle();
1709         bpStyle.bigPicture(icon);
1710 
1711         Bundle extras = new Bundle();
1712         bpStyle.addExtras(extras);
1713 
1714         assertThat(extras.containsKey(EXTRA_PICTURE)).isTrue();
1715         final Parcelable picture = extras.getParcelable(EXTRA_PICTURE);
1716         assertThat(picture).isNull();
1717     }
1718 
1719     @Test
testMessagingChange_text()1720     public void testMessagingChange_text() {
1721         Notification.Builder nM1 = new Notification.Builder(mContext, "test")
1722                 .setStyle(new Notification.MessagingStyle("")
1723                         .addMessage(new Notification.MessagingStyle.Message(
1724                                 "a", 100, new Person.Builder().setName("hi").build())));
1725         Notification.Builder nM2 = new Notification.Builder(mContext, "test")
1726                 .setStyle(new Notification.MessagingStyle("")
1727                         .addMessage(new Notification.MessagingStyle.Message(
1728                                 "a", 100, new Person.Builder().setName("hi").build()))
1729                         .addMessage(new Notification.MessagingStyle.Message(
1730                                 "b", 100, new Person.Builder().setName("hi").build()))
1731                 );
1732 
1733         assertTrue(Notification.areStyledNotificationsVisiblyDifferent(nM1, nM2));
1734     }
1735 
1736     @Test
testMessagingChange_data()1737     public void testMessagingChange_data() {
1738         Notification.Builder nM1 = new Notification.Builder(mContext, "test")
1739                 .setStyle(new Notification.MessagingStyle("")
1740                         .addMessage(new Notification.MessagingStyle.Message(
1741                                 "a", 100, new Person.Builder().setName("hi").build())
1742                                 .setData("text", mock(Uri.class))));
1743         Notification.Builder nM2 = new Notification.Builder(mContext, "test")
1744                 .setStyle(new Notification.MessagingStyle("")
1745                         .addMessage(new Notification.MessagingStyle.Message(
1746                                 "a", 100, new Person.Builder().setName("hi").build())));
1747 
1748         assertTrue(Notification.areStyledNotificationsVisiblyDifferent(nM1, nM2));
1749     }
1750 
1751     @Test
testMessagingChange_sender()1752     public void testMessagingChange_sender() {
1753         Person a = new Person.Builder().setName("A").build();
1754         Person b = new Person.Builder().setName("b").build();
1755         Notification.Builder nM1 = new Notification.Builder(mContext, "test")
1756                 .setStyle(new Notification.MessagingStyle("")
1757                         .addMessage(new Notification.MessagingStyle.Message("a", 100, b)));
1758         Notification.Builder nM2 = new Notification.Builder(mContext, "test")
1759                 .setStyle(new Notification.MessagingStyle("")
1760                         .addMessage(new Notification.MessagingStyle.Message("a", 100, a)));
1761 
1762         assertTrue(Notification.areStyledNotificationsVisiblyDifferent(nM1, nM2));
1763     }
1764 
1765     @Test
testMessagingChange_key()1766     public void testMessagingChange_key() {
1767         Person a = new Person.Builder().setName("hi").setKey("A").build();
1768         Person b = new Person.Builder().setName("hi").setKey("b").build();
1769         Notification.Builder nM1 = new Notification.Builder(mContext, "test")
1770                 .setStyle(new Notification.MessagingStyle("")
1771                         .addMessage(new Notification.MessagingStyle.Message("a", 100, a)));
1772         Notification.Builder nM2 = new Notification.Builder(mContext, "test")
1773                 .setStyle(new Notification.MessagingStyle("")
1774                         .addMessage(new Notification.MessagingStyle.Message("a", 100, b)));
1775 
1776         assertTrue(Notification.areStyledNotificationsVisiblyDifferent(nM1, nM2));
1777     }
1778 
1779     @Test
testMessagingChange_ignoreTimeChange()1780     public void testMessagingChange_ignoreTimeChange() {
1781         Notification.Builder nM1 = new Notification.Builder(mContext, "test")
1782                 .setStyle(new Notification.MessagingStyle("")
1783                         .addMessage(new Notification.MessagingStyle.Message(
1784                                 "a", 100, new Person.Builder().setName("hi").build())));
1785         Notification.Builder nM2 = new Notification.Builder(mContext, "test")
1786                 .setStyle(new Notification.MessagingStyle("")
1787                         .addMessage(new Notification.MessagingStyle.Message(
1788                                 "a", 1000, new Person.Builder().setName("hi").build()))
1789                 );
1790 
1791         assertFalse(Notification.areStyledNotificationsVisiblyDifferent(nM1, nM2));
1792     }
1793 
1794     @Test
testRemoteViews_nullChange()1795     public void testRemoteViews_nullChange() {
1796         Notification.Builder n1 = new Notification.Builder(mContext, "test")
1797                 .setContent(mock(RemoteViews.class));
1798         Notification.Builder n2 = new Notification.Builder(mContext, "test");
1799         assertTrue(Notification.areRemoteViewsChanged(n1, n2));
1800 
1801         n1 = new Notification.Builder(mContext, "test");
1802         n2 = new Notification.Builder(mContext, "test")
1803                 .setContent(mock(RemoteViews.class));
1804         assertTrue(Notification.areRemoteViewsChanged(n1, n2));
1805 
1806         n1 = new Notification.Builder(mContext, "test")
1807                 .setCustomBigContentView(mock(RemoteViews.class));
1808         n2 = new Notification.Builder(mContext, "test");
1809         assertTrue(Notification.areRemoteViewsChanged(n1, n2));
1810 
1811         n1 = new Notification.Builder(mContext, "test");
1812         n2 = new Notification.Builder(mContext, "test")
1813                 .setCustomBigContentView(mock(RemoteViews.class));
1814         assertTrue(Notification.areRemoteViewsChanged(n1, n2));
1815 
1816         n1 = new Notification.Builder(mContext, "test");
1817         n2 = new Notification.Builder(mContext, "test");
1818         assertFalse(Notification.areRemoteViewsChanged(n1, n2));
1819     }
1820 
1821     @Test
testRemoteViews_layoutChange()1822     public void testRemoteViews_layoutChange() {
1823         RemoteViews a = mock(RemoteViews.class);
1824         when(a.getLayoutId()).thenReturn(234);
1825         RemoteViews b = mock(RemoteViews.class);
1826         when(b.getLayoutId()).thenReturn(189);
1827 
1828         Notification.Builder n1 = new Notification.Builder(mContext, "test").setContent(a);
1829         Notification.Builder n2 = new Notification.Builder(mContext, "test").setContent(b);
1830         assertTrue(Notification.areRemoteViewsChanged(n1, n2));
1831 
1832         n1 = new Notification.Builder(mContext, "test").setCustomBigContentView(a);
1833         n2 = new Notification.Builder(mContext, "test").setCustomBigContentView(b);
1834         assertTrue(Notification.areRemoteViewsChanged(n1, n2));
1835 
1836         n1 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(a);
1837         n2 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(b);
1838         assertTrue(Notification.areRemoteViewsChanged(n1, n2));
1839     }
1840 
1841     @Test
testRemoteViews_layoutSame()1842     public void testRemoteViews_layoutSame() {
1843         RemoteViews a = mock(RemoteViews.class);
1844         when(a.getLayoutId()).thenReturn(234);
1845         RemoteViews b = mock(RemoteViews.class);
1846         when(b.getLayoutId()).thenReturn(234);
1847 
1848         Notification.Builder n1 = new Notification.Builder(mContext, "test").setContent(a);
1849         Notification.Builder n2 = new Notification.Builder(mContext, "test").setContent(b);
1850         assertFalse(Notification.areRemoteViewsChanged(n1, n2));
1851 
1852         n1 = new Notification.Builder(mContext, "test").setCustomBigContentView(a);
1853         n2 = new Notification.Builder(mContext, "test").setCustomBigContentView(b);
1854         assertFalse(Notification.areRemoteViewsChanged(n1, n2));
1855 
1856         n1 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(a);
1857         n2 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(b);
1858         assertFalse(Notification.areRemoteViewsChanged(n1, n2));
1859     }
1860 
1861     @Test
testRemoteViews_sequenceChange()1862     public void testRemoteViews_sequenceChange() {
1863         RemoteViews a = mock(RemoteViews.class);
1864         when(a.getLayoutId()).thenReturn(234);
1865         when(a.getSequenceNumber()).thenReturn(1);
1866         RemoteViews b = mock(RemoteViews.class);
1867         when(b.getLayoutId()).thenReturn(234);
1868         when(b.getSequenceNumber()).thenReturn(2);
1869 
1870         Notification.Builder n1 = new Notification.Builder(mContext, "test").setContent(a);
1871         Notification.Builder n2 = new Notification.Builder(mContext, "test").setContent(b);
1872         assertTrue(Notification.areRemoteViewsChanged(n1, n2));
1873 
1874         n1 = new Notification.Builder(mContext, "test").setCustomBigContentView(a);
1875         n2 = new Notification.Builder(mContext, "test").setCustomBigContentView(b);
1876         assertTrue(Notification.areRemoteViewsChanged(n1, n2));
1877 
1878         n1 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(a);
1879         n2 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(b);
1880         assertTrue(Notification.areRemoteViewsChanged(n1, n2));
1881     }
1882 
1883     @Test
testRemoteViews_sequenceSame()1884     public void testRemoteViews_sequenceSame() {
1885         RemoteViews a = mock(RemoteViews.class);
1886         when(a.getLayoutId()).thenReturn(234);
1887         when(a.getSequenceNumber()).thenReturn(1);
1888         RemoteViews b = mock(RemoteViews.class);
1889         when(b.getLayoutId()).thenReturn(234);
1890         when(b.getSequenceNumber()).thenReturn(1);
1891 
1892         Notification.Builder n1 = new Notification.Builder(mContext, "test").setContent(a);
1893         Notification.Builder n2 = new Notification.Builder(mContext, "test").setContent(b);
1894         assertFalse(Notification.areRemoteViewsChanged(n1, n2));
1895 
1896         n1 = new Notification.Builder(mContext, "test").setCustomBigContentView(a);
1897         n2 = new Notification.Builder(mContext, "test").setCustomBigContentView(b);
1898         assertFalse(Notification.areRemoteViewsChanged(n1, n2));
1899 
1900         n1 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(a);
1901         n2 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(b);
1902         assertFalse(Notification.areRemoteViewsChanged(n1, n2));
1903     }
1904 
1905     @Test
testActionsDifferent_null()1906     public void testActionsDifferent_null() {
1907         Notification n1 = new Notification.Builder(mContext, "test")
1908                 .build();
1909         Notification n2 = new Notification.Builder(mContext, "test")
1910                 .build();
1911 
1912         assertFalse(Notification.areActionsVisiblyDifferent(n1, n2));
1913     }
1914 
1915     @Test
testActionsDifferentSame()1916     public void testActionsDifferentSame() {
1917         PendingIntent intent = PendingIntent.getActivity(
1918                 mContext, 0, new Intent("test1"), PendingIntent.FLAG_IMMUTABLE);;
1919         Icon icon = Icon.createWithBitmap(Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888));
1920 
1921         Notification n1 = new Notification.Builder(mContext, "test")
1922                 .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent).build())
1923                 .build();
1924         Notification n2 = new Notification.Builder(mContext, "test")
1925                 .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent).build())
1926                 .build();
1927 
1928         assertFalse(Notification.areActionsVisiblyDifferent(n1, n2));
1929     }
1930 
1931     @Test
testActionsDifferentText()1932     public void testActionsDifferentText() {
1933         PendingIntent intent = PendingIntent.getActivity(
1934                 mContext, 0, new Intent("test1"), PendingIntent.FLAG_IMMUTABLE);;
1935         Icon icon = Icon.createWithBitmap(Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888));
1936 
1937         Notification n1 = new Notification.Builder(mContext, "test")
1938                 .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent).build())
1939                 .build();
1940         Notification n2 = new Notification.Builder(mContext, "test")
1941                 .addAction(new Notification.Action.Builder(icon, "TEXT 2", intent).build())
1942                 .build();
1943 
1944         assertTrue(Notification.areActionsVisiblyDifferent(n1, n2));
1945     }
1946 
1947     @Test
testActionsDifferentSpannables()1948     public void testActionsDifferentSpannables() {
1949         PendingIntent intent = PendingIntent.getActivity(
1950                 mContext, 0, new Intent("test1"), PendingIntent.FLAG_IMMUTABLE);;
1951         Icon icon = Icon.createWithBitmap(Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888));
1952 
1953         Notification n1 = new Notification.Builder(mContext, "test")
1954                 .addAction(new Notification.Action.Builder(icon,
1955                         new SpannableStringBuilder().append("test1",
1956                                 new StyleSpan(Typeface.BOLD),
1957                                 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE),
1958                         intent).build())
1959                 .build();
1960         Notification n2 = new Notification.Builder(mContext, "test")
1961                 .addAction(new Notification.Action.Builder(icon, "test1", intent).build())
1962                 .build();
1963 
1964         assertFalse(Notification.areActionsVisiblyDifferent(n1, n2));
1965     }
1966 
1967     @Test
testActionsDifferentNumber()1968     public void testActionsDifferentNumber() {
1969         PendingIntent intent = PendingIntent.getActivity(
1970                 mContext, 0, new Intent("test1"), PendingIntent.FLAG_IMMUTABLE);
1971         Icon icon = Icon.createWithBitmap(Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888));
1972 
1973         Notification n1 = new Notification.Builder(mContext, "test")
1974                 .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent).build())
1975                 .build();
1976         Notification n2 = new Notification.Builder(mContext, "test")
1977                 .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent).build())
1978                 .addAction(new Notification.Action.Builder(icon, "TEXT 2", intent).build())
1979                 .build();
1980 
1981         assertTrue(Notification.areActionsVisiblyDifferent(n1, n2));
1982     }
1983 
1984     @Test
testActionsDifferentIntent()1985     public void testActionsDifferentIntent() {
1986         PendingIntent intent1 = PendingIntent.getActivity(
1987                 mContext, 0, new Intent("test1"), PendingIntent.FLAG_IMMUTABLE);
1988         PendingIntent intent2 = PendingIntent.getActivity(
1989                 mContext, 0, new Intent("test1"), PendingIntent.FLAG_IMMUTABLE);
1990         Icon icon = Icon.createWithBitmap(Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888));
1991 
1992         Notification n1 = new Notification.Builder(mContext, "test")
1993                 .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent1).build())
1994                 .build();
1995         Notification n2 = new Notification.Builder(mContext, "test")
1996                 .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent2).build())
1997                 .build();
1998 
1999         assertFalse(Notification.areActionsVisiblyDifferent(n1, n2));
2000     }
2001 
2002     @Test
testActionsIgnoresRemoteInputs()2003     public void testActionsIgnoresRemoteInputs() {
2004         PendingIntent intent = PendingIntent.getActivity(
2005                 mContext, 0, new Intent("test1"), PendingIntent.FLAG_IMMUTABLE);;
2006         Icon icon = Icon.createWithBitmap(Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888));
2007 
2008         Notification n1 = new Notification.Builder(mContext, "test")
2009                 .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent)
2010                         .addRemoteInput(new RemoteInput.Builder("a")
2011                                 .setChoices(new CharSequence[] {"i", "m"})
2012                                 .build())
2013                         .build())
2014                 .build();
2015         Notification n2 = new Notification.Builder(mContext, "test")
2016                 .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent)
2017                         .addRemoteInput(new RemoteInput.Builder("a")
2018                                 .setChoices(new CharSequence[] {"t", "m"})
2019                                 .build())
2020                         .build())
2021                 .build();
2022 
2023         assertFalse(Notification.areActionsVisiblyDifferent(n1, n2));
2024     }
2025 
2026     @Test
testFreeformRemoteInputActionPair_noRemoteInput()2027     public void testFreeformRemoteInputActionPair_noRemoteInput() {
2028         PendingIntent intent = PendingIntent.getActivity(
2029                 mContext, 0, new Intent("test1"), PendingIntent.FLAG_IMMUTABLE);;
2030         Icon icon = Icon.createWithBitmap(Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888));
2031         Notification notification = new Notification.Builder(mContext, "test")
2032                 .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent)
2033                         .build())
2034                 .build();
2035         Assert.assertNull(notification.findRemoteInputActionPair(false));
2036     }
2037 
2038     @Test
testFreeformRemoteInputActionPair_hasRemoteInput()2039     public void testFreeformRemoteInputActionPair_hasRemoteInput() {
2040         PendingIntent intent = PendingIntent.getActivity(
2041                 mContext, 0, new Intent("test1"), PendingIntent.FLAG_IMMUTABLE);;
2042         Icon icon = Icon.createWithBitmap(Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888));
2043 
2044         RemoteInput remoteInput = new RemoteInput.Builder("a").build();
2045 
2046         Notification.Action actionWithRemoteInput =
2047                 new Notification.Action.Builder(icon, "TEXT 1", intent)
2048                         .addRemoteInput(remoteInput)
2049                         .addRemoteInput(remoteInput)
2050                         .build();
2051 
2052         Notification.Action actionWithoutRemoteInput =
2053                 new Notification.Action.Builder(icon, "TEXT 2", intent)
2054                         .build();
2055 
2056         Notification notification = new Notification.Builder(mContext, "test")
2057                 .addAction(actionWithoutRemoteInput)
2058                 .addAction(actionWithRemoteInput)
2059                 .build();
2060 
2061         Pair<RemoteInput, Notification.Action> remoteInputActionPair =
2062                 notification.findRemoteInputActionPair(false);
2063 
2064         assertNotNull(remoteInputActionPair);
2065         Assert.assertEquals(remoteInput, remoteInputActionPair.first);
2066         Assert.assertEquals(actionWithRemoteInput, remoteInputActionPair.second);
2067     }
2068 
2069     @Test
testFreeformRemoteInputActionPair_requestFreeform_noFreeformRemoteInput()2070     public void testFreeformRemoteInputActionPair_requestFreeform_noFreeformRemoteInput() {
2071         PendingIntent intent = PendingIntent.getActivity(
2072                 mContext, 0, new Intent("test1"), PendingIntent.FLAG_IMMUTABLE);;
2073         Icon icon = Icon.createWithBitmap(Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888));
2074         Notification notification = new Notification.Builder(mContext, "test")
2075                 .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent)
2076                         .addRemoteInput(
2077                                 new RemoteInput.Builder("a")
2078                                         .setAllowFreeFormInput(false).build())
2079                         .build())
2080                 .build();
2081         Assert.assertNull(notification.findRemoteInputActionPair(true));
2082     }
2083 
2084     @Test
testFreeformRemoteInputActionPair_requestFreeform_hasFreeformRemoteInput()2085     public void testFreeformRemoteInputActionPair_requestFreeform_hasFreeformRemoteInput() {
2086         PendingIntent intent = PendingIntent.getActivity(
2087                 mContext, 0, new Intent("test1"), PendingIntent.FLAG_IMMUTABLE);;
2088         Icon icon = Icon.createWithBitmap(Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888));
2089 
2090         RemoteInput remoteInput =
2091                 new RemoteInput.Builder("a").setAllowFreeFormInput(false).build();
2092         RemoteInput freeformRemoteInput =
2093                 new RemoteInput.Builder("b").setAllowFreeFormInput(true).build();
2094 
2095         Notification.Action actionWithFreeformRemoteInput =
2096                 new Notification.Action.Builder(icon, "TEXT 1", intent)
2097                         .addRemoteInput(remoteInput)
2098                         .addRemoteInput(freeformRemoteInput)
2099                         .build();
2100 
2101         Notification.Action actionWithoutFreeformRemoteInput =
2102                 new Notification.Action.Builder(icon, "TEXT 2", intent)
2103                         .addRemoteInput(remoteInput)
2104                         .build();
2105 
2106         Notification notification = new Notification.Builder(mContext, "test")
2107                 .addAction(actionWithoutFreeformRemoteInput)
2108                 .addAction(actionWithFreeformRemoteInput)
2109                 .build();
2110 
2111         Pair<RemoteInput, Notification.Action> remoteInputActionPair =
2112                 notification.findRemoteInputActionPair(true);
2113 
2114         assertNotNull(remoteInputActionPair);
2115         Assert.assertEquals(freeformRemoteInput, remoteInputActionPair.first);
2116         Assert.assertEquals(actionWithFreeformRemoteInput, remoteInputActionPair.second);
2117     }
2118 
2119     // Ensures that extras in a Notification Builder can be updated.
2120     @Test
testExtras_cachedExtrasOverwrittenByUserProvided()2121     public void testExtras_cachedExtrasOverwrittenByUserProvided() {
2122         Bundle extras = new Bundle();
2123         extras.putCharSequence(EXTRA_TITLE, "test title");
2124         extras.putCharSequence(EXTRA_SUMMARY_TEXT, "summary text");
2125 
2126         Notification.Builder builder = new Notification.Builder(mContext, "test id")
2127                 .addExtras(extras);
2128 
2129         Notification notification = builder.build();
2130         assertThat(notification.extras.getCharSequence(EXTRA_TITLE).toString()).isEqualTo(
2131                 "test title");
2132         assertThat(notification.extras.getCharSequence(EXTRA_SUMMARY_TEXT).toString()).isEqualTo(
2133                 "summary text");
2134 
2135         extras.putCharSequence(EXTRA_TITLE, "new title");
2136         builder.addExtras(extras);
2137         notification = builder.build();
2138         assertThat(notification.extras.getCharSequence(EXTRA_TITLE).toString()).isEqualTo(
2139                 "new title");
2140         assertThat(notification.extras.getCharSequence(EXTRA_SUMMARY_TEXT).toString()).isEqualTo(
2141                 "summary text");
2142     }
2143 
2144     // Ensures that extras in a Notification Builder can be updated by an extender.
2145     @Test
testExtras_cachedExtrasOverwrittenByExtender()2146     public void testExtras_cachedExtrasOverwrittenByExtender() {
2147         Notification.CarExtender extender = new Notification.CarExtender().setColor(1234);
2148 
2149         Notification notification = new Notification.Builder(mContext, "test id")
2150                 .extend(extender).build();
2151 
2152         extender.setColor(5678);
2153 
2154         Notification.Builder.recoverBuilder(mContext, notification).extend(extender).build();
2155 
2156         Notification.CarExtender recoveredExtender = new Notification.CarExtender(notification);
2157         assertThat(recoveredExtender.getColor()).isEqualTo(5678);
2158     }
2159 
2160     @Test
2161     @CoreCompatChangeRule.EnableCompatChanges({Notification.WEARABLE_EXTENDER_BACKGROUND_BLOCKED})
wearableBackgroundBlockEnabled_wearableBackgroundSet_valueRemainsNull()2162     public void wearableBackgroundBlockEnabled_wearableBackgroundSet_valueRemainsNull() {
2163         Notification.WearableExtender extender = new Notification.WearableExtender();
2164         Bitmap bitmap = Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888);
2165         extender.setBackground(bitmap);
2166         Notification notif =
2167                 new Notification.Builder(mContext, "test id")
2168                         .setSmallIcon(1)
2169                         .setContentTitle("test_title")
2170                         .extend(extender)
2171                         .build();
2172 
2173         Notification.WearableExtender result = new Notification.WearableExtender(notif);
2174         Assert.assertNull(result.getBackground());
2175     }
2176 
2177     @Test
2178     @CoreCompatChangeRule.DisableCompatChanges({Notification.WEARABLE_EXTENDER_BACKGROUND_BLOCKED})
wearableBackgroundBlockDisabled_wearableBackgroundSet_valueKeepsBitmap()2179     public void wearableBackgroundBlockDisabled_wearableBackgroundSet_valueKeepsBitmap() {
2180         Notification.WearableExtender extender = new Notification.WearableExtender();
2181         Bitmap bitmap = Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888);
2182         extender.setBackground(bitmap);
2183         Notification notif =
2184                 new Notification.Builder(mContext, "test id")
2185                         .setSmallIcon(1)
2186                         .setContentTitle("test_title")
2187                         .extend(extender)
2188                         .build();
2189 
2190         Notification.WearableExtender result = new Notification.WearableExtender(notif);
2191         Bitmap resultBitmap = result.getBackground();
2192         assertNotNull(resultBitmap);
2193         Assert.assertEquals(bitmap, resultBitmap);
2194     }
2195 
2196     @Test
testGetWhen_zero()2197     public void testGetWhen_zero() {
2198         Notification n = new Notification.Builder(mContext, "test")
2199                 .setWhen(0)
2200                 .build();
2201 
2202         mSetFlagsRule.disableFlags(Flags.FLAG_SORT_SECTION_BY_TIME);
2203 
2204         assertThat(n.getWhen()).isEqualTo(0);
2205 
2206         mSetFlagsRule.enableFlags(Flags.FLAG_SORT_SECTION_BY_TIME);
2207 
2208         assertThat(n.getWhen()).isEqualTo(n.creationTime);
2209     }
2210 
2211     @Test
testGetWhen_devProvidedNonZero()2212     public void testGetWhen_devProvidedNonZero() {
2213         Notification n = new Notification.Builder(mContext, "test")
2214                 .setWhen(9)
2215                 .build();
2216 
2217         mSetFlagsRule.disableFlags(Flags.FLAG_SORT_SECTION_BY_TIME);
2218 
2219         assertThat(n.getWhen()).isEqualTo(9);
2220 
2221         mSetFlagsRule.enableFlags(Flags.FLAG_SORT_SECTION_BY_TIME);
2222 
2223         assertThat(n.getWhen()).isEqualTo(9);
2224     }
2225 
2226     @Test
getNotificationStyleClass_forPlatformClassName_returnsPlatformClass()2227     public void getNotificationStyleClass_forPlatformClassName_returnsPlatformClass() {
2228         final List<Class<? extends Notification.Style>> platformStyleClasses = List.of(
2229                 Notification.BigTextStyle.class, Notification.BigPictureStyle.class,
2230                 Notification.MessagingStyle.class, Notification.CallStyle.class,
2231                 Notification.InboxStyle.class, Notification.MediaStyle.class,
2232                 Notification.DecoratedCustomViewStyle.class,
2233                 Notification.DecoratedMediaCustomViewStyle.class
2234         );
2235 
2236         for (Class<? extends Notification.Style> platformStyleClass : platformStyleClasses) {
2237             assertThat(Notification.getNotificationStyleClass(platformStyleClass.getName()))
2238                     .isEqualTo(platformStyleClass);
2239         }
2240     }
2241 
2242     @Test
getNotificationStyleClass_forNotPlatformClassName_returnsNull()2243     public void getNotificationStyleClass_forNotPlatformClassName_returnsNull() {
2244         assertThat(Notification.getNotificationStyleClass(NotAPlatformStyle.class.getName()))
2245                 .isNull();
2246     }
2247 
2248     @Test
2249     @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
progressStyle_richOngoingEnabled_platformClass()2250     public void progressStyle_richOngoingEnabled_platformClass() {
2251         assertThat(
2252                 Notification.getNotificationStyleClass(Notification.ProgressStyle.class.getName()))
2253                 .isEqualTo(Notification.ProgressStyle.class);
2254     }
2255 
2256     @Test
2257     @DisableFlags(Flags.FLAG_API_RICH_ONGOING)
progressStyle_richOngoingDisabled_notPlatformClass()2258     public void progressStyle_richOngoingDisabled_notPlatformClass() {
2259         assertThat(
2260                 Notification.getNotificationStyleClass(Notification.ProgressStyle.class.getName()))
2261                 .isNull();
2262     }
2263 
2264     @Test
2265     @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
progressStyle_onSegmentChange_visiblyDifferent()2266     public void progressStyle_onSegmentChange_visiblyDifferent() {
2267         final Notification.Builder nProgress1 = new Notification.Builder(mContext, "test")
2268                 .setStyle(new Notification.ProgressStyle()
2269                         .addProgressSegment(new Notification.ProgressStyle.Segment(100))
2270                         .addProgressSegment(new Notification.ProgressStyle.Segment(50)
2271                                 .setColor(Color.RED)));
2272 
2273         final Notification.Builder nProgress2 = new Notification.Builder(mContext, "test")
2274                 .setStyle(new Notification.ProgressStyle()
2275                         .addProgressSegment(new Notification.ProgressStyle.Segment(100))
2276                         .addProgressSegment(new Notification.ProgressStyle.Segment(50)
2277                                 .setColor(Color.BLUE)));
2278 
2279         assertThat(Notification.areStyledNotificationsVisiblyDifferent(nProgress1, nProgress2))
2280                 .isTrue();
2281     }
2282 
2283     @Test
2284     @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
indeterminateProgressStyle_onSegmentChange_visiblyNotDifferent()2285     public void indeterminateProgressStyle_onSegmentChange_visiblyNotDifferent() {
2286         final Notification.Builder nProgress1 = new Notification.Builder(mContext, "test")
2287                 .setStyle(new Notification.ProgressStyle().setProgressIndeterminate(true)
2288                         .addProgressSegment(new Notification.ProgressStyle.Segment(100))
2289                         .addProgressSegment(new Notification.ProgressStyle.Segment(50)
2290                                 .setColor(Color.RED)));
2291 
2292         final Notification.Builder nProgress2 = new Notification.Builder(mContext, "test")
2293                 .setStyle(new Notification.ProgressStyle().setProgressIndeterminate(true)
2294                         .addProgressSegment(new Notification.ProgressStyle.Segment(100))
2295                         .addProgressSegment(new Notification.ProgressStyle.Segment(50)
2296                                 .setColor(Color.BLUE)));
2297 
2298         assertThat(Notification.areStyledNotificationsVisiblyDifferent(nProgress1, nProgress2))
2299                 .isFalse();
2300     }
2301 
2302     @Test
2303     @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
progressStyle_onStartIconChange_visiblyDifferent()2304     public void progressStyle_onStartIconChange_visiblyDifferent() {
2305         final Icon icon1 = Icon.createWithBitmap(BitmapFactory.decodeResource(
2306                 mContext.getResources(), com.android.frameworks.coretests.R.drawable.test128x96));
2307 
2308         final Icon icon2 = Icon.createWithBitmap(
2309                 Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888));
2310 
2311         final Notification.Builder nProgress1 = new Notification.Builder(mContext, "test")
2312                 .setStyle(new Notification.ProgressStyle().setProgressStartIcon(icon1));
2313         final Notification.Builder nProgress2 = new Notification.Builder(mContext, "test")
2314                 .setStyle(new Notification.ProgressStyle().setProgressStartIcon(icon2));
2315 
2316         assertThat(Notification.areStyledNotificationsVisiblyDifferent(nProgress1, nProgress2))
2317                 .isTrue();
2318     }
2319 
2320     @Test
2321     @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
progressStyle_onEndIconChange_visiblyDifferent()2322     public void progressStyle_onEndIconChange_visiblyDifferent() {
2323         final Icon icon1 = Icon.createWithBitmap(BitmapFactory.decodeResource(
2324                 mContext.getResources(), com.android.frameworks.coretests.R.drawable.test128x96));
2325 
2326         final Icon icon2 = Icon.createWithBitmap(
2327                 Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888));
2328 
2329         final Notification.Builder nProgress1 = new Notification.Builder(mContext, "test")
2330                 .setStyle(new Notification.ProgressStyle().setProgressEndIcon(icon1));
2331         final Notification.Builder nProgress2 = new Notification.Builder(mContext, "test")
2332                 .setStyle(new Notification.ProgressStyle().setProgressEndIcon(icon2));
2333 
2334         assertThat(Notification.areStyledNotificationsVisiblyDifferent(nProgress1, nProgress2))
2335                 .isTrue();
2336     }
2337 
2338     @Test
2339     @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
progressStyle_onProgressChange_visiblyDifferent()2340     public void progressStyle_onProgressChange_visiblyDifferent() {
2341         final Notification.Builder nProgress1 = new Notification.Builder(mContext, "test")
2342                 .setStyle(new Notification.ProgressStyle().setProgress(20));
2343         final Notification.Builder nProgress2 = new Notification.Builder(mContext, "test")
2344                 .setStyle(new Notification.ProgressStyle().setProgress(21));
2345 
2346         assertThat(Notification.areStyledNotificationsVisiblyDifferent(nProgress1, nProgress2))
2347                 .isTrue();
2348     }
2349 
2350     @Test
2351     @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
indeterminateProgressStyle_onProgressChange_visiblyNotDifferent()2352     public void indeterminateProgressStyle_onProgressChange_visiblyNotDifferent() {
2353         final Notification.Builder nProgress1 = new Notification.Builder(mContext, "test")
2354                 .setStyle(new Notification.ProgressStyle()
2355                         .setProgressIndeterminate(true).setProgress(20));
2356         final Notification.Builder nProgress2 = new Notification.Builder(mContext, "test")
2357                 .setStyle(new Notification.ProgressStyle()
2358                         .setProgressIndeterminate(true).setProgress(21));
2359 
2360         assertThat(Notification.areStyledNotificationsVisiblyDifferent(nProgress1, nProgress2))
2361                 .isFalse();
2362     }
2363 
2364     @Test
2365     @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
progressStyle_onIsStyledByProgressChange_visiblyDifferent()2366     public void progressStyle_onIsStyledByProgressChange_visiblyDifferent() {
2367         final Notification.Builder nProgress1 = new Notification.Builder(mContext, "test")
2368                 .setStyle(new Notification.ProgressStyle().setStyledByProgress(true));
2369         final Notification.Builder nProgress2 = new Notification.Builder(mContext, "test")
2370                 .setStyle(new Notification.ProgressStyle().setStyledByProgress(false));
2371 
2372         assertThat(Notification.areStyledNotificationsVisiblyDifferent(nProgress1, nProgress2))
2373                 .isTrue();
2374     }
2375 
2376     @Test
2377     @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
indeterminateProgressStyle_onIsStyledByProgressChange_visiblyNotDifferent()2378     public void indeterminateProgressStyle_onIsStyledByProgressChange_visiblyNotDifferent() {
2379         final Notification.Builder nProgress1 = new Notification.Builder(mContext, "test")
2380                 .setStyle(new Notification.ProgressStyle()
2381                         .setProgressIndeterminate(true).setStyledByProgress(true));
2382         final Notification.Builder nProgress2 = new Notification.Builder(mContext, "test")
2383                 .setStyle(new Notification.ProgressStyle()
2384                         .setProgressIndeterminate(true).setStyledByProgress(false));
2385 
2386         assertThat(Notification.areStyledNotificationsVisiblyDifferent(nProgress1, nProgress2))
2387                 .isFalse();
2388     }
2389 
2390     @Test
2391     @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
progressStyle_onProgressPointChange_visiblyDifferent()2392     public void progressStyle_onProgressPointChange_visiblyDifferent() {
2393         final Notification.Builder nProgress1 = new Notification.Builder(mContext, "test")
2394                 .setStyle(new Notification.ProgressStyle()
2395                         .addProgressPoint(new Notification.ProgressStyle.Point(10)));
2396         final Notification.Builder nProgress2 = new Notification.Builder(mContext, "test")
2397                 .setStyle(new Notification.ProgressStyle()
2398                         .addProgressPoint(new Notification.ProgressStyle.Point(12)));
2399 
2400         assertThat(Notification.areStyledNotificationsVisiblyDifferent(nProgress1, nProgress2))
2401                 .isTrue();
2402     }
2403 
2404     @Test
2405     @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
indeterminateProgressStyle_onProgressPointChange_visiblyNotDifferent()2406     public void indeterminateProgressStyle_onProgressPointChange_visiblyNotDifferent() {
2407         final Notification.Builder nProgress1 = new Notification.Builder(mContext, "test")
2408                 .setStyle(new Notification.ProgressStyle().setProgressIndeterminate(true)
2409                         .addProgressPoint(new Notification.ProgressStyle.Point(10)));
2410         final Notification.Builder nProgress2 = new Notification.Builder(mContext, "test")
2411                 .setStyle(new Notification.ProgressStyle().setProgressIndeterminate(true)
2412                         .addProgressPoint(new Notification.ProgressStyle.Point(12)));
2413 
2414         assertThat(Notification.areStyledNotificationsVisiblyDifferent(nProgress1, nProgress2))
2415                 .isFalse();
2416     }
2417 
2418     @Test
2419     @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
progressStyle_onTrackerIconChange_visiblyDifferent()2420     public void progressStyle_onTrackerIconChange_visiblyDifferent() {
2421         final Icon icon1 = Icon.createWithBitmap(BitmapFactory.decodeResource(
2422                 mContext.getResources(), com.android.frameworks.coretests.R.drawable.test128x96));
2423 
2424         final Icon icon2 = Icon.createWithBitmap(
2425                 Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888));
2426 
2427         final Notification.Builder nProgress1 = new Notification.Builder(mContext, "test")
2428                 .setStyle(new Notification.ProgressStyle().setProgressTrackerIcon(icon1));
2429         final Notification.Builder nProgress2 = new Notification.Builder(mContext, "test")
2430                 .setStyle(new Notification.ProgressStyle().setProgressTrackerIcon(icon2));
2431 
2432         assertThat(Notification.areStyledNotificationsVisiblyDifferent(nProgress1, nProgress2))
2433                 .isTrue();
2434     }
2435 
2436     @Test
2437     @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
indeterminateProgressStyle_onTrackerIconChange_visiblyNotDifferent()2438     public void indeterminateProgressStyle_onTrackerIconChange_visiblyNotDifferent() {
2439         final Icon icon1 = Icon.createWithBitmap(BitmapFactory.decodeResource(
2440                 mContext.getResources(), com.android.frameworks.coretests.R.drawable.test128x96));
2441 
2442         final Icon icon2 = Icon.createWithBitmap(
2443                 Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888));
2444 
2445         final Notification.Builder nProgress1 = new Notification.Builder(mContext, "test")
2446                 .setStyle(new Notification.ProgressStyle().setProgressIndeterminate(true)
2447                         .setProgressTrackerIcon(icon1));
2448         final Notification.Builder nProgress2 = new Notification.Builder(mContext, "test")
2449                 .setStyle(new Notification.ProgressStyle()
2450                         .setProgressIndeterminate(true).setProgressTrackerIcon(icon2));
2451 
2452         assertThat(Notification.areStyledNotificationsVisiblyDifferent(nProgress1, nProgress2))
2453                 .isFalse();
2454     }
2455 
2456     @Test
2457     @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
progressStyle_onIndeterminateChange_visiblyDifferent()2458     public void progressStyle_onIndeterminateChange_visiblyDifferent() {
2459         final Notification.Builder nProgress1 = new Notification.Builder(mContext, "test")
2460                 .setStyle(new Notification.ProgressStyle().setProgressIndeterminate(true));
2461         final Notification.Builder nProgress2 = new Notification.Builder(mContext, "test")
2462                 .setStyle(new Notification.ProgressStyle().setProgressIndeterminate(false));
2463 
2464         assertThat(Notification.areStyledNotificationsVisiblyDifferent(nProgress1, nProgress2))
2465                 .isTrue();
2466     }
2467 
2468     @Test
2469     @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
progressStyle_getProgressMax_default100()2470     public void progressStyle_getProgressMax_default100() {
2471         final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle();
2472         assertThat(progressStyle.getProgressMax()).isEqualTo(100);
2473     }
2474 
2475     @Test
2476     @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
progressStyle_getProgressMax_noSegments_returnsDefault()2477     public void progressStyle_getProgressMax_noSegments_returnsDefault() {
2478         final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle();
2479         progressStyle.setProgressSegments(Collections.emptyList());
2480         assertThat(progressStyle.getProgressMax()).isEqualTo(100);
2481     }
2482 
2483     @Test
2484     @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
progressStyle_getProgressMax_returnsSumOfSegmentLength()2485     public void progressStyle_getProgressMax_returnsSumOfSegmentLength() {
2486         final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle();
2487         progressStyle
2488                 .setProgressSegments(List.of(new Notification.ProgressStyle.Segment(15),
2489                         new Notification.ProgressStyle.Segment(25)))
2490                 .addProgressSegment(new Notification.ProgressStyle.Segment(10))
2491                 .addProgressSegment(new Notification.ProgressStyle.Segment(20));
2492 
2493         assertThat(progressStyle.getProgressMax()).isEqualTo(70);
2494     }
2495 
2496     @Test
2497     @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
progressStyle_getProgressMax_onSetProgressSegments_resets()2498     public void progressStyle_getProgressMax_onSetProgressSegments_resets() {
2499         final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle();
2500         progressStyle
2501                 .addProgressSegment(new Notification.ProgressStyle.Segment(10))
2502                 .addProgressSegment(new Notification.ProgressStyle.Segment(20))
2503                 .setProgressSegments(List.of(new Notification.ProgressStyle.Segment(15),
2504                         new Notification.ProgressStyle.Segment(25)));
2505 
2506         assertThat(progressStyle.getProgressMax()).isEqualTo(40);
2507     }
2508 
2509     @Test
2510     @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
progressStyle_getProgressMax_onSegmentOverflow_returnsDefault()2511     public void progressStyle_getProgressMax_onSegmentOverflow_returnsDefault() {
2512         final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle();
2513         progressStyle
2514                 .addProgressSegment(new Notification.ProgressStyle.Segment(Integer.MAX_VALUE))
2515                 .addProgressSegment(new Notification.ProgressStyle.Segment(10));
2516 
2517         assertThat(progressStyle.getProgressMax()).isEqualTo(100);
2518     }
2519 
2520     @Test
2521     @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
progressStyle_getProgressMax_onSegmentLimitExceeded_returnsSumOfSegmentLength()2522     public void progressStyle_getProgressMax_onSegmentLimitExceeded_returnsSumOfSegmentLength() {
2523         // GIVEN
2524         final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle();
2525         // limit is 10 for ProgressStyle
2526         for (int i = 0; i < 30; i++) {
2527             progressStyle
2528                     .addProgressSegment(new Notification.ProgressStyle.Segment(10));
2529         }
2530 
2531         // THEN
2532         assertThat(progressStyle.getProgressMax()).isEqualTo(300);
2533     }
2534 
2535     @Test
2536     @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
progressStyle_addProgressSegment_dropsInvalidSegments()2537     public void progressStyle_addProgressSegment_dropsInvalidSegments() {
2538         // GIVEN
2539         final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle();
2540         // Segments should be a positive integer.
2541         progressStyle
2542                 .addProgressSegment(new Notification.ProgressStyle.Segment(0));
2543         progressStyle
2544                 .addProgressSegment(new Notification.ProgressStyle.Segment(-1));
2545 
2546         // THEN
2547         assertThat(progressStyle.getProgressSegments()).isEmpty();
2548     }
2549 
2550     @Test
2551     @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
progressStyle_setProgressSegment_dropsInvalidSegments()2552     public void progressStyle_setProgressSegment_dropsInvalidSegments() {
2553         // GIVEN
2554         final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle();
2555         // Segments should be a positive integer.
2556         progressStyle
2557                 .setProgressSegments(List.of(new Notification.ProgressStyle.Segment(0),
2558                         new Notification.ProgressStyle.Segment(-1)));
2559 
2560         // THEN
2561         assertThat(progressStyle.getProgressSegments()).isEmpty();
2562     }
2563 
2564     @Test
2565     @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
progressStyle_addProgressPoint_dropsNegativePoints()2566     public void progressStyle_addProgressPoint_dropsNegativePoints() {
2567         // GIVEN
2568         final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle();
2569         // Points should not be a negative integer.
2570         progressStyle
2571                 .addProgressPoint(new Notification.ProgressStyle.Point(-1))
2572                 .addProgressPoint(new Notification.ProgressStyle.Point(-100));
2573 
2574         // THEN
2575         assertThat(progressStyle.getProgressPoints()).isEmpty();
2576     }
2577 
2578     @Test
2579     @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
progressStyle_setProgressPoint_dropsNegativePoints()2580     public void progressStyle_setProgressPoint_dropsNegativePoints() {
2581         // GIVEN
2582         final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle();
2583         // Points should not be a negative integer.
2584         progressStyle
2585                 .setProgressPoints(List.of(new Notification.ProgressStyle.Point(-1),
2586                         new Notification.ProgressStyle.Point(-100)));
2587 
2588         // THEN
2589         assertThat(progressStyle.getProgressPoints()).isEmpty();
2590     }
2591 
2592     @Test
2593     @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
progressStyle_addProgressPoint_dropsZeroPoints()2594     public void progressStyle_addProgressPoint_dropsZeroPoints() {
2595         // GIVEN
2596         final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle();
2597         // Points should not be a negative integer.
2598         progressStyle
2599                 .addProgressPoint(new Notification.ProgressStyle.Point(0));
2600 
2601         // THEN
2602         assertThat(progressStyle.getProgressPoints()).isEmpty();
2603     }
2604 
2605     @Test
2606     @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
progressStyle_setProgressPoint_dropsZeroPoints()2607     public void progressStyle_setProgressPoint_dropsZeroPoints() {
2608         // GIVEN
2609         final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle();
2610         // Points should not be a negative integer.
2611         progressStyle
2612                 .setProgressPoints(List.of(new Notification.ProgressStyle.Point(0)));
2613 
2614         // THEN
2615         assertThat(progressStyle.getProgressPoints()).isEmpty();
2616     }
2617 
2618     @Test
2619     @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
progressStyle_createProgressModel_ignoresPointsAtMax()2620     public void progressStyle_createProgressModel_ignoresPointsAtMax() {
2621         // GIVEN
2622         final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle();
2623         progressStyle.addProgressSegment(new Notification.ProgressStyle.Segment(100));
2624         // Points should not larger than progress maximum.
2625         progressStyle
2626                 .addProgressPoint(new Notification.ProgressStyle.Point(100));
2627 
2628         // THEN
2629         assertThat(progressStyle.createProgressModel(Color.BLUE, Color.RED).getPoints()).isEmpty();
2630     }
2631 
2632     @Test
2633     @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
progressStyle_createProgressModel_ignoresPointsExceedingMax()2634     public void progressStyle_createProgressModel_ignoresPointsExceedingMax() {
2635         // GIVEN
2636         final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle();
2637         progressStyle.addProgressSegment(new Notification.ProgressStyle.Segment(100));
2638         // Points should not larger than progress maximum.
2639         progressStyle
2640                 .addProgressPoint(new Notification.ProgressStyle.Point(101))
2641                 .addProgressPoint(new Notification.ProgressStyle.Point(500));
2642 
2643         // THEN
2644         assertThat(progressStyle.createProgressModel(Color.BLUE, Color.RED).getPoints()).isEmpty();
2645     }
2646 
2647     @Test
2648     @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
progressStyle_createProgressModel_ignoresOverLimitPoints()2649     public void progressStyle_createProgressModel_ignoresOverLimitPoints() {
2650         // GIVEN
2651         final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle();
2652         progressStyle.addProgressSegment(new Notification.ProgressStyle.Segment(100));
2653 
2654         // maximum 4 points are going to be rendered.
2655         progressStyle
2656                 .addProgressPoint(new Notification.ProgressStyle.Point(0))
2657                 .addProgressPoint(new Notification.ProgressStyle.Point(20))
2658                 .addProgressPoint(new Notification.ProgressStyle.Point(150))
2659                 .addProgressPoint(new Notification.ProgressStyle.Point(50))
2660                 .addProgressPoint(new Notification.ProgressStyle.Point(70))
2661                 .addProgressPoint(new Notification.ProgressStyle.Point(80))
2662                 .addProgressPoint(new Notification.ProgressStyle.Point(90))
2663                 .addProgressPoint(new Notification.ProgressStyle.Point(95))
2664                 .addProgressPoint(new Notification.ProgressStyle.Point(100));
2665         final int backgroundColor = Color.RED;
2666         final int defaultProgressColor = Color.BLUE;
2667         final int expectedProgressColor = Notification.ProgressStyle.sanitizeProgressColor(
2668                 /* color = */Notification.COLOR_DEFAULT,
2669                 /* bg = */backgroundColor,
2670                 /* defaultColor = */defaultProgressColor);
2671 
2672         // THEN
2673         assertThat(progressStyle.createProgressModel(defaultProgressColor, backgroundColor)
2674                 .getPoints()).isEqualTo(
2675                         List.of(new Notification.ProgressStyle.Point(20)
2676                                 .setColor(expectedProgressColor),
2677                                 new Notification.ProgressStyle.Point(50)
2678                                 .setColor(expectedProgressColor),
2679                                 new Notification.ProgressStyle.Point(70)
2680                                 .setColor(expectedProgressColor),
2681                                 new Notification.ProgressStyle.Point(80)
2682                                         .setColor(expectedProgressColor)
2683                         )
2684         );
2685     }
2686 
2687     @Test
2688     @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
progressStyle_createProgressModel_mergeSegmentsOnOverflow()2689     public void progressStyle_createProgressModel_mergeSegmentsOnOverflow() {
2690         // GIVEN
2691         final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle();
2692 
2693         for (int i = 0; i < 15; i++) {
2694             progressStyle
2695                     .addProgressSegment(new Notification.ProgressStyle.Segment(10));
2696         }
2697 
2698         final NotificationProgressModel progressModel = progressStyle.createProgressModel(
2699                 Color.BLUE, Color.RED);
2700 
2701         // THEN
2702         assertThat(progressModel.getSegments().size()).isEqualTo(1);
2703         assertThat(progressModel.getProgressMax()).isEqualTo(150);
2704     }
2705 
2706     @Test
2707     @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
progressStyle_createProgressModel_useSegmentColorWhenAllMatch()2708     public void progressStyle_createProgressModel_useSegmentColorWhenAllMatch() {
2709         // GIVEN
2710         final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle();
2711         final int segmentColor = Color.YELLOW;
2712         final int defaultProgressColor = Color.BLUE;
2713         final int backgroundColor = Color.RED;
2714         // contrast ensured color for segmentColor.
2715         final int expectedSegmentColor = Notification.ProgressStyle.sanitizeProgressColor(
2716                 /* color = */   segmentColor,
2717                 /* bg = */  backgroundColor,
2718                 /* defaultColor = */ defaultProgressColor);
2719 
2720         for (int i = 0; i < 15; i++) {
2721             progressStyle
2722                     .addProgressSegment(new Notification.ProgressStyle.Segment(10)
2723                             .setColor(segmentColor));
2724         }
2725 
2726         final NotificationProgressModel progressModel = progressStyle.createProgressModel(
2727                 defaultProgressColor, backgroundColor);
2728 
2729         // THEN
2730         assertThat(progressModel.getSegments())
2731                 .isEqualTo(List.of(new Notification.ProgressStyle.Segment(150)
2732                         .setColor(expectedSegmentColor)));
2733     }
2734 
2735     @Test
2736     @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
progressStyle_createProgressModel_useDefaultColorWhenAllNotMatch()2737     public void progressStyle_createProgressModel_useDefaultColorWhenAllNotMatch() {
2738         // GIVEN
2739         final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle();
2740         final int defaultProgressColor = Color.BLUE;
2741         final int backgroundColor = Color.RED;
2742         // contrast ensured color for default progress color.
2743         final int expectedSegmentColor = Notification.ProgressStyle.sanitizeProgressColor(
2744                 /* color = */  defaultProgressColor,
2745                 /* bg = */ backgroundColor,
2746                 /* defaultColor = */ defaultProgressColor);
2747 
2748         for (int i = 0; i < 15; i++) {
2749             progressStyle
2750                     .addProgressSegment(new Notification.ProgressStyle.Segment(5)
2751                             .setColor(Color.BLUE))
2752                     .addProgressSegment(new Notification.ProgressStyle.Segment(5)
2753                             .setColor(Color.CYAN));
2754         }
2755 
2756         final NotificationProgressModel progressModel = progressStyle.createProgressModel(
2757                 defaultProgressColor, backgroundColor);
2758 
2759         // THEN
2760         assertThat(progressModel.getSegments())
2761                 .isEqualTo(List.of(new Notification.ProgressStyle.Segment(150)
2762                         .setColor(expectedSegmentColor)));
2763     }
2764 
2765     @Test
2766     @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
progressStyle_indeterminate_defaultValueFalse()2767     public void progressStyle_indeterminate_defaultValueFalse() {
2768         final Notification.ProgressStyle progressStyle1 = new Notification.ProgressStyle();
2769 
2770         assertThat(progressStyle1.isProgressIndeterminate()).isFalse();
2771     }
2772 
2773     @Test
2774     @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
progressStyle_styledByProgress_defaultValueTrue()2775     public void progressStyle_styledByProgress_defaultValueTrue() {
2776         final Notification.ProgressStyle progressStyle1 = new Notification.ProgressStyle();
2777 
2778         assertThat(progressStyle1.isStyledByProgress()).isTrue();
2779     }
assertValid(Notification.Colors c)2780     private void assertValid(Notification.Colors c) {
2781         // Assert that all colors are populated
2782         assertThat(c.getBackgroundColor()).isNotEqualTo(Notification.COLOR_INVALID);
2783         assertThat(c.getProtectionColor()).isNotEqualTo(Notification.COLOR_INVALID);
2784         assertThat(c.getPrimaryTextColor()).isNotEqualTo(Notification.COLOR_INVALID);
2785         assertThat(c.getSecondaryTextColor()).isNotEqualTo(Notification.COLOR_INVALID);
2786         assertThat(c.getPrimaryAccentColor()).isNotEqualTo(Notification.COLOR_INVALID);
2787         assertThat(c.getSecondaryAccentColor()).isNotEqualTo(Notification.COLOR_INVALID);
2788         assertThat(c.getTertiaryAccentColor()).isNotEqualTo(Notification.COLOR_INVALID);
2789         assertThat(c.getOnTertiaryAccentTextColor()).isNotEqualTo(Notification.COLOR_INVALID);
2790         assertThat(c.getTertiaryFixedDimAccentColor()).isNotEqualTo(Notification.COLOR_INVALID);
2791         assertThat(c.getOnTertiaryFixedAccentTextColor()).isNotEqualTo(Notification.COLOR_INVALID);
2792         assertThat(c.getErrorColor()).isNotEqualTo(Notification.COLOR_INVALID);
2793         assertThat(c.getContrastColor()).isNotEqualTo(Notification.COLOR_INVALID);
2794         assertThat(c.getRippleAlpha()).isAtLeast(0x00);
2795         assertThat(c.getRippleAlpha()).isAtMost(0xff);
2796 
2797         // Assert that various colors have sufficient contrast with the background
2798         assertContrastIsAtLeast(c.getPrimaryTextColor(), c.getBackgroundColor(), 4.5);
2799         assertContrastIsAtLeast(c.getSecondaryTextColor(), c.getBackgroundColor(), 4.5);
2800         assertContrastIsAtLeast(c.getPrimaryAccentColor(), c.getBackgroundColor(), 4.5);
2801         assertContrastIsAtLeast(c.getErrorColor(), c.getBackgroundColor(), 4.5);
2802         assertContrastIsAtLeast(c.getContrastColor(), c.getBackgroundColor(), 4.5);
2803 
2804         // These colors are only used for emphasized buttons; they do not need contrast
2805         assertContrastIsAtLeast(c.getSecondaryAccentColor(), c.getBackgroundColor(), 1);
2806         assertContrastIsAtLeast(c.getTertiaryAccentColor(), c.getBackgroundColor(), 1);
2807         assertContrastIsAtLeast(c.getTertiaryFixedDimAccentColor(), c.getBackgroundColor(), 1);
2808 
2809         // The text that is used within the accent color DOES need to have contrast
2810         assertContrastIsAtLeast(c.getOnTertiaryAccentTextColor(), c.getTertiaryAccentColor(), 4.5);
2811         assertContrastIsAtLeast(c.getOnTertiaryFixedAccentTextColor(),
2812                 c.getTertiaryFixedDimAccentColor(), 4.5);
2813     }
2814 
resolveColorsInNightMode(boolean nightMode, Notification.Colors c, int rawColor, boolean colorized)2815     private void resolveColorsInNightMode(boolean nightMode, Notification.Colors c, int rawColor,
2816             boolean colorized) {
2817         runInNightMode(nightMode,
2818                 () -> c.resolvePalette(mContext, rawColor, colorized, nightMode));
2819     }
2820 
runInNightMode(boolean nightMode, Runnable task)2821     private void runInNightMode(boolean nightMode, Runnable task) {
2822         final String initialNightMode = changeNightMode(nightMode);
2823         try {
2824             Configuration currentConfig = mContext.getResources().getConfiguration();
2825             boolean isNightMode = (currentConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK)
2826                     == Configuration.UI_MODE_NIGHT_YES;
2827             assertEquals(nightMode, isNightMode);
2828             task.run();
2829         } finally {
2830             runShellCommand("cmd uimode night " + initialNightMode);
2831         }
2832     }
2833 
2834 
2835     // Change the night mode and return the previous mode
changeNightMode(boolean nightMode)2836     private String changeNightMode(boolean nightMode) {
2837         final String nightModeText = runShellCommand("cmd uimode night");
2838         final String[] nightModeSplit = nightModeText.split(":");
2839         if (nightModeSplit.length != 2) {
2840             fail("Failed to get initial night mode value from " + nightModeText);
2841         }
2842         String previousMode = nightModeSplit[1].trim();
2843         runShellCommand("cmd uimode night " + (nightMode ? "yes" : "no"));
2844         return previousMode;
2845     }
2846 
2847     /**
2848       * Writes an arbitrary {@link Parcelable} into a {@link Parcel} using its writeToParcel
2849       * method before reading it out again to check that it was sent properly.
2850       */
writeAndReadParcelable(T original)2851     private static <T extends Parcelable> T writeAndReadParcelable(T original) {
2852         Parcel p = Parcel.obtain();
2853         p.writeParcelable(original, /* flags */ 0);
2854         p.setDataPosition(0);
2855         return p.readParcelable(/* classLoader */ null);
2856     }
2857 
2858     /**
2859      * Creates a Notification.Action by mocking initial dependencies and then applying
2860      * transformations if they're defined.
2861      */
makeNotificationAction( @ullable Consumer<Notification.Action.Builder> transformation)2862     private Notification.Action makeNotificationAction(
2863             @Nullable Consumer<Notification.Action.Builder> transformation) {
2864         Notification.Action.Builder actionBuilder =
2865                 new Notification.Action.Builder(null, "Test Title", null);
2866         if (transformation != null) {
2867             transformation.accept(actionBuilder);
2868         }
2869         return actionBuilder.build();
2870     }
2871 
2872     /**
2873      * Creates a PendingIntent with the given action.
2874      */
createPendingIntent(String action)2875     private PendingIntent createPendingIntent(String action) {
2876         return PendingIntent.getActivity(mContext, 0,
2877                 new Intent(action).setPackage(mContext.getPackageName()),
2878                 PendingIntent.FLAG_MUTABLE);
2879     }
2880 
2881     private static class NotAPlatformStyle extends Notification.Style {
2882         @Override
areNotificationsVisiblyDifferent(Notification.Style other)2883         public boolean areNotificationsVisiblyDifferent(Notification.Style other) {
2884             return false;
2885         }
2886     }
2887 }
2888