summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Beverly Tai <beverlyt@google.com> 2024-01-30 13:29:39 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2024-01-30 13:29:39 +0000
commit3cec4a195ff54c4ca115b4cf2edd41be7a417676 (patch)
tree26bb857b19ab6c8e645ac3932e2220c80e535d7f
parent9d6a9b7fea8d29dd59794e8c04d0357d08b90db1 (diff)
parentc82878ee820ef4b538195d97e8711813dc0aba2e (diff)
Merge "Only register for face auth lift gesture when device is interactive" into main
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/ui/binder/LiftToRunFaceAuthBinderTest.kt200
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/deviceentry/ui/binder/LiftToRunFaceAuthBinder.kt143
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthModule.kt (renamed from packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardFaceAuthModule.kt)12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt128
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/android/content/PackageManagerKosmos.kt22
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorKosmos.kt35
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorKosmos.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/ui/binder/LiftToRunFaceAuthBinderKosmos.kt45
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsKosmos.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelKosmos.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/util/sensors/AsyncSensorManagerKosmos.kt21
15 files changed, 488 insertions, 153 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/ui/binder/LiftToRunFaceAuthBinderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/ui/binder/LiftToRunFaceAuthBinderTest.kt
new file mode 100644
index 000000000000..e9e85c9f210b
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/ui/binder/LiftToRunFaceAuthBinderTest.kt
@@ -0,0 +1,200 @@
+/*
+ * 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.deviceentry.domain.ui.binder
+
+import android.content.packageManager
+import android.content.pm.PackageManager
+import android.hardware.Sensor
+import android.hardware.TriggerEventListener
+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.bouncer.data.repository.keyguardBouncerRepository
+import com.android.systemui.deviceentry.ui.binder.liftToRunFaceAuthBinder
+import com.android.systemui.keyguard.data.repository.biometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.power.data.repository.fakePowerRepository
+import com.android.systemui.testKosmos
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.sensors.asyncSensorManager
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.clearInvocations
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class LiftToRunFaceAuthBinderTest : SysuiTestCase() {
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+ private val sensorManager = kosmos.asyncSensorManager
+ private val powerRepository = kosmos.fakePowerRepository
+ private val keyguardRepository = kosmos.fakeKeyguardRepository
+ private val bouncerRepository = kosmos.keyguardBouncerRepository
+ private val biometricSettingsRepository = kosmos.biometricSettingsRepository
+ private val packageManager = kosmos.packageManager
+
+ @Captor private lateinit var triggerEventListenerCaptor: ArgumentCaptor<TriggerEventListener>
+ @Mock private lateinit var mockSensor: Sensor
+
+ private val underTest = kosmos.liftToRunFaceAuthBinder
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ whenever(packageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true)
+ whenever(sensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE)).thenReturn(mockSensor)
+ }
+
+ @Test
+ fun doNotListenForGesture() =
+ testScope.runTest {
+ start()
+ verifyNeverRequestsTriggerSensor()
+ }
+
+ @Test
+ fun awakeKeyguard_listenForGesture() =
+ testScope.runTest {
+ start()
+ givenAwakeKeyguard(true)
+ runCurrent()
+ verifyRequestTriggerSensor()
+ }
+
+ @Test
+ fun faceNotEnrolled_listenForGesture() =
+ testScope.runTest {
+ start()
+ givenAwakeKeyguard(true)
+ biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(false)
+ runCurrent()
+ verifyNeverRequestsTriggerSensor()
+ }
+
+ @Test
+ fun notInteractive_doNotListenForGesture() =
+ testScope.runTest {
+ start()
+ givenAwakeKeyguard(true)
+ powerRepository.setInteractive(false)
+ runCurrent()
+ verifyNeverRequestsTriggerSensor()
+ }
+
+ @Test
+ fun primaryBouncer_listenForGesture() =
+ testScope.runTest {
+ start()
+ givenAwakeKeyguard(false)
+ givenPrimaryBouncerShowing()
+ runCurrent()
+ verifyRequestTriggerSensor()
+ }
+
+ @Test
+ fun alternateBouncer_listenForGesture() =
+ testScope.runTest {
+ start()
+ givenAwakeKeyguard(false)
+ givenAlternateBouncerShowing()
+ runCurrent()
+ verifyRequestTriggerSensor()
+ }
+
+ @Test
+ fun restartListeningForGestureAfterSensorTrigger() =
+ testScope.runTest {
+ start()
+ givenAwakeKeyguard(true)
+ runCurrent()
+ verifyRequestTriggerSensor()
+ clearInvocations(sensorManager)
+
+ triggerEventListenerCaptor.value.onTrigger(null)
+ runCurrent()
+ verifyRequestTriggerSensor()
+ }
+
+ @Test
+ fun cancelTriggerSensor_keyguardNotAwakeAnymore() =
+ testScope.runTest {
+ start()
+ givenAwakeKeyguard(true)
+ runCurrent()
+ verifyRequestTriggerSensor()
+
+ givenAwakeKeyguard(false)
+ runCurrent()
+ verifyCancelTriggerSensor()
+ }
+
+ private fun start() {
+ underTest.start()
+ biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(true)
+ givenAwakeKeyguard(false)
+ givenBouncerNotShowing()
+ }
+
+ private fun givenAwakeKeyguard(isAwake: Boolean) {
+ powerRepository.setInteractive(isAwake)
+ keyguardRepository.setKeyguardShowing(isAwake)
+ keyguardRepository.setKeyguardOccluded(false)
+ }
+
+ private fun givenPrimaryBouncerShowing() {
+ bouncerRepository.setPrimaryShow(true)
+ bouncerRepository.setAlternateVisible(false)
+ }
+
+ private fun givenBouncerNotShowing() {
+ bouncerRepository.setPrimaryShow(false)
+ bouncerRepository.setAlternateVisible(false)
+ }
+
+ private fun givenAlternateBouncerShowing() {
+ bouncerRepository.setPrimaryShow(false)
+ bouncerRepository.setAlternateVisible(true)
+ }
+
+ private fun verifyRequestTriggerSensor() {
+ verify(sensorManager).requestTriggerSensor(capture(triggerEventListenerCaptor), any())
+ }
+
+ private fun verifyNeverRequestsTriggerSensor() {
+ verify(sensorManager, never()).requestTriggerSensor(any(), any())
+ }
+
+ private fun verifyCancelTriggerSensor() {
+ verify(sensorManager).cancelTriggerSensor(any(), any())
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
index 30ac34402ffd..6fc5be1e376d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
@@ -19,7 +19,7 @@ package com.android.systemui.keyguard.ui.viewmodel
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.bouncer.domain.interactor.primaryBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.mockPrimaryBouncerInteractor
import com.android.systemui.coroutines.collectValues
import com.android.systemui.flags.Flags
import com.android.systemui.flags.fakeFeatureFlagsClassic
@@ -52,11 +52,9 @@ class PrimaryBouncerToGoneTransitionViewModelTest : SysuiTestCase() {
val testScope = kosmos.testScope
val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
- val primaryBouncerInteractor = kosmos.primaryBouncerInteractor
+ val primaryBouncerInteractor = kosmos.mockPrimaryBouncerInteractor
val sysuiStatusBarStateController = kosmos.sysuiStatusBarStateController
- val underTest by lazy {
- kosmos.primaryBouncerToGoneTransitionViewModel
- }
+ val underTest by lazy { kosmos.primaryBouncerToGoneTransitionViewModel }
@Before
fun setUp() {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
index 817087955971..9504cfcdbe3c 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
@@ -51,7 +51,6 @@ import com.android.systemui.shortcut.ShortcutKeyDispatcher
import com.android.systemui.statusbar.ImmersiveModeConfirmation
import com.android.systemui.statusbar.gesture.GesturePointerEventListener
import com.android.systemui.statusbar.notification.InstantAppNotifier
-import com.android.systemui.statusbar.phone.KeyguardLiftController
import com.android.systemui.statusbar.phone.ScrimController
import com.android.systemui.statusbar.phone.StatusBarHeadsUpChangeListener
import com.android.systemui.stylus.StylusUsiPowerStartable
@@ -225,12 +224,6 @@ abstract class SystemUICoreStartableModule {
@ClassKey(WMShell::class)
abstract fun bindWMShell(sysui: WMShell): CoreStartable
- /** Inject into KeyguardLiftController. */
- @Binds
- @IntoMap
- @ClassKey(KeyguardLiftController::class)
- abstract fun bindKeyguardLiftController(sysui: KeyguardLiftController): CoreStartable
-
/** Inject into MediaTttSenderCoordinator. */
@Binds
@IntoMap
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/ui/binder/LiftToRunFaceAuthBinder.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/ui/binder/LiftToRunFaceAuthBinder.kt
new file mode 100644
index 000000000000..1fd7d009cee4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/ui/binder/LiftToRunFaceAuthBinder.kt
@@ -0,0 +1,143 @@
+/*
+ * 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.deviceentry.ui.binder
+
+import android.content.pm.PackageManager
+import android.hardware.Sensor
+import android.hardware.TriggerEvent
+import android.hardware.TriggerEventListener
+import com.android.keyguard.ActiveUnlockConfig
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.CoreStartable
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.util.Assert
+import com.android.systemui.util.sensors.AsyncSensorManager
+import java.io.PrintWriter
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.filterNot
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.launch
+
+/**
+ * Triggers face auth and active unlock on lift when the device is showing the lock screen or
+ * bouncer. Only initialized if face auth is supported on the device. Not to be confused with the
+ * lift to wake gesture which is handled by {@link com.android.server.policy.PhoneWindowManager}.
+ */
+@SysUISingleton
+class LiftToRunFaceAuthBinder
+@Inject
+constructor(
+ @Application private val scope: CoroutineScope,
+ private val packageManager: PackageManager,
+ private val asyncSensorManager: AsyncSensorManager,
+ private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+ keyguardInteractor: KeyguardInteractor,
+ primaryBouncerInteractor: PrimaryBouncerInteractor,
+ alternateBouncerInteractor: AlternateBouncerInteractor,
+ private val deviceEntryFaceAuthInteractor: DeviceEntryFaceAuthInteractor,
+ powerInteractor: PowerInteractor,
+) : CoreStartable {
+
+ private var pickupSensor: Sensor? = null
+ private val isListening: MutableStateFlow<Boolean> = MutableStateFlow(false)
+ private val stoppedListening: Flow<Unit> = isListening.filterNot { it }.map {} // map to Unit
+
+ private val onAwakeKeyguard: Flow<Boolean> =
+ combine(
+ powerInteractor.isInteractive,
+ keyguardInteractor.isKeyguardVisible,
+ ) { isInteractive, isKeyguardVisible ->
+ isInteractive && isKeyguardVisible
+ }
+ private val bouncerShowing: Flow<Boolean> =
+ combine(
+ primaryBouncerInteractor.isShowing,
+ alternateBouncerInteractor.isVisible,
+ ) { primaryBouncerShowing, alternateBouncerShowing ->
+ primaryBouncerShowing || alternateBouncerShowing
+ }
+ private val listenForPickupSensor: Flow<Boolean> =
+ combine(
+ stoppedListening,
+ bouncerShowing,
+ onAwakeKeyguard,
+ ) { _, bouncerShowing, onAwakeKeyguard ->
+ (onAwakeKeyguard || bouncerShowing) &&
+ deviceEntryFaceAuthInteractor.isFaceAuthEnabledAndEnrolled()
+ }
+
+ override fun start() {
+ if (packageManager.hasSystemFeature(PackageManager.FEATURE_FACE)) {
+ init()
+ }
+ }
+
+ private fun init() {
+ pickupSensor = asyncSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE)
+ scope.launch {
+ listenForPickupSensor.collect { listenForPickupSensor ->
+ updateListeningState(listenForPickupSensor)
+ }
+ }
+ }
+
+ private val listener: TriggerEventListener =
+ object : TriggerEventListener() {
+ override fun onTrigger(event: TriggerEvent?) {
+ Assert.isMainThread()
+ deviceEntryFaceAuthInteractor.onDeviceLifted()
+ keyguardUpdateMonitor.requestActiveUnlock(
+ ActiveUnlockConfig.ActiveUnlockRequestOrigin.WAKE,
+ "KeyguardLiftController"
+ )
+
+ // Not listening anymore since trigger events unregister themselves
+ isListening.value = false
+ }
+ }
+
+ override fun dump(pw: PrintWriter, args: Array<out String>) {
+ pw.println("LiftToRunFaceAuthBinder:")
+ pw.println(" pickupSensor: $pickupSensor")
+ pw.println(" isListening: ${isListening.value}")
+ }
+
+ private fun updateListeningState(shouldListen: Boolean) {
+ if (pickupSensor == null) {
+ return
+ }
+ if (shouldListen != isListening.value) {
+ isListening.value = shouldListen
+
+ if (shouldListen) {
+ asyncSensorManager.requestTriggerSensor(listener, pickupSensor)
+ } else {
+ asyncSensorManager.cancelTriggerSensor(listener, pickupSensor)
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index 13e38358477a..e16f8dcbb00e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -51,7 +51,7 @@ import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.WindowManagerLockscreenVisibilityManager;
import com.android.systemui.keyguard.data.quickaffordance.KeyguardDataQuickAffordanceModule;
-import com.android.systemui.keyguard.data.repository.KeyguardFaceAuthModule;
+import com.android.systemui.keyguard.data.repository.DeviceEntryFaceAuthModule;
import com.android.systemui.keyguard.data.repository.KeyguardRepositoryModule;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.domain.interactor.StartKeyguardTransitionModule;
@@ -104,7 +104,7 @@ import kotlinx.coroutines.CoroutineDispatcher;
FalsingModule.class,
KeyguardDataQuickAffordanceModule.class,
KeyguardRepositoryModule.class,
- KeyguardFaceAuthModule.class,
+ DeviceEntryFaceAuthModule.class,
KeyguardDisplayModule.class,
StartKeyguardTransitionModule.class,
ResourceTrimmerModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardFaceAuthModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthModule.kt
index fede47957a7b..4cd544ff658e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardFaceAuthModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthModule.kt
@@ -23,6 +23,7 @@ import com.android.systemui.deviceentry.data.repository.DeviceEntryFaceAuthRepos
import com.android.systemui.deviceentry.data.repository.DeviceEntryFaceAuthRepositoryImpl
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor
import com.android.systemui.deviceentry.domain.interactor.SystemUIDeviceEntryFaceAuthInteractor
+import com.android.systemui.deviceentry.ui.binder.LiftToRunFaceAuthBinder
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.TableLogBufferFactory
import dagger.Binds
@@ -32,7 +33,7 @@ import dagger.multibindings.ClassKey
import dagger.multibindings.IntoMap
@Module
-interface KeyguardFaceAuthModule {
+interface DeviceEntryFaceAuthModule {
@Binds
fun deviceEntryFaceAuthRepository(
impl: DeviceEntryFaceAuthRepositoryImpl
@@ -41,13 +42,20 @@ interface KeyguardFaceAuthModule {
@Binds
@IntoMap
@ClassKey(SystemUIDeviceEntryFaceAuthInteractor::class)
- fun bind(impl: SystemUIDeviceEntryFaceAuthInteractor): CoreStartable
+ fun bindSystemUIDeviceEntryFaceAuthInteractor(
+ impl: SystemUIDeviceEntryFaceAuthInteractor
+ ): CoreStartable
@Binds
fun keyguardFaceAuthInteractor(
impl: SystemUIDeviceEntryFaceAuthInteractor
): DeviceEntryFaceAuthInteractor
+ @Binds
+ @IntoMap
+ @ClassKey(LiftToRunFaceAuthBinder::class)
+ fun bindLiftToRunFaceAuthBinder(impl: LiftToRunFaceAuthBinder): CoreStartable
+
companion object {
@Provides
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
deleted file mode 100644
index 9f0863385ca1..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2019 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.statusbar.phone
-
-import android.content.Context
-import android.content.pm.PackageManager
-import android.hardware.Sensor
-import android.hardware.TriggerEvent
-import android.hardware.TriggerEventListener
-import com.android.keyguard.ActiveUnlockConfig
-import com.android.keyguard.KeyguardUpdateMonitor
-import com.android.keyguard.KeyguardUpdateMonitorCallback
-import com.android.systemui.CoreStartable
-import com.android.systemui.Dumpable
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dump.DumpManager
-import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor
-import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.user.domain.interactor.SelectedUserInteractor
-import com.android.systemui.util.Assert
-import com.android.systemui.util.sensors.AsyncSensorManager
-import java.io.PrintWriter
-import javax.inject.Inject
-
-/**
- * Triggers face auth on lift when the device is showing the lock screen. Only initialized
- * if face auth is supported on the device. Not to be confused with the lift to wake gesture
- * which is handled by {@link com.android.server.policy.PhoneWindowManager}.
- */
-@SysUISingleton
-class KeyguardLiftController @Inject constructor(
- private val context: Context,
- private val statusBarStateController: StatusBarStateController,
- private val asyncSensorManager: AsyncSensorManager,
- private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
- private val deviceEntryFaceAuthInteractor: DeviceEntryFaceAuthInteractor,
- private val dumpManager: DumpManager,
- private val selectedUserInteractor: SelectedUserInteractor,
-) : Dumpable, CoreStartable {
-
- private val pickupSensor = asyncSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE)
- private var isListening = false
- private var bouncerVisible = false
-
- override fun start() {
- if (context.packageManager.hasSystemFeature(PackageManager.FEATURE_FACE)) {
- init()
- }
- }
-
- private fun init() {
- dumpManager.registerDumpable(this)
- statusBarStateController.addCallback(statusBarStateListener)
- keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
- updateListeningState()
- }
-
- private val listener: TriggerEventListener = object : TriggerEventListener() {
- override fun onTrigger(event: TriggerEvent?) {
- Assert.isMainThread()
- // Not listening anymore since trigger events unregister themselves
- isListening = false
- updateListeningState()
- deviceEntryFaceAuthInteractor.onDeviceLifted()
- keyguardUpdateMonitor.requestActiveUnlock(
- ActiveUnlockConfig.ActiveUnlockRequestOrigin.WAKE,
- "KeyguardLiftController")
- }
- }
-
- private val keyguardUpdateMonitorCallback = object : KeyguardUpdateMonitorCallback() {
- override fun onKeyguardBouncerFullyShowingChanged(bouncer: Boolean) {
- bouncerVisible = bouncer
- updateListeningState()
- }
-
- override fun onKeyguardVisibilityChanged(visible: Boolean) {
- updateListeningState()
- }
- }
-
- private val statusBarStateListener = object : StatusBarStateController.StateListener {
- override fun onDozingChanged(isDozing: Boolean) {
- updateListeningState()
- }
- }
-
- override fun dump(pw: PrintWriter, args: Array<out String>) {
- pw.println("KeyguardLiftController:")
- pw.println(" pickupSensor: $pickupSensor")
- pw.println(" isListening: $isListening")
- pw.println(" bouncerVisible: $bouncerVisible")
- }
-
- private fun updateListeningState() {
- if (pickupSensor == null) {
- return
- }
- val onKeyguard = keyguardUpdateMonitor.isKeyguardVisible &&
- !statusBarStateController.isDozing
-
- val isFaceEnabled = deviceEntryFaceAuthInteractor.isFaceAuthEnabledAndEnrolled()
- val shouldListen = (onKeyguard || bouncerVisible) && isFaceEnabled
- if (shouldListen != isListening) {
- isListening = shouldListen
-
- if (shouldListen) {
- asyncSensorManager.requestTriggerSensor(listener, pickupSensor)
- } else {
- asyncSensorManager.cancelTriggerSensor(listener, pickupSensor)
- }
- }
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt
index 75994da6c934..ad2ae8b41af9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt
@@ -19,7 +19,7 @@ package com.android.systemui.keyguard.ui.viewmodel
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.bouncer.domain.interactor.primaryBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.mockPrimaryBouncerInteractor
import com.android.systemui.coroutines.collectValues
import com.android.systemui.flags.Flags
import com.android.systemui.flags.fakeFeatureFlagsClassic
@@ -65,7 +65,7 @@ class BouncerToGoneFlowsTest : SysuiTestCase() {
private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
private val shadeRepository = kosmos.shadeRepository
private val sysuiStatusBarStateController = kosmos.sysuiStatusBarStateController
- private val primaryBouncerInteractor = kosmos.primaryBouncerInteractor
+ private val primaryBouncerInteractor = kosmos.mockPrimaryBouncerInteractor
private val underTest = kosmos.bouncerToGoneFlows
@Before
diff --git a/packages/SystemUI/tests/utils/src/android/content/PackageManagerKosmos.kt b/packages/SystemUI/tests/utils/src/android/content/PackageManagerKosmos.kt
new file mode 100644
index 000000000000..8901314d8e76
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/android/content/PackageManagerKosmos.kt
@@ -0,0 +1,22 @@
+/*
+ * 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 android.content
+
+import android.content.pm.PackageManager
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.util.mockito.mock
+
+val Kosmos.packageManager by Kosmos.Fixture { mock<PackageManager>() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorKosmos.kt
index 06b6cda62806..244ef8d81ebd 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorKosmos.kt
@@ -16,7 +16,40 @@
package com.android.systemui.bouncer.domain.interactor
+import android.content.applicationContext
+import com.android.keyguard.keyguardSecurityModel
+import com.android.keyguard.keyguardUpdateMonitor
+import com.android.systemui.bouncer.data.repository.keyguardBouncerRepository
+import com.android.systemui.bouncer.ui.BouncerView
+import com.android.systemui.classifier.falsingCollector
+import com.android.systemui.concurrency.fakeExecutor
+import com.android.systemui.deviceentry.domain.interactor.deviceEntryFaceAuthInteractor
+import com.android.systemui.keyguard.DismissCallbackRegistry
+import com.android.systemui.keyguard.data.repository.trustRepository
import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.statusbar.policy.KeyguardStateControllerImpl
+import com.android.systemui.user.domain.interactor.selectedUserInteractor
+import com.android.systemui.util.concurrency.mockExecutorHandler
import com.android.systemui.util.mockito.mock
-var Kosmos.primaryBouncerInteractor by Kosmos.Fixture { mock<PrimaryBouncerInteractor>() }
+var Kosmos.mockPrimaryBouncerInteractor by Kosmos.Fixture { mock<PrimaryBouncerInteractor>() }
+var Kosmos.primaryBouncerInteractor by
+ Kosmos.Fixture {
+ PrimaryBouncerInteractor(
+ repository = keyguardBouncerRepository,
+ primaryBouncerView = mock<BouncerView>(),
+ mainHandler = mockExecutorHandler(executor = fakeExecutor),
+ keyguardStateController = mock<KeyguardStateControllerImpl>(),
+ keyguardSecurityModel = keyguardSecurityModel,
+ primaryBouncerCallbackInteractor = mock<PrimaryBouncerCallbackInteractor>(),
+ falsingCollector = falsingCollector,
+ dismissCallbackRegistry = mock<DismissCallbackRegistry>(),
+ context = applicationContext,
+ keyguardUpdateMonitor = keyguardUpdateMonitor,
+ trustRepository = trustRepository,
+ applicationScope = applicationCoroutineScope,
+ selectedUserInteractor = selectedUserInteractor,
+ deviceEntryFaceAuthInteractor = deviceEntryFaceAuthInteractor,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorKosmos.kt
index 0b1fb4074226..5575b05b3874 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorKosmos.kt
@@ -23,7 +23,7 @@ import com.android.keyguard.keyguardUpdateMonitor
import com.android.keyguard.trustManager
import com.android.systemui.biometrics.data.repository.facePropertyRepository
import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor
-import com.android.systemui.bouncer.domain.interactor.primaryBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.mockPrimaryBouncerInteractor
import com.android.systemui.deviceentry.data.repository.faceWakeUpTriggersConfig
import com.android.systemui.keyguard.data.repository.biometricSettingsRepository
import com.android.systemui.keyguard.data.repository.deviceEntryFaceAuthRepository
@@ -46,7 +46,7 @@ val Kosmos.deviceEntryFaceAuthInteractor by
applicationScope = applicationCoroutineScope,
mainDispatcher = testDispatcher,
repository = deviceEntryFaceAuthRepository,
- primaryBouncerInteractor = { primaryBouncerInteractor },
+ primaryBouncerInteractor = { mockPrimaryBouncerInteractor },
alternateBouncerInteractor = alternateBouncerInteractor,
keyguardTransitionInteractor = keyguardTransitionInteractor,
faceAuthenticationLogger = faceAuthLogger,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/ui/binder/LiftToRunFaceAuthBinderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/ui/binder/LiftToRunFaceAuthBinderKosmos.kt
new file mode 100644
index 000000000000..2fead91b430a
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/ui/binder/LiftToRunFaceAuthBinderKosmos.kt
@@ -0,0 +1,45 @@
+/*
+ * 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.deviceentry.ui.binder
+
+import android.content.packageManager
+import com.android.keyguard.keyguardUpdateMonitor
+import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.primaryBouncerInteractor
+import com.android.systemui.deviceentry.domain.interactor.deviceEntryFaceAuthInteractor
+import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.power.domain.interactor.powerInteractor
+import com.android.systemui.util.sensors.asyncSensorManager
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+
+@ExperimentalCoroutinesApi
+val Kosmos.liftToRunFaceAuthBinder by
+ Kosmos.Fixture {
+ LiftToRunFaceAuthBinder(
+ scope = applicationCoroutineScope,
+ packageManager = packageManager,
+ asyncSensorManager = asyncSensorManager,
+ keyguardUpdateMonitor = keyguardUpdateMonitor,
+ keyguardInteractor = keyguardInteractor,
+ primaryBouncerInteractor = primaryBouncerInteractor,
+ alternateBouncerInteractor = alternateBouncerInteractor,
+ deviceEntryFaceAuthInteractor = deviceEntryFaceAuthInteractor,
+ powerInteractor = powerInteractor,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsKosmos.kt
index c71c1c3ea5f0..ffa4133c7269 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsKosmos.kt
@@ -18,7 +18,7 @@
package com.android.systemui.keyguard.ui.viewmodel
-import com.android.systemui.bouncer.domain.interactor.primaryBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.mockPrimaryBouncerInteractor
import com.android.systemui.flags.featureFlagsClassic
import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
import com.android.systemui.kosmos.Kosmos
@@ -31,7 +31,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
val Kosmos.bouncerToGoneFlows by Fixture {
BouncerToGoneFlows(
statusBarStateController = sysuiStatusBarStateController,
- primaryBouncerInteractor = primaryBouncerInteractor,
+ primaryBouncerInteractor = mockPrimaryBouncerInteractor,
keyguardDismissActionInteractor = mock(),
featureFlags = featureFlagsClassic,
shadeInteractor = shadeInteractor,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelKosmos.kt
index ab28d0d670ef..4ecff73f71ed 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelKosmos.kt
@@ -18,7 +18,7 @@
package com.android.systemui.keyguard.ui.viewmodel
-import com.android.systemui.bouncer.domain.interactor.primaryBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.mockPrimaryBouncerInteractor
import com.android.systemui.flags.featureFlagsClassic
import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
import com.android.systemui.kosmos.Kosmos
@@ -30,7 +30,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
val Kosmos.primaryBouncerToGoneTransitionViewModel by Fixture {
PrimaryBouncerToGoneTransitionViewModel(
statusBarStateController = sysuiStatusBarStateController,
- primaryBouncerInteractor = primaryBouncerInteractor,
+ primaryBouncerInteractor = mockPrimaryBouncerInteractor,
keyguardDismissActionInteractor = mock(),
featureFlags = featureFlagsClassic,
bouncerToGoneFlows = bouncerToGoneFlows,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/sensors/AsyncSensorManagerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/sensors/AsyncSensorManagerKosmos.kt
new file mode 100644
index 000000000000..117ae8c46d3c
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/sensors/AsyncSensorManagerKosmos.kt
@@ -0,0 +1,21 @@
+/*
+ * 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.util.sensors
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.util.mockito.mock
+
+val Kosmos.asyncSensorManager by Kosmos.Fixture { mock<AsyncSensorManager>() }