1 /* 2 * Copyright (C) 2022 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 18 package com.android.systemui.keyguard.domain.interactor 19 20 import android.app.admin.DevicePolicyManager 21 import android.os.UserHandle 22 import androidx.test.ext.junit.runners.AndroidJUnit4 23 import androidx.test.filters.SmallTest 24 import com.android.internal.widget.LockPatternUtils 25 import com.android.keyguard.logging.KeyguardQuickAffordancesLogger 26 import com.android.systemui.SysuiTestCase 27 import com.android.systemui.animation.DialogTransitionAnimator 28 import com.android.systemui.common.shared.model.ContentDescription 29 import com.android.systemui.common.shared.model.Icon 30 import com.android.systemui.coroutines.collectLastValue 31 import com.android.systemui.coroutines.collectValues 32 import com.android.systemui.dock.DockManager 33 import com.android.systemui.dock.DockManagerFake 34 import com.android.systemui.flags.EnableSceneContainer 35 import com.android.systemui.flags.FakeFeatureFlags 36 import com.android.systemui.keyguard.data.quickaffordance.BuiltInKeyguardQuickAffordanceKeys 37 import com.android.systemui.keyguard.data.quickaffordance.FakeKeyguardQuickAffordanceConfig 38 import com.android.systemui.keyguard.data.quickaffordance.FakeKeyguardQuickAffordanceProviderClientFactory 39 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig 40 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLegacySettingSyncer 41 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLocalUserSelectionManager 42 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceRemoteUserSelectionManager 43 import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository 44 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository 45 import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository 46 import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordanceModel 47 import com.android.systemui.keyguard.shared.model.KeyguardQuickAffordancePickerRepresentation 48 import com.android.systemui.keyguard.shared.quickaffordance.ActivationState 49 import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition 50 import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLogger 51 import com.android.systemui.kosmos.testDispatcher 52 import com.android.systemui.kosmos.testScope 53 import com.android.systemui.plugins.ActivityStarter 54 import com.android.systemui.res.R 55 import com.android.systemui.scene.domain.interactor.sceneInteractor 56 import com.android.systemui.settings.UserFileManager 57 import com.android.systemui.settings.UserTracker 58 import com.android.systemui.shade.cameraLauncher 59 import com.android.systemui.shade.domain.interactor.ShadeInteractor 60 import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots 61 import com.android.systemui.statusbar.policy.KeyguardStateController 62 import com.android.systemui.testKosmos 63 import com.android.systemui.util.FakeSharedPreferences 64 import com.android.systemui.util.mockito.mock 65 import com.android.systemui.util.mockito.whenever 66 import com.android.systemui.util.settings.fakeSettings 67 import com.google.common.truth.Truth.assertThat 68 import kotlinx.coroutines.ExperimentalCoroutinesApi 69 import kotlinx.coroutines.flow.MutableStateFlow 70 import kotlinx.coroutines.test.runCurrent 71 import kotlinx.coroutines.test.runTest 72 import org.junit.Before 73 import org.junit.Test 74 import org.junit.runner.RunWith 75 import org.mockito.ArgumentMatchers.anyInt 76 import org.mockito.ArgumentMatchers.anyString 77 import org.mockito.Mock 78 import org.mockito.MockitoAnnotations 79 80 @OptIn(ExperimentalCoroutinesApi::class) 81 @SmallTest 82 @RunWith(AndroidJUnit4::class) 83 class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { 84 85 private val kosmos = testKosmos() 86 private val testScope = kosmos.testScope 87 private val settings = kosmos.fakeSettings 88 89 @Mock private lateinit var lockPatternUtils: LockPatternUtils 90 @Mock private lateinit var keyguardStateController: KeyguardStateController 91 @Mock private lateinit var userTracker: UserTracker 92 @Mock private lateinit var activityStarter: ActivityStarter 93 @Mock private lateinit var launchAnimator: DialogTransitionAnimator 94 @Mock private lateinit var devicePolicyManager: DevicePolicyManager 95 @Mock private lateinit var shadeInteractor: ShadeInteractor 96 @Mock private lateinit var logger: KeyguardQuickAffordancesLogger 97 @Mock private lateinit var metricsLogger: KeyguardQuickAffordancesMetricsLogger 98 99 private lateinit var underTest: KeyguardQuickAffordanceInteractor 100 101 private lateinit var repository: FakeKeyguardRepository 102 private lateinit var homeControls: FakeKeyguardQuickAffordanceConfig 103 private lateinit var quickAccessWallet: FakeKeyguardQuickAffordanceConfig 104 private lateinit var qrCodeScanner: FakeKeyguardQuickAffordanceConfig 105 private lateinit var featureFlags: FakeFeatureFlags 106 private lateinit var dockManager: DockManagerFake 107 private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository 108 109 @Before setUpnull110 fun setUp() { 111 MockitoAnnotations.initMocks(this) 112 113 overrideResource(R.bool.custom_lockscreen_shortcuts_enabled, true) 114 overrideResource( 115 R.array.config_keyguardQuickAffordanceDefaults, 116 arrayOf( 117 KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START + 118 ":" + 119 BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS, 120 KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END + 121 ":" + 122 BuiltInKeyguardQuickAffordanceKeys.QUICK_ACCESS_WALLET, 123 ), 124 ) 125 126 repository = FakeKeyguardRepository() 127 repository.setKeyguardShowing(true) 128 129 homeControls = 130 FakeKeyguardQuickAffordanceConfig(BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS) 131 quickAccessWallet = 132 FakeKeyguardQuickAffordanceConfig( 133 BuiltInKeyguardQuickAffordanceKeys.QUICK_ACCESS_WALLET 134 ) 135 qrCodeScanner = 136 FakeKeyguardQuickAffordanceConfig(BuiltInKeyguardQuickAffordanceKeys.QR_CODE_SCANNER) 137 138 dockManager = DockManagerFake() 139 biometricSettingsRepository = FakeBiometricSettingsRepository() 140 141 val localUserSelectionManager = 142 KeyguardQuickAffordanceLocalUserSelectionManager( 143 context = context, 144 userFileManager = 145 mock<UserFileManager>().apply { 146 whenever(getSharedPreferences(anyString(), anyInt(), anyInt())) 147 .thenReturn(FakeSharedPreferences()) 148 }, 149 userTracker = userTracker, 150 broadcastDispatcher = fakeBroadcastDispatcher, 151 ) 152 val remoteUserSelectionManager = 153 KeyguardQuickAffordanceRemoteUserSelectionManager( 154 scope = testScope.backgroundScope, 155 userTracker = userTracker, 156 clientFactory = FakeKeyguardQuickAffordanceProviderClientFactory(userTracker), 157 userHandle = UserHandle.SYSTEM, 158 ) 159 val quickAffordanceRepository = 160 KeyguardQuickAffordanceRepository( 161 appContext = context, 162 scope = testScope.backgroundScope, 163 localUserSelectionManager = localUserSelectionManager, 164 remoteUserSelectionManager = remoteUserSelectionManager, 165 userTracker = userTracker, 166 legacySettingSyncer = 167 KeyguardQuickAffordanceLegacySettingSyncer( 168 scope = testScope.backgroundScope, 169 backgroundDispatcher = kosmos.testDispatcher, 170 secureSettings = settings, 171 selectionsManager = localUserSelectionManager, 172 ), 173 configs = setOf(homeControls, quickAccessWallet, qrCodeScanner), 174 dumpManager = mock(), 175 userHandle = UserHandle.SYSTEM, 176 ) 177 featureFlags = FakeFeatureFlags() 178 179 val withDeps = 180 KeyguardInteractorFactory.create(featureFlags = featureFlags, repository = repository) 181 underTest = 182 KeyguardQuickAffordanceInteractor( 183 keyguardInteractor = withDeps.keyguardInteractor, 184 shadeInteractor = shadeInteractor, 185 lockPatternUtils = lockPatternUtils, 186 keyguardStateController = keyguardStateController, 187 userTracker = userTracker, 188 activityStarter = activityStarter, 189 featureFlags = featureFlags, 190 repository = { quickAffordanceRepository }, 191 launchAnimator = launchAnimator, 192 logger = logger, 193 metricsLogger = metricsLogger, 194 devicePolicyManager = devicePolicyManager, 195 dockManager = dockManager, 196 biometricSettingsRepository = biometricSettingsRepository, 197 backgroundDispatcher = kosmos.testDispatcher, 198 appContext = context, 199 sceneInteractor = { kosmos.sceneInteractor }, 200 ) 201 kosmos.keyguardQuickAffordanceInteractor = underTest 202 203 whenever(shadeInteractor.anyExpansion).thenReturn(MutableStateFlow(0f)) 204 } 205 206 @Test quickAffordance_bottomStartAffordanceIsVisiblenull207 fun quickAffordance_bottomStartAffordanceIsVisible() = 208 testScope.runTest { 209 val configKey = BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS 210 homeControls.setState( 211 KeyguardQuickAffordanceConfig.LockScreenState.Visible( 212 icon = ICON, 213 activationState = ActivationState.Active, 214 ) 215 ) 216 217 val collectedValue = 218 collectLastValue( 219 underTest.quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_START) 220 ) 221 222 assertThat(collectedValue()) 223 .isInstanceOf(KeyguardQuickAffordanceModel.Visible::class.java) 224 val visibleModel = collectedValue() as KeyguardQuickAffordanceModel.Visible 225 assertThat(visibleModel.configKey) 226 .isEqualTo("${KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START}::$configKey") 227 assertThat(visibleModel.icon).isEqualTo(ICON) 228 assertThat(visibleModel.icon.contentDescription) 229 .isEqualTo(ContentDescription.Resource(res = CONTENT_DESCRIPTION_RESOURCE_ID)) 230 assertThat(visibleModel.activationState).isEqualTo(ActivationState.Active) 231 } 232 233 @Test quickAffordance_bottomEndAffordanceIsVisiblenull234 fun quickAffordance_bottomEndAffordanceIsVisible() = 235 testScope.runTest { 236 val configKey = BuiltInKeyguardQuickAffordanceKeys.QUICK_ACCESS_WALLET 237 quickAccessWallet.setState( 238 KeyguardQuickAffordanceConfig.LockScreenState.Visible(icon = ICON) 239 ) 240 241 val collectedValue = 242 collectLastValue( 243 underTest.quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_END) 244 ) 245 246 assertThat(collectedValue()) 247 .isInstanceOf(KeyguardQuickAffordanceModel.Visible::class.java) 248 val visibleModel = collectedValue() as KeyguardQuickAffordanceModel.Visible 249 assertThat(visibleModel.configKey) 250 .isEqualTo("${KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END}::$configKey") 251 assertThat(visibleModel.icon).isEqualTo(ICON) 252 assertThat(visibleModel.icon.contentDescription) 253 .isEqualTo(ContentDescription.Resource(res = CONTENT_DESCRIPTION_RESOURCE_ID)) 254 assertThat(visibleModel.activationState).isEqualTo(ActivationState.NotSupported) 255 } 256 257 @Test quickAffordance_hiddenWhenAllFeaturesAreDisabledByDevicePolicynull258 fun quickAffordance_hiddenWhenAllFeaturesAreDisabledByDevicePolicy() = 259 testScope.runTest { 260 whenever(devicePolicyManager.getKeyguardDisabledFeatures(null, userTracker.userId)) 261 .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_ALL) 262 quickAccessWallet.setState( 263 KeyguardQuickAffordanceConfig.LockScreenState.Visible(icon = ICON) 264 ) 265 266 val collectedValue by 267 collectLastValue( 268 underTest.quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_END) 269 ) 270 271 assertThat(collectedValue).isInstanceOf(KeyguardQuickAffordanceModel.Hidden::class.java) 272 } 273 274 @Test quickAffordance_hiddenWhenShortcutsFeatureIsDisabledByDevicePolicynull275 fun quickAffordance_hiddenWhenShortcutsFeatureIsDisabledByDevicePolicy() = 276 testScope.runTest { 277 whenever(devicePolicyManager.getKeyguardDisabledFeatures(null, userTracker.userId)) 278 .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_SHORTCUTS_ALL) 279 quickAccessWallet.setState( 280 KeyguardQuickAffordanceConfig.LockScreenState.Visible(icon = ICON) 281 ) 282 283 val collectedValue by 284 collectLastValue( 285 underTest.quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_END) 286 ) 287 288 assertThat(collectedValue).isInstanceOf(KeyguardQuickAffordanceModel.Hidden::class.java) 289 } 290 291 @Test quickAffordance_hiddenWhenUserIsInLockdownModenull292 fun quickAffordance_hiddenWhenUserIsInLockdownMode() = 293 testScope.runTest { 294 biometricSettingsRepository.setIsUserInLockdown(true) 295 quickAccessWallet.setState( 296 KeyguardQuickAffordanceConfig.LockScreenState.Visible(icon = ICON) 297 ) 298 299 val collectedValue by 300 collectLastValue( 301 underTest.quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_END) 302 ) 303 304 assertThat(collectedValue).isEqualTo(KeyguardQuickAffordanceModel.Hidden) 305 } 306 307 @Test quickAffordance_bottomStartAffordanceHiddenWhileDozingnull308 fun quickAffordance_bottomStartAffordanceHiddenWhileDozing() = 309 testScope.runTest { 310 repository.setIsDozing(true) 311 homeControls.setState( 312 KeyguardQuickAffordanceConfig.LockScreenState.Visible(icon = ICON) 313 ) 314 315 val collectedValue = 316 collectLastValue( 317 underTest.quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_START) 318 ) 319 assertThat(collectedValue()).isEqualTo(KeyguardQuickAffordanceModel.Hidden) 320 } 321 322 @Test quickAffordance_bottomStartAffordanceHiddenWhenLockscreenIsNotShowingnull323 fun quickAffordance_bottomStartAffordanceHiddenWhenLockscreenIsNotShowing() = 324 testScope.runTest { 325 repository.setKeyguardShowing(false) 326 homeControls.setState( 327 KeyguardQuickAffordanceConfig.LockScreenState.Visible(icon = ICON) 328 ) 329 330 val collectedValue = 331 collectLastValue( 332 underTest.quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_START) 333 ) 334 assertThat(collectedValue()).isEqualTo(KeyguardQuickAffordanceModel.Hidden) 335 } 336 337 @Test quickAffordance_updateOncePerShadeExpansionnull338 fun quickAffordance_updateOncePerShadeExpansion() = 339 testScope.runTest { 340 val shadeExpansion = MutableStateFlow(0f) 341 whenever(shadeInteractor.anyExpansion).thenReturn(shadeExpansion) 342 343 val collectedValue by 344 collectValues( 345 underTest.quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_START) 346 ) 347 348 val initialSize = collectedValue.size 349 for (i in 0..10) { 350 shadeExpansion.value = i / 10f 351 } 352 353 assertThat(collectedValue.size).isEqualTo(initialSize + 1) 354 } 355 356 @Test quickAffordanceAlwaysVisible_notVisible_restrictedByPolicyManagernull357 fun quickAffordanceAlwaysVisible_notVisible_restrictedByPolicyManager() = 358 testScope.runTest { 359 whenever(devicePolicyManager.getKeyguardDisabledFeatures(null, userTracker.userId)) 360 .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_SHORTCUTS_ALL) 361 362 repository.setKeyguardShowing(false) 363 repository.setIsDozing(true) 364 homeControls.setState( 365 KeyguardQuickAffordanceConfig.LockScreenState.Visible( 366 icon = ICON, 367 activationState = ActivationState.Active, 368 ) 369 ) 370 371 val collectedValue by 372 collectLastValue( 373 underTest.quickAffordanceAlwaysVisible( 374 KeyguardQuickAffordancePosition.BOTTOM_START 375 ) 376 ) 377 378 assertThat(collectedValue).isInstanceOf(KeyguardQuickAffordanceModel.Hidden::class.java) 379 } 380 381 @Test quickAffordanceAlwaysVisible_evenWhenLockScreenNotShowingAndDozingnull382 fun quickAffordanceAlwaysVisible_evenWhenLockScreenNotShowingAndDozing() = 383 testScope.runTest { 384 repository.setKeyguardShowing(false) 385 repository.setIsDozing(true) 386 val configKey = BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS 387 homeControls.setState( 388 KeyguardQuickAffordanceConfig.LockScreenState.Visible( 389 icon = ICON, 390 activationState = ActivationState.Active, 391 ) 392 ) 393 394 val collectedValue = 395 collectLastValue( 396 underTest.quickAffordanceAlwaysVisible( 397 KeyguardQuickAffordancePosition.BOTTOM_START 398 ) 399 ) 400 assertThat(collectedValue()) 401 .isInstanceOf(KeyguardQuickAffordanceModel.Visible::class.java) 402 val visibleModel = collectedValue() as KeyguardQuickAffordanceModel.Visible 403 assertThat(visibleModel.configKey) 404 .isEqualTo("${KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START}::$configKey") 405 assertThat(visibleModel.icon).isEqualTo(ICON) 406 assertThat(visibleModel.icon.contentDescription) 407 .isEqualTo(ContentDescription.Resource(res = CONTENT_DESCRIPTION_RESOURCE_ID)) 408 assertThat(visibleModel.activationState).isEqualTo(ActivationState.Active) 409 } 410 411 @Test quickAffordanceAlwaysVisible_withNonNullOverrideKeyguardQuickAffordanceIdnull412 fun quickAffordanceAlwaysVisible_withNonNullOverrideKeyguardQuickAffordanceId() = 413 testScope.runTest { 414 quickAccessWallet.setState( 415 KeyguardQuickAffordanceConfig.LockScreenState.Visible( 416 icon = ICON, 417 activationState = ActivationState.Active, 418 ) 419 ) 420 homeControls.setState( 421 KeyguardQuickAffordanceConfig.LockScreenState.Visible( 422 icon = ICON, 423 activationState = ActivationState.Active, 424 ) 425 ) 426 427 // The default case 428 val collectedValue = 429 collectLastValue( 430 underTest.quickAffordanceAlwaysVisible( 431 KeyguardQuickAffordancePosition.BOTTOM_START 432 ) 433 ) 434 assertThat(collectedValue()) 435 .isInstanceOf(KeyguardQuickAffordanceModel.Visible::class.java) 436 val visibleModel = collectedValue() as KeyguardQuickAffordanceModel.Visible 437 assertThat(visibleModel.configKey) 438 .isEqualTo( 439 "${KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START}::${homeControls.key}" 440 ) 441 assertThat(visibleModel.icon).isEqualTo(ICON) 442 assertThat(visibleModel.icon.contentDescription) 443 .isEqualTo(ContentDescription.Resource(res = CONTENT_DESCRIPTION_RESOURCE_ID)) 444 assertThat(visibleModel.activationState).isEqualTo(ActivationState.Active) 445 446 // With override 447 val collectedValueWithOverride = 448 collectLastValue( 449 underTest.quickAffordanceAlwaysVisible( 450 position = KeyguardQuickAffordancePosition.BOTTOM_START, 451 overrideQuickAffordanceId = 452 BuiltInKeyguardQuickAffordanceKeys.QUICK_ACCESS_WALLET, 453 ) 454 ) 455 assertThat(collectedValueWithOverride()) 456 .isInstanceOf(KeyguardQuickAffordanceModel.Visible::class.java) 457 val visibleModelWithOverride = 458 collectedValueWithOverride() as KeyguardQuickAffordanceModel.Visible 459 assertThat(visibleModelWithOverride.configKey) 460 .isEqualTo( 461 "${KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START}::${quickAccessWallet.key}" 462 ) 463 assertThat(visibleModelWithOverride.icon).isEqualTo(ICON) 464 assertThat(visibleModelWithOverride.icon.contentDescription) 465 .isEqualTo(ContentDescription.Resource(res = CONTENT_DESCRIPTION_RESOURCE_ID)) 466 assertThat(visibleModelWithOverride.activationState).isEqualTo(ActivationState.Active) 467 } 468 469 @Test selectnull470 fun select() = 471 testScope.runTest { 472 overrideResource(R.array.config_keyguardQuickAffordanceDefaults, arrayOf<String>()) 473 homeControls.setState( 474 KeyguardQuickAffordanceConfig.LockScreenState.Visible(icon = ICON) 475 ) 476 quickAccessWallet.setState( 477 KeyguardQuickAffordanceConfig.LockScreenState.Visible(icon = ICON) 478 ) 479 qrCodeScanner.setState( 480 KeyguardQuickAffordanceConfig.LockScreenState.Visible(icon = ICON) 481 ) 482 483 assertThat(underTest.getSelections()) 484 .isEqualTo( 485 mapOf<String, List<String>>( 486 KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START to emptyList(), 487 KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END to emptyList(), 488 ) 489 ) 490 491 val startConfig = 492 collectLastValue( 493 underTest.quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_START) 494 ) 495 val endConfig = 496 collectLastValue( 497 underTest.quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_END) 498 ) 499 500 underTest.select(KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START, homeControls.key) 501 502 assertThat(startConfig()) 503 .isEqualTo( 504 KeyguardQuickAffordanceModel.Visible( 505 configKey = 506 KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START + 507 "::${homeControls.key}", 508 icon = ICON, 509 activationState = ActivationState.NotSupported, 510 ) 511 ) 512 assertThat(endConfig()).isEqualTo(KeyguardQuickAffordanceModel.Hidden) 513 assertThat(underTest.getSelections()) 514 .isEqualTo( 515 mapOf( 516 KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START to 517 listOf( 518 KeyguardQuickAffordancePickerRepresentation( 519 id = homeControls.key, 520 name = homeControls.pickerName(), 521 iconResourceId = homeControls.pickerIconResourceId, 522 ) 523 ), 524 KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END to emptyList(), 525 ) 526 ) 527 528 underTest.select( 529 KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START, 530 quickAccessWallet.key, 531 ) 532 533 assertThat(startConfig()) 534 .isEqualTo( 535 KeyguardQuickAffordanceModel.Visible( 536 configKey = 537 KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START + 538 "::${quickAccessWallet.key}", 539 icon = ICON, 540 activationState = ActivationState.NotSupported, 541 ) 542 ) 543 assertThat(endConfig()).isEqualTo(KeyguardQuickAffordanceModel.Hidden) 544 assertThat(underTest.getSelections()) 545 .isEqualTo( 546 mapOf( 547 KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START to 548 listOf( 549 KeyguardQuickAffordancePickerRepresentation( 550 id = quickAccessWallet.key, 551 name = quickAccessWallet.pickerName(), 552 iconResourceId = quickAccessWallet.pickerIconResourceId, 553 ) 554 ), 555 KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END to emptyList(), 556 ) 557 ) 558 559 underTest.select(KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END, qrCodeScanner.key) 560 561 assertThat(startConfig()) 562 .isEqualTo( 563 KeyguardQuickAffordanceModel.Visible( 564 configKey = 565 KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START + 566 "::${quickAccessWallet.key}", 567 icon = ICON, 568 activationState = ActivationState.NotSupported, 569 ) 570 ) 571 assertThat(endConfig()) 572 .isEqualTo( 573 KeyguardQuickAffordanceModel.Visible( 574 configKey = 575 KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END + 576 "::${qrCodeScanner.key}", 577 icon = ICON, 578 activationState = ActivationState.NotSupported, 579 ) 580 ) 581 assertThat(underTest.getSelections()) 582 .isEqualTo( 583 mapOf( 584 KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START to 585 listOf( 586 KeyguardQuickAffordancePickerRepresentation( 587 id = quickAccessWallet.key, 588 name = quickAccessWallet.pickerName(), 589 iconResourceId = quickAccessWallet.pickerIconResourceId, 590 ) 591 ), 592 KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END to 593 listOf( 594 KeyguardQuickAffordancePickerRepresentation( 595 id = qrCodeScanner.key, 596 name = qrCodeScanner.pickerName(), 597 iconResourceId = qrCodeScanner.pickerIconResourceId, 598 ) 599 ), 600 ) 601 ) 602 } 603 604 @Test unselect_onenull605 fun unselect_one() = 606 testScope.runTest { 607 homeControls.setState( 608 KeyguardQuickAffordanceConfig.LockScreenState.Visible(icon = ICON) 609 ) 610 quickAccessWallet.setState( 611 KeyguardQuickAffordanceConfig.LockScreenState.Visible(icon = ICON) 612 ) 613 qrCodeScanner.setState( 614 KeyguardQuickAffordanceConfig.LockScreenState.Visible(icon = ICON) 615 ) 616 617 val startConfig = 618 collectLastValue( 619 underTest.quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_START) 620 ) 621 val endConfig = 622 collectLastValue( 623 underTest.quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_END) 624 ) 625 underTest.select(KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START, homeControls.key) 626 underTest.select(KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END, quickAccessWallet.key) 627 underTest.unselect(KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START, homeControls.key) 628 629 assertThat(startConfig()).isEqualTo(KeyguardQuickAffordanceModel.Hidden) 630 assertThat(endConfig()) 631 .isEqualTo( 632 KeyguardQuickAffordanceModel.Visible( 633 configKey = 634 KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END + 635 "::${quickAccessWallet.key}", 636 icon = ICON, 637 activationState = ActivationState.NotSupported, 638 ) 639 ) 640 assertThat(underTest.getSelections()) 641 .isEqualTo( 642 mapOf( 643 KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START to emptyList(), 644 KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END to 645 listOf( 646 KeyguardQuickAffordancePickerRepresentation( 647 id = quickAccessWallet.key, 648 name = quickAccessWallet.pickerName(), 649 iconResourceId = quickAccessWallet.pickerIconResourceId, 650 ) 651 ), 652 ) 653 ) 654 655 underTest.unselect( 656 KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END, 657 quickAccessWallet.key, 658 ) 659 660 assertThat(startConfig()).isEqualTo(KeyguardQuickAffordanceModel.Hidden) 661 assertThat(endConfig()).isEqualTo(KeyguardQuickAffordanceModel.Hidden) 662 assertThat(underTest.getSelections()) 663 .isEqualTo( 664 mapOf<String, List<String>>( 665 KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START to emptyList(), 666 KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END to emptyList(), 667 ) 668 ) 669 } 670 671 @Test useLongPress_whenDocked_isFalsenull672 fun useLongPress_whenDocked_isFalse() = 673 testScope.runTest { 674 dockManager.setIsDocked(true) 675 676 val useLongPress by collectLastValue(underTest.useLongPress()) 677 678 assertThat(useLongPress).isFalse() 679 } 680 681 @Test useLongPress_whenNotDocked_isTruenull682 fun useLongPress_whenNotDocked_isTrue() = 683 testScope.runTest { 684 dockManager.setIsDocked(false) 685 686 val useLongPress by collectLastValue(underTest.useLongPress()) 687 688 assertThat(useLongPress).isTrue() 689 } 690 691 @Test useLongPress_whenNotDocked_isTrue_changedTo_whenDocked_isFalsenull692 fun useLongPress_whenNotDocked_isTrue_changedTo_whenDocked_isFalse() = 693 testScope.runTest { 694 dockManager.setIsDocked(false) 695 val firstUseLongPress by collectLastValue(underTest.useLongPress()) 696 runCurrent() 697 698 assertThat(firstUseLongPress).isTrue() 699 700 dockManager.setIsDocked(true) 701 dockManager.setDockEvent(DockManager.STATE_DOCKED) 702 val secondUseLongPress by collectLastValue(underTest.useLongPress()) 703 runCurrent() 704 705 assertThat(secondUseLongPress).isFalse() 706 } 707 708 @Test unselect_allnull709 fun unselect_all() = 710 testScope.runTest { 711 homeControls.setState( 712 KeyguardQuickAffordanceConfig.LockScreenState.Visible(icon = ICON) 713 ) 714 quickAccessWallet.setState( 715 KeyguardQuickAffordanceConfig.LockScreenState.Visible(icon = ICON) 716 ) 717 qrCodeScanner.setState( 718 KeyguardQuickAffordanceConfig.LockScreenState.Visible(icon = ICON) 719 ) 720 721 underTest.select(KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START, homeControls.key) 722 underTest.select(KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END, quickAccessWallet.key) 723 underTest.unselect(KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START, null) 724 725 assertThat(underTest.getSelections()) 726 .isEqualTo( 727 mapOf( 728 KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START to emptyList(), 729 KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END to 730 listOf( 731 KeyguardQuickAffordancePickerRepresentation( 732 id = quickAccessWallet.key, 733 name = quickAccessWallet.pickerName(), 734 iconResourceId = quickAccessWallet.pickerIconResourceId, 735 ) 736 ), 737 ) 738 ) 739 740 underTest.unselect(KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END, null) 741 742 assertThat(underTest.getSelections()) 743 .isEqualTo( 744 mapOf<String, List<String>>( 745 KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START to emptyList(), 746 KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END to emptyList(), 747 ) 748 ) 749 } 750 751 @EnableSceneContainer 752 @Test updatesLaunchingAffordanceFromCameraLaunchernull753 fun updatesLaunchingAffordanceFromCameraLauncher() = 754 testScope.runTest { 755 val launchingAffordance by collectLastValue(underTest.launchingAffordance) 756 runCurrent() 757 758 kosmos.cameraLauncher.setLaunchingAffordance(true) 759 runCurrent() 760 assertThat(launchingAffordance).isTrue() 761 762 kosmos.cameraLauncher.setLaunchingAffordance(false) 763 runCurrent() 764 assertThat(launchingAffordance).isFalse() 765 } 766 767 companion object { 768 private const val CONTENT_DESCRIPTION_RESOURCE_ID = 1337 769 private val ICON: Icon = 770 Icon.Resource( 771 res = CONTENT_DESCRIPTION_RESOURCE_ID, 772 contentDescription = 773 ContentDescription.Resource(res = CONTENT_DESCRIPTION_RESOURCE_ID), 774 ) 775 } 776 } 777