diff options
17 files changed, 461 insertions, 422 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt index 75a77cf781d2..4bc71fd6d363 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt @@ -27,6 +27,17 @@ import android.hardware.face.FaceSensorProperties import android.hardware.face.FaceSensorPropertiesInternal import android.hardware.fingerprint.FingerprintSensorProperties import android.hardware.fingerprint.FingerprintSensorPropertiesInternal +import com.android.keyguard.keyguardUpdateMonitor +import com.android.systemui.SysuiTestableContext +import com.android.systemui.biometrics.data.repository.biometricStatusRepository +import com.android.systemui.biometrics.shared.model.AuthenticationReason +import com.android.systemui.bouncer.data.repository.keyguardBouncerRepository +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.res.R +import com.android.systemui.util.mockito.whenever +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runCurrent /** Create [FingerprintSensorPropertiesInternal] for a test. */ internal fun fingerprintSensorPropertiesInternal( @@ -145,3 +156,67 @@ internal fun promptInfo( info.negativeButtonText = negativeButton return info } + +@OptIn(ExperimentalCoroutinesApi::class) +internal fun TestScope.updateSfpsIndicatorRequests( + kosmos: Kosmos, + mContext: SysuiTestableContext, + primaryBouncerRequest: Boolean? = null, + alternateBouncerRequest: Boolean? = null, + biometricPromptRequest: Boolean? = null, + // TODO(b/365182034): update when rest to unlock feature is implemented + // progressBarShowing: Boolean? = null +) { + biometricPromptRequest?.let { hasBiometricPromptRequest -> + if (hasBiometricPromptRequest) { + kosmos.biometricStatusRepository.setFingerprintAuthenticationReason( + AuthenticationReason.BiometricPromptAuthentication + ) + } else { + kosmos.biometricStatusRepository.setFingerprintAuthenticationReason( + AuthenticationReason.NotRunning + ) + } + } + + primaryBouncerRequest?.let { hasPrimaryBouncerRequest -> + updatePrimaryBouncer( + kosmos, + mContext, + isShowing = hasPrimaryBouncerRequest, + isAnimatingAway = false, + fpsDetectionRunning = true, + isUnlockingWithFpAllowed = true + ) + } + + alternateBouncerRequest?.let { hasAlternateBouncerRequest -> + kosmos.keyguardBouncerRepository.setAlternateVisible(hasAlternateBouncerRequest) + } + + // TODO(b/365182034): set progress bar visibility when rest to unlock feature is implemented + + runCurrent() +} + +internal fun updatePrimaryBouncer( + kosmos: Kosmos, + mContext: SysuiTestableContext, + isShowing: Boolean, + isAnimatingAway: Boolean, + fpsDetectionRunning: Boolean, + isUnlockingWithFpAllowed: Boolean, +) { + kosmos.keyguardBouncerRepository.setPrimaryShow(isShowing) + kosmos.keyguardBouncerRepository.setPrimaryStartingToHide(false) + val primaryStartDisappearAnimation = if (isAnimatingAway) Runnable {} else null + kosmos.keyguardBouncerRepository.setPrimaryStartDisappearAnimation( + primaryStartDisappearAnimation + ) + + whenever(kosmos.keyguardUpdateMonitor.isFingerprintDetectionRunning) + .thenReturn(fpsDetectionRunning) + whenever(kosmos.keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed) + .thenReturn(isUnlockingWithFpAllowed) + mContext.orCreateTestableResources.addOverride(R.bool.config_show_sidefps_hint_on_bouncer, true) +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractorTest.kt new file mode 100644 index 000000000000..298b54a5be5a --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractorTest.kt @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.biometrics.domain.interactor + +import android.testing.TestableLooper +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.biometrics.data.repository.biometricStatusRepository +import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository +import com.android.systemui.biometrics.shared.model.AuthenticationReason +import com.android.systemui.biometrics.shared.model.FingerprintSensorType +import com.android.systemui.biometrics.shared.model.SensorStrength +import com.android.systemui.biometrics.updateSfpsIndicatorRequests +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.display.data.repository.displayRepository +import com.android.systemui.display.data.repository.displayStateRepository +import com.android.systemui.kosmos.testScope +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Ignore +import org.junit.Test +import org.junit.runner.RunWith + +@OptIn(ExperimentalCoroutinesApi::class) +@SmallTest +@RunWith(AndroidJUnit4::class) +@TestableLooper.RunWithLooper(setAsMainLooper = true) +class SideFpsOverlayInteractorTest : SysuiTestCase() { + private val kosmos = testKosmos() + private val underTest = kosmos.sideFpsOverlayInteractor + + @Test + fun verifyIsShowingFalse_whenInRearDisplayMode() { + kosmos.testScope.runTest { + val isShowing by collectLastValue(underTest.isShowing) + setupTestConfiguration(isInRearDisplayMode = true) + + updateSfpsIndicatorRequests(kosmos, mContext, primaryBouncerRequest = true) + runCurrent() + + assertThat(isShowing).isFalse() + } + } + + @Test + fun verifyIsShowingUpdates_onPrimaryBouncerShowAndHide() { + kosmos.testScope.runTest { + val isShowing by collectLastValue(underTest.isShowing) + setupTestConfiguration(isInRearDisplayMode = false) + + // Show primary bouncer + updateSfpsIndicatorRequests(kosmos, mContext, primaryBouncerRequest = true) + runCurrent() + + assertThat(isShowing).isTrue() + + // Hide primary bouncer + updateSfpsIndicatorRequests(kosmos, mContext, primaryBouncerRequest = false) + runCurrent() + + assertThat(isShowing).isFalse() + } + } + + @Test + fun verifyIsShowingUpdates_onAlternateBouncerShowAndHide() { + kosmos.testScope.runTest { + val isShowing by collectLastValue(underTest.isShowing) + setupTestConfiguration(isInRearDisplayMode = false) + + updateSfpsIndicatorRequests(kosmos, mContext, alternateBouncerRequest = true) + runCurrent() + + assertThat(isShowing).isTrue() + + // Hide alternate bouncer + updateSfpsIndicatorRequests(kosmos, mContext, alternateBouncerRequest = false) + runCurrent() + + assertThat(isShowing).isFalse() + } + } + + @Test + fun verifyIsShowingUpdates_onSystemServerAuthenticationStartedAndStopped() { + kosmos.testScope.runTest { + val isShowing by collectLastValue(underTest.isShowing) + setupTestConfiguration(isInRearDisplayMode = false) + + updateSfpsIndicatorRequests(kosmos, mContext, biometricPromptRequest = true) + runCurrent() + + assertThat(isShowing).isTrue() + + // System server authentication stopped + updateSfpsIndicatorRequests(kosmos, mContext, biometricPromptRequest = false) + runCurrent() + + assertThat(isShowing).isFalse() + } + } + + // On progress bar shown - hide indicator + // On progress bar hidden - show indicator + // TODO(b/365182034): update + enable when rest to unlock feature is implemented + @Ignore("b/365182034") + @Test + fun verifyIsShowingUpdates_onProgressBarInteraction() { + kosmos.testScope.runTest { + val isShowing by collectLastValue(underTest.isShowing) + setupTestConfiguration(isInRearDisplayMode = false) + + updateSfpsIndicatorRequests(kosmos, mContext, primaryBouncerRequest = true) + runCurrent() + + assertThat(isShowing).isTrue() + + // updateSfpsIndicatorRequests( + // kosmos, mContext, primaryBouncerRequest = true, progressBarShowing = + // true + // ) + runCurrent() + + assertThat(isShowing).isFalse() + + // Set progress bar invisible + // updateSfpsIndicatorRequests( + // kosmos, mContext, primaryBouncerRequest = true, progressBarShowing = + // false + // ) + runCurrent() + + // Verify indicator shown + assertThat(isShowing).isTrue() + } + } + + private suspend fun TestScope.setupTestConfiguration(isInRearDisplayMode: Boolean) { + kosmos.fingerprintPropertyRepository.setProperties( + sensorId = 1, + strength = SensorStrength.STRONG, + sensorType = FingerprintSensorType.POWER_BUTTON, + sensorLocations = emptyMap() + ) + + kosmos.displayStateRepository.setIsInRearDisplayMode(isInRearDisplayMode) + kosmos.displayRepository.emitDisplayChangeEvent(0) + runCurrent() + + kosmos.biometricStatusRepository.setFingerprintAuthenticationReason( + AuthenticationReason.NotRunning + ) + // TODO(b/365182034): set progress bar visibility once rest to unlock feature is implemented + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt index 7fa165c19f60..2eea6681ecca 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt @@ -16,64 +16,48 @@ package com.android.systemui.biometrics.ui.binder -import android.animation.Animator -import android.graphics.Rect -import android.hardware.biometrics.SensorLocationInternal -import android.hardware.display.DisplayManager -import android.hardware.display.DisplayManagerGlobal import android.testing.TestableLooper -import android.view.Display -import android.view.DisplayInfo import android.view.LayoutInflater import android.view.View -import android.view.ViewPropertyAnimator -import android.view.WindowInsets import android.view.WindowManager -import android.view.WindowMetrics import android.view.layoutInflater import android.view.windowManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.airbnb.lottie.LottieAnimationView -import com.android.keyguard.keyguardUpdateMonitor import com.android.systemui.SysuiTestCase -import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider -import com.android.systemui.biometrics.data.repository.biometricStatusRepository import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository -import com.android.systemui.biometrics.shared.model.AuthenticationReason import com.android.systemui.biometrics.shared.model.DisplayRotation import com.android.systemui.biometrics.shared.model.FingerprintSensorType import com.android.systemui.biometrics.shared.model.SensorStrength -import com.android.systemui.bouncer.data.repository.keyguardBouncerRepository +import com.android.systemui.biometrics.updateSfpsIndicatorRequests import com.android.systemui.display.data.repository.displayRepository import com.android.systemui.display.data.repository.displayStateRepository -import com.android.systemui.keyguard.ui.viewmodel.sideFpsProgressBarViewModel import com.android.systemui.kosmos.testScope import com.android.systemui.res.R import com.android.systemui.testKosmos import com.android.systemui.util.mockito.eq -import com.android.systemui.util.mockito.whenever import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before +import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.Captor import org.mockito.Mock -import org.mockito.Mockito import org.mockito.Mockito.any import org.mockito.Mockito.inOrder import org.mockito.Mockito.mock import org.mockito.Mockito.never -import org.mockito.Mockito.spy import org.mockito.Mockito.verify import org.mockito.Mockito.`when` import org.mockito.junit.MockitoJUnit import org.mockito.junit.MockitoRule -import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.firstValue @OptIn(ExperimentalCoroutinesApi::class) @SmallTest @@ -83,84 +67,25 @@ class SideFpsOverlayViewBinderTest : SysuiTestCase() { private val kosmos = testKosmos() @JvmField @Rule var mockitoRule: MockitoRule = MockitoJUnit.rule() - @Mock private lateinit var displayManager: DisplayManager - @Mock - private lateinit var fingerprintInteractiveToAuthProvider: FingerprintInteractiveToAuthProvider @Mock private lateinit var layoutInflater: LayoutInflater @Mock private lateinit var sideFpsView: View - - private val contextDisplayInfo = DisplayInfo() - - private var displayWidth: Int = 0 - private var displayHeight: Int = 0 - private var boundsWidth: Int = 0 - private var boundsHeight: Int = 0 - - private lateinit var deviceConfig: DeviceConfig - private lateinit var sensorLocation: SensorLocationInternal - - enum class DeviceConfig { - X_ALIGNED, - Y_ALIGNED, - } + @Captor private lateinit var viewCaptor: ArgumentCaptor<View> @Before fun setup() { allowTestableLooperAsMainThread() // repeatWhenAttached requires the main thread - - mContext = spy(mContext) - - val resources = mContext.resources - whenever(mContext.display) - .thenReturn( - Display(mock(DisplayManagerGlobal::class.java), 1, contextDisplayInfo, resources) - ) - kosmos.layoutInflater = layoutInflater - - whenever(fingerprintInteractiveToAuthProvider.enabledForCurrentUser) - .thenReturn(MutableStateFlow(false)) - - context.addMockSystemService(DisplayManager::class.java, displayManager) context.addMockSystemService(WindowManager::class.java, kosmos.windowManager) - `when`(layoutInflater.inflate(R.layout.sidefps_view, null, false)).thenReturn(sideFpsView) `when`(sideFpsView.requireViewById<LottieAnimationView>(eq(R.id.sidefps_animation))) .thenReturn(mock(LottieAnimationView::class.java)) - with(mock(ViewPropertyAnimator::class.java)) { - `when`(sideFpsView.animate()).thenReturn(this) - `when`(alpha(Mockito.anyFloat())).thenReturn(this) - `when`(setStartDelay(Mockito.anyLong())).thenReturn(this) - `when`(setDuration(Mockito.anyLong())).thenReturn(this) - `when`(setListener(any())).thenAnswer { - (it.arguments[0] as Animator.AnimatorListener).onAnimationEnd( - mock(Animator::class.java) - ) - this - } - } } @Test fun verifyIndicatorNotAdded_whenInRearDisplayMode() { kosmos.testScope.runTest { - setupTestConfiguration( - DeviceConfig.X_ALIGNED, - rotation = DisplayRotation.ROTATION_0, - isInRearDisplayMode = true - ) - kosmos.biometricStatusRepository.setFingerprintAuthenticationReason( - AuthenticationReason.NotRunning - ) - kosmos.sideFpsProgressBarViewModel.setVisible(false) - updatePrimaryBouncer( - isShowing = true, - isAnimatingAway = false, - fpsDetectionRunning = true, - isUnlockingWithFpAllowed = true - ) - runCurrent() - + setupTestConfiguration(isInRearDisplayMode = true) + updateSfpsIndicatorRequests(kosmos, mContext, primaryBouncerRequest = true) verify(kosmos.windowManager, never()).addView(any(), any()) } } @@ -168,33 +93,14 @@ class SideFpsOverlayViewBinderTest : SysuiTestCase() { @Test fun verifyIndicatorShowAndHide_onPrimaryBouncerShowAndHide() { kosmos.testScope.runTest { - setupTestConfiguration( - DeviceConfig.X_ALIGNED, - rotation = DisplayRotation.ROTATION_0, - isInRearDisplayMode = false - ) - kosmos.biometricStatusRepository.setFingerprintAuthenticationReason( - AuthenticationReason.NotRunning - ) - kosmos.sideFpsProgressBarViewModel.setVisible(false) - // Show primary bouncer - updatePrimaryBouncer( - isShowing = true, - isAnimatingAway = false, - fpsDetectionRunning = true, - isUnlockingWithFpAllowed = true - ) + setupTestConfiguration(isInRearDisplayMode = false) + updateSfpsIndicatorRequests(kosmos, mContext, primaryBouncerRequest = true) runCurrent() verify(kosmos.windowManager).addView(any(), any()) // Hide primary bouncer - updatePrimaryBouncer( - isShowing = false, - isAnimatingAway = false, - fpsDetectionRunning = true, - isUnlockingWithFpAllowed = true - ) + updateSfpsIndicatorRequests(kosmos, mContext, primaryBouncerRequest = false) runCurrent() verify(kosmos.windowManager).removeView(any()) @@ -204,30 +110,19 @@ class SideFpsOverlayViewBinderTest : SysuiTestCase() { @Test fun verifyIndicatorShowAndHide_onAlternateBouncerShowAndHide() { kosmos.testScope.runTest { - setupTestConfiguration( - DeviceConfig.X_ALIGNED, - rotation = DisplayRotation.ROTATION_0, - isInRearDisplayMode = false - ) - kosmos.biometricStatusRepository.setFingerprintAuthenticationReason( - AuthenticationReason.NotRunning - ) - kosmos.sideFpsProgressBarViewModel.setVisible(false) - // Show alternate bouncer - kosmos.keyguardBouncerRepository.setAlternateVisible(true) + setupTestConfiguration(isInRearDisplayMode = false) + updateSfpsIndicatorRequests(kosmos, mContext, alternateBouncerRequest = true) runCurrent() verify(kosmos.windowManager).addView(any(), any()) - var viewCaptor = argumentCaptor<View>() verify(kosmos.windowManager).addView(viewCaptor.capture(), any()) verify(viewCaptor.firstValue) .announceForAccessibility( mContext.getText(R.string.accessibility_side_fingerprint_indicator_label) ) - // Hide alternate bouncer - kosmos.keyguardBouncerRepository.setAlternateVisible(false) + updateSfpsIndicatorRequests(kosmos, mContext, alternateBouncerRequest = false) runCurrent() verify(kosmos.windowManager).removeView(any()) @@ -237,30 +132,14 @@ class SideFpsOverlayViewBinderTest : SysuiTestCase() { @Test fun verifyIndicatorShownAndHidden_onSystemServerAuthenticationStartedAndStopped() { kosmos.testScope.runTest { - setupTestConfiguration( - DeviceConfig.X_ALIGNED, - rotation = DisplayRotation.ROTATION_0, - isInRearDisplayMode = false - ) - kosmos.sideFpsProgressBarViewModel.setVisible(false) - updatePrimaryBouncer( - isShowing = false, - isAnimatingAway = false, - fpsDetectionRunning = true, - isUnlockingWithFpAllowed = true - ) - // System server authentication started - kosmos.biometricStatusRepository.setFingerprintAuthenticationReason( - AuthenticationReason.BiometricPromptAuthentication - ) + setupTestConfiguration(isInRearDisplayMode = false) + updateSfpsIndicatorRequests(kosmos, mContext, biometricPromptRequest = true) runCurrent() verify(kosmos.windowManager).addView(any(), any()) // System server authentication stopped - kosmos.biometricStatusRepository.setFingerprintAuthenticationReason( - AuthenticationReason.NotRunning - ) + updateSfpsIndicatorRequests(kosmos, mContext, biometricPromptRequest = false) runCurrent() verify(kosmos.windowManager).removeView(any()) @@ -269,45 +148,35 @@ class SideFpsOverlayViewBinderTest : SysuiTestCase() { // On progress bar shown - hide indicator // On progress bar hidden - show indicator + // TODO(b/365182034): update + enable when rest to unlock feature is implemented + @Ignore("b/365182034") @Test fun verifyIndicatorProgressBarInteraction() { kosmos.testScope.runTest { // Pre-auth conditions - setupTestConfiguration( - DeviceConfig.X_ALIGNED, - rotation = DisplayRotation.ROTATION_0, - isInRearDisplayMode = false - ) - kosmos.biometricStatusRepository.setFingerprintAuthenticationReason( - AuthenticationReason.NotRunning - ) - kosmos.sideFpsProgressBarViewModel.setVisible(false) - - // Show primary bouncer - updatePrimaryBouncer( - isShowing = true, - isAnimatingAway = false, - fpsDetectionRunning = true, - isUnlockingWithFpAllowed = true - ) + setupTestConfiguration(isInRearDisplayMode = false) + updateSfpsIndicatorRequests(kosmos, mContext, primaryBouncerRequest = true) runCurrent() val inOrder = inOrder(kosmos.windowManager) - // Verify indicator shown inOrder.verify(kosmos.windowManager).addView(any(), any()) // Set progress bar visible - kosmos.sideFpsProgressBarViewModel.setVisible(true) - + // updateSfpsIndicatorRequests( + // kosmos, mContext, primaryBouncerRequest = true, progressBarShowing = + // true + // ) runCurrent() // Verify indicator hidden inOrder.verify(kosmos.windowManager).removeView(any()) // Set progress bar invisible - kosmos.sideFpsProgressBarViewModel.setVisible(false) - + // updateSfpsIndicatorRequests( + // kosmos, mContext, primaryBouncerRequest = true, progressBarShowing = + // false + // ) runCurrent() // Verify indicator shown @@ -315,78 +184,18 @@ class SideFpsOverlayViewBinderTest : SysuiTestCase() { } } - private fun updatePrimaryBouncer( - isShowing: Boolean, - isAnimatingAway: Boolean, - fpsDetectionRunning: Boolean, - isUnlockingWithFpAllowed: Boolean, - ) { - kosmos.keyguardBouncerRepository.setPrimaryShow(isShowing) - kosmos.keyguardBouncerRepository.setPrimaryStartingToHide(false) - val primaryStartDisappearAnimation = if (isAnimatingAway) Runnable {} else null - kosmos.keyguardBouncerRepository.setPrimaryStartDisappearAnimation( - primaryStartDisappearAnimation - ) - - whenever(kosmos.keyguardUpdateMonitor.isFingerprintDetectionRunning) - .thenReturn(fpsDetectionRunning) - whenever(kosmos.keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed) - .thenReturn(isUnlockingWithFpAllowed) - mContext.orCreateTestableResources.addOverride( - R.bool.config_show_sidefps_hint_on_bouncer, - true - ) - } - - private suspend fun TestScope.setupTestConfiguration( - deviceConfig: DeviceConfig, - rotation: DisplayRotation = DisplayRotation.ROTATION_0, - isInRearDisplayMode: Boolean, - ) { - this@SideFpsOverlayViewBinderTest.deviceConfig = deviceConfig - - when (deviceConfig) { - DeviceConfig.X_ALIGNED -> { - displayWidth = 3000 - displayHeight = 1500 - boundsWidth = 200 - boundsHeight = 100 - sensorLocation = SensorLocationInternal("", 2500, 0, boundsWidth / 2) - } - DeviceConfig.Y_ALIGNED -> { - displayWidth = 2500 - displayHeight = 2000 - boundsWidth = 100 - boundsHeight = 200 - sensorLocation = SensorLocationInternal("", displayWidth, 300, boundsHeight / 2) - } - } - - whenever(kosmos.windowManager.maximumWindowMetrics) - .thenReturn( - WindowMetrics( - Rect(0, 0, displayWidth, displayHeight), - mock(WindowInsets::class.java), - ) - ) - - contextDisplayInfo.uniqueId = DISPLAY_ID - + private suspend fun TestScope.setupTestConfiguration(isInRearDisplayMode: Boolean) { kosmos.fingerprintPropertyRepository.setProperties( sensorId = 1, strength = SensorStrength.STRONG, sensorType = FingerprintSensorType.POWER_BUTTON, - sensorLocations = mapOf(DISPLAY_ID to sensorLocation) + sensorLocations = emptyMap() ) kosmos.displayStateRepository.setIsInRearDisplayMode(isInRearDisplayMode) - kosmos.displayStateRepository.setCurrentRotation(rotation) + kosmos.displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_0) kosmos.displayRepository.emitDisplayChangeEvent(0) kosmos.sideFpsOverlayViewBinder.start() runCurrent() } - - companion object { - private const val DISPLAY_ID = "displayId" - } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt index 0db7b62b8ef1..27b1371deb12 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt @@ -30,23 +30,19 @@ import android.view.windowManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.airbnb.lottie.model.KeyPath -import com.android.keyguard.keyguardUpdateMonitor import com.android.settingslib.Utils import com.android.systemui.SysuiTestCase import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider -import com.android.systemui.biometrics.data.repository.biometricStatusRepository import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository import com.android.systemui.biometrics.domain.interactor.displayStateInteractor -import com.android.systemui.biometrics.shared.model.AuthenticationReason import com.android.systemui.biometrics.shared.model.DisplayRotation import com.android.systemui.biometrics.shared.model.FingerprintSensorType import com.android.systemui.biometrics.shared.model.LottieCallback import com.android.systemui.biometrics.shared.model.SensorStrength -import com.android.systemui.bouncer.data.repository.keyguardBouncerRepository +import com.android.systemui.biometrics.updateSfpsIndicatorRequests import com.android.systemui.coroutines.collectLastValue import com.android.systemui.display.data.repository.displayRepository import com.android.systemui.display.data.repository.displayStateRepository -import com.android.systemui.keyguard.ui.viewmodel.sideFpsProgressBarViewModel import com.android.systemui.kosmos.testScope import com.android.systemui.res.R import com.android.systemui.testKosmos @@ -284,17 +280,7 @@ class SideFpsOverlayViewModelTest : SysuiTestCase() { kosmos.testScope.runTest { val lottieCallbacks by collectLastValue(kosmos.sideFpsOverlayViewModel.lottieCallbacks) - kosmos.biometricStatusRepository.setFingerprintAuthenticationReason( - AuthenticationReason.NotRunning - ) - kosmos.sideFpsProgressBarViewModel.setVisible(false) - - updatePrimaryBouncer( - isShowing = true, - isAnimatingAway = false, - fpsDetectionRunning = true, - isUnlockingWithFpAllowed = true - ) + updateSfpsIndicatorRequests(kosmos, mContext, primaryBouncerRequest = true) runCurrent() assertThat(lottieCallbacks) @@ -312,17 +298,7 @@ class SideFpsOverlayViewModelTest : SysuiTestCase() { val lottieCallbacks by collectLastValue(kosmos.sideFpsOverlayViewModel.lottieCallbacks) setDarkMode(true) - kosmos.biometricStatusRepository.setFingerprintAuthenticationReason( - AuthenticationReason.BiometricPromptAuthentication - ) - kosmos.sideFpsProgressBarViewModel.setVisible(false) - - updatePrimaryBouncer( - isShowing = false, - isAnimatingAway = false, - fpsDetectionRunning = true, - isUnlockingWithFpAllowed = true - ) + updateSfpsIndicatorRequests(kosmos, mContext, biometricPromptRequest = true) runCurrent() assertThat(lottieCallbacks) @@ -338,17 +314,7 @@ class SideFpsOverlayViewModelTest : SysuiTestCase() { val lottieCallbacks by collectLastValue(kosmos.sideFpsOverlayViewModel.lottieCallbacks) setDarkMode(false) - kosmos.biometricStatusRepository.setFingerprintAuthenticationReason( - AuthenticationReason.BiometricPromptAuthentication - ) - kosmos.sideFpsProgressBarViewModel.setVisible(false) - - updatePrimaryBouncer( - isShowing = false, - isAnimatingAway = false, - fpsDetectionRunning = true, - isUnlockingWithFpAllowed = true - ) + updateSfpsIndicatorRequests(kosmos, mContext, biometricPromptRequest = true) runCurrent() assertThat(lottieCallbacks) @@ -371,29 +337,6 @@ class SideFpsOverlayViewModelTest : SysuiTestCase() { mContext.resources.configuration.uiMode = uiMode } - private fun updatePrimaryBouncer( - isShowing: Boolean, - isAnimatingAway: Boolean, - fpsDetectionRunning: Boolean, - isUnlockingWithFpAllowed: Boolean, - ) { - kosmos.keyguardBouncerRepository.setPrimaryShow(isShowing) - kosmos.keyguardBouncerRepository.setPrimaryStartingToHide(false) - val primaryStartDisappearAnimation = if (isAnimatingAway) Runnable {} else null - kosmos.keyguardBouncerRepository.setPrimaryStartDisappearAnimation( - primaryStartDisappearAnimation - ) - - whenever(kosmos.keyguardUpdateMonitor.isFingerprintDetectionRunning) - .thenReturn(fpsDetectionRunning) - whenever(kosmos.keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed) - .thenReturn(isUnlockingWithFpAllowed) - mContext.orCreateTestableResources.addOverride( - R.bool.config_show_sidefps_hint_on_bouncer, - true - ) - } - private suspend fun TestScope.setupTestConfiguration( deviceConfig: DeviceConfig, rotation: DisplayRotation = DisplayRotation.ROTATION_0, diff --git a/packages/SystemUI/res/layout/biometric_prompt_one_pane_layout.xml b/packages/SystemUI/res/layout/biometric_prompt_one_pane_layout.xml index 3b3ed39c8993..91cd019c85d1 100644 --- a/packages/SystemUI/res/layout/biometric_prompt_one_pane_layout.xml +++ b/packages/SystemUI/res/layout/biometric_prompt_one_pane_layout.xml @@ -215,17 +215,4 @@ app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="1.0" tools:srcCompat="@tools:sample/avatars" /> - - <com.android.systemui.biometrics.BiometricPromptLottieViewWrapper - android:id="@+id/biometric_icon_overlay" - android:layout_width="0dp" - android:layout_height="0dp" - android:layout_gravity="center" - android:contentDescription="@null" - android:scaleType="fitXY" - android:importantForAccessibility="no" - app:layout_constraintBottom_toBottomOf="@+id/biometric_icon" - app:layout_constraintEnd_toEndOf="@+id/biometric_icon" - app:layout_constraintStart_toStartOf="@+id/biometric_icon" - app:layout_constraintTop_toTopOf="@+id/biometric_icon" /> </androidx.constraintlayout.widget.ConstraintLayout> diff --git a/packages/SystemUI/res/layout/biometric_prompt_two_pane_layout.xml b/packages/SystemUI/res/layout/biometric_prompt_two_pane_layout.xml index 2a00495e9d01..51117a7845df 100644 --- a/packages/SystemUI/res/layout/biometric_prompt_two_pane_layout.xml +++ b/packages/SystemUI/res/layout/biometric_prompt_two_pane_layout.xml @@ -40,19 +40,6 @@ android:layout_height="match_parent"> app:layout_constraintTop_toTopOf="parent" tools:srcCompat="@tools:sample/avatars" /> - <com.android.systemui.biometrics.BiometricPromptLottieViewWrapper - android:id="@+id/biometric_icon_overlay" - android:layout_width="0dp" - android:layout_height="0dp" - android:layout_gravity="center" - android:contentDescription="@null" - android:scaleType="fitXY" - android:importantForAccessibility="no" - app:layout_constraintBottom_toBottomOf="@+id/biometric_icon" - app:layout_constraintEnd_toEndOf="@+id/biometric_icon" - app:layout_constraintStart_toStartOf="@+id/biometric_icon" - app:layout_constraintTop_toTopOf="@+id/biometric_icon" /> - <ScrollView android:id="@+id/scrollView" android:layout_width="0dp" diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/BiometricsDomainLayerModule.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/BiometricsDomainLayerModule.kt index ec3fd9f7da35..7ecbb88099cb 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/BiometricsDomainLayerModule.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/BiometricsDomainLayerModule.kt @@ -25,6 +25,8 @@ import com.android.systemui.biometrics.domain.interactor.LogContextInteractor import com.android.systemui.biometrics.domain.interactor.LogContextInteractorImpl import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractorImpl +import com.android.systemui.biometrics.domain.interactor.SideFpsOverlayInteractor +import com.android.systemui.biometrics.domain.interactor.SideFpsOverlayInteractorImpl import com.android.systemui.dagger.SysUISingleton import dagger.Binds import dagger.Module @@ -46,6 +48,12 @@ interface BiometricsDomainLayerModule { @Binds @SysUISingleton + fun providesSideFpsOverlayInteractor( + impl: SideFpsOverlayInteractorImpl + ): SideFpsOverlayInteractor + + @Binds + @SysUISingleton fun providesCredentialInteractor(impl: CredentialInteractorImpl): CredentialInteractor @Binds diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractor.kt new file mode 100644 index 000000000000..10c3483de452 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractor.kt @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.biometrics.domain.interactor + +import android.util.Log +import com.android.systemui.biometrics.shared.model.AuthenticationReason.NotRunning +import com.android.systemui.keyguard.domain.interactor.DeviceEntrySideFpsOverlayInteractor +import com.android.systemui.util.kotlin.sample +import javax.inject.Inject +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.onEach + +/** Encapsulates business logic for showing and hiding the side fingerprint sensor indicator. */ +interface SideFpsOverlayInteractor { + /** Whether the side fingerprint sensor indicator is currently showing. */ + val isShowing: Flow<Boolean> +} + +@OptIn(ExperimentalCoroutinesApi::class) +class SideFpsOverlayInteractorImpl +@Inject +constructor( + biometricStatusInteractor: BiometricStatusInteractor, + displayStateInteractor: DisplayStateInteractor, + deviceEntrySideFpsOverlayInteractor: DeviceEntrySideFpsOverlayInteractor, + sfpsSensorInteractor: SideFpsSensorInteractor, + // TODO(b/365182034): add progress bar input when rest to unlock feature is implemented +) : SideFpsOverlayInteractor { + private val sfpsOverlayEnabled: Flow<Boolean> = + sfpsSensorInteractor.isAvailable.sample(displayStateInteractor.isInRearDisplayMode) { + isAvailable: Boolean, + isInRearDisplayMode: Boolean -> + isAvailable && !isInRearDisplayMode + } + + private val showSideFpsOverlay: Flow<Boolean> = + combine( + biometricStatusInteractor.sfpsAuthenticationReason, + deviceEntrySideFpsOverlayInteractor.showIndicatorForDeviceEntry, + // TODO(b/365182034): add progress bar input when rest to unlock feature is implemented + ) { systemServerAuthReason, showIndicatorForDeviceEntry -> + Log.d( + TAG, + "systemServerAuthReason = $systemServerAuthReason, " + + "showIndicatorForDeviceEntry = $showIndicatorForDeviceEntry, " + ) + systemServerAuthReason != NotRunning || showIndicatorForDeviceEntry + } + + override val isShowing: Flow<Boolean> = + sfpsOverlayEnabled + .flatMapLatest { sfpsOverlayEnabled -> + if (!sfpsOverlayEnabled) { + flowOf(false) + } else { + showSideFpsOverlay + } + } + .onEach { Log.d(TAG, "isShowing: $it") } + + companion object { + private const val TAG = "SideFpsOverlayInteractor" + } +} diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt index d69e87534cb6..d055731b2698 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt @@ -158,16 +158,13 @@ object BiometricViewSizeBinder { fun setVisibilities(hideSensorIcon: Boolean, size: PromptSize) { viewsToHideWhenSmall.forEach { it.showContentOrHide(forceHide = size.isSmall) } largeConstraintSet.setVisibility(iconHolderView.id, View.GONE) - largeConstraintSet.setVisibility(R.id.biometric_icon_overlay, View.GONE) largeConstraintSet.setVisibility(R.id.indicator, View.GONE) largeConstraintSet.setVisibility(R.id.scrollView, View.GONE) if (hideSensorIcon) { smallConstraintSet.setVisibility(iconHolderView.id, View.GONE) - smallConstraintSet.setVisibility(R.id.biometric_icon_overlay, View.GONE) smallConstraintSet.setVisibility(R.id.indicator, View.GONE) mediumConstraintSet.setVisibility(iconHolderView.id, View.GONE) - mediumConstraintSet.setVisibility(R.id.biometric_icon_overlay, View.GONE) mediumConstraintSet.setVisibility(R.id.indicator, View.GONE) } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt index 9578da4238ee..9fe1dc51f4c2 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt @@ -33,89 +33,44 @@ import com.airbnb.lottie.LottieProperty import com.android.app.animation.Interpolators import com.android.keyguard.KeyguardPINView import com.android.systemui.CoreStartable -import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractor -import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor -import com.android.systemui.biometrics.domain.interactor.SideFpsSensorInteractor -import com.android.systemui.biometrics.shared.model.AuthenticationReason.NotRunning +import com.android.systemui.biometrics.domain.interactor.SideFpsOverlayInteractor import com.android.systemui.biometrics.shared.model.LottieCallback import com.android.systemui.biometrics.ui.viewmodel.SideFpsOverlayViewModel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application -import com.android.systemui.keyguard.domain.interactor.DeviceEntrySideFpsOverlayInteractor -import com.android.systemui.keyguard.ui.viewmodel.SideFpsProgressBarViewModel import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.res.R -import com.android.systemui.util.kotlin.sample import dagger.Lazy import javax.inject.Inject import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.combine import kotlinx.coroutines.launch /** Binds the side fingerprint sensor indicator view to [SideFpsOverlayViewModel]. */ -@OptIn(ExperimentalCoroutinesApi::class) @SysUISingleton class SideFpsOverlayViewBinder @Inject constructor( @Application private val applicationScope: CoroutineScope, @Application private val applicationContext: Context, - private val biometricStatusInteractor: Lazy<BiometricStatusInteractor>, - private val displayStateInteractor: Lazy<DisplayStateInteractor>, - private val deviceEntrySideFpsOverlayInteractor: Lazy<DeviceEntrySideFpsOverlayInteractor>, private val layoutInflater: Lazy<LayoutInflater>, - private val sideFpsProgressBarViewModel: Lazy<SideFpsProgressBarViewModel>, - private val sfpsSensorInteractor: Lazy<SideFpsSensorInteractor>, + private val sideFpsOverlayInteractor: Lazy<SideFpsOverlayInteractor>, + private val sideFpsOverlayViewModel: Lazy<SideFpsOverlayViewModel>, private val windowManager: Lazy<WindowManager> ) : CoreStartable { + private var overlayView: View? = null override fun start() { - applicationScope - .launch { - sfpsSensorInteractor.get().isAvailable.collect { isSfpsAvailable -> - if (isSfpsAvailable) { - combine( - biometricStatusInteractor.get().sfpsAuthenticationReason, - deviceEntrySideFpsOverlayInteractor - .get() - .showIndicatorForDeviceEntry, - sideFpsProgressBarViewModel.get().isVisible, - ::Triple - ) - .sample(displayStateInteractor.get().isInRearDisplayMode, ::Pair) - .collect { (combinedFlows, isInRearDisplayMode: Boolean) -> - val ( - systemServerAuthReason, - showIndicatorForDeviceEntry, - progressBarIsVisible) = - combinedFlows - Log.d( - TAG, - "systemServerAuthReason = $systemServerAuthReason, " + - "showIndicatorForDeviceEntry = " + - "$showIndicatorForDeviceEntry, " + - "progressBarIsVisible = $progressBarIsVisible" - ) - if (!isInRearDisplayMode) { - if (progressBarIsVisible) { - hide() - } else if (systemServerAuthReason != NotRunning) { - show() - } else if (showIndicatorForDeviceEntry) { - show() - } else { - hide() - } - } - } - } + applicationScope.launch { + sideFpsOverlayInteractor.get().isShowing.collect { isShowing: Boolean -> + if (isShowing) { + show() + } else { + hide() } } + } } - private var overlayView: View? = null - /** Show the side fingerprint sensor indicator */ private fun show() { if (overlayView?.isAttachedToWindow == true) { @@ -125,17 +80,10 @@ constructor( ) return } - overlayView = layoutInflater.get().inflate(R.layout.sidefps_view, null, false) - - val overlayViewModel = - SideFpsOverlayViewModel( - applicationContext, - deviceEntrySideFpsOverlayInteractor.get(), - displayStateInteractor.get(), - sfpsSensorInteractor.get(), - ) + val overlayViewModel = sideFpsOverlayViewModel.get() bind(overlayView!!, overlayViewModel, windowManager.get()) + overlayView!!.visibility = View.INVISIBLE Log.d(TAG, "show(): adding overlayView $overlayView") windowManager.get().addView(overlayView, overlayViewModel.defaultOverlayViewParams) @@ -161,6 +109,20 @@ constructor( companion object { private const val TAG = "SideFpsOverlayViewBinder" + private val accessibilityDelegate = + object : View.AccessibilityDelegate() { + override fun dispatchPopulateAccessibilityEvent( + host: View, + event: AccessibilityEvent + ): Boolean { + return if (event.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { + true + } else { + super.dispatchPopulateAccessibilityEvent(host, event) + } + } + } + /** Binds overlayView (side fingerprint sensor indicator view) to SideFpsOverlayViewModel */ fun bind( overlayView: View, @@ -184,24 +146,7 @@ constructor( overlayShowAnimator.start() - it.setAccessibilityDelegate( - object : View.AccessibilityDelegate() { - override fun dispatchPopulateAccessibilityEvent( - host: View, - event: AccessibilityEvent - ): Boolean { - return if ( - event.getEventType() === - android.view.accessibility.AccessibilityEvent - .TYPE_WINDOW_STATE_CHANGED - ) { - true - } else { - super.dispatchPopulateAccessibilityEvent(host, event) - } - } - } - ) + it.accessibilityDelegate = accessibilityDelegate repeatOnLifecycle(Lifecycle.State.STARTED) { launch { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt index 168ba11309cc..85f221fa951e 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt @@ -78,11 +78,11 @@ import kotlinx.coroutines.launch class PromptViewModel @Inject constructor( - displayStateInteractor: DisplayStateInteractor, + private val displayStateInteractor: DisplayStateInteractor, private val promptSelectorInteractor: PromptSelectorInteractor, @Application private val context: Context, - private val udfpsOverlayInteractor: UdfpsOverlayInteractor, - private val biometricStatusInteractor: BiometricStatusInteractor, + udfpsOverlayInteractor: UdfpsOverlayInteractor, + biometricStatusInteractor: BiometricStatusInteractor, private val udfpsUtils: UdfpsUtils, private val iconProvider: IconProvider, private val activityTaskManager: ActivityTaskManager, @@ -135,11 +135,13 @@ constructor( R.dimen.biometric_prompt_landscape_medium_horizontal_padding ) + val currentRotation: StateFlow<DisplayRotation> = displayStateInteractor.currentRotation + val udfpsOverlayParams: StateFlow<UdfpsOverlayParams> = udfpsOverlayInteractor.udfpsOverlayParams private val udfpsSensorBounds: Flow<Rect> = - combine(udfpsOverlayParams, displayStateInteractor.currentRotation) { params, rotation -> + combine(udfpsOverlayParams, currentRotation) { params, rotation -> val rotatedBounds = Rect(params.sensorBounds) RotationUtils.rotateBounds( rotatedBounds, @@ -262,7 +264,7 @@ constructor( _forceLargeSize, promptKind, displayStateInteractor.isLargeScreen, - displayStateInteractor.currentRotation, + currentRotation, modalities ) { forceLarge, promptKind, isLargeScreen, rotation, modalities -> when { @@ -454,7 +456,7 @@ constructor( /** Padding for prompt UI elements */ val promptPadding: Flow<Rect> = - combine(size, displayStateInteractor.currentRotation) { size, rotation -> + combine(size, currentRotation) { size, rotation -> if (size != PromptSize.LARGE) { val navBarInsets = Utils.getNavbarInsets(context) if (rotation == DisplayRotation.ROTATION_90) { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModel.kt index c2a4ee36dec6..7c1984e506c9 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModel.kt @@ -147,8 +147,7 @@ constructor( _lottieBounds, sensorLocation, displayRotation, - ) { bounds: Rect?, sensorLocation: SideFpsSensorLocation, displayRotation: DisplayRotation - -> + ) { _: Rect?, sensorLocation: SideFpsSensorLocation, _: DisplayRotation -> val topLeft = Point(sensorLocation.left, sensorLocation.top) defaultOverlayViewParams.apply { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt index c5909ed24c50..75e38714f1fa 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt @@ -107,6 +107,8 @@ constructor( } } + // TODO(b/365182034): move to interactor, add as dependency of SideFpsOverlayInteractor when + // rest to unlock feature is implemented val isVisible: Flow<Boolean> = _visible.asStateFlow() val progress: Flow<Float> = _progress.asStateFlow() diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt index 55fd3440ea07..48505102eba5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt @@ -54,6 +54,7 @@ import com.android.systemui.biometrics.data.repository.biometricStatusRepository import com.android.systemui.biometrics.data.repository.fakeFingerprintPropertyRepository import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor import com.android.systemui.biometrics.domain.interactor.promptSelectorInteractor +import com.android.systemui.biometrics.domain.interactor.sideFpsOverlayInteractor import com.android.systemui.biometrics.domain.interactor.udfpsOverlayInteractor import com.android.systemui.biometrics.extractAuthenticatorTypes import com.android.systemui.biometrics.faceSensorPropertiesInternal @@ -1453,11 +1454,15 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa @Test fun switch_to_credential_fallback() = runGenericTest { val size by collectLastValue(kosmos.promptViewModel.size) + val isShowingSfpsIndicator by collectLastValue(kosmos.sideFpsOverlayInteractor.isShowing) // TODO(b/251476085): remove Spaghetti, migrate logic, and update this test kosmos.promptViewModel.onSwitchToCredential() assertThat(size).isEqualTo(PromptSize.LARGE) + if (testCase.modalities.hasSfps) { + assertThat(isShowingSfpsIndicator).isFalse() + } } @Test diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractorKosmos.kt new file mode 100644 index 000000000000..15c7e25f8a5c --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractorKosmos.kt @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.biometrics.domain.interactor + +import com.android.systemui.keyguard.domain.interactor.deviceEntrySideFpsOverlayInteractor +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import kotlinx.coroutines.ExperimentalCoroutinesApi + +@OptIn(ExperimentalCoroutinesApi::class) +val Kosmos.sideFpsOverlayInteractor by Fixture { + SideFpsOverlayInteractorImpl( + biometricStatusInteractor, + displayStateInteractor, + deviceEntrySideFpsOverlayInteractor, + sideFpsSensorInteractor, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderKosmos.kt index 79d58a1d4e40..59809e3d253f 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderKosmos.kt @@ -19,27 +19,19 @@ package com.android.systemui.biometrics.ui.binder import android.content.applicationContext import android.view.layoutInflater import android.view.windowManager -import com.android.systemui.biometrics.domain.interactor.biometricStatusInteractor -import com.android.systemui.biometrics.domain.interactor.displayStateInteractor -import com.android.systemui.biometrics.domain.interactor.sideFpsSensorInteractor -import com.android.systemui.keyguard.domain.interactor.deviceEntrySideFpsOverlayInteractor -import com.android.systemui.keyguard.ui.viewmodel.sideFpsProgressBarViewModel +import com.android.systemui.biometrics.domain.interactor.sideFpsOverlayInteractor +import com.android.systemui.biometrics.ui.viewmodel.sideFpsOverlayViewModel import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.kosmos.applicationCoroutineScope -import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) val Kosmos.sideFpsOverlayViewBinder by Fixture { SideFpsOverlayViewBinder( - applicationScope = applicationCoroutineScope, - applicationContext = applicationContext, - { biometricStatusInteractor }, - { displayStateInteractor }, - { deviceEntrySideFpsOverlayInteractor }, + applicationCoroutineScope, + applicationContext, { layoutInflater }, - { sideFpsProgressBarViewModel }, - { sideFpsSensorInteractor }, + { sideFpsOverlayInteractor }, + { sideFpsOverlayViewModel }, { windowManager } ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelKosmos.kt index de038559fc38..e10b2dd6497d 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelKosmos.kt @@ -27,9 +27,9 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi @OptIn(ExperimentalCoroutinesApi::class) val Kosmos.sideFpsOverlayViewModel by Fixture { SideFpsOverlayViewModel( - applicationContext = applicationContext, - deviceEntrySideFpsOverlayInteractor = deviceEntrySideFpsOverlayInteractor, - displayStateInteractor = displayStateInteractor, - sfpsSensorInteractor = sideFpsSensorInteractor, + applicationContext, + deviceEntrySideFpsOverlayInteractor, + displayStateInteractor, + sideFpsSensorInteractor, ) } |