diff options
5 files changed, 62 insertions, 27 deletions
diff --git a/packages/SystemUI/res/layout/biometric_prompt_one_pane_layout.xml b/packages/SystemUI/res/layout/biometric_prompt_one_pane_layout.xml index 4002f7808637..1e4a07f5fc30 100644 --- a/packages/SystemUI/res/layout/biometric_prompt_one_pane_layout.xml +++ b/packages/SystemUI/res/layout/biometric_prompt_one_pane_layout.xml @@ -22,7 +22,7 @@ android:layout_width="0dp" android:layout_height="0dp" android:accessibilityLiveRegion="assertive" - android:importantForAccessibility="yes" + android:importantForAccessibility="auto" android:clickable="false" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@id/rightGuideline" diff --git a/packages/SystemUI/res/layout/biometric_prompt_two_pane_layout.xml b/packages/SystemUI/res/layout/biometric_prompt_two_pane_layout.xml index 3c8cb6860a41..8234c24a7e17 100644 --- a/packages/SystemUI/res/layout/biometric_prompt_two_pane_layout.xml +++ b/packages/SystemUI/res/layout/biometric_prompt_two_pane_layout.xml @@ -23,7 +23,7 @@ android:layout_height="match_parent"> android:layout_width="0dp" android:layout_height="0dp" android:accessibilityLiveRegion="assertive" - android:importantForAccessibility="yes" + android:importantForAccessibility="auto" android:clickable="false" android:paddingHorizontal="16dp" android:paddingVertical="16dp" diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt index 3b22e13f29a2..80d06f4a2d37 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt @@ -27,6 +27,7 @@ import android.util.Log import android.view.MotionEvent import android.view.View import android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO +import android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES import android.view.accessibility.AccessibilityManager import android.widget.Button import android.widget.ImageView @@ -43,7 +44,6 @@ import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import com.airbnb.lottie.LottieAnimationView import com.airbnb.lottie.LottieCompositionFactory -import com.android.app.tracing.coroutines.launchTraced as launch import com.android.systemui.biometrics.Utils.ellipsize import com.android.systemui.biometrics.shared.model.BiometricModalities import com.android.systemui.biometrics.shared.model.BiometricModality @@ -63,6 +63,7 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch private const val TAG = "BiometricViewBinder" @@ -123,25 +124,6 @@ object BiometricViewBinder { val confirmationButton = view.requireViewById<Button>(R.id.button_confirm) val retryButton = view.requireViewById<Button>(R.id.button_try_again) - // Handles custom "Cancel Authentication" talkback action - val cancelDelegate: AccessibilityDelegateCompat = - object : AccessibilityDelegateCompat() { - override fun onInitializeAccessibilityNodeInfo( - host: View, - info: AccessibilityNodeInfoCompat, - ) { - super.onInitializeAccessibilityNodeInfo(host, info) - info.addAction( - AccessibilityActionCompat( - AccessibilityNodeInfoCompat.ACTION_CLICK, - view.context.getString(R.string.biometric_dialog_cancel_authentication), - ) - ) - } - } - ViewCompat.setAccessibilityDelegate(backgroundView, cancelDelegate) - ViewCompat.setAccessibilityDelegate(cancelButton, cancelDelegate) - // TODO(b/330788871): temporary workaround for the unsafe callbacks & legacy controllers val adapter = Spaghetti( @@ -155,6 +137,33 @@ object BiometricViewBinder { var boundSize = false view.repeatWhenAttached { + // Handles custom "Cancel Authentication" talkback action + val cancelDelegate: AccessibilityDelegateCompat = + object : AccessibilityDelegateCompat() { + override fun onInitializeAccessibilityNodeInfo( + host: View, + info: AccessibilityNodeInfoCompat, + ) { + super.onInitializeAccessibilityNodeInfo(host, info) + lifecycleScope.launch { + // Clears UDFPS guidance hint after focus moves to cancel view + viewModel.onClearUdfpsGuidanceHint( + accessibilityManager.isTouchExplorationEnabled + ) + } + info.addAction( + AccessibilityActionCompat( + AccessibilityNodeInfoCompat.ACTION_CLICK, + view.context.getString( + R.string.biometric_dialog_cancel_authentication + ), + ) + ) + } + } + ViewCompat.setAccessibilityDelegate(backgroundView, cancelDelegate) + ViewCompat.setAccessibilityDelegate(cancelButton, cancelDelegate) + // these do not change and need to be set before any size transitions val modalities = viewModel.modalities.first() @@ -404,11 +413,16 @@ object BiometricViewBinder { } false } + launch { viewModel.accessibilityHint.collect { message -> - if (message.isNotBlank()) { - udfpsGuidanceView.contentDescription = message - } + udfpsGuidanceView.importantForAccessibility = + if (message == null) { + IMPORTANT_FOR_ACCESSIBILITY_NO + } else { + IMPORTANT_FOR_ACCESSIBILITY_YES + } + udfpsGuidanceView.contentDescription = message } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt index 4e17a2658ee7..27fc1878cc99 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt @@ -187,10 +187,10 @@ constructor( } } - private val _accessibilityHint = MutableSharedFlow<String>() + private val _accessibilityHint = MutableSharedFlow<String?>() /** Hint for talkback directional guidance */ - val accessibilityHint: Flow<String> = _accessibilityHint.asSharedFlow() + val accessibilityHint: Flow<String?> = _accessibilityHint.asSharedFlow() private val _isAuthenticating: MutableStateFlow<Boolean> = MutableStateFlow(false) @@ -923,6 +923,19 @@ constructor( return false } + /** Clears the message used for UDFPS directional guidance */ + suspend fun onClearUdfpsGuidanceHint(touchExplorationEnabled: Boolean) { + if ( + modalities.first().hasUdfps && + touchExplorationEnabled && + !isAuthenticated.first().isAuthenticated + ) { + // Add delay to make sure we read the guidance message before clearing it + delay(1000) + _accessibilityHint.emit(null) + } + } + /** * Switch to the credential view. * diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt index bf79d11b2fb8..515a10792c02 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt @@ -1482,6 +1482,14 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa } else { assertThat(hint.isNullOrBlank()).isTrue() } + + kosmos.promptViewModel.onClearUdfpsGuidanceHint(true) + + if (testCase.modalities.hasUdfps) { + assertThat(hint).isNull() + } else { + assertThat(hint.isNullOrBlank()).isTrue() + } } @Test |