Loading packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/AccessibilityRepositoryTest.kt +82 −3 Original line number Diff line number Diff line Loading @@ -16,11 +16,15 @@ package com.android.systemui.accessibility.data.repository import android.accessibilityservice.AccessibilityServiceInfo import android.view.accessibility.AccessibilityManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.kosmos.backgroundScope import com.android.systemui.kosmos.testScope import com.android.systemui.testKosmos import com.android.systemui.util.mockito.whenever import com.android.systemui.util.mockito.withArgCaptor import com.google.common.truth.Truth.assertThat Loading @@ -29,6 +33,7 @@ import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.eq import org.mockito.Mock import org.mockito.Mockito.verify import org.mockito.junit.MockitoJUnit Loading @@ -42,9 +47,12 @@ class AccessibilityRepositoryTest : SysuiTestCase() { // mocks @Mock private lateinit var a11yManager: AccessibilityManager private val testKosmos = testKosmos() private val testScope = testKosmos.testScope private val backgroundScope = testKosmos.backgroundScope // real impls private val underTest by lazy { AccessibilityRepository(a11yManager) } private val underTest by lazy { AccessibilityRepository(a11yManager, backgroundScope) } @Test fun isTouchExplorationEnabled_reflectsA11yManager_initFalse() = runTest { Loading Loading @@ -79,4 +87,75 @@ class AccessibilityRepositoryTest : SysuiTestCase() { .onTouchExplorationStateChanged(/* enabled= */ false) assertThat(isTouchExplorationEnabled).isFalse() } @Test fun isEnabledFiltered_reflectsA11yManager_initFalse() = testScope.runTest { whenever(a11yManager.getEnabledAccessibilityServiceList(eq(FILTERED_A11Y_SERVICES))) .thenReturn(emptyList<AccessibilityServiceInfo>()) val isEnabledFiltered by collectLastValue(underTest.isEnabledFiltered) assertThat(isEnabledFiltered).isFalse() } @Test fun isEnabledFiltered_reflectsA11yManager_changeTrue() = testScope.runTest { whenever(a11yManager.getEnabledAccessibilityServiceList(eq(FILTERED_A11Y_SERVICES))) .thenReturn(emptyList()) val isEnabledFiltered by collectLastValue(underTest.isEnabledFiltered) runCurrent() withArgCaptor { verify(a11yManager).addAccessibilityServicesStateChangeListener(capture()) } .onAccessibilityServicesStateChanged(a11yManager) assertThat(isEnabledFiltered).isFalse() // Change the services list to a non-empty list val wantedList = listOf(AccessibilityServiceInfo()) whenever(a11yManager.getEnabledAccessibilityServiceList(eq(FILTERED_A11Y_SERVICES))) .thenReturn(wantedList) val isEnabledFiltered2 by collectLastValue(underTest.isEnabledFiltered) runCurrent() withArgCaptor { verify(a11yManager).addAccessibilityServicesStateChangeListener(capture()) } .onAccessibilityServicesStateChanged(a11yManager) assertThat(isEnabledFiltered2).isTrue() } @Test fun isEnabledFiltered_reflectsA11yManager_changeFalse() = testScope.runTest { val wantedList = listOf(AccessibilityServiceInfo()) whenever(a11yManager.getEnabledAccessibilityServiceList(eq(FILTERED_A11Y_SERVICES))) .thenReturn(wantedList) val isEnabledFiltered by collectLastValue(underTest.isEnabledFiltered) runCurrent() withArgCaptor { verify(a11yManager).addAccessibilityServicesStateChangeListener(capture()) } .onAccessibilityServicesStateChanged(a11yManager) assertThat(isEnabledFiltered).isTrue() // Change the services list to an emptylist whenever(a11yManager.getEnabledAccessibilityServiceList(eq(FILTERED_A11Y_SERVICES))) .thenReturn(emptyList()) val isEnabledFiltered2 by collectLastValue(underTest.isEnabledFiltered) runCurrent() withArgCaptor { verify(a11yManager).addAccessibilityServicesStateChangeListener(capture()) } .onAccessibilityServicesStateChanged(a11yManager) assertThat(isEnabledFiltered2).isFalse() } companion object { private const val FILTERED_A11Y_SERVICES = AccessibilityServiceInfo.FEEDBACK_AUDIBLE or AccessibilityServiceInfo.FEEDBACK_SPOKEN or AccessibilityServiceInfo.FEEDBACK_VISUAL or AccessibilityServiceInfo.FEEDBACK_HAPTIC or AccessibilityServiceInfo.FEEDBACK_BRAILLE } } packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt +7 −6 Original line number Diff line number Diff line Loading @@ -20,13 +20,14 @@ package com.android.systemui.keyguard.domain.interactor import android.app.admin.DevicePolicyManager import android.os.UserHandle import android.platform.test.annotations.EnableFlags import android.view.accessibility.AccessibilityManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.widget.LockPatternUtils import com.android.keyguard.logging.KeyguardQuickAffordancesLogger import com.android.systemui.Flags import com.android.systemui.SysuiTestCase import com.android.systemui.accessibility.domain.interactor.AccessibilityInteractor import com.android.systemui.accessibility.domain.interactor.accessibilityInteractor import com.android.systemui.animation.DialogTransitionAnimator import com.android.systemui.common.shared.model.ContentDescription import com.android.systemui.common.shared.model.Icon Loading Loading @@ -99,7 +100,7 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { @Mock private lateinit var shadeInteractor: ShadeInteractor @Mock private lateinit var logger: KeyguardQuickAffordancesLogger @Mock private lateinit var metricsLogger: KeyguardQuickAffordancesMetricsLogger @Mock private lateinit var accessibilityManager: AccessibilityManager @Mock private lateinit var accessibilityInteractor: AccessibilityInteractor private lateinit var underTest: KeyguardQuickAffordanceInteractor Loading Loading @@ -201,14 +202,14 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { biometricSettingsRepository = biometricSettingsRepository, backgroundDispatcher = kosmos.testDispatcher, appContext = context, accessibilityManager = accessibilityManager, accessibilityInteractor = accessibilityInteractor, sceneInteractor = { kosmos.sceneInteractor }, msdlPlayer = msdlPlayer, ) kosmos.keyguardQuickAffordanceInteractor = underTest whenever(shadeInteractor.anyExpansion).thenReturn(MutableStateFlow(0f)) whenever(accessibilityManager.isEnabled()).thenReturn(false) whenever(accessibilityInteractor.isEnabledFiltered).thenReturn(MutableStateFlow(false)) } @Test Loading Loading @@ -679,7 +680,7 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { @Test fun useLongPress_withA11yEnabled_isFalse() = testScope.runTest { whenever(accessibilityManager.isEnabled()).thenReturn(true) whenever(accessibilityInteractor.isEnabledFiltered).thenReturn(MutableStateFlow(true)) val useLongPress by collectLastValue(underTest.useLongPress()) assertThat(useLongPress).isFalse() } Loading @@ -687,7 +688,7 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { @Test fun useLongPress_withA11yDisabled_isFalse() = testScope.runTest { whenever(accessibilityManager.isEnabled()).thenReturn(false) whenever(accessibilityInteractor.isEnabledFiltered).thenReturn(MutableStateFlow(false)) val useLongPress by collectLastValue(underTest.useLongPress()) assertThat(useLongPress).isTrue() } Loading packages/SystemUI/src/com/android/systemui/accessibility/data/repository/AccessibilityRepository.kt +44 −5 Original line number Diff line number Diff line Loading @@ -16,16 +16,22 @@ package com.android.systemui.accessibility.data.repository import android.accessibilityservice.AccessibilityServiceInfo import android.view.accessibility.AccessibilityManager import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener import com.android.app.tracing.FlowTracing.tracedAwaitClose import com.android.app.tracing.FlowTracing.tracedConflatedCallbackFlow import com.android.systemui.dagger.qualifiers.Background import dagger.Module import dagger.Provides import kotlin.time.Duration import kotlin.time.Duration.Companion.milliseconds import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.stateIn /** Exposes accessibility-related state. */ interface AccessibilityRepository { Loading @@ -34,18 +40,25 @@ interface AccessibilityRepository { /** @see [AccessibilityManager.isEnabled] */ val isEnabled: Flow<Boolean> /** Returns whether a filtered set of [AccessibilityServiceInfo]s are enabled. */ val isEnabledFiltered: StateFlow<Boolean> fun getRecommendedTimeout(originalTimeout: Duration, uiFlags: Int): Duration companion object { operator fun invoke(a11yManager: AccessibilityManager): AccessibilityRepository = AccessibilityRepositoryImpl(a11yManager) operator fun invoke( a11yManager: AccessibilityManager, @Background backgroundScope: CoroutineScope, ): AccessibilityRepository = AccessibilityRepositoryImpl(a11yManager, backgroundScope) } } private const val TAG = "AccessibilityRepository" private class AccessibilityRepositoryImpl(private val manager: AccessibilityManager) : AccessibilityRepository { private class AccessibilityRepositoryImpl( private val manager: AccessibilityManager, @Background private val scope: CoroutineScope, ) : AccessibilityRepository { override val isTouchExplorationEnabled: Flow<Boolean> = tracedConflatedCallbackFlow(TAG) { val listener = TouchExplorationStateChangeListener(::trySend) Loading @@ -66,6 +79,30 @@ private class AccessibilityRepositoryImpl(private val manager: AccessibilityMana } .distinctUntilChanged() override val isEnabledFiltered: StateFlow<Boolean> = tracedConflatedCallbackFlow(TAG) { val listener = AccessibilityManager.AccessibilityServicesStateChangeListener { accessibilityManager -> trySend( accessibilityManager .getEnabledAccessibilityServiceList( AccessibilityServiceInfo.FEEDBACK_AUDIBLE or AccessibilityServiceInfo.FEEDBACK_SPOKEN or AccessibilityServiceInfo.FEEDBACK_VISUAL or AccessibilityServiceInfo.FEEDBACK_HAPTIC or AccessibilityServiceInfo.FEEDBACK_BRAILLE ) .isNotEmpty() ) } manager.addAccessibilityServicesStateChangeListener(listener) tracedAwaitClose(TAG) { manager.removeAccessibilityServicesStateChangeListener(listener) } } .stateIn(scope = scope, started = SharingStarted.Eagerly, initialValue = false) override fun getRecommendedTimeout(originalTimeout: Duration, uiFlags: Int): Duration { return manager .getRecommendedTimeoutMillis(originalTimeout.inWholeMilliseconds.toInt(), uiFlags) Loading @@ -75,5 +112,7 @@ private class AccessibilityRepositoryImpl(private val manager: AccessibilityMana @Module object AccessibilityRepositoryModule { @Provides fun provideRepo(manager: AccessibilityManager) = AccessibilityRepository(manager) @Provides fun provideRepo(manager: AccessibilityManager, @Background backgroundScope: CoroutineScope) = AccessibilityRepository(manager, backgroundScope) } packages/SystemUI/src/com/android/systemui/accessibility/domain/interactor/AccessibilityInteractor.kt +5 −0 Original line number Diff line number Diff line Loading @@ -16,10 +16,12 @@ package com.android.systemui.accessibility.domain.interactor import android.accessibilityservice.AccessibilityServiceInfo import com.android.systemui.accessibility.data.repository.AccessibilityRepository import com.android.systemui.dagger.SysUISingleton import javax.inject.Inject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow @SysUISingleton class AccessibilityInteractor Loading @@ -32,4 +34,7 @@ constructor( /** @see [android.view.accessibility.AccessibilityManager.isEnabled] */ val isEnabled: Flow<Boolean> = a11yRepo.isEnabled /** This returns whether a filtered set of [AccessibilityServiceInfo]s are enabled. */ val isEnabledFiltered: StateFlow<Boolean> = a11yRepo.isEnabledFiltered } packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt +6 −4 Original line number Diff line number Diff line Loading @@ -22,12 +22,12 @@ import android.app.admin.DevicePolicyManager import android.content.Context import android.content.Intent import android.util.Log import android.view.accessibility.AccessibilityManager import com.android.app.tracing.coroutines.withContextTraced as withContext import com.android.compose.animation.scene.ObservableTransitionState import com.android.internal.widget.LockPatternUtils import com.android.keyguard.logging.KeyguardQuickAffordancesLogger import com.android.systemui.Flags.msdlFeedback import com.android.systemui.accessibility.domain.interactor.AccessibilityInteractor import com.android.systemui.animation.DialogTransitionAnimator import com.android.systemui.animation.Expandable import com.android.systemui.dagger.SysUISingleton Loading Loading @@ -91,7 +91,7 @@ constructor( private val devicePolicyManager: DevicePolicyManager, private val dockManager: DockManager, private val biometricSettingsRepository: BiometricSettingsRepository, private val accessibilityManager: AccessibilityManager, private val accessibilityInteractor: AccessibilityInteractor, @Background private val backgroundDispatcher: CoroutineDispatcher, @ShadeDisplayAware private val appContext: Context, private val sceneInteractor: Lazy<SceneInteractor>, Loading @@ -109,8 +109,10 @@ constructor( * If `false`, the UI goes back to using single taps. */ fun useLongPress(): Flow<Boolean> = dockManager.retrieveIsDocked().map { isDocked -> !isDocked && !accessibilityManager.isEnabled() combine(dockManager.retrieveIsDocked(), accessibilityInteractor.isEnabledFiltered) { isDocked, isAccessibilityEnabled -> !isDocked && !isAccessibilityEnabled } /** Returns an observable for the quick affordance at the given position. */ Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/AccessibilityRepositoryTest.kt +82 −3 Original line number Diff line number Diff line Loading @@ -16,11 +16,15 @@ package com.android.systemui.accessibility.data.repository import android.accessibilityservice.AccessibilityServiceInfo import android.view.accessibility.AccessibilityManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.kosmos.backgroundScope import com.android.systemui.kosmos.testScope import com.android.systemui.testKosmos import com.android.systemui.util.mockito.whenever import com.android.systemui.util.mockito.withArgCaptor import com.google.common.truth.Truth.assertThat Loading @@ -29,6 +33,7 @@ import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.eq import org.mockito.Mock import org.mockito.Mockito.verify import org.mockito.junit.MockitoJUnit Loading @@ -42,9 +47,12 @@ class AccessibilityRepositoryTest : SysuiTestCase() { // mocks @Mock private lateinit var a11yManager: AccessibilityManager private val testKosmos = testKosmos() private val testScope = testKosmos.testScope private val backgroundScope = testKosmos.backgroundScope // real impls private val underTest by lazy { AccessibilityRepository(a11yManager) } private val underTest by lazy { AccessibilityRepository(a11yManager, backgroundScope) } @Test fun isTouchExplorationEnabled_reflectsA11yManager_initFalse() = runTest { Loading Loading @@ -79,4 +87,75 @@ class AccessibilityRepositoryTest : SysuiTestCase() { .onTouchExplorationStateChanged(/* enabled= */ false) assertThat(isTouchExplorationEnabled).isFalse() } @Test fun isEnabledFiltered_reflectsA11yManager_initFalse() = testScope.runTest { whenever(a11yManager.getEnabledAccessibilityServiceList(eq(FILTERED_A11Y_SERVICES))) .thenReturn(emptyList<AccessibilityServiceInfo>()) val isEnabledFiltered by collectLastValue(underTest.isEnabledFiltered) assertThat(isEnabledFiltered).isFalse() } @Test fun isEnabledFiltered_reflectsA11yManager_changeTrue() = testScope.runTest { whenever(a11yManager.getEnabledAccessibilityServiceList(eq(FILTERED_A11Y_SERVICES))) .thenReturn(emptyList()) val isEnabledFiltered by collectLastValue(underTest.isEnabledFiltered) runCurrent() withArgCaptor { verify(a11yManager).addAccessibilityServicesStateChangeListener(capture()) } .onAccessibilityServicesStateChanged(a11yManager) assertThat(isEnabledFiltered).isFalse() // Change the services list to a non-empty list val wantedList = listOf(AccessibilityServiceInfo()) whenever(a11yManager.getEnabledAccessibilityServiceList(eq(FILTERED_A11Y_SERVICES))) .thenReturn(wantedList) val isEnabledFiltered2 by collectLastValue(underTest.isEnabledFiltered) runCurrent() withArgCaptor { verify(a11yManager).addAccessibilityServicesStateChangeListener(capture()) } .onAccessibilityServicesStateChanged(a11yManager) assertThat(isEnabledFiltered2).isTrue() } @Test fun isEnabledFiltered_reflectsA11yManager_changeFalse() = testScope.runTest { val wantedList = listOf(AccessibilityServiceInfo()) whenever(a11yManager.getEnabledAccessibilityServiceList(eq(FILTERED_A11Y_SERVICES))) .thenReturn(wantedList) val isEnabledFiltered by collectLastValue(underTest.isEnabledFiltered) runCurrent() withArgCaptor { verify(a11yManager).addAccessibilityServicesStateChangeListener(capture()) } .onAccessibilityServicesStateChanged(a11yManager) assertThat(isEnabledFiltered).isTrue() // Change the services list to an emptylist whenever(a11yManager.getEnabledAccessibilityServiceList(eq(FILTERED_A11Y_SERVICES))) .thenReturn(emptyList()) val isEnabledFiltered2 by collectLastValue(underTest.isEnabledFiltered) runCurrent() withArgCaptor { verify(a11yManager).addAccessibilityServicesStateChangeListener(capture()) } .onAccessibilityServicesStateChanged(a11yManager) assertThat(isEnabledFiltered2).isFalse() } companion object { private const val FILTERED_A11Y_SERVICES = AccessibilityServiceInfo.FEEDBACK_AUDIBLE or AccessibilityServiceInfo.FEEDBACK_SPOKEN or AccessibilityServiceInfo.FEEDBACK_VISUAL or AccessibilityServiceInfo.FEEDBACK_HAPTIC or AccessibilityServiceInfo.FEEDBACK_BRAILLE } }
packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt +7 −6 Original line number Diff line number Diff line Loading @@ -20,13 +20,14 @@ package com.android.systemui.keyguard.domain.interactor import android.app.admin.DevicePolicyManager import android.os.UserHandle import android.platform.test.annotations.EnableFlags import android.view.accessibility.AccessibilityManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.widget.LockPatternUtils import com.android.keyguard.logging.KeyguardQuickAffordancesLogger import com.android.systemui.Flags import com.android.systemui.SysuiTestCase import com.android.systemui.accessibility.domain.interactor.AccessibilityInteractor import com.android.systemui.accessibility.domain.interactor.accessibilityInteractor import com.android.systemui.animation.DialogTransitionAnimator import com.android.systemui.common.shared.model.ContentDescription import com.android.systemui.common.shared.model.Icon Loading Loading @@ -99,7 +100,7 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { @Mock private lateinit var shadeInteractor: ShadeInteractor @Mock private lateinit var logger: KeyguardQuickAffordancesLogger @Mock private lateinit var metricsLogger: KeyguardQuickAffordancesMetricsLogger @Mock private lateinit var accessibilityManager: AccessibilityManager @Mock private lateinit var accessibilityInteractor: AccessibilityInteractor private lateinit var underTest: KeyguardQuickAffordanceInteractor Loading Loading @@ -201,14 +202,14 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { biometricSettingsRepository = biometricSettingsRepository, backgroundDispatcher = kosmos.testDispatcher, appContext = context, accessibilityManager = accessibilityManager, accessibilityInteractor = accessibilityInteractor, sceneInteractor = { kosmos.sceneInteractor }, msdlPlayer = msdlPlayer, ) kosmos.keyguardQuickAffordanceInteractor = underTest whenever(shadeInteractor.anyExpansion).thenReturn(MutableStateFlow(0f)) whenever(accessibilityManager.isEnabled()).thenReturn(false) whenever(accessibilityInteractor.isEnabledFiltered).thenReturn(MutableStateFlow(false)) } @Test Loading Loading @@ -679,7 +680,7 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { @Test fun useLongPress_withA11yEnabled_isFalse() = testScope.runTest { whenever(accessibilityManager.isEnabled()).thenReturn(true) whenever(accessibilityInteractor.isEnabledFiltered).thenReturn(MutableStateFlow(true)) val useLongPress by collectLastValue(underTest.useLongPress()) assertThat(useLongPress).isFalse() } Loading @@ -687,7 +688,7 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { @Test fun useLongPress_withA11yDisabled_isFalse() = testScope.runTest { whenever(accessibilityManager.isEnabled()).thenReturn(false) whenever(accessibilityInteractor.isEnabledFiltered).thenReturn(MutableStateFlow(false)) val useLongPress by collectLastValue(underTest.useLongPress()) assertThat(useLongPress).isTrue() } Loading
packages/SystemUI/src/com/android/systemui/accessibility/data/repository/AccessibilityRepository.kt +44 −5 Original line number Diff line number Diff line Loading @@ -16,16 +16,22 @@ package com.android.systemui.accessibility.data.repository import android.accessibilityservice.AccessibilityServiceInfo import android.view.accessibility.AccessibilityManager import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener import com.android.app.tracing.FlowTracing.tracedAwaitClose import com.android.app.tracing.FlowTracing.tracedConflatedCallbackFlow import com.android.systemui.dagger.qualifiers.Background import dagger.Module import dagger.Provides import kotlin.time.Duration import kotlin.time.Duration.Companion.milliseconds import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.stateIn /** Exposes accessibility-related state. */ interface AccessibilityRepository { Loading @@ -34,18 +40,25 @@ interface AccessibilityRepository { /** @see [AccessibilityManager.isEnabled] */ val isEnabled: Flow<Boolean> /** Returns whether a filtered set of [AccessibilityServiceInfo]s are enabled. */ val isEnabledFiltered: StateFlow<Boolean> fun getRecommendedTimeout(originalTimeout: Duration, uiFlags: Int): Duration companion object { operator fun invoke(a11yManager: AccessibilityManager): AccessibilityRepository = AccessibilityRepositoryImpl(a11yManager) operator fun invoke( a11yManager: AccessibilityManager, @Background backgroundScope: CoroutineScope, ): AccessibilityRepository = AccessibilityRepositoryImpl(a11yManager, backgroundScope) } } private const val TAG = "AccessibilityRepository" private class AccessibilityRepositoryImpl(private val manager: AccessibilityManager) : AccessibilityRepository { private class AccessibilityRepositoryImpl( private val manager: AccessibilityManager, @Background private val scope: CoroutineScope, ) : AccessibilityRepository { override val isTouchExplorationEnabled: Flow<Boolean> = tracedConflatedCallbackFlow(TAG) { val listener = TouchExplorationStateChangeListener(::trySend) Loading @@ -66,6 +79,30 @@ private class AccessibilityRepositoryImpl(private val manager: AccessibilityMana } .distinctUntilChanged() override val isEnabledFiltered: StateFlow<Boolean> = tracedConflatedCallbackFlow(TAG) { val listener = AccessibilityManager.AccessibilityServicesStateChangeListener { accessibilityManager -> trySend( accessibilityManager .getEnabledAccessibilityServiceList( AccessibilityServiceInfo.FEEDBACK_AUDIBLE or AccessibilityServiceInfo.FEEDBACK_SPOKEN or AccessibilityServiceInfo.FEEDBACK_VISUAL or AccessibilityServiceInfo.FEEDBACK_HAPTIC or AccessibilityServiceInfo.FEEDBACK_BRAILLE ) .isNotEmpty() ) } manager.addAccessibilityServicesStateChangeListener(listener) tracedAwaitClose(TAG) { manager.removeAccessibilityServicesStateChangeListener(listener) } } .stateIn(scope = scope, started = SharingStarted.Eagerly, initialValue = false) override fun getRecommendedTimeout(originalTimeout: Duration, uiFlags: Int): Duration { return manager .getRecommendedTimeoutMillis(originalTimeout.inWholeMilliseconds.toInt(), uiFlags) Loading @@ -75,5 +112,7 @@ private class AccessibilityRepositoryImpl(private val manager: AccessibilityMana @Module object AccessibilityRepositoryModule { @Provides fun provideRepo(manager: AccessibilityManager) = AccessibilityRepository(manager) @Provides fun provideRepo(manager: AccessibilityManager, @Background backgroundScope: CoroutineScope) = AccessibilityRepository(manager, backgroundScope) }
packages/SystemUI/src/com/android/systemui/accessibility/domain/interactor/AccessibilityInteractor.kt +5 −0 Original line number Diff line number Diff line Loading @@ -16,10 +16,12 @@ package com.android.systemui.accessibility.domain.interactor import android.accessibilityservice.AccessibilityServiceInfo import com.android.systemui.accessibility.data.repository.AccessibilityRepository import com.android.systemui.dagger.SysUISingleton import javax.inject.Inject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow @SysUISingleton class AccessibilityInteractor Loading @@ -32,4 +34,7 @@ constructor( /** @see [android.view.accessibility.AccessibilityManager.isEnabled] */ val isEnabled: Flow<Boolean> = a11yRepo.isEnabled /** This returns whether a filtered set of [AccessibilityServiceInfo]s are enabled. */ val isEnabledFiltered: StateFlow<Boolean> = a11yRepo.isEnabledFiltered }
packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt +6 −4 Original line number Diff line number Diff line Loading @@ -22,12 +22,12 @@ import android.app.admin.DevicePolicyManager import android.content.Context import android.content.Intent import android.util.Log import android.view.accessibility.AccessibilityManager import com.android.app.tracing.coroutines.withContextTraced as withContext import com.android.compose.animation.scene.ObservableTransitionState import com.android.internal.widget.LockPatternUtils import com.android.keyguard.logging.KeyguardQuickAffordancesLogger import com.android.systemui.Flags.msdlFeedback import com.android.systemui.accessibility.domain.interactor.AccessibilityInteractor import com.android.systemui.animation.DialogTransitionAnimator import com.android.systemui.animation.Expandable import com.android.systemui.dagger.SysUISingleton Loading Loading @@ -91,7 +91,7 @@ constructor( private val devicePolicyManager: DevicePolicyManager, private val dockManager: DockManager, private val biometricSettingsRepository: BiometricSettingsRepository, private val accessibilityManager: AccessibilityManager, private val accessibilityInteractor: AccessibilityInteractor, @Background private val backgroundDispatcher: CoroutineDispatcher, @ShadeDisplayAware private val appContext: Context, private val sceneInteractor: Lazy<SceneInteractor>, Loading @@ -109,8 +109,10 @@ constructor( * If `false`, the UI goes back to using single taps. */ fun useLongPress(): Flow<Boolean> = dockManager.retrieveIsDocked().map { isDocked -> !isDocked && !accessibilityManager.isEnabled() combine(dockManager.retrieveIsDocked(), accessibilityInteractor.isEnabledFiltered) { isDocked, isAccessibilityEnabled -> !isDocked && !isAccessibilityEnabled } /** Returns an observable for the quick affordance at the given position. */ Loading