1 package com.android.systemui.biometrics.domain.interactor 2 3 import android.hardware.biometrics.AuthenticateOptions 4 import android.hardware.biometrics.IBiometricContextListener 5 import android.hardware.biometrics.IBiometricContextListener.FoldState 6 import androidx.test.filters.SmallTest 7 import com.android.systemui.SysuiTestCase 8 import com.android.systemui.coroutines.collectLastValue 9 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository 10 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory 11 import com.android.systemui.keyguard.shared.model.KeyguardState 12 import com.android.systemui.keyguard.shared.model.TransitionState 13 import com.android.systemui.keyguard.shared.model.TransitionStep 14 import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_CLOSED 15 import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_FULL_OPEN 16 import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_HALF_OPEN 17 import com.android.systemui.unfold.updates.FOLD_UPDATE_START_CLOSING 18 import com.android.systemui.unfold.updates.FOLD_UPDATE_START_OPENING 19 import com.android.systemui.unfold.updates.FoldStateProvider 20 import com.android.systemui.util.mockito.withArgCaptor 21 import com.google.common.truth.Truth.assertThat 22 import kotlinx.coroutines.ExperimentalCoroutinesApi 23 import kotlinx.coroutines.test.TestScope 24 import kotlinx.coroutines.test.runCurrent 25 import kotlinx.coroutines.test.runTest 26 import org.junit.Before 27 import org.junit.Rule 28 import org.junit.Test 29 import org.junit.runner.RunWith 30 import org.junit.runners.JUnit4 31 import org.mockito.Mock 32 import org.mockito.Mockito.verify 33 import org.mockito.junit.MockitoJUnit 34 35 @OptIn(ExperimentalCoroutinesApi::class) 36 @SmallTest 37 @RunWith(JUnit4::class) 38 class LogContextInteractorImplTest : SysuiTestCase() { 39 40 @JvmField @Rule var mockitoRule = MockitoJUnit.rule() 41 42 private val testScope = TestScope() 43 44 @Mock private lateinit var foldProvider: FoldStateProvider 45 46 private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository 47 48 private lateinit var interactor: LogContextInteractorImpl 49 50 @Before 51 fun setup() { 52 keyguardTransitionRepository = FakeKeyguardTransitionRepository() 53 interactor = 54 LogContextInteractorImpl( 55 testScope.backgroundScope, 56 foldProvider, 57 KeyguardTransitionInteractorFactory.create( 58 repository = keyguardTransitionRepository, 59 scope = testScope.backgroundScope, 60 ) 61 .keyguardTransitionInteractor, 62 ) 63 } 64 65 @Test 66 fun isAodChanges() = 67 testScope.runTest { 68 val isAod = collectLastValue(interactor.isAod) 69 70 keyguardTransitionRepository.startTransitionTo(KeyguardState.OFF) 71 assertThat(isAod()).isFalse() 72 73 keyguardTransitionRepository.startTransitionTo(KeyguardState.DOZING) 74 assertThat(isAod()).isFalse() 75 76 keyguardTransitionRepository.startTransitionTo(KeyguardState.DREAMING) 77 assertThat(isAod()).isFalse() 78 79 keyguardTransitionRepository.startTransitionTo(KeyguardState.AOD) 80 assertThat(isAod()).isTrue() 81 82 keyguardTransitionRepository.startTransitionTo(KeyguardState.ALTERNATE_BOUNCER) 83 assertThat(isAod()).isFalse() 84 85 keyguardTransitionRepository.startTransitionTo(KeyguardState.PRIMARY_BOUNCER) 86 assertThat(isAod()).isFalse() 87 88 keyguardTransitionRepository.startTransitionTo(KeyguardState.LOCKSCREEN) 89 assertThat(isAod()).isFalse() 90 91 keyguardTransitionRepository.startTransitionTo(KeyguardState.GONE) 92 assertThat(isAod()).isFalse() 93 94 keyguardTransitionRepository.startTransitionTo(KeyguardState.OCCLUDED) 95 assertThat(isAod()).isFalse() 96 } 97 98 @Test 99 fun isAwakeChanges() = 100 testScope.runTest { 101 val isAwake = collectLastValue(interactor.isAwake) 102 103 keyguardTransitionRepository.startTransitionTo(KeyguardState.OFF) 104 assertThat(isAwake()).isFalse() 105 106 keyguardTransitionRepository.startTransitionTo(KeyguardState.DOZING) 107 assertThat(isAwake()).isFalse() 108 109 keyguardTransitionRepository.startTransitionTo(KeyguardState.DREAMING) 110 assertThat(isAwake()).isTrue() 111 112 keyguardTransitionRepository.startTransitionTo(KeyguardState.AOD) 113 assertThat(isAwake()).isFalse() 114 115 keyguardTransitionRepository.startTransitionTo(KeyguardState.ALTERNATE_BOUNCER) 116 assertThat(isAwake()).isTrue() 117 118 keyguardTransitionRepository.startTransitionTo(KeyguardState.PRIMARY_BOUNCER) 119 assertThat(isAwake()).isTrue() 120 121 keyguardTransitionRepository.startTransitionTo(KeyguardState.LOCKSCREEN) 122 assertThat(isAwake()).isTrue() 123 124 keyguardTransitionRepository.startTransitionTo(KeyguardState.GONE) 125 assertThat(isAwake()).isTrue() 126 127 keyguardTransitionRepository.startTransitionTo(KeyguardState.OCCLUDED) 128 assertThat(isAwake()).isTrue() 129 } 130 131 @Test 132 fun displayStateChanges() = 133 testScope.runTest { 134 val displayState = collectLastValue(interactor.displayState) 135 136 keyguardTransitionRepository.startTransitionTo(KeyguardState.OFF) 137 assertThat(displayState()).isEqualTo(AuthenticateOptions.DISPLAY_STATE_NO_UI) 138 139 keyguardTransitionRepository.startTransitionTo(KeyguardState.DOZING) 140 assertThat(displayState()).isEqualTo(AuthenticateOptions.DISPLAY_STATE_NO_UI) 141 142 keyguardTransitionRepository.startTransitionTo(KeyguardState.DREAMING) 143 assertThat(displayState()).isEqualTo(AuthenticateOptions.DISPLAY_STATE_SCREENSAVER) 144 145 keyguardTransitionRepository.startTransitionTo(KeyguardState.AOD) 146 assertThat(displayState()).isEqualTo(AuthenticateOptions.DISPLAY_STATE_AOD) 147 148 keyguardTransitionRepository.startTransitionTo(KeyguardState.ALTERNATE_BOUNCER) 149 assertThat(displayState()).isEqualTo(AuthenticateOptions.DISPLAY_STATE_LOCKSCREEN) 150 151 keyguardTransitionRepository.startTransitionTo(KeyguardState.PRIMARY_BOUNCER) 152 assertThat(displayState()).isEqualTo(AuthenticateOptions.DISPLAY_STATE_LOCKSCREEN) 153 154 keyguardTransitionRepository.startTransitionTo(KeyguardState.LOCKSCREEN) 155 assertThat(displayState()).isEqualTo(AuthenticateOptions.DISPLAY_STATE_LOCKSCREEN) 156 157 keyguardTransitionRepository.startTransitionTo(KeyguardState.GONE) 158 assertThat(displayState()).isEqualTo(AuthenticateOptions.DISPLAY_STATE_UNKNOWN) 159 160 keyguardTransitionRepository.startTransitionTo(KeyguardState.OCCLUDED) 161 assertThat(displayState()).isEqualTo(AuthenticateOptions.DISPLAY_STATE_LOCKSCREEN) 162 } 163 164 @Test 165 fun foldStateChanges() = 166 testScope.runTest { 167 val foldState = collectLastValue(interactor.foldState) 168 runCurrent() 169 val listener = foldProvider.captureListener() 170 171 listener.onFoldUpdate(FOLD_UPDATE_START_OPENING) 172 assertThat(foldState()).isEqualTo(FoldState.UNKNOWN) 173 174 listener.onFoldUpdate(FOLD_UPDATE_FINISH_HALF_OPEN) 175 assertThat(foldState()).isEqualTo(FoldState.HALF_OPENED) 176 177 listener.onFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN) 178 assertThat(foldState()).isEqualTo(FoldState.FULLY_OPENED) 179 180 listener.onFoldUpdate(FOLD_UPDATE_START_CLOSING) 181 assertThat(foldState()).isEqualTo(FoldState.FULLY_OPENED) 182 183 listener.onFoldUpdate(FOLD_UPDATE_FINISH_CLOSED) 184 assertThat(foldState()).isEqualTo(FoldState.FULLY_CLOSED) 185 } 186 187 @Test 188 fun contextSubscriberChanges() = 189 testScope.runTest { 190 runCurrent() 191 val foldListener = foldProvider.captureListener() 192 foldListener.onFoldUpdate(FOLD_UPDATE_START_CLOSING) 193 foldListener.onFoldUpdate(FOLD_UPDATE_FINISH_CLOSED) 194 keyguardTransitionRepository.startTransitionTo(KeyguardState.AOD) 195 196 var folded: Int? = null 197 var displayState: Int? = null 198 val job = 199 interactor.addBiometricContextListener( 200 object : IBiometricContextListener.Stub() { 201 override fun onFoldChanged(foldState: Int) { 202 folded = foldState 203 } 204 205 override fun onDisplayStateChanged(newDisplayState: Int) { 206 displayState = newDisplayState 207 } 208 } 209 ) 210 runCurrent() 211 212 assertThat(folded).isEqualTo(FoldState.FULLY_CLOSED) 213 assertThat(displayState).isEqualTo(AuthenticateOptions.DISPLAY_STATE_AOD) 214 215 foldListener.onFoldUpdate(FOLD_UPDATE_START_OPENING) 216 foldListener.onFoldUpdate(FOLD_UPDATE_FINISH_HALF_OPEN) 217 keyguardTransitionRepository.startTransitionTo(KeyguardState.LOCKSCREEN) 218 runCurrent() 219 220 assertThat(folded).isEqualTo(FoldState.HALF_OPENED) 221 assertThat(displayState).isEqualTo(AuthenticateOptions.DISPLAY_STATE_LOCKSCREEN) 222 223 job.cancel() 224 225 // stale updates should be ignored 226 foldListener.onFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN) 227 keyguardTransitionRepository.startTransitionTo(KeyguardState.AOD) 228 runCurrent() 229 230 assertThat(folded).isEqualTo(FoldState.HALF_OPENED) 231 assertThat(displayState).isEqualTo(AuthenticateOptions.DISPLAY_STATE_LOCKSCREEN) 232 } 233 } 234 235 private suspend fun FakeKeyguardTransitionRepository.startTransitionTo(newState: KeyguardState) = 236 sendTransitionStep(TransitionStep(to = newState, transitionState = TransitionState.STARTED)) 237 238 private fun FoldStateProvider.captureListener() = 239 withArgCaptor<FoldStateProvider.FoldUpdatesListener> { 240 verify(this@captureListener).addCallback(capture()) 241 } 242