From 8d994b4690d018260b56efcd3c83542dff6cfe95 Mon Sep 17 00:00:00 2001 From: Beverly Date: Thu, 20 Jul 2023 19:23:56 +0000 Subject: Add face auth a11y action to bouncer view Test: atest FaceAuthAccessibilityDelegateTest KeyguardSecurityContainerControllerTest Test: manually enable switch access and see user has a way to retrigger face auth using switch access (tested with and without new face auth refactor) Fixes: 289162753 Merged-In: I42a77f815ec90dab60a3c585a63993e2e1e579d9 Change-Id: I42a77f815ec90dab60a3c585a63993e2e1e579d9 --- packages/SystemUI/res/values/strings.xml | 3 + .../src/com/android/keyguard/FaceAuthReason.kt | 8 +- .../KeyguardSecurityContainerController.java | 5 +- .../android/keyguard/KeyguardUpdateMonitor.java | 4 + .../biometrics/FaceAuthAccessibilityDelegate.kt | 62 ++++++++++++ .../interactor/KeyguardFaceAuthInteractor.kt | 1 + .../interactor/NoopKeyguardFaceAuthInteractor.kt | 1 + .../SystemUIKeyguardFaceAuthInteractor.kt | 4 + .../KeyguardSecurityContainerControllerTest.java | 11 +- .../FaceAuthAccessibilityDelegateTest.kt | 111 +++++++++++++++++++++ 10 files changed, 207 insertions(+), 3 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/biometrics/FaceAuthAccessibilityDelegate.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/biometrics/FaceAuthAccessibilityDelegateTest.kt diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 070748cb92f8..8e205f6bff41 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2563,6 +2563,9 @@ Swipe to see more + + Retry face authentication + Loading recommendations diff --git a/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt b/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt index d8085b9f9f2e..22cdb30376d0 100644 --- a/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt +++ b/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt @@ -20,6 +20,7 @@ import android.annotation.StringDef import android.os.PowerManager import com.android.internal.logging.UiEvent import com.android.internal.logging.UiEventLogger +import com.android.keyguard.FaceAuthApiRequestReason.Companion.ACCESSIBILITY_ACTION import com.android.keyguard.FaceAuthApiRequestReason.Companion.NOTIFICATION_PANEL_CLICKED import com.android.keyguard.FaceAuthApiRequestReason.Companion.PICK_UP_GESTURE_TRIGGERED import com.android.keyguard.FaceAuthApiRequestReason.Companion.QS_EXPANDED @@ -71,6 +72,7 @@ import com.android.keyguard.InternalFaceAuthReasons.USER_SWITCHING NOTIFICATION_PANEL_CLICKED, QS_EXPANDED, PICK_UP_GESTURE_TRIGGERED, + ACCESSIBILITY_ACTION, ) annotation class FaceAuthApiRequestReason { companion object { @@ -80,6 +82,7 @@ annotation class FaceAuthApiRequestReason { const val QS_EXPANDED = "Face auth due to QS expansion." const val PICK_UP_GESTURE_TRIGGERED = "Face auth due to pickup gesture triggered when the device is awake and not from AOD." + const val ACCESSIBILITY_ACTION = "Face auth due to an accessibility action." } } @@ -217,7 +220,8 @@ constructor(private val id: Int, val reason: String, var extraInfo: Int = 0) : @UiEvent(doc = STRONG_AUTH_ALLOWED_CHANGED) FACE_AUTH_UPDATED_STRONG_AUTH_CHANGED(1255, STRONG_AUTH_ALLOWED_CHANGED), @UiEvent(doc = NON_STRONG_BIOMETRIC_ALLOWED_CHANGED) - FACE_AUTH_NON_STRONG_BIOMETRIC_ALLOWED_CHANGED(1256, NON_STRONG_BIOMETRIC_ALLOWED_CHANGED); + FACE_AUTH_NON_STRONG_BIOMETRIC_ALLOWED_CHANGED(1256, NON_STRONG_BIOMETRIC_ALLOWED_CHANGED), + @UiEvent(doc = ACCESSIBILITY_ACTION) FACE_AUTH_ACCESSIBILITY_ACTION(1454, ACCESSIBILITY_ACTION); override fun getId(): Int = this.id @@ -233,6 +237,8 @@ private val apiRequestReasonToUiEvent = FaceAuthUiEvent.FACE_AUTH_TRIGGERED_NOTIFICATION_PANEL_CLICKED, QS_EXPANDED to FaceAuthUiEvent.FACE_AUTH_TRIGGERED_QS_EXPANDED, PICK_UP_GESTURE_TRIGGERED to FaceAuthUiEvent.FACE_AUTH_TRIGGERED_PICK_UP_GESTURE_TRIGGERED, + PICK_UP_GESTURE_TRIGGERED to FaceAuthUiEvent.FACE_AUTH_TRIGGERED_PICK_UP_GESTURE_TRIGGERED, + ACCESSIBILITY_ACTION to FaceAuthUiEvent.FACE_AUTH_ACCESSIBILITY_ACTION, ) /** Converts the [reason] to the corresponding [FaceAuthUiEvent]. */ diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java index 74b29a77aad4..78142cea2201 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java @@ -68,6 +68,7 @@ import com.android.keyguard.dagger.KeyguardBouncerScope; import com.android.settingslib.utils.ThreadUtils; import com.android.systemui.Gefingerpoken; import com.android.systemui.R; +import com.android.systemui.biometrics.FaceAuthAccessibilityDelegate; import com.android.systemui.biometrics.SideFpsController; import com.android.systemui.biometrics.SideFpsUiRequestSource; import com.android.systemui.classifier.FalsingA11yDelegate; @@ -385,9 +386,11 @@ public class KeyguardSecurityContainerController extends ViewController mKeyguardUpdateMonitorCallback; @@ -216,7 +219,8 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { mUserSwitcherController, mFeatureFlags, mGlobalSettings, mSessionTracker, Optional.of(mSideFpsController), mFalsingA11yDelegate, mTelephonyManager, mViewMediatorCallback, mAudioManager, - mock(KeyguardFaceAuthInteractor.class)); + mock(KeyguardFaceAuthInteractor.class), + mFaceAuthAccessibilityDelegate); } @Test @@ -685,6 +689,11 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { verify(mView).setTranslationY(0f); } + @Test + public void setAccessibilityDelegate() { + verify(mView).setAccessibilityDelegate(eq(mFaceAuthAccessibilityDelegate)); + } + private KeyguardSecurityContainer.SwipeListener getRegisteredSwipeListener() { mKeyguardSecurityContainerController.onViewAttached(); verify(mView).setSwipeListener(mSwipeListenerArgumentCaptor.capture()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/FaceAuthAccessibilityDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/FaceAuthAccessibilityDelegateTest.kt new file mode 100644 index 000000000000..ec17794d4ee2 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/FaceAuthAccessibilityDelegateTest.kt @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2023 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.testing.TestableLooper +import android.view.View +import android.view.accessibility.AccessibilityNodeInfo +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.keyguard.FaceAuthApiRequestReason +import com.android.keyguard.KeyguardUpdateMonitor +import com.android.systemui.SysuiTestCase +import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.argumentCaptor +import com.android.systemui.util.mockito.eq +import com.android.systemui.util.mockito.whenever +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.mock +import org.mockito.Mockito.never +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@RunWith(AndroidJUnit4::class) +@SmallTest +@TestableLooper.RunWithLooper +class FaceAuthAccessibilityDelegateTest : SysuiTestCase() { + + @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor + @Mock private lateinit var hostView: View + @Mock private lateinit var faceAuthInteractor: KeyguardFaceAuthInteractor + private lateinit var underTest: FaceAuthAccessibilityDelegate + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + underTest = + FaceAuthAccessibilityDelegate( + context.resources, + keyguardUpdateMonitor, + faceAuthInteractor, + ) + } + + @Test + fun shouldListenForFaceTrue_onInitializeAccessibilityNodeInfo_clickActionAdded() { + whenever(keyguardUpdateMonitor.shouldListenForFace()).thenReturn(true) + + // WHEN node is initialized + val mockedNodeInfo = mock(AccessibilityNodeInfo::class.java) + underTest.onInitializeAccessibilityNodeInfo(hostView, mockedNodeInfo) + + // THEN a11y action is added + val argumentCaptor = argumentCaptor() + verify(mockedNodeInfo).addAction(argumentCaptor.capture()) + + // AND the a11y action is a click action + assertEquals( + AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK.id, + argumentCaptor.value.id + ) + } + + @Test + fun shouldListenForFaceFalse_onInitializeAccessibilityNodeInfo_clickActionNotAdded() { + whenever(keyguardUpdateMonitor.shouldListenForFace()).thenReturn(false) + + // WHEN node is initialized + val mockedNodeInfo = mock(AccessibilityNodeInfo::class.java) + underTest.onInitializeAccessibilityNodeInfo(hostView, mockedNodeInfo) + + // THEN a11y action is NOT added + verify(mockedNodeInfo, never()) + .addAction(any(AccessibilityNodeInfo.AccessibilityAction::class.java)) + } + + @Test + fun performAccessibilityAction_actionClick_retriesFaceAuth() { + whenever(keyguardUpdateMonitor.shouldListenForFace()).thenReturn(true) + + // WHEN click action is performed + underTest.performAccessibilityAction( + hostView, + AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK.id, + null + ) + + // THEN retry face auth + verify(keyguardUpdateMonitor) + .requestFaceAuth(eq(FaceAuthApiRequestReason.ACCESSIBILITY_ACTION)) + verify(faceAuthInteractor).onAccessibilityAction() + } +} -- cgit v1.2.3-59-g8ed1b