Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 91125d7e authored by Beverly's avatar Beverly
Browse files

When a11y is enabled, device entry icon is also clickable

In addition to the device entry icon longpress, when a11y
is enabled, make the device entry icon clickable too so it's easier
for the user to interact with it when a11y features like talkback are
enabled. We don't want the icon to be clickable when a11y isn't enabled
because this can lead to false-touches entering the device.

Flag: ACONFIG com.android.systemui.device_entry_udfps_refactor NEXTFOOD
Fixes: 336313562
Test: atest DeviceEntryIconViewModelTest
Test: manually enable talkback and observe "double click" can be used
to act on the device entry icon in addition to "click and then hold"

Change-Id: I04cb421d1f2f75d51356801df9f0a71e6b655131
parent f57b481f
Loading
Loading
Loading
Loading
+12 −1
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@ package com.android.systemui.accessibility.data.repository

import android.view.accessibility.AccessibilityManager
import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
import dagger.Module
import dagger.Provides
import kotlinx.coroutines.channels.awaitClose
@@ -29,6 +29,8 @@ import kotlinx.coroutines.flow.distinctUntilChanged
interface AccessibilityRepository {
    /** @see [AccessibilityManager.isTouchExplorationEnabled] */
    val isTouchExplorationEnabled: Flow<Boolean>
    /** @see [AccessibilityManager.isEnabled] */
    val isEnabled: Flow<Boolean>

    companion object {
        operator fun invoke(a11yManager: AccessibilityManager): AccessibilityRepository =
@@ -47,6 +49,15 @@ private class AccessibilityRepositoryImpl(
                awaitClose { manager.removeTouchExplorationStateChangeListener(listener) }
            }
            .distinctUntilChanged()

    override val isEnabled: Flow<Boolean> =
        conflatedCallbackFlow {
                val listener = AccessibilityManager.AccessibilityStateChangeListener(::trySend)
                manager.addAccessibilityStateChangeListener(listener)
                trySend(manager.isEnabled)
                awaitClose { manager.removeAccessibilityStateChangeListener(listener) }
            }
            .distinctUntilChanged()
}

@Module
+4 −2
Original line number Diff line number Diff line
@@ -28,6 +28,8 @@ constructor(
    private val a11yRepo: AccessibilityRepository,
) {
    /** @see [android.view.accessibility.AccessibilityManager.isTouchExplorationEnabled] */
    val isTouchExplorationEnabled: Flow<Boolean>
        get() = a11yRepo.isTouchExplorationEnabled
    val isTouchExplorationEnabled: Flow<Boolean> = a11yRepo.isTouchExplorationEnabled

    /** @see [android.view.accessibility.AccessibilityManager.isEnabled] */
    val isEnabled: Flow<Boolean> = a11yRepo.isEnabled
}
+12 −1
Original line number Diff line number Diff line
@@ -76,7 +76,7 @@ object DeviceEntryIconViewBinder {
                        view,
                        HapticFeedbackConstants.CONFIRM,
                    )
                    applicationScope.launch { viewModel.onLongPress() }
                    applicationScope.launch { viewModel.onUserInteraction() }
                }
            }

@@ -116,6 +116,17 @@ object DeviceEntryIconViewBinder {
                launch("$TAG#viewModel.accessibilityDelegateHint") {
                    viewModel.accessibilityDelegateHint.collect { hint ->
                        view.accessibilityHintType = hint
                        if (hint != DeviceEntryIconView.AccessibilityHintType.NONE) {
                            view.setOnClickListener {
                                vibratorHelper.performHapticFeedback(
                                    view,
                                    HapticFeedbackConstants.CONFIRM,
                                )
                                applicationScope.launch { viewModel.onUserInteraction() }
                            }
                        } else {
                            view.setOnClickListener(null)
                        }
                    }
                }
                launch("$TAG#viewModel.useBackgroundProtection") {
+2 −2
Original line number Diff line number Diff line
@@ -65,12 +65,12 @@ constructor(
            object : AccessibilityDelegate() {
                private val accessibilityAuthenticateHint =
                    AccessibilityNodeInfo.AccessibilityAction(
                        AccessibilityNodeInfoCompat.ACTION_LONG_CLICK,
                        AccessibilityNodeInfoCompat.ACTION_CLICK,
                        resources.getString(R.string.accessibility_authenticate_hint)
                    )
                private val accessibilityEnterHint =
                    AccessibilityNodeInfo.AccessibilityAction(
                        AccessibilityNodeInfoCompat.ACTION_LONG_CLICK,
                        AccessibilityNodeInfoCompat.ACTION_CLICK,
                        resources.getString(R.string.accessibility_enter_hint)
                    )
                override fun onInitializeAccessibilityNodeInfo(
+17 −7
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.systemui.keyguard.ui.viewmodel
import android.animation.FloatEvaluator
import android.animation.IntEvaluator
import com.android.keyguard.KeyguardViewController
import com.android.systemui.accessibility.domain.interactor.AccessibilityInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
@@ -68,6 +69,7 @@ constructor(
    private val keyguardViewController: Lazy<KeyguardViewController>,
    private val deviceEntryInteractor: DeviceEntryInteractor,
    private val deviceEntrySourceInteractor: DeviceEntrySourceInteractor,
    private val accessibilityInteractor: AccessibilityInteractor,
    @Application private val scope: CoroutineScope,
) {
    val isUdfpsSupported: StateFlow<Boolean> = deviceEntryUdfpsInteractor.isUdfpsSupported
@@ -232,7 +234,8 @@ constructor(
            }
        }
    val isVisible: Flow<Boolean> = deviceEntryViewAlpha.map { it > 0f }.distinctUntilChanged()
    val isLongPressEnabled: Flow<Boolean> =

    private val isInteractive: Flow<Boolean> =
        combine(
            iconType,
            isUdfpsSupported,
@@ -244,17 +247,24 @@ constructor(
                DeviceEntryIconView.IconType.NONE -> false
            }
        }

    val accessibilityDelegateHint: Flow<DeviceEntryIconView.AccessibilityHintType> =
        combine(iconType, isLongPressEnabled) { deviceEntryStatus, longPressEnabled ->
            if (longPressEnabled) {
                deviceEntryStatus.toAccessibilityHintType()
        accessibilityInteractor.isEnabled.flatMapLatest { touchExplorationEnabled ->
            if (touchExplorationEnabled) {
                combine(iconType, isInteractive) { iconType, isInteractive ->
                    if (isInteractive) {
                        iconType.toAccessibilityHintType()
                    } else {
                        DeviceEntryIconView.AccessibilityHintType.NONE
                    }
                }
            } else {
                flowOf(DeviceEntryIconView.AccessibilityHintType.NONE)
            }
        }

    val isLongPressEnabled: Flow<Boolean> = isInteractive

    suspend fun onLongPress() {
    suspend fun onUserInteraction() {
        if (SceneContainerFlag.isEnabled) {
            deviceEntryInteractor.attemptDeviceEntry()
        } else {
Loading