diff --git a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/AccessibilityInteractor.kt b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/AccessibilityInteractor.kt index 9f62ed03572..bf0084d14a8 100644 --- a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/AccessibilityInteractor.kt +++ b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/AccessibilityInteractor.kt @@ -16,6 +16,7 @@ package com.android.settings.biometrics.fingerprint2.domain.interactor +import android.util.Log import android.view.accessibility.AccessibilityEvent import android.view.accessibility.AccessibilityEvent.TYPE_ANNOUNCEMENT import android.view.accessibility.AccessibilityManager @@ -30,23 +31,26 @@ import kotlinx.coroutines.flow.stateIn interface AccessibilityInteractor { /** A flow that contains whether or not accessibility is enabled */ fun isEnabledFlow(scope: CoroutineScope): Flow + val isEnabled: Boolean + fun announce(clazz: Class<*>, announcement: CharSequence?) + + fun interrupt() } -class AccessibilityInteractorImpl( - private val accessibilityManager: AccessibilityManager, -) : AccessibilityInteractor { +class AccessibilityInteractorImpl(private val accessibilityManager: AccessibilityManager) : + AccessibilityInteractor { /** A flow that contains whether or not accessibility is enabled */ override fun isEnabledFlow(scope: CoroutineScope): Flow = callbackFlow { - val listener = - AccessibilityManager.AccessibilityStateChangeListener { enabled -> trySend(enabled) } - accessibilityManager.addAccessibilityStateChangeListener(listener) + val listener = + AccessibilityManager.AccessibilityStateChangeListener { enabled -> trySend(enabled) } + accessibilityManager.addAccessibilityStateChangeListener(listener) - // This clause will be called when no one is listening to the flow - awaitClose { accessibilityManager.removeAccessibilityStateChangeListener(listener) } - } + // This clause will be called when no one is listening to the flow + awaitClose { accessibilityManager.removeAccessibilityStateChangeListener(listener) } + } .stateIn( scope, SharingStarted.WhileSubscribed(), // When no longer subscribed, we removeTheListener @@ -63,4 +67,17 @@ class AccessibilityInteractorImpl( event.text.add(announcement) accessibilityManager.sendAccessibilityEvent(event) } + + /** Interrupts the current accessibility manager from announcing a phrase. */ + override fun interrupt() { + try { + accessibilityManager.interrupt() + } catch (e: IllegalStateException) { + Log.e(TAG, "Error trying to interrupt when accessibility isn't enabled $e") + } + } + + companion object { + const val TAG = "AccessibilityInteractor" + } } diff --git a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/OrientationInteractor.kt b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/OrientationInteractor.kt index e55d6b899ca..e273bb76c8f 100644 --- a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/OrientationInteractor.kt +++ b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/OrientationInteractor.kt @@ -19,10 +19,13 @@ package com.android.settings.biometrics.fingerprint2.domain.interactor import android.content.Context import android.view.OrientationEventListener import com.android.internal.R +import com.android.settings.biometrics.fingerprint2.lib.model.Orientation import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.callbackFlow +import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.transform /** Interactor which provides information about orientation */ @@ -45,6 +48,9 @@ interface OrientationInteractor { * [R.bool.config_reverseDefaultConfigRotation] */ fun getRotationFromDefault(rotation: Int): Int + + /** Indicates an orientation changed event has occurred */ + val orientationChanged: Flow } class OrientationInteractorImpl(private val context: Context) : OrientationInteractor { @@ -60,7 +66,10 @@ class OrientationInteractorImpl(private val context: Context) : OrientationInter awaitClose { orientationEventListener.disable() } } - override val rotation: Flow = orientation.transform { emit(context.display.rotation) } + override val rotation: Flow = + orientation + .transform { emit(context.display.rotation) } + .onStart { emit(context.display.rotation) } override val rotationFromDefault: Flow = rotation.map { getRotationFromDefault(it) } @@ -73,4 +82,24 @@ class OrientationInteractorImpl(private val context: Context) : OrientationInter rotation } } + + override val orientationChanged: Flow = + rotationFromDefault + .map { + when (it) { + 1 -> { + Orientation.Portrait + } + 2 -> { + Orientation.ReverseLandscape + } + 3 -> { + Orientation.UpsideDownPortrait + } + else -> { + Orientation.Landscape + } + } + } + .distinctUntilChanged() } diff --git a/src/com/android/settings/biometrics/fingerprint2/lib/model/Orientation.kt b/src/com/android/settings/biometrics/fingerprint2/lib/model/Orientation.kt new file mode 100644 index 00000000000..c88067772b8 --- /dev/null +++ b/src/com/android/settings/biometrics/fingerprint2/lib/model/Orientation.kt @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2024 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.settings.biometrics.fingerprint2.lib.model + +/** The orientation events correspond to androids internal orientation events. */ +sealed class Orientation { + /** Indicates the device is in landscape orientation */ + data object Landscape : Orientation() + + /** Indicates the device is in reverse landscape orientation */ + data object ReverseLandscape : Orientation() + + /** Indicates the device is in portrait orientation */ + data object Portrait : Orientation() + + /** Indicates the device is in the upside down portrait orientation */ + data object UpsideDownPortrait : Orientation() +} diff --git a/tests/screenshot/src/com/android/settings/tests/screenshot/biometrics/fingerprint/Injector.kt b/tests/screenshot/src/com/android/settings/tests/screenshot/biometrics/fingerprint/Injector.kt index a5d0461e4a3..2f68521f3a1 100644 --- a/tests/screenshot/src/com/android/settings/tests/screenshot/biometrics/fingerprint/Injector.kt +++ b/tests/screenshot/src/com/android/settings/tests/screenshot/biometrics/fingerprint/Injector.kt @@ -29,6 +29,7 @@ import com.android.settings.biometrics.fingerprint2.domain.interactor.Accessibil import com.android.settings.biometrics.fingerprint2.domain.interactor.FoldStateInteractor import com.android.settings.biometrics.fingerprint2.domain.interactor.OrientationInteractor import com.android.settings.biometrics.fingerprint2.lib.model.Default +import com.android.settings.biometrics.fingerprint2.lib.model.Orientation import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.rfps.ui.viewmodel.RFPSIconTouchViewModel import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.rfps.ui.viewmodel.RFPSViewModel import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.BackgroundViewModel @@ -78,6 +79,7 @@ class Injector(step: FingerprintNavigationStep.UiStep) { override val isEnabled: Boolean get() = true override fun announce(clazz: Class<*>, announcement: CharSequence?) {} + override fun interrupt() {} } var foldStateInteractor = @@ -97,6 +99,7 @@ class Injector(step: FingerprintNavigationStep.UiStep) { override val rotationFromDefault: Flow = rotation override fun getRotationFromDefault(rotation: Int): Int = rotation + override val orientationChanged: Flow = flowOf(Orientation.Portrait) } var gatekeeperViewModel = FingerprintGatekeeperViewModel(fingerprintManagerInteractor) diff --git a/tests/unit/src/com/android/settings/fingerprint2/enrollment/viewmodel/FingerprintEnrollFindSensorViewModelV2Test.kt b/tests/unit/src/com/android/settings/fingerprint2/enrollment/viewmodel/FingerprintEnrollFindSensorViewModelV2Test.kt index a8c5e684d33..70e6de10a07 100644 --- a/tests/unit/src/com/android/settings/fingerprint2/enrollment/viewmodel/FingerprintEnrollFindSensorViewModelV2Test.kt +++ b/tests/unit/src/com/android/settings/fingerprint2/enrollment/viewmodel/FingerprintEnrollFindSensorViewModelV2Test.kt @@ -30,6 +30,7 @@ import com.android.settings.biometrics.fingerprint2.domain.interactor.Accessibil import com.android.settings.biometrics.fingerprint2.domain.interactor.FoldStateInteractor import com.android.settings.biometrics.fingerprint2.domain.interactor.OrientationInteractor import com.android.settings.biometrics.fingerprint2.lib.model.Default +import com.android.settings.biometrics.fingerprint2.lib.model.Orientation import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.BackgroundViewModel import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollFindSensorViewModel import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollViewModel @@ -111,6 +112,8 @@ class FingerprintEnrollFindSensorViewModelV2Test { override val isEnabled: Boolean get() = true override fun announce(clazz: Class<*>, announcement: CharSequence?) {} + override fun interrupt() { + } } foldStateInteractor = object : FoldStateInteractor { @@ -128,6 +131,7 @@ class FingerprintEnrollFindSensorViewModelV2Test { override val rotationFromDefault: Flow = flowOf(Surface.ROTATION_0) override fun getRotationFromDefault(rotation: Int): Int = rotation + override val orientationChanged: Flow = flowOf(Orientation.Portrait) } underTest = FingerprintEnrollFindSensorViewModel(