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