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