summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt75
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractorTest.kt174
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt255
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt65
-rw-r--r--packages/SystemUI/res/layout/biometric_prompt_one_pane_layout.xml13
-rw-r--r--packages/SystemUI/res/layout/biometric_prompt_two_pane_layout.xml13
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/domain/BiometricsDomainLayerModule.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractor.kt82
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt111
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModel.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt5
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractorKosmos.kt32
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderKosmos.kt20
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelKosmos.kt8
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,
)
}