diff options
9 files changed, 123 insertions, 15 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/BackGestureTutorialScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/BackGestureTutorialScreen.kt index e89a31f8fad3..618722a79a6f 100644 --- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/BackGestureTutorialScreen.kt +++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/BackGestureTutorialScreen.kt @@ -27,7 +27,10 @@ import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialScreenCon import com.android.systemui.inputdevice.tutorial.ui.composable.rememberColorFilterProperty import com.android.systemui.res.R import com.android.systemui.touchpad.tutorial.ui.gesture.BackGestureRecognizer +import com.android.systemui.touchpad.tutorial.ui.gesture.GestureFlowAdapter import com.android.systemui.touchpad.tutorial.ui.gesture.GestureRecognizer +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map @Composable fun BackGestureTutorialScreen(onDoneButtonClicked: () -> Unit, onBack: () -> Unit) { @@ -48,7 +51,17 @@ fun BackGestureTutorialScreen(onDoneButtonClicked: () -> Unit, onBack: () -> Uni ), ) val recognizer = rememberBackGestureRecognizer(LocalContext.current.resources) - GestureTutorialScreen(screenConfig, recognizer, onDoneButtonClicked, onBack) + val gestureUiState: Flow<GestureUiState> = + remember(recognizer) { + GestureFlowAdapter(recognizer).gestureStateAsFlow.map { + it.toGestureUiState( + progressStartMark = "", + progressEndMark = "", + successAnimation = R.raw.trackpad_back_success, + ) + } + } + GestureTutorialScreen(screenConfig, recognizer, gestureUiState, onDoneButtonClicked, onBack) } @Composable diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/GestureTutorialScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/GestureTutorialScreen.kt index 7899f5b42a25..11e1ff49074a 100644 --- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/GestureTutorialScreen.kt +++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/GestureTutorialScreen.kt @@ -17,6 +17,7 @@ package com.android.systemui.touchpad.tutorial.ui.composable import androidx.activity.compose.BackHandler +import androidx.annotation.RawRes import androidx.compose.animation.core.Animatable import androidx.compose.animation.core.tween import androidx.compose.foundation.layout.Box @@ -31,23 +32,49 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.input.pointer.pointerInteropFilter +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.systemui.inputdevice.tutorial.ui.composable.ActionTutorialContent import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialScreenConfig +import com.android.systemui.touchpad.tutorial.ui.composable.GestureUiState.Finished +import com.android.systemui.touchpad.tutorial.ui.composable.GestureUiState.NotStarted import com.android.systemui.touchpad.tutorial.ui.gesture.EasterEggGestureMonitor import com.android.systemui.touchpad.tutorial.ui.gesture.GestureRecognizer import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState -import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.Finished -import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.InProgress -import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.NotStarted import com.android.systemui.touchpad.tutorial.ui.gesture.TouchpadGestureHandler +import kotlinx.coroutines.flow.Flow -fun GestureState.toTutorialActionState(): TutorialActionState { +sealed interface GestureUiState { + data object NotStarted : GestureUiState + + data class Finished(@RawRes val successAnimation: Int) : GestureUiState + + data class InProgress( + val progress: Float = 0f, + val progressStartMark: String = "", + val progressEndMark: String = "", + ) : GestureUiState +} + +fun GestureState.toGestureUiState( + progressStartMark: String, + progressEndMark: String, + successAnimation: Int, +): GestureUiState { + return when (this) { + GestureState.NotStarted -> NotStarted + is GestureState.InProgress -> + GestureUiState.InProgress(this.progress, progressStartMark, progressEndMark) + is GestureState.Finished -> GestureUiState.Finished(successAnimation) + } +} + +fun GestureUiState.toTutorialActionState(): TutorialActionState { return when (this) { NotStarted -> TutorialActionState.NotStarted // progress is disabled for now as views are not ready to handle varying progress - is InProgress -> TutorialActionState.InProgress(0f) - Finished -> TutorialActionState.Finished + is GestureUiState.InProgress -> TutorialActionState.InProgress(progress = 0f) + is Finished -> TutorialActionState.Finished } } @@ -55,15 +82,13 @@ fun GestureState.toTutorialActionState(): TutorialActionState { fun GestureTutorialScreen( screenConfig: TutorialScreenConfig, gestureRecognizer: GestureRecognizer, + gestureUiStateFlow: Flow<GestureUiState>, onDoneButtonClicked: () -> Unit, onBack: () -> Unit, ) { BackHandler(onBack = onBack) - var gestureState: GestureState by remember { mutableStateOf(NotStarted) } var easterEggTriggered by remember { mutableStateOf(false) } - LaunchedEffect(gestureRecognizer) { - gestureRecognizer.addGestureStateCallback { gestureState = it } - } + val gestureState by gestureUiStateFlow.collectAsStateWithLifecycle(NotStarted) val easterEggMonitor = EasterEggGestureMonitor { easterEggTriggered = true } val gestureHandler = remember(gestureRecognizer) { TouchpadGestureHandler(gestureRecognizer, easterEggMonitor) } @@ -84,7 +109,7 @@ fun GestureTutorialScreen( @Composable private fun TouchpadGesturesHandlingBox( gestureHandler: TouchpadGestureHandler, - gestureState: GestureState, + gestureState: GestureUiState, easterEggTriggered: Boolean, resetEasterEggFlag: () -> Unit, modifier: Modifier = Modifier, @@ -110,7 +135,7 @@ private fun TouchpadGesturesHandlingBox( .pointerInteropFilter( onTouchEvent = { event -> // FINISHED is the final state so we don't need to process touches anymore - if (gestureState == Finished) { + if (gestureState is Finished) { false } else { gestureHandler.onMotionEvent(event) diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/HomeGestureTutorialScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/HomeGestureTutorialScreen.kt index 3ddf760b9704..05871ce91e39 100644 --- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/HomeGestureTutorialScreen.kt +++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/HomeGestureTutorialScreen.kt @@ -25,8 +25,11 @@ import com.android.compose.theme.LocalAndroidColorScheme import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialScreenConfig import com.android.systemui.inputdevice.tutorial.ui.composable.rememberColorFilterProperty import com.android.systemui.res.R +import com.android.systemui.touchpad.tutorial.ui.gesture.GestureFlowAdapter import com.android.systemui.touchpad.tutorial.ui.gesture.GestureRecognizer import com.android.systemui.touchpad.tutorial.ui.gesture.HomeGestureRecognizer +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map @Composable fun HomeGestureTutorialScreen(onDoneButtonClicked: () -> Unit, onBack: () -> Unit) { @@ -47,7 +50,17 @@ fun HomeGestureTutorialScreen(onDoneButtonClicked: () -> Unit, onBack: () -> Uni ), ) val recognizer = rememberHomeGestureRecognizer(LocalContext.current.resources) - GestureTutorialScreen(screenConfig, recognizer, onDoneButtonClicked, onBack) + val gestureUiState: Flow<GestureUiState> = + remember(recognizer) { + GestureFlowAdapter(recognizer).gestureStateAsFlow.map { + it.toGestureUiState( + progressStartMark = "", + progressEndMark = "", + successAnimation = R.raw.trackpad_home_success, + ) + } + } + GestureTutorialScreen(screenConfig, recognizer, gestureUiState, onDoneButtonClicked, onBack) } @Composable diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/RecentAppsGestureTutorialScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/RecentAppsGestureTutorialScreen.kt index 30a21bf3b632..4fd16448e9f2 100644 --- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/RecentAppsGestureTutorialScreen.kt +++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/RecentAppsGestureTutorialScreen.kt @@ -25,8 +25,11 @@ import com.android.compose.theme.LocalAndroidColorScheme import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialScreenConfig import com.android.systemui.inputdevice.tutorial.ui.composable.rememberColorFilterProperty import com.android.systemui.res.R +import com.android.systemui.touchpad.tutorial.ui.gesture.GestureFlowAdapter import com.android.systemui.touchpad.tutorial.ui.gesture.GestureRecognizer import com.android.systemui.touchpad.tutorial.ui.gesture.RecentAppsGestureRecognizer +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map @Composable fun RecentAppsGestureTutorialScreen(onDoneButtonClicked: () -> Unit, onBack: () -> Unit) { @@ -47,7 +50,17 @@ fun RecentAppsGestureTutorialScreen(onDoneButtonClicked: () -> Unit, onBack: () ), ) val recognizer = rememberRecentAppsGestureRecognizer(LocalContext.current.resources) - GestureTutorialScreen(screenConfig, recognizer, onDoneButtonClicked, onBack) + val gestureUiState: Flow<GestureUiState> = + remember(recognizer) { + GestureFlowAdapter(recognizer).gestureStateAsFlow.map { + it.toGestureUiState( + progressStartMark = "", + progressEndMark = "", + successAnimation = R.raw.trackpad_recent_apps_success, + ) + } + } + GestureTutorialScreen(screenConfig, recognizer, gestureUiState, onDoneButtonClicked, onBack) } @Composable diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/BackGestureRecognizer.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/BackGestureRecognizer.kt index 80f800390852..024048cbbb24 100644 --- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/BackGestureRecognizer.kt +++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/BackGestureRecognizer.kt @@ -33,6 +33,10 @@ class BackGestureRecognizer(private val gestureDistanceThresholdPx: Int) : Gestu gestureStateChangedCallback = callback } + override fun clearGestureStateCallback() { + gestureStateChangedCallback = {} + } + override fun accept(event: MotionEvent) { if (!isThreeFingerTouchpadSwipe(event)) return val gestureState = distanceTracker.processEvent(event) diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/GestureFlowAdapter.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/GestureFlowAdapter.kt new file mode 100644 index 000000000000..23e31b0a9efd --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/GestureFlowAdapter.kt @@ -0,0 +1,30 @@ +/* + * 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.systemui.touchpad.tutorial.ui.gesture + +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.Flow + +class GestureFlowAdapter(gestureRecognizer: GestureRecognizer) { + + val gestureStateAsFlow: Flow<GestureState> = conflatedCallbackFlow { + val callback: (GestureState) -> Unit = { trySend(it) } + gestureRecognizer.addGestureStateCallback(callback) + awaitClose { gestureRecognizer.clearGestureStateCallback() } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/GestureRecognizer.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/GestureRecognizer.kt index d146268304a6..68a2ef9528eb 100644 --- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/GestureRecognizer.kt +++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/GestureRecognizer.kt @@ -22,6 +22,8 @@ import java.util.function.Consumer /** Based on passed [MotionEvent]s recognizes different states of gesture and notifies callback. */ interface GestureRecognizer : Consumer<MotionEvent> { fun addGestureStateCallback(callback: (GestureState) -> Unit) + + fun clearGestureStateCallback() } fun isThreeFingerTouchpadSwipe(event: MotionEvent) = isNFingerTouchpadSwipe(event, fingerCount = 3) diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/HomeGestureRecognizer.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/HomeGestureRecognizer.kt index 2b84a4c50613..b804b9a0d4c7 100644 --- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/HomeGestureRecognizer.kt +++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/HomeGestureRecognizer.kt @@ -29,6 +29,10 @@ class HomeGestureRecognizer(private val gestureDistanceThresholdPx: Int) : Gestu gestureStateChangedCallback = callback } + override fun clearGestureStateCallback() { + gestureStateChangedCallback = {} + } + override fun accept(event: MotionEvent) { if (!isThreeFingerTouchpadSwipe(event)) return val gestureState = distanceTracker.processEvent(event) diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/RecentAppsGestureRecognizer.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/RecentAppsGestureRecognizer.kt index 69b7c5edd750..7d484ee85b7c 100644 --- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/RecentAppsGestureRecognizer.kt +++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/RecentAppsGestureRecognizer.kt @@ -38,6 +38,10 @@ class RecentAppsGestureRecognizer( gestureStateChangedCallback = callback } + override fun clearGestureStateCallback() { + gestureStateChangedCallback = {} + } + override fun accept(event: MotionEvent) { if (!isThreeFingerTouchpadSwipe(event)) return val gestureState = distanceTracker.processEvent(event) |