Merge "Add face auth a11y action to bouncer view" into udc-d1-dev am: 2b0765ae5b
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/24163069 Change-Id: I458aecd3f2276dc6adbabe978e495abd02997c42 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -2563,6 +2563,9 @@
|
|||||||
<!-- Tooltip to show in management screen when there are multiple structures [CHAR_LIMIT=50] -->
|
<!-- Tooltip to show in management screen when there are multiple structures [CHAR_LIMIT=50] -->
|
||||||
<string name="controls_structure_tooltip">Swipe to see more</string>
|
<string name="controls_structure_tooltip">Swipe to see more</string>
|
||||||
|
|
||||||
|
<!-- Accessibility action informing the user how they can retry face authentication [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="retry_face">Retry face authentication</string>
|
||||||
|
|
||||||
<!-- Message to tell the user to wait while systemui attempts to load a set of
|
<!-- Message to tell the user to wait while systemui attempts to load a set of
|
||||||
recommended controls [CHAR_LIMIT=60] -->
|
recommended controls [CHAR_LIMIT=60] -->
|
||||||
<string name="controls_seeding_in_progress">Loading recommendations</string>
|
<string name="controls_seeding_in_progress">Loading recommendations</string>
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import android.annotation.StringDef
|
|||||||
import android.os.PowerManager
|
import android.os.PowerManager
|
||||||
import com.android.internal.logging.UiEvent
|
import com.android.internal.logging.UiEvent
|
||||||
import com.android.internal.logging.UiEventLogger
|
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.NOTIFICATION_PANEL_CLICKED
|
||||||
import com.android.keyguard.FaceAuthApiRequestReason.Companion.PICK_UP_GESTURE_TRIGGERED
|
import com.android.keyguard.FaceAuthApiRequestReason.Companion.PICK_UP_GESTURE_TRIGGERED
|
||||||
import com.android.keyguard.FaceAuthApiRequestReason.Companion.QS_EXPANDED
|
import com.android.keyguard.FaceAuthApiRequestReason.Companion.QS_EXPANDED
|
||||||
@@ -71,6 +72,7 @@ import com.android.keyguard.InternalFaceAuthReasons.USER_SWITCHING
|
|||||||
NOTIFICATION_PANEL_CLICKED,
|
NOTIFICATION_PANEL_CLICKED,
|
||||||
QS_EXPANDED,
|
QS_EXPANDED,
|
||||||
PICK_UP_GESTURE_TRIGGERED,
|
PICK_UP_GESTURE_TRIGGERED,
|
||||||
|
ACCESSIBILITY_ACTION,
|
||||||
)
|
)
|
||||||
annotation class FaceAuthApiRequestReason {
|
annotation class FaceAuthApiRequestReason {
|
||||||
companion object {
|
companion object {
|
||||||
@@ -80,6 +82,7 @@ annotation class FaceAuthApiRequestReason {
|
|||||||
const val QS_EXPANDED = "Face auth due to QS expansion."
|
const val QS_EXPANDED = "Face auth due to QS expansion."
|
||||||
const val PICK_UP_GESTURE_TRIGGERED =
|
const val PICK_UP_GESTURE_TRIGGERED =
|
||||||
"Face auth due to pickup gesture triggered when the device is awake and not from AOD."
|
"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)
|
@UiEvent(doc = STRONG_AUTH_ALLOWED_CHANGED)
|
||||||
FACE_AUTH_UPDATED_STRONG_AUTH_CHANGED(1255, STRONG_AUTH_ALLOWED_CHANGED),
|
FACE_AUTH_UPDATED_STRONG_AUTH_CHANGED(1255, STRONG_AUTH_ALLOWED_CHANGED),
|
||||||
@UiEvent(doc = NON_STRONG_BIOMETRIC_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
|
override fun getId(): Int = this.id
|
||||||
|
|
||||||
@@ -233,6 +237,8 @@ private val apiRequestReasonToUiEvent =
|
|||||||
FaceAuthUiEvent.FACE_AUTH_TRIGGERED_NOTIFICATION_PANEL_CLICKED,
|
FaceAuthUiEvent.FACE_AUTH_TRIGGERED_NOTIFICATION_PANEL_CLICKED,
|
||||||
QS_EXPANDED to FaceAuthUiEvent.FACE_AUTH_TRIGGERED_QS_EXPANDED,
|
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,
|
||||||
|
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]. */
|
/** Converts the [reason] to the corresponding [FaceAuthUiEvent]. */
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ import com.android.keyguard.dagger.KeyguardBouncerScope;
|
|||||||
import com.android.settingslib.utils.ThreadUtils;
|
import com.android.settingslib.utils.ThreadUtils;
|
||||||
import com.android.systemui.Gefingerpoken;
|
import com.android.systemui.Gefingerpoken;
|
||||||
import com.android.systemui.R;
|
import com.android.systemui.R;
|
||||||
|
import com.android.systemui.biometrics.FaceAuthAccessibilityDelegate;
|
||||||
import com.android.systemui.biometrics.SideFpsController;
|
import com.android.systemui.biometrics.SideFpsController;
|
||||||
import com.android.systemui.biometrics.SideFpsUiRequestSource;
|
import com.android.systemui.biometrics.SideFpsUiRequestSource;
|
||||||
import com.android.systemui.classifier.FalsingA11yDelegate;
|
import com.android.systemui.classifier.FalsingA11yDelegate;
|
||||||
@@ -385,9 +386,11 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
|
|||||||
TelephonyManager telephonyManager,
|
TelephonyManager telephonyManager,
|
||||||
ViewMediatorCallback viewMediatorCallback,
|
ViewMediatorCallback viewMediatorCallback,
|
||||||
AudioManager audioManager,
|
AudioManager audioManager,
|
||||||
KeyguardFaceAuthInteractor keyguardFaceAuthInteractor
|
KeyguardFaceAuthInteractor keyguardFaceAuthInteractor,
|
||||||
|
FaceAuthAccessibilityDelegate faceAuthAccessibilityDelegate
|
||||||
) {
|
) {
|
||||||
super(view);
|
super(view);
|
||||||
|
view.setAccessibilityDelegate(faceAuthAccessibilityDelegate);
|
||||||
mLockPatternUtils = lockPatternUtils;
|
mLockPatternUtils = lockPatternUtils;
|
||||||
mUpdateMonitor = keyguardUpdateMonitor;
|
mUpdateMonitor = keyguardUpdateMonitor;
|
||||||
mSecurityModel = keyguardSecurityModel;
|
mSecurityModel = keyguardSecurityModel;
|
||||||
|
|||||||
@@ -3136,6 +3136,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isFaceAuthInteractorEnabled()) {
|
||||||
|
return mFaceAuthInteractor.canFaceAuthRun();
|
||||||
|
}
|
||||||
|
|
||||||
final boolean statusBarShadeLocked = mStatusBarState == StatusBarState.SHADE_LOCKED;
|
final boolean statusBarShadeLocked = mStatusBarState == StatusBarState.SHADE_LOCKED;
|
||||||
final boolean awakeKeyguard = isKeyguardVisible() && mDeviceInteractive
|
final boolean awakeKeyguard = isKeyguardVisible() && mDeviceInteractive
|
||||||
&& !statusBarShadeLocked;
|
&& !statusBarShadeLocked;
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* 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.content.res.Resources
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import android.view.accessibility.AccessibilityNodeInfo
|
||||||
|
import com.android.keyguard.FaceAuthApiRequestReason
|
||||||
|
import com.android.keyguard.KeyguardUpdateMonitor
|
||||||
|
import com.android.systemui.R
|
||||||
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
|
import com.android.systemui.dagger.qualifiers.Main
|
||||||
|
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accessibility delegate that will add a click accessibility action to a view when face auth can
|
||||||
|
* run. When the click a11y action is triggered, face auth will retry.
|
||||||
|
*/
|
||||||
|
@SysUISingleton
|
||||||
|
class FaceAuthAccessibilityDelegate
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
@Main private val resources: Resources,
|
||||||
|
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
|
||||||
|
private val faceAuthInteractor: KeyguardFaceAuthInteractor,
|
||||||
|
) : View.AccessibilityDelegate() {
|
||||||
|
override fun onInitializeAccessibilityNodeInfo(host: View?, info: AccessibilityNodeInfo) {
|
||||||
|
super.onInitializeAccessibilityNodeInfo(host, info)
|
||||||
|
if (keyguardUpdateMonitor.shouldListenForFace()) {
|
||||||
|
val clickActionToRetryFace =
|
||||||
|
AccessibilityNodeInfo.AccessibilityAction(
|
||||||
|
AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK.id,
|
||||||
|
resources.getString(R.string.retry_face)
|
||||||
|
)
|
||||||
|
info.addAction(clickActionToRetryFace)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun performAccessibilityAction(host: View?, action: Int, args: Bundle?): Boolean {
|
||||||
|
return if (action == AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK.id) {
|
||||||
|
keyguardUpdateMonitor.requestFaceAuth(FaceAuthApiRequestReason.ACCESSIBILITY_ACTION)
|
||||||
|
faceAuthInteractor.onAccessibilityAction()
|
||||||
|
true
|
||||||
|
} else super.performAccessibilityAction(host, action, args)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -60,6 +60,7 @@ interface KeyguardFaceAuthInteractor {
|
|||||||
fun onNotificationPanelClicked()
|
fun onNotificationPanelClicked()
|
||||||
fun onSwipeUpOnBouncer()
|
fun onSwipeUpOnBouncer()
|
||||||
fun onPrimaryBouncerUserInput()
|
fun onPrimaryBouncerUserInput()
|
||||||
|
fun onAccessibilityAction()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -60,4 +60,5 @@ class NoopKeyguardFaceAuthInteractor @Inject constructor() : KeyguardFaceAuthInt
|
|||||||
|
|
||||||
override fun onSwipeUpOnBouncer() {}
|
override fun onSwipeUpOnBouncer() {}
|
||||||
override fun onPrimaryBouncerUserInput() {}
|
override fun onPrimaryBouncerUserInput() {}
|
||||||
|
override fun onAccessibilityAction() {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,6 +133,10 @@ constructor(
|
|||||||
runFaceAuth(FaceAuthUiEvent.FACE_AUTH_TRIGGERED_UDFPS_POINTER_DOWN, false)
|
runFaceAuth(FaceAuthUiEvent.FACE_AUTH_TRIGGERED_UDFPS_POINTER_DOWN, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onAccessibilityAction() {
|
||||||
|
runFaceAuth(FaceAuthUiEvent.FACE_AUTH_ACCESSIBILITY_ACTION, false)
|
||||||
|
}
|
||||||
|
|
||||||
override fun registerListener(listener: FaceAuthenticationListener) {
|
override fun registerListener(listener: FaceAuthenticationListener) {
|
||||||
listeners.add(listener)
|
listeners.add(listener)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ import com.android.internal.widget.LockPatternUtils;
|
|||||||
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
|
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
|
||||||
import com.android.systemui.R;
|
import com.android.systemui.R;
|
||||||
import com.android.systemui.SysuiTestCase;
|
import com.android.systemui.SysuiTestCase;
|
||||||
|
import com.android.systemui.biometrics.FaceAuthAccessibilityDelegate;
|
||||||
import com.android.systemui.biometrics.SideFpsController;
|
import com.android.systemui.biometrics.SideFpsController;
|
||||||
import com.android.systemui.biometrics.SideFpsUiRequestSource;
|
import com.android.systemui.biometrics.SideFpsUiRequestSource;
|
||||||
import com.android.systemui.classifier.FalsingA11yDelegate;
|
import com.android.systemui.classifier.FalsingA11yDelegate;
|
||||||
@@ -158,6 +159,8 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
|
|||||||
private ViewMediatorCallback mViewMediatorCallback;
|
private ViewMediatorCallback mViewMediatorCallback;
|
||||||
@Mock
|
@Mock
|
||||||
private AudioManager mAudioManager;
|
private AudioManager mAudioManager;
|
||||||
|
@Mock
|
||||||
|
private FaceAuthAccessibilityDelegate mFaceAuthAccessibilityDelegate;
|
||||||
|
|
||||||
@Captor
|
@Captor
|
||||||
private ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardUpdateMonitorCallback;
|
private ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardUpdateMonitorCallback;
|
||||||
@@ -216,7 +219,8 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
|
|||||||
mUserSwitcherController, mFeatureFlags, mGlobalSettings,
|
mUserSwitcherController, mFeatureFlags, mGlobalSettings,
|
||||||
mSessionTracker, Optional.of(mSideFpsController), mFalsingA11yDelegate,
|
mSessionTracker, Optional.of(mSideFpsController), mFalsingA11yDelegate,
|
||||||
mTelephonyManager, mViewMediatorCallback, mAudioManager,
|
mTelephonyManager, mViewMediatorCallback, mAudioManager,
|
||||||
mock(KeyguardFaceAuthInteractor.class));
|
mock(KeyguardFaceAuthInteractor.class),
|
||||||
|
mFaceAuthAccessibilityDelegate);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -685,6 +689,11 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
|
|||||||
verify(mView).setTranslationY(0f);
|
verify(mView).setTranslationY(0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void setAccessibilityDelegate() {
|
||||||
|
verify(mView).setAccessibilityDelegate(eq(mFaceAuthAccessibilityDelegate));
|
||||||
|
}
|
||||||
|
|
||||||
private KeyguardSecurityContainer.SwipeListener getRegisteredSwipeListener() {
|
private KeyguardSecurityContainer.SwipeListener getRegisteredSwipeListener() {
|
||||||
mKeyguardSecurityContainerController.onViewAttached();
|
mKeyguardSecurityContainerController.onViewAttached();
|
||||||
verify(mView).setSwipeListener(mSwipeListenerArgumentCaptor.capture());
|
verify(mView).setSwipeListener(mSwipeListenerArgumentCaptor.capture());
|
||||||
|
|||||||
@@ -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<AccessibilityNodeInfo.AccessibilityAction>()
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user