1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.deviceentry.domain.ui.binder 18 19 import android.content.packageManager 20 import android.content.pm.PackageManager 21 import android.hardware.Sensor 22 import android.hardware.TriggerEventListener 23 import android.testing.TestableLooper 24 import androidx.test.ext.junit.runners.AndroidJUnit4 25 import androidx.test.filters.SmallTest 26 import com.android.systemui.SysuiTestCase 27 import com.android.systemui.bouncer.data.repository.keyguardBouncerRepository 28 import com.android.systemui.deviceentry.ui.binder.liftToRunFaceAuthBinder 29 import com.android.systemui.keyguard.data.repository.biometricSettingsRepository 30 import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository 31 import com.android.systemui.kosmos.testScope 32 import com.android.systemui.power.data.repository.fakePowerRepository 33 import com.android.systemui.testKosmos 34 import com.android.systemui.util.mockito.any 35 import com.android.systemui.util.mockito.capture 36 import com.android.systemui.util.mockito.whenever 37 import com.android.systemui.util.sensors.asyncSensorManager 38 import kotlinx.coroutines.ExperimentalCoroutinesApi 39 import kotlinx.coroutines.test.runCurrent 40 import kotlinx.coroutines.test.runTest 41 import org.junit.Before 42 import org.junit.Test 43 import org.junit.runner.RunWith 44 import org.mockito.ArgumentCaptor 45 import org.mockito.Captor 46 import org.mockito.Mock 47 import org.mockito.Mockito.clearInvocations 48 import org.mockito.Mockito.never 49 import org.mockito.Mockito.verify 50 import org.mockito.MockitoAnnotations 51 52 @ExperimentalCoroutinesApi 53 @SmallTest 54 @RunWith(AndroidJUnit4::class) 55 @TestableLooper.RunWithLooper(setAsMainLooper = true) 56 class LiftToRunFaceAuthBinderTest : SysuiTestCase() { 57 private val kosmos = testKosmos() 58 private val testScope = kosmos.testScope 59 private val sensorManager = kosmos.asyncSensorManager 60 private val powerRepository = kosmos.fakePowerRepository 61 private val keyguardRepository = kosmos.fakeKeyguardRepository 62 private val bouncerRepository = kosmos.keyguardBouncerRepository 63 private val biometricSettingsRepository = kosmos.biometricSettingsRepository 64 private val packageManager = kosmos.packageManager 65 66 @Captor private lateinit var triggerEventListenerCaptor: ArgumentCaptor<TriggerEventListener> 67 @Mock private lateinit var mockSensor: Sensor 68 <lambda>null69 private val underTest by lazy { kosmos.liftToRunFaceAuthBinder } 70 71 @Before setupnull72 fun setup() { 73 MockitoAnnotations.initMocks(this) 74 whenever(packageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true) 75 whenever(sensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE)).thenReturn(mockSensor) 76 } 77 78 @Test doNotListenForGesturenull79 fun doNotListenForGesture() = 80 testScope.runTest { 81 start() 82 verifyNeverRequestsTriggerSensor() 83 } 84 85 @Test awakeKeyguard_listenForGesturenull86 fun awakeKeyguard_listenForGesture() = 87 testScope.runTest { 88 start() 89 givenAwakeKeyguard(true) 90 runCurrent() 91 verifyRequestTriggerSensor() 92 } 93 94 @Test faceNotEnrolled_listenForGesturenull95 fun faceNotEnrolled_listenForGesture() = 96 testScope.runTest { 97 start() 98 givenAwakeKeyguard(true) 99 biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(false) 100 runCurrent() 101 verifyNeverRequestsTriggerSensor() 102 } 103 104 @Test notInteractive_doNotListenForGesturenull105 fun notInteractive_doNotListenForGesture() = 106 testScope.runTest { 107 start() 108 givenAwakeKeyguard(true) 109 powerRepository.setInteractive(false) 110 runCurrent() 111 verifyNeverRequestsTriggerSensor() 112 } 113 114 @Test primaryBouncer_listenForGesturenull115 fun primaryBouncer_listenForGesture() = 116 testScope.runTest { 117 start() 118 givenAwakeKeyguard(false) 119 givenPrimaryBouncerShowing() 120 runCurrent() 121 verifyRequestTriggerSensor() 122 } 123 124 @Test alternateBouncer_listenForGesturenull125 fun alternateBouncer_listenForGesture() = 126 testScope.runTest { 127 start() 128 givenAwakeKeyguard(false) 129 givenAlternateBouncerShowing() 130 runCurrent() 131 verifyRequestTriggerSensor() 132 } 133 134 @Test restartListeningForGestureAfterSensorTriggernull135 fun restartListeningForGestureAfterSensorTrigger() = 136 testScope.runTest { 137 start() 138 givenAwakeKeyguard(true) 139 runCurrent() 140 verifyRequestTriggerSensor() 141 clearInvocations(sensorManager) 142 143 triggerEventListenerCaptor.value.onTrigger(null) 144 runCurrent() 145 verifyRequestTriggerSensor() 146 } 147 148 @Test cancelTriggerSensor_keyguardNotAwakeAnymorenull149 fun cancelTriggerSensor_keyguardNotAwakeAnymore() = 150 testScope.runTest { 151 start() 152 givenAwakeKeyguard(true) 153 runCurrent() 154 verifyRequestTriggerSensor() 155 156 givenAwakeKeyguard(false) 157 runCurrent() 158 verifyCancelTriggerSensor() 159 } 160 startnull161 private fun start() { 162 underTest.start() 163 biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(true) 164 givenAwakeKeyguard(false) 165 givenBouncerNotShowing() 166 } 167 givenAwakeKeyguardnull168 private fun givenAwakeKeyguard(isAwake: Boolean) { 169 powerRepository.setInteractive(isAwake) 170 keyguardRepository.setKeyguardShowing(isAwake) 171 keyguardRepository.setKeyguardOccluded(false) 172 } 173 givenPrimaryBouncerShowingnull174 private fun givenPrimaryBouncerShowing() { 175 bouncerRepository.setPrimaryShow(true) 176 bouncerRepository.setAlternateVisible(false) 177 } 178 givenBouncerNotShowingnull179 private fun givenBouncerNotShowing() { 180 bouncerRepository.setPrimaryShow(false) 181 bouncerRepository.setAlternateVisible(false) 182 } 183 givenAlternateBouncerShowingnull184 private fun givenAlternateBouncerShowing() { 185 bouncerRepository.setPrimaryShow(false) 186 bouncerRepository.setAlternateVisible(true) 187 } 188 verifyRequestTriggerSensornull189 private fun verifyRequestTriggerSensor() { 190 verify(sensorManager).requestTriggerSensor(capture(triggerEventListenerCaptor), any()) 191 } 192 verifyNeverRequestsTriggerSensornull193 private fun verifyNeverRequestsTriggerSensor() { 194 verify(sensorManager, never()).requestTriggerSensor(any(), any()) 195 } 196 verifyCancelTriggerSensornull197 private fun verifyCancelTriggerSensor() { 198 verify(sensorManager).cancelTriggerSensor(any(), any()) 199 } 200 } 201