• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.statusbar.notification.row;
18 
19 import static android.app.Notification.FLAG_BUBBLE;
20 import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
21 import static android.app.NotificationManager.IMPORTANCE_HIGH;
22 
23 import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking;
24 
25 import static org.junit.Assert.assertEquals;
26 import static org.junit.Assert.assertTrue;
27 import static org.mockito.ArgumentMatchers.any;
28 import static org.mockito.ArgumentMatchers.anyInt;
29 import static org.mockito.Mockito.mock;
30 import static org.mockito.Mockito.verify;
31 import static org.mockito.Mockito.when;
32 
33 import android.annotation.Nullable;
34 import android.app.ActivityManager;
35 import android.app.Notification;
36 import android.app.Notification.BubbleMetadata;
37 import android.app.NotificationChannel;
38 import android.app.PendingIntent;
39 import android.content.Context;
40 import android.content.Intent;
41 import android.content.pm.LauncherApps;
42 import android.graphics.drawable.Icon;
43 import android.os.UserHandle;
44 import android.service.notification.StatusBarNotification;
45 import android.testing.TestableLooper;
46 import android.text.TextUtils;
47 import android.view.LayoutInflater;
48 import android.widget.RemoteViews;
49 
50 import com.android.internal.logging.MetricsLogger;
51 import com.android.internal.statusbar.IStatusBarService;
52 import com.android.systemui.TestableDependency;
53 import com.android.systemui.classifier.FalsingCollectorFake;
54 import com.android.systemui.classifier.FalsingManagerFake;
55 import com.android.systemui.flags.FeatureFlags;
56 import com.android.systemui.media.controls.util.MediaFeatureFlag;
57 import com.android.systemui.media.dialog.MediaOutputDialogFactory;
58 import com.android.systemui.plugins.statusbar.StatusBarStateController;
59 import com.android.systemui.statusbar.NotificationMediaManager;
60 import com.android.systemui.statusbar.NotificationRemoteInputManager;
61 import com.android.systemui.statusbar.NotificationShadeWindowController;
62 import com.android.systemui.statusbar.SmartReplyController;
63 import com.android.systemui.statusbar.notification.ConversationNotificationProcessor;
64 import com.android.systemui.statusbar.notification.SourceType;
65 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
66 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
67 import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
68 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
69 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
70 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
71 import com.android.systemui.statusbar.notification.icon.IconBuilder;
72 import com.android.systemui.statusbar.notification.icon.IconManager;
73 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
74 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.ExpandableNotificationRowLogger;
75 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.OnExpandClickListener;
76 import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
77 import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
78 import com.android.systemui.statusbar.phone.KeyguardBypassController;
79 import com.android.systemui.statusbar.policy.InflatedSmartReplyState;
80 import com.android.systemui.statusbar.policy.InflatedSmartReplyViewHolder;
81 import com.android.systemui.statusbar.policy.SmartReplyConstants;
82 import com.android.systemui.statusbar.policy.SmartReplyStateInflater;
83 import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent;
84 import com.android.systemui.tests.R;
85 import com.android.systemui.wmshell.BubblesManager;
86 import com.android.systemui.wmshell.BubblesTestActivity;
87 
88 import org.mockito.ArgumentCaptor;
89 
90 import java.util.Optional;
91 import java.util.concurrent.CountDownLatch;
92 import java.util.concurrent.Executor;
93 import java.util.concurrent.TimeUnit;
94 
95 /**
96  * A helper class to create {@link ExpandableNotificationRow} (for both individual and group
97  * notifications).
98  */
99 public class NotificationTestHelper {
100 
101     /** Package name for testing purposes. */
102     public static final String PKG = "com.android.systemui";
103     /** System UI id for testing purposes. */
104     public static final int UID = 1000;
105     /** Current {@link UserHandle} of the system. */
106     public static final UserHandle USER_HANDLE = UserHandle.of(ActivityManager.getCurrentUser());
107 
108     private static final String GROUP_KEY = "gruKey";
109     private static final String APP_NAME = "appName";
110 
111     private final Context mContext;
112     private final TestableLooper mTestLooper;
113     private int mId;
114     private final ExpandableNotificationRowLogger mMockLogger;
115     private final GroupMembershipManager mGroupMembershipManager;
116     private final GroupExpansionManager mGroupExpansionManager;
117     private ExpandableNotificationRow mRow;
118     private final HeadsUpManagerPhone mHeadsUpManager;
119     private final NotifBindPipeline mBindPipeline;
120     private final NotifCollectionListener mBindPipelineEntryListener;
121     private final RowContentBindStage mBindStage;
122     private final IconManager mIconManager;
123     private final StatusBarStateController mStatusBarStateController;
124     private final PeopleNotificationIdentifier mPeopleNotificationIdentifier;
125     public final OnUserInteractionCallback mOnUserInteractionCallback;
126     public final Runnable mFutureDismissalRunnable;
127     private @InflationFlag int mDefaultInflationFlags;
128     private FeatureFlags mFeatureFlags;
129 
NotificationTestHelper( Context context, TestableDependency dependency, TestableLooper testLooper)130     public NotificationTestHelper(
131             Context context,
132             TestableDependency dependency,
133             TestableLooper testLooper) {
134         mContext = context;
135         mTestLooper = testLooper;
136         dependency.injectMockDependency(NotificationMediaManager.class);
137         dependency.injectMockDependency(NotificationShadeWindowController.class);
138         dependency.injectMockDependency(MediaOutputDialogFactory.class);
139         mMockLogger = mock(ExpandableNotificationRowLogger.class);
140         mStatusBarStateController = mock(StatusBarStateController.class);
141         mGroupMembershipManager = mock(GroupMembershipManager.class);
142         mGroupExpansionManager = mock(GroupExpansionManager.class);
143         mHeadsUpManager = mock(HeadsUpManagerPhone.class);
144         mIconManager = new IconManager(
145                 mock(CommonNotifCollection.class),
146                 mock(LauncherApps.class),
147                 new IconBuilder(mContext));
148 
149         NotificationContentInflater contentBinder = new NotificationContentInflater(
150                 mock(NotifRemoteViewCache.class),
151                 mock(NotificationRemoteInputManager.class),
152                 mock(ConversationNotificationProcessor.class),
153                 mock(MediaFeatureFlag.class),
154                 mock(Executor.class),
155                 new MockSmartReplyInflater());
156         contentBinder.setInflateSynchronously(true);
157         mBindStage = new RowContentBindStage(contentBinder,
158                 mock(NotifInflationErrorManager.class),
159                 mock(RowContentBindStageLogger.class));
160 
161         CommonNotifCollection collection = mock(CommonNotifCollection.class);
162 
163         mBindPipeline = new NotifBindPipeline(
164                 collection,
165                 mock(NotifBindPipelineLogger.class),
166                 mTestLooper.getLooper());
167         mBindPipeline.setStage(mBindStage);
168 
169         ArgumentCaptor<NotifCollectionListener> collectionListenerCaptor =
170                 ArgumentCaptor.forClass(NotifCollectionListener.class);
171         verify(collection).addCollectionListener(collectionListenerCaptor.capture());
172         mBindPipelineEntryListener = collectionListenerCaptor.getValue();
173         mPeopleNotificationIdentifier = mock(PeopleNotificationIdentifier.class);
174         mOnUserInteractionCallback = mock(OnUserInteractionCallback.class);
175         mFutureDismissalRunnable = mock(Runnable.class);
176         when(mOnUserInteractionCallback.registerFutureDismissal(any(), anyInt()))
177                 .thenReturn(mFutureDismissalRunnable);
178         mFeatureFlags = mock(FeatureFlags.class);
179     }
180 
setDefaultInflationFlags(@nflationFlag int defaultInflationFlags)181     public void setDefaultInflationFlags(@InflationFlag int defaultInflationFlags) {
182         mDefaultInflationFlags = defaultInflationFlags;
183     }
184 
setFeatureFlags(FeatureFlags featureFlags)185     public void setFeatureFlags(FeatureFlags featureFlags) {
186         mFeatureFlags = featureFlags;
187     }
188 
getMockLogger()189     public ExpandableNotificationRowLogger getMockLogger() {
190         return mMockLogger;
191     }
192 
193     /**
194      * Creates a generic row with rounded border.
195      *
196      * @return a generic row with the set roundness.
197      * @throws Exception
198      */
createRowWithRoundness( float topRoundness, float bottomRoundness, SourceType sourceType )199     public ExpandableNotificationRow createRowWithRoundness(
200             float topRoundness,
201             float bottomRoundness,
202             SourceType sourceType
203     ) throws Exception {
204         ExpandableNotificationRow row = createRow();
205         row.requestRoundness(topRoundness, bottomRoundness, sourceType, /*animate = */ false);
206         assertEquals(topRoundness, row.getTopRoundness(), /* delta = */ 0f);
207         assertEquals(bottomRoundness, row.getBottomRoundness(), /* delta = */ 0f);
208         return row;
209     }
210 
211     /**
212      * Creates a generic row.
213      *
214      * @return a generic row with no special properties.
215      * @throws Exception
216      */
createRow()217     public ExpandableNotificationRow createRow() throws Exception {
218         return createRow(PKG, UID, USER_HANDLE);
219     }
220 
221     /**
222      * Create a row with the package and user id specified.
223      *
224      * @param pkg package
225      * @param uid user id
226      * @return a row with a notification using the package and user id
227      * @throws Exception
228      */
createRow(String pkg, int uid, UserHandle userHandle)229     public ExpandableNotificationRow createRow(String pkg, int uid, UserHandle userHandle)
230             throws Exception {
231         return createRow(pkg, uid, userHandle, false /* isGroupSummary */, null /* groupKey */);
232     }
233 
234     /**
235      * Creates a row based off the notification given.
236      *
237      * @param notification the notification
238      * @return a row built off the notification
239      * @throws Exception
240      */
createRow(Notification notification)241     public ExpandableNotificationRow createRow(Notification notification) throws Exception {
242         return generateRow(notification, PKG, UID, USER_HANDLE, mDefaultInflationFlags);
243     }
244 
245     /**
246      * Create a row with the specified content views inflated in addition to the default.
247      *
248      * @param extraInflationFlags the flags corresponding to the additional content views that
249      *                            should be inflated
250      * @return a row with the specified content views inflated in addition to the default
251      * @throws Exception
252      */
createRow(@nflationFlag int extraInflationFlags)253     public ExpandableNotificationRow createRow(@InflationFlag int extraInflationFlags)
254             throws Exception {
255         return generateRow(createNotification(), PKG, UID, USER_HANDLE, extraInflationFlags);
256     }
257 
258     /**
259      * Returns an {@link ExpandableNotificationRow} group with the given number of child
260      * notifications.
261      */
createGroup(int numChildren)262     public ExpandableNotificationRow createGroup(int numChildren) throws Exception {
263         ExpandableNotificationRow row = createGroupSummary(GROUP_KEY);
264         for (int i = 0; i < numChildren; i++) {
265             ExpandableNotificationRow childRow = createGroupChild(GROUP_KEY);
266             row.addChildNotification(childRow);
267         }
268         return row;
269     }
270 
271     /** Returns a group notification with 2 child notifications. */
createGroup()272     public ExpandableNotificationRow createGroup() throws Exception {
273         return createGroup(2);
274     }
275 
createGroupSummary(String groupkey)276     private ExpandableNotificationRow createGroupSummary(String groupkey) throws Exception {
277         return createRow(PKG, UID, USER_HANDLE, true /* isGroupSummary */, groupkey);
278     }
279 
createGroupChild(String groupkey)280     private ExpandableNotificationRow createGroupChild(String groupkey) throws Exception {
281         return createRow(PKG, UID, USER_HANDLE, false /* isGroupSummary */, groupkey);
282     }
283 
284     /**
285      * Returns an {@link ExpandableNotificationRow} that should be shown as a bubble.
286      */
createBubble()287     public ExpandableNotificationRow createBubble()
288             throws Exception {
289         Notification n = createNotification(false /* isGroupSummary */,
290                 null /* groupKey */,
291                 makeBubbleMetadata(null /* deleteIntent */, false /* autoExpand */));
292         n.flags |= FLAG_BUBBLE;
293         ExpandableNotificationRow row = generateRow(n, PKG, UID, USER_HANDLE,
294                 mDefaultInflationFlags, IMPORTANCE_HIGH);
295         modifyRanking(row.getEntry())
296                 .setCanBubble(true)
297                 .build();
298         return row;
299     }
300 
301     /**
302      * Returns an {@link ExpandableNotificationRow} that should be shown as a bubble.
303      */
createShortcutBubble(String shortcutId)304     public ExpandableNotificationRow createShortcutBubble(String shortcutId)
305             throws Exception {
306         Notification n = createNotification(false /* isGroupSummary */,
307                 null /* groupKey */, makeShortcutBubbleMetadata(shortcutId));
308         n.flags |= FLAG_BUBBLE;
309         ExpandableNotificationRow row = generateRow(n, PKG, UID, USER_HANDLE,
310                 mDefaultInflationFlags, IMPORTANCE_HIGH);
311         modifyRanking(row.getEntry())
312                 .setCanBubble(true)
313                 .build();
314         return row;
315     }
316 
317     /**
318      * Returns an {@link ExpandableNotificationRow} that should be shown as a bubble and is part
319      * of a group of notifications.
320      */
createBubbleInGroup()321     public ExpandableNotificationRow createBubbleInGroup()
322             throws Exception {
323         Notification n = createNotification(false /* isGroupSummary */,
324                 GROUP_KEY /* groupKey */,
325                 makeBubbleMetadata(null /* deleteIntent */, false /* autoExpand */));
326         n.flags |= FLAG_BUBBLE;
327         ExpandableNotificationRow row = generateRow(n, PKG, UID, USER_HANDLE,
328                 mDefaultInflationFlags, IMPORTANCE_HIGH);
329         modifyRanking(row.getEntry())
330                 .setCanBubble(true)
331                 .build();
332         return row;
333     }
334 
335     /**
336      * Returns an {@link NotificationEntry} that should be shown as a bubble.
337      *
338      * @param deleteIntent the intent to assign to {@link BubbleMetadata#deleteIntent}
339      */
createBubble(@ullable PendingIntent deleteIntent)340     public NotificationEntry createBubble(@Nullable PendingIntent deleteIntent) {
341         return createBubble(makeBubbleMetadata(deleteIntent, false /* autoExpand */), USER_HANDLE);
342     }
343 
344     /**
345      * Returns an {@link NotificationEntry} that should be shown as a bubble.
346      *
347      * @param handle the user to associate with this bubble.
348      */
createBubble(UserHandle handle)349     public NotificationEntry createBubble(UserHandle handle) {
350         return createBubble(makeBubbleMetadata(null /* deleteIntent */, false /* autoExpand */),
351                 handle);
352     }
353 
354     /**
355      * Returns an {@link NotificationEntry} that should be shown as a auto-expanded bubble.
356      */
createAutoExpandedBubble()357     public NotificationEntry createAutoExpandedBubble() {
358         return createBubble(makeBubbleMetadata(null /* deleteIntent */, true /* autoExpand */),
359                 USER_HANDLE);
360     }
361 
362     /**
363      * Returns an {@link NotificationEntry} that should be shown as a bubble.
364      *
365      * @param userHandle the user to associate with this notification.
366      */
createBubble(BubbleMetadata metadata, UserHandle userHandle)367     private NotificationEntry createBubble(BubbleMetadata metadata, UserHandle userHandle) {
368         Notification n = createNotification(false /* isGroupSummary */, null /* groupKey */,
369                 metadata);
370         n.flags |= FLAG_BUBBLE;
371 
372         final NotificationChannel channel =
373                 new NotificationChannel(
374                         n.getChannelId(),
375                         n.getChannelId(),
376                         IMPORTANCE_HIGH);
377         channel.setBlockable(true);
378 
379         NotificationEntry entry = new NotificationEntryBuilder()
380                 .setPkg(PKG)
381                 .setOpPkg(PKG)
382                 .setId(mId++)
383                 .setUid(UID)
384                 .setInitialPid(2000)
385                 .setNotification(n)
386                 .setUser(userHandle)
387                 .setPostTime(System.currentTimeMillis())
388                 .setChannel(channel)
389                 .build();
390 
391         modifyRanking(entry)
392                 .setCanBubble(true)
393                 .build();
394         return entry;
395     }
396 
397     /**
398      * Creates a notification row with the given details.
399      *
400      * @param pkg package used for creating a {@link StatusBarNotification}
401      * @param uid uid used for creating a {@link StatusBarNotification}
402      * @param isGroupSummary whether the notification row is a group summary
403      * @param groupKey the group key for the notification group used across notifications
404      * @return a row with that's either a standalone notification or a group notification if the
405      *         groupKey is non-null
406      * @throws Exception
407      */
createRow( String pkg, int uid, UserHandle userHandle, boolean isGroupSummary, @Nullable String groupKey)408     private ExpandableNotificationRow createRow(
409             String pkg,
410             int uid,
411             UserHandle userHandle,
412             boolean isGroupSummary,
413             @Nullable String groupKey)
414             throws Exception {
415         Notification notif = createNotification(isGroupSummary, groupKey);
416         return generateRow(notif, pkg, uid, userHandle, mDefaultInflationFlags);
417     }
418 
419     /**
420      * Creates a generic notification.
421      *
422      * @return a notification with no special properties
423      */
createNotification()424     public Notification createNotification() {
425         return createNotification(false /* isGroupSummary */, null /* groupKey */);
426     }
427 
428     /**
429      * Creates a notification with the given parameters.
430      *
431      * @param isGroupSummary whether the notification is a group summary
432      * @param groupKey the group key for the notification group used across notifications
433      * @return a notification that is in the group specified or standalone if unspecified
434      */
createNotification(boolean isGroupSummary, @Nullable String groupKey)435     private Notification createNotification(boolean isGroupSummary, @Nullable String groupKey) {
436         return createNotification(isGroupSummary, groupKey, null /* bubble metadata */);
437     }
438 
439     /**
440      * Creates a notification with the given parameters.
441      *
442      * @param isGroupSummary whether the notification is a group summary
443      * @param groupKey the group key for the notification group used across notifications
444      * @param bubbleMetadata the bubble metadata to use for this notification if it exists.
445      * @return a notification that is in the group specified or standalone if unspecified
446      */
createNotification(boolean isGroupSummary, @Nullable String groupKey, @Nullable BubbleMetadata bubbleMetadata)447     public Notification createNotification(boolean isGroupSummary,
448             @Nullable String groupKey, @Nullable BubbleMetadata bubbleMetadata) {
449         Notification publicVersion = new Notification.Builder(mContext).setSmallIcon(
450                 R.drawable.ic_person)
451                 .setCustomContentView(new RemoteViews(mContext.getPackageName(),
452                         R.layout.custom_view_dark))
453                 .build();
454         Notification.Builder notificationBuilder = new Notification.Builder(mContext, "channelId")
455                 .setSmallIcon(R.drawable.ic_person)
456                 .setContentTitle("Title")
457                 .setContentText("Text")
458                 .setPublicVersion(publicVersion)
459                 .setStyle(new Notification.BigTextStyle().bigText("Big Text"));
460         if (isGroupSummary) {
461             notificationBuilder.setGroupSummary(true);
462         }
463         if (!TextUtils.isEmpty(groupKey)) {
464             notificationBuilder.setGroup(groupKey);
465         }
466         if (bubbleMetadata != null) {
467             notificationBuilder.setBubbleMetadata(bubbleMetadata);
468         }
469         return notificationBuilder.build();
470     }
471 
getStatusBarStateController()472     public StatusBarStateController getStatusBarStateController() {
473         return mStatusBarStateController;
474     }
475 
generateRow( Notification notification, String pkg, int uid, UserHandle userHandle, @InflationFlag int extraInflationFlags)476     private ExpandableNotificationRow generateRow(
477             Notification notification,
478             String pkg,
479             int uid,
480             UserHandle userHandle,
481             @InflationFlag int extraInflationFlags)
482             throws Exception {
483         return generateRow(notification, pkg, uid, userHandle, extraInflationFlags,
484                 IMPORTANCE_DEFAULT);
485     }
486 
generateRow( Notification notification, String pkg, int uid, UserHandle userHandle, @InflationFlag int extraInflationFlags, int importance)487     private ExpandableNotificationRow generateRow(
488             Notification notification,
489             String pkg,
490             int uid,
491             UserHandle userHandle,
492             @InflationFlag int extraInflationFlags,
493             int importance)
494             throws Exception {
495         LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
496                 mContext.LAYOUT_INFLATER_SERVICE);
497         mRow = (ExpandableNotificationRow) inflater.inflate(
498                 R.layout.status_bar_notification_row,
499                 null /* root */,
500                 false /* attachToRoot */);
501         ExpandableNotificationRow row = mRow;
502 
503         final NotificationChannel channel =
504                 new NotificationChannel(
505                         notification.getChannelId(),
506                         notification.getChannelId(),
507                         importance);
508         channel.setBlockable(true);
509 
510         NotificationEntry entry = new NotificationEntryBuilder()
511                 .setPkg(pkg)
512                 .setOpPkg(pkg)
513                 .setId(mId++)
514                 .setUid(uid)
515                 .setInitialPid(2000)
516                 .setNotification(notification)
517                 .setUser(userHandle)
518                 .setPostTime(System.currentTimeMillis())
519                 .setChannel(channel)
520                 .build();
521 
522         entry.setRow(row);
523         mIconManager.createIcons(entry);
524 
525         mBindPipelineEntryListener.onEntryInit(entry);
526         mBindPipeline.manageRow(entry, row);
527 
528         row.initialize(
529                 entry,
530                 mock(RemoteInputViewSubcomponent.Factory.class),
531                 APP_NAME,
532                 entry.getKey(),
533                 mMockLogger,
534                 mock(KeyguardBypassController.class),
535                 mGroupMembershipManager,
536                 mGroupExpansionManager,
537                 mHeadsUpManager,
538                 mBindStage,
539                 mock(OnExpandClickListener.class),
540                 mock(NotificationMediaManager.class),
541                 mock(ExpandableNotificationRow.CoordinateOnClickListener.class),
542                 new FalsingManagerFake(),
543                 new FalsingCollectorFake(),
544                 mStatusBarStateController,
545                 mPeopleNotificationIdentifier,
546                 mOnUserInteractionCallback,
547                 Optional.of(mock(BubblesManager.class)),
548                 mock(NotificationGutsManager.class),
549                 mock(MetricsLogger.class),
550                 mock(SmartReplyConstants.class),
551                 mock(SmartReplyController.class),
552                 mFeatureFlags,
553                 mock(IStatusBarService.class));
554 
555         row.setAboveShelfChangedListener(aboveShelf -> { });
556         mBindStage.getStageParams(entry).requireContentViews(extraInflationFlags);
557         inflateAndWait(entry);
558 
559         return row;
560     }
561 
inflateAndWait(NotificationEntry entry)562     private void inflateAndWait(NotificationEntry entry) throws Exception {
563         CountDownLatch countDownLatch = new CountDownLatch(1);
564         mBindStage.requestRebind(entry, en -> countDownLatch.countDown());
565         mTestLooper.processAllMessages();
566         assertTrue(countDownLatch.await(500, TimeUnit.MILLISECONDS));
567     }
568 
makeBubbleMetadata(PendingIntent deleteIntent, boolean autoExpand)569     private BubbleMetadata makeBubbleMetadata(PendingIntent deleteIntent, boolean autoExpand) {
570         Intent target = new Intent(mContext, BubblesTestActivity.class);
571         PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, target,
572                 PendingIntent.FLAG_MUTABLE);
573 
574         return new BubbleMetadata.Builder(bubbleIntent,
575                         Icon.createWithResource(mContext, R.drawable.android))
576                 .setDeleteIntent(deleteIntent)
577                 .setDesiredHeight(314)
578                 .setAutoExpandBubble(autoExpand)
579                 .build();
580     }
581 
makeShortcutBubbleMetadata(String shortcutId)582     private BubbleMetadata makeShortcutBubbleMetadata(String shortcutId) {
583         return new BubbleMetadata.Builder(shortcutId)
584                 .setDesiredHeight(314)
585                 .build();
586     }
587 
588     private static class MockSmartReplyInflater implements SmartReplyStateInflater {
589         @Override
inflateSmartReplyState(NotificationEntry entry)590         public InflatedSmartReplyState inflateSmartReplyState(NotificationEntry entry) {
591             return mock(InflatedSmartReplyState.class);
592         }
593 
594         @Override
inflateSmartReplyViewHolder(Context sysuiContext, Context notifPackageContext, NotificationEntry entry, InflatedSmartReplyState existingSmartReplyState, InflatedSmartReplyState newSmartReplyState)595         public InflatedSmartReplyViewHolder inflateSmartReplyViewHolder(Context sysuiContext,
596                 Context notifPackageContext, NotificationEntry entry,
597                 InflatedSmartReplyState existingSmartReplyState,
598                 InflatedSmartReplyState newSmartReplyState) {
599             return mock(InflatedSmartReplyViewHolder.class);
600         }
601     }
602 }
603