1 /* 2 * Copyright (C) 2022 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.biometrics 18 19 import android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING 20 import android.hardware.biometrics.BiometricManager 21 import android.hardware.biometrics.PromptInfo 22 import android.hardware.face.FaceSensorPropertiesInternal 23 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal 24 import android.os.Handler 25 import android.os.IBinder 26 import android.os.UserManager 27 import android.testing.AndroidTestingRunner 28 import android.testing.TestableLooper 29 import android.testing.ViewUtils 30 import androidx.test.filters.SmallTest 31 import com.android.internal.jank.InteractionJankMonitor 32 import com.android.internal.widget.LockPatternUtils 33 import com.android.internal.widget.LockPatternView 34 import com.android.internal.widget.VerifyCredentialResponse 35 import com.android.systemui.SysuiTestCase 36 import com.android.systemui.biometrics.AuthContainerView.BiometricCallback 37 import com.android.systemui.biometrics.AuthCredentialView.ErrorTimer 38 import com.android.systemui.keyguard.WakefulnessLifecycle 39 import com.android.systemui.util.concurrency.FakeExecutor 40 import com.android.systemui.util.time.FakeSystemClock 41 import com.google.common.truth.Truth.assertThat 42 import org.junit.After 43 import org.junit.Rule 44 import org.junit.Test 45 import org.junit.runner.RunWith 46 import org.mockito.Mock 47 import org.mockito.Mockito.anyInt 48 import org.mockito.Mockito.spy 49 import org.mockito.Mockito.verify 50 import org.mockito.Mockito.`when` 51 import org.mockito.junit.MockitoJUnit 52 53 @RunWith(AndroidTestingRunner::class) 54 @TestableLooper.RunWithLooper(setAsMainLooper = true) 55 @SmallTest 56 class AuthCredentialViewTest : SysuiTestCase() { 57 @JvmField @Rule var mockitoRule = MockitoJUnit.rule() 58 59 @Mock lateinit var callback: AuthDialogCallback 60 @Mock lateinit var lockPatternUtils: LockPatternUtils 61 @Mock lateinit var userManager: UserManager 62 @Mock lateinit var wakefulnessLifecycle: WakefulnessLifecycle 63 @Mock lateinit var windowToken: IBinder 64 @Mock lateinit var interactionJankMonitor: InteractionJankMonitor 65 66 private var authContainer: TestAuthContainerView? = null 67 private var authCredentialView: AuthCredentialPatternView? = null 68 private var lockPatternView: LockPatternView? = null 69 private var biometricCallback: BiometricCallback? = null 70 private var errorTimer: ErrorTimer? = null 71 72 @After tearDownnull73 fun tearDown() { 74 if (authContainer?.isAttachedToWindow == true) { 75 ViewUtils.detachView(authContainer) 76 } 77 } 78 79 @Test testAuthCredentialPatternView_onErrorTimeoutFinish_setPatternEnablednull80 fun testAuthCredentialPatternView_onErrorTimeoutFinish_setPatternEnabled() { 81 `when`(lockPatternUtils.getCredentialTypeForUser(anyInt())) 82 .thenReturn(LockPatternUtils.CREDENTIAL_TYPE_PATTERN) 83 `when`(lockPatternUtils.getKeyguardStoredPasswordQuality(anyInt())) 84 .thenReturn(PASSWORD_QUALITY_SOMETHING) 85 val errorResponse: VerifyCredentialResponse = VerifyCredentialResponse.fromError() 86 87 assertThat(initializeFingerprintContainer()).isNotNull() 88 authContainer?.animateToCredentialUI() 89 waitForIdleSync() 90 91 authCredentialView = spy(authContainer?.mCredentialView as AuthCredentialPatternView) 92 authCredentialView?.onCredentialVerified(errorResponse, 5000) 93 errorTimer = authCredentialView?.mErrorTimer 94 errorTimer?.onFinish() 95 waitForIdleSync() 96 97 verify(authCredentialView)?.onErrorTimeoutFinish() 98 99 lockPatternView = authCredentialView?.mLockPatternView 100 assertThat(lockPatternView?.isEnabled).isTrue() 101 } 102 initializeFingerprintContainernull103 private fun initializeFingerprintContainer( 104 authenticators: Int = BiometricManager.Authenticators.BIOMETRIC_WEAK, 105 addToView: Boolean = true 106 ) = 107 initializeContainer( 108 TestAuthContainerView( 109 authenticators = authenticators, 110 fingerprintProps = fingerprintSensorPropertiesInternal() 111 ), 112 addToView 113 ) 114 115 private fun initializeContainer( 116 view: TestAuthContainerView, 117 addToView: Boolean 118 ): TestAuthContainerView { 119 authContainer = view 120 if (addToView) { 121 authContainer!!.addToView() 122 biometricCallback = authContainer?.mBiometricCallback 123 } 124 return authContainer!! 125 } 126 127 private inner class TestAuthContainerView( 128 authenticators: Int = BiometricManager.Authenticators.BIOMETRIC_WEAK, 129 fingerprintProps: List<FingerprintSensorPropertiesInternal> = listOf(), 130 faceProps: List<FaceSensorPropertiesInternal> = listOf() 131 ) : 132 AuthContainerView( <lambda>null133 Config().apply { 134 mContext = context 135 mCallback = callback 136 mSensorIds = 137 (fingerprintProps.map { it.sensorId } + faceProps.map { it.sensorId }) 138 .toIntArray() 139 mSkipAnimation = true 140 mPromptInfo = PromptInfo().apply { this.authenticators = authenticators } 141 }, 142 fingerprintProps, 143 faceProps, 144 wakefulnessLifecycle, 145 userManager, 146 lockPatternUtils, 147 interactionJankMonitor, 148 Handler(TestableLooper.get(this).looper), 149 FakeExecutor(FakeSystemClock()) 150 ) { postOnAnimationnull151 override fun postOnAnimation(runnable: Runnable) { 152 runnable.run() 153 } 154 } 155 waitForIdleSyncnull156 override fun waitForIdleSync() = TestableLooper.get(this).processAllMessages() 157 158 private fun AuthContainerView.addToView() { 159 ViewUtils.attachView(this) 160 waitForIdleSync() 161 assertThat(isAttachedToWindow).isTrue() 162 } 163 } 164