diff options
4 files changed, 169 insertions, 6 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java index 80c6c48cb7ee..37da2c7d3379 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java @@ -120,7 +120,7 @@ public class AuthContainerView extends LinearLayout @VisibleForTesting final BiometricCallback mBiometricCallback; @Nullable private AuthBiometricView mBiometricView; - @Nullable private AuthCredentialView mCredentialView; + @VisibleForTesting @Nullable AuthCredentialView mCredentialView; private final AuthPanelController mPanelController; private final FrameLayout mFrameLayout; private final ImageView mBackgroundView; diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPatternView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPatternView.java index f9e44a0c1724..85cb39849f1f 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPatternView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPatternView.java @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.content.Context; import android.util.AttributeSet; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.widget.LockPatternChecker; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockPatternView; @@ -34,7 +35,7 @@ import java.util.List; */ public class AuthCredentialPatternView extends AuthCredentialView { - private LockPatternView mLockPatternView; + @VisibleForTesting LockPatternView mLockPatternView; private class UnlockPatternListener implements LockPatternView.OnPatternListener { @@ -93,9 +94,7 @@ public class AuthCredentialPatternView extends AuthCredentialView { @Override protected void onErrorTimeoutFinish() { super.onErrorTimeoutFinish(); - // select to enable marquee unless a screen reader is enabled - mLockPatternView.setEnabled(!mAccessibilityManager.isEnabled() - || !mAccessibilityManager.isTouchExplorationEnabled()); + mLockPatternView.setEnabled(true); } public AuthCredentialPatternView(Context context, AttributeSet attrs) { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java index 5958e6a436f1..157f14fb4c51 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java @@ -47,6 +47,7 @@ import android.widget.LinearLayout; import android.widget.TextView; import androidx.annotation.StringRes; +import androidx.annotation.VisibleForTesting; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.VerifyCredentialResponse; @@ -98,7 +99,7 @@ public abstract class AuthCredentialView extends LinearLayout { protected int mUserId; protected long mOperationId; protected int mEffectiveUserId; - protected ErrorTimer mErrorTimer; + @VisibleForTesting ErrorTimer mErrorTimer; protected @Background DelayableExecutor mBackgroundExecutor; diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthCredentialViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthCredentialViewTest.kt new file mode 100644 index 000000000000..fbda08fab799 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthCredentialViewTest.kt @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2022 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 + +import android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING +import android.hardware.biometrics.BiometricManager +import android.hardware.biometrics.PromptInfo +import android.hardware.face.FaceSensorPropertiesInternal +import android.hardware.fingerprint.FingerprintSensorPropertiesInternal +import android.os.Handler +import android.os.IBinder +import android.os.UserManager +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import android.testing.ViewUtils +import androidx.test.filters.SmallTest +import com.android.internal.jank.InteractionJankMonitor +import com.android.internal.widget.LockPatternUtils +import com.android.internal.widget.LockPatternView +import com.android.internal.widget.VerifyCredentialResponse +import com.android.systemui.SysuiTestCase +import com.android.systemui.biometrics.AuthContainerView.BiometricCallback +import com.android.systemui.biometrics.AuthCredentialView.ErrorTimer +import com.android.systemui.keyguard.WakefulnessLifecycle +import com.android.systemui.util.concurrency.FakeExecutor +import com.android.systemui.util.time.FakeSystemClock +import com.google.common.truth.Truth.assertThat +import org.junit.After +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.anyInt +import org.mockito.Mockito.spy +import org.mockito.Mockito.verify +import org.mockito.Mockito.`when` +import org.mockito.junit.MockitoJUnit + +@RunWith(AndroidTestingRunner::class) +@TestableLooper.RunWithLooper(setAsMainLooper = true) +@SmallTest +class AuthCredentialViewTest : SysuiTestCase() { + @JvmField @Rule var mockitoRule = MockitoJUnit.rule() + + @Mock lateinit var callback: AuthDialogCallback + @Mock lateinit var lockPatternUtils: LockPatternUtils + @Mock lateinit var userManager: UserManager + @Mock lateinit var wakefulnessLifecycle: WakefulnessLifecycle + @Mock lateinit var windowToken: IBinder + @Mock lateinit var interactionJankMonitor: InteractionJankMonitor + + private var authContainer: TestAuthContainerView? = null + private var authCredentialView: AuthCredentialPatternView? = null + private var lockPatternView: LockPatternView? = null + private var biometricCallback: BiometricCallback? = null + private var errorTimer: ErrorTimer? = null + + @After + fun tearDown() { + if (authContainer?.isAttachedToWindow == true) { + ViewUtils.detachView(authContainer) + } + } + + @Test + fun testAuthCredentialPatternView_onErrorTimeoutFinish_setPatternEnabled() { + `when`(lockPatternUtils.getCredentialTypeForUser(anyInt())) + .thenReturn(LockPatternUtils.CREDENTIAL_TYPE_PATTERN) + `when`(lockPatternUtils.getKeyguardStoredPasswordQuality(anyInt())) + .thenReturn(PASSWORD_QUALITY_SOMETHING) + val errorResponse: VerifyCredentialResponse = VerifyCredentialResponse.fromError() + + assertThat(initializeFingerprintContainer()).isNotNull() + authContainer?.animateToCredentialUI() + waitForIdleSync() + + authCredentialView = spy(authContainer?.mCredentialView as AuthCredentialPatternView) + authCredentialView?.onCredentialVerified(errorResponse, 5000) + errorTimer = authCredentialView?.mErrorTimer + errorTimer?.onFinish() + waitForIdleSync() + + verify(authCredentialView)?.onErrorTimeoutFinish() + + lockPatternView = authCredentialView?.mLockPatternView + assertThat(lockPatternView?.isEnabled).isTrue() + } + + private fun initializeFingerprintContainer( + authenticators: Int = BiometricManager.Authenticators.BIOMETRIC_WEAK, + addToView: Boolean = true + ) = + initializeContainer( + TestAuthContainerView( + authenticators = authenticators, + fingerprintProps = fingerprintSensorPropertiesInternal() + ), + addToView + ) + + private fun initializeContainer( + view: TestAuthContainerView, + addToView: Boolean + ): TestAuthContainerView { + authContainer = view + if (addToView) { + authContainer!!.addToView() + biometricCallback = authContainer?.mBiometricCallback + } + return authContainer!! + } + + private inner class TestAuthContainerView( + authenticators: Int = BiometricManager.Authenticators.BIOMETRIC_WEAK, + fingerprintProps: List<FingerprintSensorPropertiesInternal> = listOf(), + faceProps: List<FaceSensorPropertiesInternal> = listOf() + ) : + AuthContainerView( + Config().apply { + mContext = context + mCallback = callback + mSensorIds = + (fingerprintProps.map { it.sensorId } + faceProps.map { it.sensorId }) + .toIntArray() + mSkipAnimation = true + mPromptInfo = PromptInfo().apply { this.authenticators = authenticators } + }, + fingerprintProps, + faceProps, + wakefulnessLifecycle, + userManager, + lockPatternUtils, + interactionJankMonitor, + Handler(TestableLooper.get(this).looper), + FakeExecutor(FakeSystemClock()) + ) { + override fun postOnAnimation(runnable: Runnable) { + runnable.run() + } + } + + override fun waitForIdleSync() = TestableLooper.get(this).processAllMessages() + + private fun AuthContainerView.addToView() { + ViewUtils.attachView(this) + waitForIdleSync() + assertThat(isAttachedToWindow).isTrue() + } +} |