Loading packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/OccludingAppDeviceEntryInteractorTest.kt +47 −9 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.systemui.deviceentry.domain.interactor import android.content.Intent import android.content.mockedContext import android.content.res.Resources import android.hardware.fingerprint.FingerprintManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest Loading @@ -41,13 +42,16 @@ import com.android.systemui.kosmos.testScope import com.android.systemui.plugins.ActivityStarter.OnDismissAction import com.android.systemui.plugins.activityStarter import com.android.systemui.power.data.repository.fakePowerRepository import com.android.systemui.res.R import com.android.systemui.testKosmos import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor Loading @@ -55,6 +59,7 @@ import org.mockito.ArgumentMatchers.eq import org.mockito.ArgumentMatchers.isNull import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.kotlin.mock @OptIn(ExperimentalCoroutinesApi::class) @SmallTest Loading @@ -63,8 +68,8 @@ class OccludingAppDeviceEntryInteractorTest : SysuiTestCase() { private val kosmos = testKosmos() private val testScope = kosmos.testScope private val underTest = kosmos.occludingAppDeviceEntryInteractor private lateinit var underTest: OccludingAppDeviceEntryInteractor private lateinit var mockedResources: Resources private val fingerprintAuthRepository = kosmos.deviceEntryFingerprintAuthRepository private val keyguardRepository = kosmos.fakeKeyguardRepository private val bouncerRepository = kosmos.keyguardBouncerRepository Loading @@ -74,9 +79,18 @@ class OccludingAppDeviceEntryInteractorTest : SysuiTestCase() { private val mockedContext = kosmos.mockedContext private val mockedActivityStarter = kosmos.activityStarter @Before fun setup() { mockedResources = mock<Resources>() whenever(mockedContext.resources).thenReturn(mockedResources) whenever(mockedResources.getBoolean(R.bool.config_goToHomeFromOccludedApps)) .thenReturn(true) } @Test fun fingerprintSuccess_goToHomeScreen() = testScope.runTest { underTest = kosmos.occludingAppDeviceEntryInteractor givenOnOccludingApp(true) fingerprintAuthRepository.setAuthenticationStatus( SuccessFingerprintAuthenticationStatus(0, true) Loading @@ -85,9 +99,24 @@ class OccludingAppDeviceEntryInteractorTest : SysuiTestCase() { verifyGoToHomeScreen() } @Test fun fingerprintSuccess_configOff_doesNotGoToHomeScreen() = testScope.runTest { whenever(mockedResources.getBoolean(R.bool.config_goToHomeFromOccludedApps)) .thenReturn(false) underTest = kosmos.occludingAppDeviceEntryInteractor givenOnOccludingApp(true) fingerprintAuthRepository.setAuthenticationStatus( SuccessFingerprintAuthenticationStatus(0, true) ) runCurrent() verifyNeverGoToHomeScreen() } @Test fun fingerprintSuccess_notInteractive_doesNotGoToHomeScreen() = testScope.runTest { underTest = kosmos.occludingAppDeviceEntryInteractor givenOnOccludingApp(true) powerRepository.setInteractive(false) fingerprintAuthRepository.setAuthenticationStatus( Loading @@ -100,6 +129,7 @@ class OccludingAppDeviceEntryInteractorTest : SysuiTestCase() { @Test fun fingerprintSuccess_dreaming_doesNotGoToHomeScreen() = testScope.runTest { underTest = kosmos.occludingAppDeviceEntryInteractor givenOnOccludingApp(true) keyguardRepository.setDreaming(true) fingerprintAuthRepository.setAuthenticationStatus( Loading @@ -112,6 +142,7 @@ class OccludingAppDeviceEntryInteractorTest : SysuiTestCase() { @Test fun fingerprintSuccess_notOnOccludingApp_doesNotGoToHomeScreen() = testScope.runTest { underTest = kosmos.occludingAppDeviceEntryInteractor givenOnOccludingApp(false) fingerprintAuthRepository.setAuthenticationStatus( SuccessFingerprintAuthenticationStatus(0, true) Loading @@ -123,11 +154,12 @@ class OccludingAppDeviceEntryInteractorTest : SysuiTestCase() { @Test fun lockout_goToHomeScreenOnDismissAction() = testScope.runTest { underTest = kosmos.occludingAppDeviceEntryInteractor givenOnOccludingApp(true) fingerprintAuthRepository.setAuthenticationStatus( ErrorFingerprintAuthenticationStatus( FingerprintManager.FINGERPRINT_ERROR_LOCKOUT, "lockoutTest" "lockoutTest", ) ) runCurrent() Loading @@ -137,11 +169,12 @@ class OccludingAppDeviceEntryInteractorTest : SysuiTestCase() { @Test fun lockout_notOnOccludingApp_neverGoToHomeScreen() = testScope.runTest { underTest = kosmos.occludingAppDeviceEntryInteractor givenOnOccludingApp(false) fingerprintAuthRepository.setAuthenticationStatus( ErrorFingerprintAuthenticationStatus( FingerprintManager.FINGERPRINT_ERROR_LOCKOUT, "lockoutTest" "lockoutTest", ) ) runCurrent() Loading @@ -151,11 +184,12 @@ class OccludingAppDeviceEntryInteractorTest : SysuiTestCase() { @Test fun lockout_onOccludingApp_onCommunal_neverGoToHomeScreen() = testScope.runTest { underTest = kosmos.occludingAppDeviceEntryInteractor givenOnOccludingApp(isOnOccludingApp = true, isOnCommunal = true) fingerprintAuthRepository.setAuthenticationStatus( ErrorFingerprintAuthenticationStatus( FingerprintManager.FINGERPRINT_ERROR_LOCKOUT, "lockoutTest" "lockoutTest", ) ) runCurrent() Loading @@ -165,6 +199,7 @@ class OccludingAppDeviceEntryInteractorTest : SysuiTestCase() { @Test fun message_fpFailOnOccludingApp_thenNotOnOccludingApp() = testScope.runTest { underTest = kosmos.occludingAppDeviceEntryInteractor val message by collectLastValue(underTest.message) givenOnOccludingApp(true) Loading @@ -186,6 +221,7 @@ class OccludingAppDeviceEntryInteractorTest : SysuiTestCase() { @Test fun message_fpErrorHelpFailOnOccludingApp() = testScope.runTest { underTest = kosmos.occludingAppDeviceEntryInteractor val message by collectLastValue(underTest.message) givenOnOccludingApp(true) Loading Loading @@ -218,6 +254,7 @@ class OccludingAppDeviceEntryInteractorTest : SysuiTestCase() { @Test fun message_fpError_lockoutFilteredOut() = testScope.runTest { underTest = kosmos.occludingAppDeviceEntryInteractor val message by collectLastValue(underTest.message) givenOnOccludingApp(true) Loading Loading @@ -246,6 +283,7 @@ class OccludingAppDeviceEntryInteractorTest : SysuiTestCase() { @Test fun noMessage_fpErrorsWhileDozing() = testScope.runTest { underTest = kosmos.occludingAppDeviceEntryInteractor val message by collectLastValue(underTest.message) givenOnOccludingApp(true) Loading @@ -254,7 +292,7 @@ class OccludingAppDeviceEntryInteractorTest : SysuiTestCase() { kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps( from = KeyguardState.OCCLUDED, to = KeyguardState.DOZING, testScope testScope, ) runCurrent() Loading Loading @@ -283,7 +321,7 @@ class OccludingAppDeviceEntryInteractorTest : SysuiTestCase() { private suspend fun givenOnOccludingApp( isOnOccludingApp: Boolean, isOnCommunal: Boolean = false isOnCommunal: Boolean = false, ) { powerRepository.setInteractive(true) keyguardRepository.setIsDozing(false) Loading @@ -305,13 +343,13 @@ class OccludingAppDeviceEntryInteractorTest : SysuiTestCase() { kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps( from = KeyguardState.LOCKSCREEN, to = KeyguardState.OCCLUDED, testScope testScope, ) } else { kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps( from = KeyguardState.OCCLUDED, to = KeyguardState.LOCKSCREEN, testScope testScope, ) } } Loading packages/SystemUI/res/values/config.xml +3 −0 Original line number Diff line number Diff line Loading @@ -338,6 +338,9 @@ <!-- Whether to show the full screen user switcher. --> <bool name="config_enableFullscreenUserSwitcher">false</bool> <!-- Whether to go to the launcher when unlocking via an occluding app --> <bool name="config_goToHomeFromOccludedApps">false</bool> <!-- Determines whether the shell features all run on another thread. --> <bool name="config_enableShellMainThread">true</bool> Loading packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/OccludingAppDeviceEntryInteractor.kt +23 −13 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.systemui.deviceentry.domain.interactor import android.content.Context import android.content.Intent import com.android.app.tracing.coroutines.launchTraced as launch import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor Loading @@ -34,6 +35,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus import com.android.systemui.plugins.ActivityStarter import com.android.systemui.power.domain.interactor.PowerInteractor import com.android.systemui.res.R import com.android.systemui.util.kotlin.combine import com.android.systemui.util.kotlin.sample import javax.inject.Inject Loading @@ -48,7 +50,6 @@ import kotlinx.coroutines.flow.filterNot import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map import com.android.app.tracing.coroutines.launchTraced as launch /** Business logic for handling authentication events when an app is occluding the lockscreen. */ @ExperimentalCoroutinesApi Loading Loading @@ -123,11 +124,19 @@ constructor( .ifKeyguardOccludedByApp(/* elseFlow */ flowOf(null)) init { // This seems undesirable in most cases, except when a video is playing and can PiP when // unlocked. It was originally added for tablets, so allow it there if (context.resources.getBoolean(R.bool.config_goToHomeFromOccludedApps)) { scope.launch { // On fingerprint success when the screen is on and not dreaming, go to the home screen // On fingerprint success when the screen is on and not dreaming, go to the home // screen fingerprintUnlockSuccessEvents .sample( combine(powerInteractor.isInteractive, keyguardInteractor.isDreaming, ::Pair) combine( powerInteractor.isInteractive, keyguardInteractor.isDreaming, ::Pair, ) ) .collect { (interactive, dreaming) -> if (interactive && !dreaming) { Loading @@ -137,6 +146,7 @@ constructor( // AOD/dozing/off/dreaming } } } scope.launch { // On device fingerprint lockout, request the bouncer with a runnable to Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/OccludingAppDeviceEntryInteractorTest.kt +47 −9 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.systemui.deviceentry.domain.interactor import android.content.Intent import android.content.mockedContext import android.content.res.Resources import android.hardware.fingerprint.FingerprintManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest Loading @@ -41,13 +42,16 @@ import com.android.systemui.kosmos.testScope import com.android.systemui.plugins.ActivityStarter.OnDismissAction import com.android.systemui.plugins.activityStarter import com.android.systemui.power.data.repository.fakePowerRepository import com.android.systemui.res.R import com.android.systemui.testKosmos import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor Loading @@ -55,6 +59,7 @@ import org.mockito.ArgumentMatchers.eq import org.mockito.ArgumentMatchers.isNull import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.kotlin.mock @OptIn(ExperimentalCoroutinesApi::class) @SmallTest Loading @@ -63,8 +68,8 @@ class OccludingAppDeviceEntryInteractorTest : SysuiTestCase() { private val kosmos = testKosmos() private val testScope = kosmos.testScope private val underTest = kosmos.occludingAppDeviceEntryInteractor private lateinit var underTest: OccludingAppDeviceEntryInteractor private lateinit var mockedResources: Resources private val fingerprintAuthRepository = kosmos.deviceEntryFingerprintAuthRepository private val keyguardRepository = kosmos.fakeKeyguardRepository private val bouncerRepository = kosmos.keyguardBouncerRepository Loading @@ -74,9 +79,18 @@ class OccludingAppDeviceEntryInteractorTest : SysuiTestCase() { private val mockedContext = kosmos.mockedContext private val mockedActivityStarter = kosmos.activityStarter @Before fun setup() { mockedResources = mock<Resources>() whenever(mockedContext.resources).thenReturn(mockedResources) whenever(mockedResources.getBoolean(R.bool.config_goToHomeFromOccludedApps)) .thenReturn(true) } @Test fun fingerprintSuccess_goToHomeScreen() = testScope.runTest { underTest = kosmos.occludingAppDeviceEntryInteractor givenOnOccludingApp(true) fingerprintAuthRepository.setAuthenticationStatus( SuccessFingerprintAuthenticationStatus(0, true) Loading @@ -85,9 +99,24 @@ class OccludingAppDeviceEntryInteractorTest : SysuiTestCase() { verifyGoToHomeScreen() } @Test fun fingerprintSuccess_configOff_doesNotGoToHomeScreen() = testScope.runTest { whenever(mockedResources.getBoolean(R.bool.config_goToHomeFromOccludedApps)) .thenReturn(false) underTest = kosmos.occludingAppDeviceEntryInteractor givenOnOccludingApp(true) fingerprintAuthRepository.setAuthenticationStatus( SuccessFingerprintAuthenticationStatus(0, true) ) runCurrent() verifyNeverGoToHomeScreen() } @Test fun fingerprintSuccess_notInteractive_doesNotGoToHomeScreen() = testScope.runTest { underTest = kosmos.occludingAppDeviceEntryInteractor givenOnOccludingApp(true) powerRepository.setInteractive(false) fingerprintAuthRepository.setAuthenticationStatus( Loading @@ -100,6 +129,7 @@ class OccludingAppDeviceEntryInteractorTest : SysuiTestCase() { @Test fun fingerprintSuccess_dreaming_doesNotGoToHomeScreen() = testScope.runTest { underTest = kosmos.occludingAppDeviceEntryInteractor givenOnOccludingApp(true) keyguardRepository.setDreaming(true) fingerprintAuthRepository.setAuthenticationStatus( Loading @@ -112,6 +142,7 @@ class OccludingAppDeviceEntryInteractorTest : SysuiTestCase() { @Test fun fingerprintSuccess_notOnOccludingApp_doesNotGoToHomeScreen() = testScope.runTest { underTest = kosmos.occludingAppDeviceEntryInteractor givenOnOccludingApp(false) fingerprintAuthRepository.setAuthenticationStatus( SuccessFingerprintAuthenticationStatus(0, true) Loading @@ -123,11 +154,12 @@ class OccludingAppDeviceEntryInteractorTest : SysuiTestCase() { @Test fun lockout_goToHomeScreenOnDismissAction() = testScope.runTest { underTest = kosmos.occludingAppDeviceEntryInteractor givenOnOccludingApp(true) fingerprintAuthRepository.setAuthenticationStatus( ErrorFingerprintAuthenticationStatus( FingerprintManager.FINGERPRINT_ERROR_LOCKOUT, "lockoutTest" "lockoutTest", ) ) runCurrent() Loading @@ -137,11 +169,12 @@ class OccludingAppDeviceEntryInteractorTest : SysuiTestCase() { @Test fun lockout_notOnOccludingApp_neverGoToHomeScreen() = testScope.runTest { underTest = kosmos.occludingAppDeviceEntryInteractor givenOnOccludingApp(false) fingerprintAuthRepository.setAuthenticationStatus( ErrorFingerprintAuthenticationStatus( FingerprintManager.FINGERPRINT_ERROR_LOCKOUT, "lockoutTest" "lockoutTest", ) ) runCurrent() Loading @@ -151,11 +184,12 @@ class OccludingAppDeviceEntryInteractorTest : SysuiTestCase() { @Test fun lockout_onOccludingApp_onCommunal_neverGoToHomeScreen() = testScope.runTest { underTest = kosmos.occludingAppDeviceEntryInteractor givenOnOccludingApp(isOnOccludingApp = true, isOnCommunal = true) fingerprintAuthRepository.setAuthenticationStatus( ErrorFingerprintAuthenticationStatus( FingerprintManager.FINGERPRINT_ERROR_LOCKOUT, "lockoutTest" "lockoutTest", ) ) runCurrent() Loading @@ -165,6 +199,7 @@ class OccludingAppDeviceEntryInteractorTest : SysuiTestCase() { @Test fun message_fpFailOnOccludingApp_thenNotOnOccludingApp() = testScope.runTest { underTest = kosmos.occludingAppDeviceEntryInteractor val message by collectLastValue(underTest.message) givenOnOccludingApp(true) Loading @@ -186,6 +221,7 @@ class OccludingAppDeviceEntryInteractorTest : SysuiTestCase() { @Test fun message_fpErrorHelpFailOnOccludingApp() = testScope.runTest { underTest = kosmos.occludingAppDeviceEntryInteractor val message by collectLastValue(underTest.message) givenOnOccludingApp(true) Loading Loading @@ -218,6 +254,7 @@ class OccludingAppDeviceEntryInteractorTest : SysuiTestCase() { @Test fun message_fpError_lockoutFilteredOut() = testScope.runTest { underTest = kosmos.occludingAppDeviceEntryInteractor val message by collectLastValue(underTest.message) givenOnOccludingApp(true) Loading Loading @@ -246,6 +283,7 @@ class OccludingAppDeviceEntryInteractorTest : SysuiTestCase() { @Test fun noMessage_fpErrorsWhileDozing() = testScope.runTest { underTest = kosmos.occludingAppDeviceEntryInteractor val message by collectLastValue(underTest.message) givenOnOccludingApp(true) Loading @@ -254,7 +292,7 @@ class OccludingAppDeviceEntryInteractorTest : SysuiTestCase() { kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps( from = KeyguardState.OCCLUDED, to = KeyguardState.DOZING, testScope testScope, ) runCurrent() Loading Loading @@ -283,7 +321,7 @@ class OccludingAppDeviceEntryInteractorTest : SysuiTestCase() { private suspend fun givenOnOccludingApp( isOnOccludingApp: Boolean, isOnCommunal: Boolean = false isOnCommunal: Boolean = false, ) { powerRepository.setInteractive(true) keyguardRepository.setIsDozing(false) Loading @@ -305,13 +343,13 @@ class OccludingAppDeviceEntryInteractorTest : SysuiTestCase() { kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps( from = KeyguardState.LOCKSCREEN, to = KeyguardState.OCCLUDED, testScope testScope, ) } else { kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps( from = KeyguardState.OCCLUDED, to = KeyguardState.LOCKSCREEN, testScope testScope, ) } } Loading
packages/SystemUI/res/values/config.xml +3 −0 Original line number Diff line number Diff line Loading @@ -338,6 +338,9 @@ <!-- Whether to show the full screen user switcher. --> <bool name="config_enableFullscreenUserSwitcher">false</bool> <!-- Whether to go to the launcher when unlocking via an occluding app --> <bool name="config_goToHomeFromOccludedApps">false</bool> <!-- Determines whether the shell features all run on another thread. --> <bool name="config_enableShellMainThread">true</bool> Loading
packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/OccludingAppDeviceEntryInteractor.kt +23 −13 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.systemui.deviceentry.domain.interactor import android.content.Context import android.content.Intent import com.android.app.tracing.coroutines.launchTraced as launch import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor Loading @@ -34,6 +35,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus import com.android.systemui.plugins.ActivityStarter import com.android.systemui.power.domain.interactor.PowerInteractor import com.android.systemui.res.R import com.android.systemui.util.kotlin.combine import com.android.systemui.util.kotlin.sample import javax.inject.Inject Loading @@ -48,7 +50,6 @@ import kotlinx.coroutines.flow.filterNot import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map import com.android.app.tracing.coroutines.launchTraced as launch /** Business logic for handling authentication events when an app is occluding the lockscreen. */ @ExperimentalCoroutinesApi Loading Loading @@ -123,11 +124,19 @@ constructor( .ifKeyguardOccludedByApp(/* elseFlow */ flowOf(null)) init { // This seems undesirable in most cases, except when a video is playing and can PiP when // unlocked. It was originally added for tablets, so allow it there if (context.resources.getBoolean(R.bool.config_goToHomeFromOccludedApps)) { scope.launch { // On fingerprint success when the screen is on and not dreaming, go to the home screen // On fingerprint success when the screen is on and not dreaming, go to the home // screen fingerprintUnlockSuccessEvents .sample( combine(powerInteractor.isInteractive, keyguardInteractor.isDreaming, ::Pair) combine( powerInteractor.isInteractive, keyguardInteractor.isDreaming, ::Pair, ) ) .collect { (interactive, dreaming) -> if (interactive && !dreaming) { Loading @@ -137,6 +146,7 @@ constructor( // AOD/dozing/off/dreaming } } } scope.launch { // On device fingerprint lockout, request the bouncer with a runnable to Loading