1 /* <lambda>null2 * Copyright (C) 2024 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 package com.android.systemui.statusbar.notification.row 17 18 import android.R 19 import android.app.AppOpsManager 20 import android.app.INotificationManager 21 import android.app.Notification 22 import android.app.NotificationChannel 23 import android.app.NotificationManager 24 import android.content.Intent 25 import android.content.pm.PackageManager 26 import android.content.pm.ShortcutManager 27 import android.content.pm.launcherApps 28 import android.graphics.Color 29 import android.os.Binder 30 import android.os.fakeExecutorHandler 31 import android.os.userManager 32 import android.provider.Settings 33 import android.service.notification.NotificationListenerService.Ranking 34 import android.testing.TestableLooper.RunWithLooper 35 import android.util.ArraySet 36 import android.view.View 37 import android.view.accessibility.accessibilityManager 38 import androidx.test.ext.junit.runners.AndroidJUnit4 39 import androidx.test.filters.SmallTest 40 import com.android.compose.animation.scene.ObservableTransitionState 41 import com.android.internal.logging.MetricsLogger 42 import com.android.internal.logging.UiEventLogger 43 import com.android.internal.logging.metricsLogger 44 import com.android.internal.logging.testing.UiEventLoggerFake 45 import com.android.internal.statusbar.statusBarService 46 import com.android.systemui.SysuiTestCase 47 import com.android.systemui.concurrency.fakeExecutor 48 import com.android.systemui.flags.EnableSceneContainer 49 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository 50 import com.android.systemui.kosmos.testScope 51 import com.android.systemui.people.widget.PeopleSpaceWidgetManager 52 import com.android.systemui.plugins.activityStarter 53 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin 54 import com.android.systemui.plugins.statusbar.statusBarStateController 55 import com.android.systemui.power.domain.interactor.PowerInteractorFactory.create 56 import com.android.systemui.scene.data.repository.WindowRootViewVisibilityRepository 57 import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor 58 import com.android.systemui.scene.domain.interactor.sceneInteractor 59 import com.android.systemui.scene.shared.model.Scenes 60 import com.android.systemui.settings.UserContextProvider 61 import com.android.systemui.shade.shadeControllerSceneImpl 62 import com.android.systemui.statusbar.NotificationEntryHelper 63 import com.android.systemui.statusbar.NotificationPresenter 64 import com.android.systemui.statusbar.notification.AssistantFeedbackController 65 import com.android.systemui.statusbar.notification.NotificationActivityStarter 66 import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider 67 import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor 68 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier 69 import com.android.systemui.statusbar.notification.stack.NotificationListContainer 70 import com.android.systemui.statusbar.notificationLockscreenUserManager 71 import com.android.systemui.statusbar.policy.deviceProvisionedController 72 import com.android.systemui.statusbar.policy.headsUpManager 73 import com.android.systemui.testKosmos 74 import com.android.systemui.util.kotlin.JavaAdapter 75 import com.android.systemui.wmshell.BubblesManager 76 import java.util.Optional 77 import junit.framework.Assert 78 import kotlin.test.assertEquals 79 import kotlinx.coroutines.flow.MutableStateFlow 80 import kotlinx.coroutines.test.runCurrent 81 import org.junit.Before 82 import org.junit.Test 83 import org.junit.runner.RunWith 84 import org.mockito.ArgumentCaptor 85 import org.mockito.ArgumentMatchers 86 import org.mockito.Mock 87 import org.mockito.Mockito 88 import org.mockito.Mockito.verify 89 import org.mockito.MockitoAnnotations 90 import org.mockito.invocation.InvocationOnMock 91 92 /** Tests for [NotificationGutsManager] with the scene container enabled. */ 93 @SmallTest 94 @RunWith(AndroidJUnit4::class) 95 @RunWithLooper 96 @EnableSceneContainer 97 class NotificationGutsManagerWithScenesTest : SysuiTestCase() { 98 private val testNotificationChannel = 99 NotificationChannel( 100 TEST_CHANNEL_ID, 101 TEST_CHANNEL_ID, 102 NotificationManager.IMPORTANCE_DEFAULT 103 ) 104 105 private val kosmos = testKosmos() 106 private val testScope = kosmos.testScope 107 private val javaAdapter = JavaAdapter(testScope.backgroundScope) 108 private val executor = kosmos.fakeExecutor 109 private val handler = kosmos.fakeExecutorHandler 110 private lateinit var helper: NotificationTestHelper 111 private lateinit var gutsManager: NotificationGutsManager 112 private lateinit var windowRootViewVisibilityInteractor: WindowRootViewVisibilityInteractor 113 114 private val metricsLogger = kosmos.metricsLogger 115 private val deviceProvisionedController = kosmos.deviceProvisionedController 116 private val accessibilityManager = kosmos.accessibilityManager 117 private val mBarService = kosmos.statusBarService 118 private val launcherApps = kosmos.launcherApps 119 private val shadeController = kosmos.shadeControllerSceneImpl 120 private val notificationLockscreenUserManager = kosmos.notificationLockscreenUserManager 121 private val statusBarStateController = kosmos.statusBarStateController 122 private val headsUpManager = kosmos.headsUpManager 123 private val activityStarter = kosmos.activityStarter 124 private val userManager = kosmos.userManager 125 private val activeNotificationsInteractor = kosmos.activeNotificationsInteractor 126 private val sceneInteractor = kosmos.sceneInteractor 127 128 @Mock private lateinit var onUserInteractionCallback: OnUserInteractionCallback 129 @Mock private lateinit var presenter: NotificationPresenter 130 @Mock private lateinit var notificationActivityStarter: NotificationActivityStarter 131 @Mock private lateinit var notificationListContainer: NotificationListContainer 132 @Mock 133 private lateinit var onSettingsClickListener: NotificationGutsManager.OnSettingsClickListener 134 @Mock private lateinit var highPriorityProvider: HighPriorityProvider 135 @Mock private lateinit var notificationManager: INotificationManager 136 @Mock private lateinit var shortcutManager: ShortcutManager 137 @Mock private lateinit var channelEditorDialogController: ChannelEditorDialogController 138 @Mock private lateinit var peopleNotificationIdentifier: PeopleNotificationIdentifier 139 @Mock private lateinit var contextTracker: UserContextProvider 140 @Mock private lateinit var bubblesManager: BubblesManager 141 @Mock private lateinit var peopleSpaceWidgetManager: PeopleSpaceWidgetManager 142 @Mock private lateinit var assistantFeedbackController: AssistantFeedbackController 143 144 @Before 145 fun setUp() { 146 MockitoAnnotations.initMocks(this) 147 allowTestableLooperAsMainThread() 148 helper = NotificationTestHelper(mContext, mDependency) 149 Mockito.`when`(accessibilityManager.isTouchExplorationEnabled).thenReturn(false) 150 windowRootViewVisibilityInteractor = 151 WindowRootViewVisibilityInteractor( 152 testScope.backgroundScope, 153 WindowRootViewVisibilityRepository(mBarService, executor), 154 FakeKeyguardRepository(), 155 headsUpManager, 156 create().powerInteractor, 157 activeNotificationsInteractor, 158 ) { 159 sceneInteractor 160 } 161 gutsManager = 162 NotificationGutsManager( 163 mContext, 164 handler, 165 handler, 166 javaAdapter, 167 accessibilityManager, 168 highPriorityProvider, 169 notificationManager, 170 userManager, 171 peopleSpaceWidgetManager, 172 launcherApps, 173 shortcutManager, 174 channelEditorDialogController, 175 contextTracker, 176 assistantFeedbackController, 177 Optional.of(bubblesManager), 178 UiEventLoggerFake(), 179 onUserInteractionCallback, 180 shadeController, 181 windowRootViewVisibilityInteractor, 182 notificationLockscreenUserManager, 183 statusBarStateController, 184 mBarService, 185 deviceProvisionedController, 186 metricsLogger, 187 headsUpManager, 188 activityStarter 189 ) 190 gutsManager.setUpWithPresenter( 191 presenter, 192 notificationListContainer, 193 onSettingsClickListener 194 ) 195 gutsManager.setNotificationActivityStarter(notificationActivityStarter) 196 gutsManager.start() 197 } 198 199 @Test 200 fun testOpenAndCloseGuts() { 201 val guts = Mockito.spy(NotificationGuts(mContext)) 202 Mockito.`when`(guts.post(ArgumentMatchers.any())).thenAnswer { invocation: InvocationOnMock 203 -> 204 handler.post((invocation.arguments[0] as Runnable)) 205 null 206 } 207 208 // Test doesn't support animation since the guts view is not attached. 209 Mockito.doNothing() 210 .`when`(guts) 211 .openControls( 212 ArgumentMatchers.anyInt(), 213 ArgumentMatchers.anyInt(), 214 ArgumentMatchers.anyBoolean(), 215 ArgumentMatchers.any(Runnable::class.java) 216 ) 217 val realRow = createTestNotificationRow() 218 val menuItem = createTestMenuItem(realRow) 219 val row = Mockito.spy(realRow) 220 Mockito.`when`(row!!.windowToken).thenReturn(Binder()) 221 Mockito.`when`(row.guts).thenReturn(guts) 222 Assert.assertTrue(gutsManager.openGutsInternal(row, 0, 0, menuItem)) 223 assertEquals(View.INVISIBLE.toLong(), guts.visibility.toLong()) 224 executor.runAllReady() 225 verify(guts) 226 .openControls( 227 ArgumentMatchers.anyInt(), 228 ArgumentMatchers.anyInt(), 229 ArgumentMatchers.anyBoolean(), 230 ArgumentMatchers.any(Runnable::class.java) 231 ) 232 verify(headsUpManager).setGutsShown(realRow!!.entry, true) 233 assertEquals(View.VISIBLE.toLong(), guts.visibility.toLong()) 234 gutsManager.closeAndSaveGuts(false, false, true, 0, 0, false) 235 verify(guts) 236 .closeControls( 237 ArgumentMatchers.anyBoolean(), 238 ArgumentMatchers.anyBoolean(), 239 ArgumentMatchers.anyInt(), 240 ArgumentMatchers.anyInt(), 241 ArgumentMatchers.anyBoolean() 242 ) 243 verify(row, Mockito.times(1)).setGutsView(ArgumentMatchers.any()) 244 executor.runAllReady() 245 verify(headsUpManager).setGutsShown(realRow.entry, false) 246 } 247 248 @Test 249 fun testLockscreenShadeVisible_visible_gutsNotClosed() { 250 // First, start out lockscreen or shade as not visible 251 setIsLockscreenOrShadeVisible(false) 252 testScope.testScheduler.runCurrent() 253 val guts = Mockito.mock(NotificationGuts::class.java) 254 gutsManager.exposedGuts = guts 255 256 // WHEN the lockscreen or shade becomes visible 257 setIsLockscreenOrShadeVisible(true) 258 testScope.testScheduler.runCurrent() 259 260 // THEN the guts are not closed 261 verify(guts, Mockito.never()).removeCallbacks(ArgumentMatchers.any()) 262 verify(guts, Mockito.never()) 263 .closeControls( 264 ArgumentMatchers.anyBoolean(), 265 ArgumentMatchers.anyBoolean(), 266 ArgumentMatchers.anyInt(), 267 ArgumentMatchers.anyInt(), 268 ArgumentMatchers.anyBoolean() 269 ) 270 } 271 272 @Test 273 fun testLockscreenShadeVisible_notVisible_gutsClosed() { 274 // First, start out lockscreen or shade as visible 275 setIsLockscreenOrShadeVisible(true) 276 testScope.testScheduler.runCurrent() 277 val guts = Mockito.mock(NotificationGuts::class.java) 278 gutsManager.exposedGuts = guts 279 280 // WHEN the lockscreen or shade is no longer visible 281 setIsLockscreenOrShadeVisible(false) 282 testScope.testScheduler.runCurrent() 283 284 // THEN the guts are closed 285 verify(guts).removeCallbacks(ArgumentMatchers.any()) 286 verify(guts) 287 .closeControls( 288 /* leavebehinds= */ ArgumentMatchers.eq(true), 289 /* controls= */ ArgumentMatchers.eq(true), 290 /* x= */ ArgumentMatchers.anyInt(), 291 /* y= */ ArgumentMatchers.anyInt(), 292 /* force= */ ArgumentMatchers.eq(true) 293 ) 294 } 295 296 @Test 297 fun testLockscreenShadeVisible_notVisible_listContainerReset() { 298 // First, start out lockscreen or shade as visible 299 setIsLockscreenOrShadeVisible(true) 300 testScope.testScheduler.runCurrent() 301 302 // WHEN the lockscreen or shade is no longer visible 303 setIsLockscreenOrShadeVisible(false) 304 testScope.testScheduler.runCurrent() 305 306 // THEN the list container is reset 307 verify(notificationListContainer) 308 .resetExposedMenuView(ArgumentMatchers.anyBoolean(), ArgumentMatchers.anyBoolean()) 309 } 310 311 @Test 312 fun testChangeDensityOrFontScale() { 313 val guts = Mockito.spy(NotificationGuts(mContext)) 314 Mockito.`when`(guts.post(ArgumentMatchers.any())).thenAnswer { invocation: InvocationOnMock 315 -> 316 handler.post((invocation.arguments[0] as Runnable)) 317 null 318 } 319 320 // Test doesn't support animation since the guts view is not attached. 321 Mockito.doNothing() 322 .`when`(guts) 323 .openControls( 324 ArgumentMatchers.anyInt(), 325 ArgumentMatchers.anyInt(), 326 ArgumentMatchers.anyBoolean(), 327 ArgumentMatchers.any(Runnable::class.java) 328 ) 329 val realRow = createTestNotificationRow() 330 val menuItem = createTestMenuItem(realRow) 331 val row = Mockito.spy(realRow) 332 Mockito.`when`(row!!.windowToken).thenReturn(Binder()) 333 Mockito.`when`(row.guts).thenReturn(guts) 334 Mockito.doNothing().`when`(row).ensureGutsInflated() 335 val realEntry = realRow!!.entry 336 val entry = Mockito.spy(realEntry) 337 Mockito.`when`(entry.row).thenReturn(row) 338 Mockito.`when`(entry.getGuts()).thenReturn(guts) 339 Assert.assertTrue(gutsManager.openGutsInternal(row, 0, 0, menuItem)) 340 executor.runAllReady() 341 verify(guts) 342 .openControls( 343 ArgumentMatchers.anyInt(), 344 ArgumentMatchers.anyInt(), 345 ArgumentMatchers.anyBoolean(), 346 ArgumentMatchers.any(Runnable::class.java) 347 ) 348 349 // called once by mGutsManager.bindGuts() in mGutsManager.openGuts() 350 verify(row).setGutsView(ArgumentMatchers.any()) 351 row.onDensityOrFontScaleChanged() 352 gutsManager.onDensityOrFontScaleChanged(entry) 353 executor.runAllReady() 354 gutsManager.closeAndSaveGuts(false, false, false, 0, 0, false) 355 verify(guts) 356 .closeControls( 357 ArgumentMatchers.anyBoolean(), 358 ArgumentMatchers.anyBoolean(), 359 ArgumentMatchers.anyInt(), 360 ArgumentMatchers.anyInt(), 361 ArgumentMatchers.anyBoolean() 362 ) 363 364 // called again by mGutsManager.bindGuts(), in mGutsManager.onDensityOrFontScaleChanged() 365 verify(row, Mockito.times(2)).setGutsView(ArgumentMatchers.any()) 366 } 367 368 @Test 369 fun testAppOpsSettingsIntent_camera() { 370 val ops = ArraySet<Int>() 371 ops.add(AppOpsManager.OP_CAMERA) 372 gutsManager.startAppOpsSettingsActivity("", 0, ops, null) 373 val captor = ArgumentCaptor.forClass(Intent::class.java) 374 verify(notificationActivityStarter, Mockito.times(1)) 375 .startNotificationGutsIntent( 376 captor.capture(), 377 ArgumentMatchers.anyInt(), 378 ArgumentMatchers.any() 379 ) 380 assertEquals(Intent.ACTION_MANAGE_APP_PERMISSIONS, captor.value.action) 381 } 382 383 @Test 384 fun testAppOpsSettingsIntent_mic() { 385 val ops = ArraySet<Int>() 386 ops.add(AppOpsManager.OP_RECORD_AUDIO) 387 gutsManager.startAppOpsSettingsActivity("", 0, ops, null) 388 val captor = ArgumentCaptor.forClass(Intent::class.java) 389 verify(notificationActivityStarter, Mockito.times(1)) 390 .startNotificationGutsIntent( 391 captor.capture(), 392 ArgumentMatchers.anyInt(), 393 ArgumentMatchers.any() 394 ) 395 assertEquals(Intent.ACTION_MANAGE_APP_PERMISSIONS, captor.value.action) 396 } 397 398 @Test 399 fun testAppOpsSettingsIntent_camera_mic() { 400 val ops = ArraySet<Int>() 401 ops.add(AppOpsManager.OP_CAMERA) 402 ops.add(AppOpsManager.OP_RECORD_AUDIO) 403 gutsManager.startAppOpsSettingsActivity("", 0, ops, null) 404 val captor = ArgumentCaptor.forClass(Intent::class.java) 405 verify(notificationActivityStarter, Mockito.times(1)) 406 .startNotificationGutsIntent( 407 captor.capture(), 408 ArgumentMatchers.anyInt(), 409 ArgumentMatchers.any() 410 ) 411 assertEquals(Intent.ACTION_MANAGE_APP_PERMISSIONS, captor.value.action) 412 } 413 414 @Test 415 fun testAppOpsSettingsIntent_overlay() { 416 val ops = ArraySet<Int>() 417 ops.add(AppOpsManager.OP_SYSTEM_ALERT_WINDOW) 418 gutsManager.startAppOpsSettingsActivity("", 0, ops, null) 419 val captor = ArgumentCaptor.forClass(Intent::class.java) 420 verify(notificationActivityStarter, Mockito.times(1)) 421 .startNotificationGutsIntent( 422 captor.capture(), 423 ArgumentMatchers.anyInt(), 424 ArgumentMatchers.any() 425 ) 426 assertEquals(Settings.ACTION_MANAGE_APP_OVERLAY_PERMISSION, captor.value.action) 427 } 428 429 @Test 430 fun testAppOpsSettingsIntent_camera_mic_overlay() { 431 val ops = ArraySet<Int>() 432 ops.add(AppOpsManager.OP_CAMERA) 433 ops.add(AppOpsManager.OP_RECORD_AUDIO) 434 ops.add(AppOpsManager.OP_SYSTEM_ALERT_WINDOW) 435 gutsManager.startAppOpsSettingsActivity("", 0, ops, null) 436 val captor = ArgumentCaptor.forClass(Intent::class.java) 437 verify(notificationActivityStarter, Mockito.times(1)) 438 .startNotificationGutsIntent( 439 captor.capture(), 440 ArgumentMatchers.anyInt(), 441 ArgumentMatchers.any() 442 ) 443 assertEquals(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, captor.value.action) 444 } 445 446 @Test 447 fun testAppOpsSettingsIntent_camera_overlay() { 448 val ops = ArraySet<Int>() 449 ops.add(AppOpsManager.OP_CAMERA) 450 ops.add(AppOpsManager.OP_SYSTEM_ALERT_WINDOW) 451 gutsManager.startAppOpsSettingsActivity("", 0, ops, null) 452 val captor = ArgumentCaptor.forClass(Intent::class.java) 453 verify(notificationActivityStarter, Mockito.times(1)) 454 .startNotificationGutsIntent( 455 captor.capture(), 456 ArgumentMatchers.anyInt(), 457 ArgumentMatchers.any() 458 ) 459 assertEquals(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, captor.value.action) 460 } 461 462 @Test 463 fun testAppOpsSettingsIntent_mic_overlay() { 464 val ops = ArraySet<Int>() 465 ops.add(AppOpsManager.OP_RECORD_AUDIO) 466 ops.add(AppOpsManager.OP_SYSTEM_ALERT_WINDOW) 467 gutsManager.startAppOpsSettingsActivity("", 0, ops, null) 468 val captor = ArgumentCaptor.forClass(Intent::class.java) 469 verify(notificationActivityStarter, Mockito.times(1)) 470 .startNotificationGutsIntent( 471 captor.capture(), 472 ArgumentMatchers.anyInt(), 473 ArgumentMatchers.any() 474 ) 475 assertEquals(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, captor.value.action) 476 } 477 478 @Test 479 @Throws(Exception::class) 480 fun testInitializeNotificationInfoView_highPriority() { 481 val notificationInfoView = Mockito.mock(NotificationInfo::class.java) 482 val row = Mockito.spy(helper.createRow()) 483 val entry = row.entry 484 NotificationEntryHelper.modifyRanking(entry) 485 .setUserSentiment(Ranking.USER_SENTIMENT_NEGATIVE) 486 .setImportance(NotificationManager.IMPORTANCE_HIGH) 487 .build() 488 Mockito.`when`(row.getIsNonblockable()).thenReturn(false) 489 Mockito.`when`(highPriorityProvider.isHighPriority(entry)).thenReturn(true) 490 val statusBarNotification = entry.sbn 491 gutsManager.initializeNotificationInfo(row, notificationInfoView) 492 verify(notificationInfoView) 493 .bindNotification( 494 ArgumentMatchers.any(PackageManager::class.java), 495 ArgumentMatchers.any(INotificationManager::class.java), 496 ArgumentMatchers.eq(onUserInteractionCallback), 497 ArgumentMatchers.eq(channelEditorDialogController), 498 ArgumentMatchers.eq(statusBarNotification.packageName), 499 ArgumentMatchers.any(NotificationChannel::class.java), 500 ArgumentMatchers.eq(entry), 501 ArgumentMatchers.any(NotificationInfo.OnSettingsClickListener::class.java), 502 ArgumentMatchers.any(NotificationInfo.OnAppSettingsClickListener::class.java), 503 ArgumentMatchers.any(UiEventLogger::class.java), 504 ArgumentMatchers.eq(true), 505 ArgumentMatchers.eq(false), 506 ArgumentMatchers.eq(true), /* wasShownHighPriority */ 507 ArgumentMatchers.eq(assistantFeedbackController), 508 ArgumentMatchers.any(MetricsLogger::class.java) 509 ) 510 } 511 512 @Test 513 @Throws(Exception::class) 514 fun testInitializeNotificationInfoView_PassesAlongProvisionedState() { 515 val notificationInfoView = Mockito.mock(NotificationInfo::class.java) 516 val row = Mockito.spy(helper.createRow()) 517 NotificationEntryHelper.modifyRanking(row.entry) 518 .setUserSentiment(Ranking.USER_SENTIMENT_NEGATIVE) 519 .build() 520 Mockito.`when`(row.getIsNonblockable()).thenReturn(false) 521 val statusBarNotification = row.entry.sbn 522 val entry = row.entry 523 gutsManager.initializeNotificationInfo(row, notificationInfoView) 524 verify(notificationInfoView) 525 .bindNotification( 526 ArgumentMatchers.any(PackageManager::class.java), 527 ArgumentMatchers.any(INotificationManager::class.java), 528 ArgumentMatchers.eq(onUserInteractionCallback), 529 ArgumentMatchers.eq(channelEditorDialogController), 530 ArgumentMatchers.eq(statusBarNotification.packageName), 531 ArgumentMatchers.any(NotificationChannel::class.java), 532 ArgumentMatchers.eq(entry), 533 ArgumentMatchers.any(NotificationInfo.OnSettingsClickListener::class.java), 534 ArgumentMatchers.any(NotificationInfo.OnAppSettingsClickListener::class.java), 535 ArgumentMatchers.any(UiEventLogger::class.java), 536 ArgumentMatchers.eq(true), 537 ArgumentMatchers.eq(false), 538 ArgumentMatchers.eq(false), /* wasShownHighPriority */ 539 ArgumentMatchers.eq(assistantFeedbackController), 540 ArgumentMatchers.any(MetricsLogger::class.java) 541 ) 542 } 543 544 @Test 545 @Throws(Exception::class) 546 fun testInitializeNotificationInfoView_withInitialAction() { 547 val notificationInfoView = Mockito.mock(NotificationInfo::class.java) 548 val row = Mockito.spy(helper.createRow()) 549 NotificationEntryHelper.modifyRanking(row.entry) 550 .setUserSentiment(Ranking.USER_SENTIMENT_NEGATIVE) 551 .build() 552 Mockito.`when`(row.getIsNonblockable()).thenReturn(false) 553 val statusBarNotification = row.entry.sbn 554 val entry = row.entry 555 gutsManager.initializeNotificationInfo(row, notificationInfoView) 556 verify(notificationInfoView) 557 .bindNotification( 558 ArgumentMatchers.any(PackageManager::class.java), 559 ArgumentMatchers.any(INotificationManager::class.java), 560 ArgumentMatchers.eq(onUserInteractionCallback), 561 ArgumentMatchers.eq(channelEditorDialogController), 562 ArgumentMatchers.eq(statusBarNotification.packageName), 563 ArgumentMatchers.any(NotificationChannel::class.java), 564 ArgumentMatchers.eq(entry), 565 ArgumentMatchers.any(NotificationInfo.OnSettingsClickListener::class.java), 566 ArgumentMatchers.any(NotificationInfo.OnAppSettingsClickListener::class.java), 567 ArgumentMatchers.any(UiEventLogger::class.java), 568 ArgumentMatchers.eq(true), 569 ArgumentMatchers.eq(false), 570 ArgumentMatchers.eq(false), /* wasShownHighPriority */ 571 ArgumentMatchers.eq(assistantFeedbackController), 572 ArgumentMatchers.any(MetricsLogger::class.java) 573 ) 574 } 575 576 private fun createTestNotificationRow(): ExpandableNotificationRow? { 577 val nb = 578 Notification.Builder(mContext, testNotificationChannel.id) 579 .setContentTitle("foo") 580 .setColorized(true) 581 .setColor(Color.RED) 582 .setFlag(Notification.FLAG_CAN_COLORIZE, true) 583 .setSmallIcon(R.drawable.sym_def_app_icon) 584 return try { 585 val row = helper.createRow(nb.build()) 586 NotificationEntryHelper.modifyRanking(row.entry) 587 .setChannel(testNotificationChannel) 588 .build() 589 row 590 } catch (e: Exception) { 591 org.junit.Assert.fail() 592 null 593 } 594 } 595 596 private fun setIsLockscreenOrShadeVisible(isVisible: Boolean) { 597 val key = 598 if (isVisible) { 599 Scenes.Lockscreen 600 } else { 601 Scenes.Bouncer 602 } 603 sceneInteractor.changeScene(key, "test") 604 sceneInteractor.setTransitionState( 605 MutableStateFlow<ObservableTransitionState>(ObservableTransitionState.Idle(key)) 606 ) 607 testScope.runCurrent() 608 } 609 610 private fun createTestMenuItem( 611 row: ExpandableNotificationRow? 612 ): NotificationMenuRowPlugin.MenuItem { 613 val menuRow: NotificationMenuRowPlugin = 614 NotificationMenuRow(mContext, peopleNotificationIdentifier) 615 menuRow.createMenu(row, row!!.entry.sbn) 616 val menuItem = menuRow.getLongpressMenuItem(mContext) 617 Assert.assertNotNull(menuItem) 618 return menuItem 619 } 620 621 companion object { 622 private const val TEST_CHANNEL_ID = "NotificationManagerServiceTestChannelId" 623 } 624 } 625