Merge changes I7331f8bb,I6ddcd605 into main
* changes:
Removing GestureRecognizerProvider
Preparing composable to handle live gesture progress in tutorial
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionTutorialContent.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionTutorialContent.kt
index 73975a0..8e01e37 100644
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionTutorialContent.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionTutorialContent.kt
@@ -16,24 +16,11 @@
package com.android.systemui.inputdevice.tutorial.ui.composable
-import android.graphics.ColorFilter
-import android.graphics.PorterDuff
-import android.graphics.PorterDuffColorFilter
-import androidx.annotation.RawRes
import androidx.annotation.StringRes
-import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.AnimatedVisibility
-import androidx.compose.animation.EnterTransition
-import androidx.compose.animation.ExitTransition
-import androidx.compose.animation.core.LinearEasing
-import androidx.compose.animation.core.snap
-import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
-import androidx.compose.animation.fadeOut
-import androidx.compose.animation.togetherWith
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
@@ -46,29 +33,20 @@
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
-import com.airbnb.lottie.LottieProperty
-import com.airbnb.lottie.compose.LottieAnimation
-import com.airbnb.lottie.compose.LottieCompositionSpec
-import com.airbnb.lottie.compose.LottieConstants
-import com.airbnb.lottie.compose.LottieDynamicProperties
-import com.airbnb.lottie.compose.LottieDynamicProperty
-import com.airbnb.lottie.compose.animateLottieCompositionAsState
-import com.airbnb.lottie.compose.rememberLottieComposition
-import com.airbnb.lottie.compose.rememberLottieDynamicProperty
import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.Finished
-import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.InProgress
-import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.NotStarted
sealed interface TutorialActionState {
data object NotStarted : TutorialActionState
- data class InProgress(val progress: Float = 0f) : TutorialActionState
+ data class InProgress(
+ val progress: Float = 0f,
+ val startMarker: String? = null,
+ val endMarker: String? = null,
+ ) : TutorialActionState
data object Finished : TutorialActionState
}
@@ -132,104 +110,3 @@
)
}
}
-
-@Composable
-fun TutorialAnimation(
- actionState: TutorialActionState,
- config: TutorialScreenConfig,
- modifier: Modifier = Modifier,
-) {
- Box(modifier = modifier.fillMaxWidth()) {
- AnimatedContent(
- targetState = actionState,
- transitionSpec = {
- if (initialState == NotStarted) {
- val transitionDurationMillis = 150
- fadeIn(animationSpec = tween(transitionDurationMillis, easing = LinearEasing))
- .togetherWith(
- fadeOut(animationSpec = snap(delayMillis = transitionDurationMillis))
- )
- // we explicitly don't want size transform because when targetState
- // animation is loaded for the first time, AnimatedContent thinks target
- // size is smaller and tries to shrink initial state animation
- .using(sizeTransform = null)
- } else {
- // empty transition works because all remaining transitions are from IN_PROGRESS
- // state which shares initial animation frame with both FINISHED and NOT_STARTED
- EnterTransition.None togetherWith ExitTransition.None
- }
- },
- ) { state ->
- when (state) {
- NotStarted ->
- EducationAnimation(
- config.animations.educationResId,
- config.colors.animationColors,
- )
- is InProgress ->
- FrozenSuccessAnimation(
- config.animations.successResId,
- config.colors.animationColors,
- )
- Finished ->
- SuccessAnimation(config.animations.successResId, config.colors.animationColors)
- }
- }
- }
-}
-
-@Composable
-private fun FrozenSuccessAnimation(
- @RawRes successAnimationId: Int,
- animationProperties: LottieDynamicProperties,
-) {
- val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(successAnimationId))
- LottieAnimation(
- composition = composition,
- progress = { 0f }, // animation should freeze on 1st frame
- dynamicProperties = animationProperties,
- )
-}
-
-@Composable
-private fun EducationAnimation(
- @RawRes educationAnimationId: Int,
- animationProperties: LottieDynamicProperties,
-) {
- val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(educationAnimationId))
- val progress by
- animateLottieCompositionAsState(composition, iterations = LottieConstants.IterateForever)
- LottieAnimation(
- composition = composition,
- progress = { progress },
- dynamicProperties = animationProperties,
- )
-}
-
-@Composable
-private fun SuccessAnimation(
- @RawRes successAnimationId: Int,
- animationProperties: LottieDynamicProperties,
-) {
- val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(successAnimationId))
- val progress by animateLottieCompositionAsState(composition, iterations = 1)
- LottieAnimation(
- composition = composition,
- progress = { progress },
- dynamicProperties = animationProperties,
- )
-}
-
-@Composable
-fun rememberColorFilterProperty(
- layerName: String,
- color: Color,
-): LottieDynamicProperty<ColorFilter> {
- return rememberLottieDynamicProperty(
- LottieProperty.COLOR_FILTER,
- value = PorterDuffColorFilter(color.toArgb(), PorterDuff.Mode.SRC_ATOP),
- // "**" below means match zero or more layers, so ** layerName ** means find layer with that
- // name at any depth
- keyPath = arrayOf("**", layerName, "**"),
- )
-}
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/LottieHelpers.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/LottieHelpers.kt
new file mode 100644
index 0000000..94b3d9f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/LottieHelpers.kt
@@ -0,0 +1,41 @@
+/*
+ * 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.inputdevice.tutorial.ui.composable
+
+import android.graphics.ColorFilter
+import android.graphics.PorterDuff
+import android.graphics.PorterDuffColorFilter
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.toArgb
+import com.airbnb.lottie.LottieProperty
+import com.airbnb.lottie.compose.LottieDynamicProperty
+import com.airbnb.lottie.compose.rememberLottieDynamicProperty
+
+@Composable
+fun rememberColorFilterProperty(
+ layerName: String,
+ color: Color,
+): LottieDynamicProperty<ColorFilter> {
+ return rememberLottieDynamicProperty(
+ LottieProperty.COLOR_FILTER,
+ value = PorterDuffColorFilter(color.toArgb(), PorterDuff.Mode.SRC_ATOP),
+ // "**" below means match zero or more layers, so ** layerName ** means find layer with that
+ // name at any depth
+ keyPath = arrayOf("**", layerName, "**"),
+ )
+}
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/TutorialAnimation.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/TutorialAnimation.kt
new file mode 100644
index 0000000..ef375a8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/TutorialAnimation.kt
@@ -0,0 +1,149 @@
+/*
+ * 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.inputdevice.tutorial.ui.composable
+
+import androidx.annotation.RawRes
+import androidx.compose.animation.AnimatedContent
+import androidx.compose.animation.EnterTransition
+import androidx.compose.animation.core.LinearEasing
+import androidx.compose.animation.core.tween
+import androidx.compose.animation.fadeOut
+import androidx.compose.animation.togetherWith
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.node.Ref
+import androidx.compose.ui.util.lerp
+import com.airbnb.lottie.LottieComposition
+import com.airbnb.lottie.compose.LottieAnimation
+import com.airbnb.lottie.compose.LottieCompositionSpec
+import com.airbnb.lottie.compose.LottieConstants
+import com.airbnb.lottie.compose.LottieDynamicProperties
+import com.airbnb.lottie.compose.animateLottieCompositionAsState
+import com.airbnb.lottie.compose.rememberLottieComposition
+import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.Finished
+import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.InProgress
+import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.NotStarted
+
+@Composable
+fun TutorialAnimation(
+ actionState: TutorialActionState,
+ config: TutorialScreenConfig,
+ modifier: Modifier = Modifier,
+) {
+ Box(modifier = modifier.fillMaxWidth()) {
+ AnimatedContent(
+ targetState = actionState::class,
+ transitionSpec = {
+ EnterTransition.None.togetherWith(
+ fadeOut(animationSpec = tween(durationMillis = 10, easing = LinearEasing))
+ )
+ // we don't want size transform because when targetState animation is loaded for
+ // the first time, AnimatedContent thinks target size is smaller and tries to
+ // shrink initial state
+ .using(sizeTransform = null)
+ },
+ ) { state ->
+ when (state) {
+ NotStarted::class ->
+ EducationAnimation(
+ config.animations.educationResId,
+ config.colors.animationColors,
+ )
+ InProgress::class ->
+ InProgressAnimation(
+ // actionState can be already of different class while this composable is
+ // transitioning to another one
+ actionState as? InProgress,
+ config.animations.educationResId,
+ config.colors.animationColors,
+ )
+ Finished::class ->
+ SuccessAnimation(config.animations.successResId, config.colors.animationColors)
+ }
+ }
+ }
+}
+
+@Composable
+private fun EducationAnimation(
+ @RawRes educationAnimationId: Int,
+ animationProperties: LottieDynamicProperties,
+) {
+ val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(educationAnimationId))
+ val progress by
+ animateLottieCompositionAsState(composition, iterations = LottieConstants.IterateForever)
+ LottieAnimation(
+ composition = composition,
+ progress = { progress },
+ dynamicProperties = animationProperties,
+ )
+}
+
+@Composable
+private fun SuccessAnimation(
+ @RawRes successAnimationId: Int,
+ animationProperties: LottieDynamicProperties,
+) {
+ val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(successAnimationId))
+ val progress by animateLottieCompositionAsState(composition, iterations = 1)
+ LottieAnimation(
+ composition = composition,
+ progress = { progress },
+ dynamicProperties = animationProperties,
+ )
+}
+
+@Composable
+private fun InProgressAnimation(
+ state: InProgress?,
+ @RawRes inProgressAnimationId: Int,
+ animationProperties: LottieDynamicProperties,
+) {
+ // Caching latest progress for when we're animating this view away and state is null.
+ // Without this there's jumpcut in the animation while it's animating away.
+ // state should never be null when composable appears, only when disappearing
+ val cached = remember { Ref<InProgress>() }
+ cached.value = state ?: cached.value
+ val progress = cached.value?.progress ?: 0f
+
+ val composition by
+ rememberLottieComposition(LottieCompositionSpec.RawRes(inProgressAnimationId))
+ val startProgress =
+ rememberSaveable(composition, cached.value?.startMarker) {
+ composition.progressForMarker(cached.value?.startMarker)
+ }
+ val endProgress =
+ rememberSaveable(composition, cached.value?.endMarker) {
+ composition.progressForMarker(cached.value?.endMarker)
+ }
+ LottieAnimation(
+ composition = composition,
+ progress = { lerp(start = startProgress, stop = endProgress, fraction = progress) },
+ dynamicProperties = animationProperties,
+ )
+}
+
+private fun LottieComposition?.progressForMarker(marker: String?): Float {
+ if (marker == null) return 0f
+ val startFrame = this?.getMarker(marker)?.startFrame ?: 0f
+ return this?.getProgressForFrame(startFrame) ?: 0f
+}
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 d85cfcd..e89a31f 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
@@ -16,15 +16,18 @@
package com.android.systemui.touchpad.tutorial.ui.composable
+import android.content.res.Resources
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
+import androidx.compose.ui.platform.LocalContext
import com.airbnb.lottie.compose.rememberLottieDynamicProperties
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.BackGestureRecognizer
+import com.android.systemui.touchpad.tutorial.ui.gesture.GestureRecognizer
@Composable
fun BackGestureTutorialScreen(onDoneButtonClicked: () -> Unit, onBack: () -> Unit) {
@@ -44,15 +47,17 @@
successResId = R.raw.trackpad_back_success,
),
)
- val gestureRecognizerProvider =
- DistanceBasedGestureRecognizerProvider(
- recognizerFactory = { distanceThresholdPx, gestureStateCallback ->
- BackGestureRecognizer(distanceThresholdPx).also {
- it.addGestureStateCallback(gestureStateCallback)
- }
- }
+ val recognizer = rememberBackGestureRecognizer(LocalContext.current.resources)
+ GestureTutorialScreen(screenConfig, recognizer, onDoneButtonClicked, onBack)
+}
+
+@Composable
+private fun rememberBackGestureRecognizer(resources: Resources): GestureRecognizer {
+ val distance =
+ resources.getDimensionPixelSize(
+ com.android.internal.R.dimen.system_gestures_distance_threshold
)
- GestureTutorialScreen(screenConfig, gestureRecognizerProvider, onDoneButtonClicked, onBack)
+ return remember(distance) { BackGestureRecognizer(distance) }
}
@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 90c0051..7899f5b 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
@@ -16,7 +16,6 @@
package com.android.systemui.touchpad.tutorial.ui.composable
-import android.content.res.Resources
import androidx.activity.compose.BackHandler
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.tween
@@ -32,7 +31,6 @@
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.pointerInteropFilter
-import androidx.compose.ui.platform.LocalContext
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
@@ -44,36 +42,6 @@
import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.NotStarted
import com.android.systemui.touchpad.tutorial.ui.gesture.TouchpadGestureHandler
-interface GestureRecognizerProvider {
-
- @Composable
- fun rememberGestureRecognizer(
- resources: Resources,
- gestureStateChangedCallback: (GestureState) -> Unit,
- ): GestureRecognizer
-}
-
-typealias gestureStateCallback = (GestureState) -> Unit
-
-class DistanceBasedGestureRecognizerProvider(
- val recognizerFactory: (Int, gestureStateCallback) -> GestureRecognizer
-) : GestureRecognizerProvider {
-
- @Composable
- override fun rememberGestureRecognizer(
- resources: Resources,
- gestureStateChangedCallback: (GestureState) -> Unit,
- ): GestureRecognizer {
- val distanceThresholdPx =
- resources.getDimensionPixelSize(
- com.android.internal.R.dimen.system_gestures_distance_threshold
- ) * 5
- return remember(distanceThresholdPx) {
- recognizerFactory(distanceThresholdPx, gestureStateChangedCallback)
- }
- }
-}
-
fun GestureState.toTutorialActionState(): TutorialActionState {
return when (this) {
NotStarted -> TutorialActionState.NotStarted
@@ -86,18 +54,16 @@
@Composable
fun GestureTutorialScreen(
screenConfig: TutorialScreenConfig,
- gestureRecognizerProvider: GestureRecognizerProvider,
+ gestureRecognizer: GestureRecognizer,
onDoneButtonClicked: () -> Unit,
onBack: () -> Unit,
) {
BackHandler(onBack = onBack)
var gestureState: GestureState by remember { mutableStateOf(NotStarted) }
var easterEggTriggered by remember { mutableStateOf(false) }
- val gestureRecognizer =
- gestureRecognizerProvider.rememberGestureRecognizer(
- resources = LocalContext.current.resources,
- gestureStateChangedCallback = { gestureState = it },
- )
+ LaunchedEffect(gestureRecognizer) {
+ gestureRecognizer.addGestureStateCallback { gestureState = it }
+ }
val easterEggMonitor = EasterEggGestureMonitor { easterEggTriggered = true }
val gestureHandler =
remember(gestureRecognizer) { TouchpadGestureHandler(gestureRecognizer, easterEggMonitor) }
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 69ec598..3ddf760 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
@@ -16,13 +16,16 @@
package com.android.systemui.touchpad.tutorial.ui.composable
+import android.content.res.Resources
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
+import androidx.compose.ui.platform.LocalContext
import com.airbnb.lottie.compose.rememberLottieDynamicProperties
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.GestureRecognizer
import com.android.systemui.touchpad.tutorial.ui.gesture.HomeGestureRecognizer
@Composable
@@ -43,15 +46,17 @@
successResId = R.raw.trackpad_home_success,
),
)
- val gestureRecognizerProvider =
- DistanceBasedGestureRecognizerProvider(
- recognizerFactory = { distanceThresholdPx, gestureStateCallback ->
- HomeGestureRecognizer(distanceThresholdPx).also {
- it.addGestureStateCallback(gestureStateCallback)
- }
- }
+ val recognizer = rememberHomeGestureRecognizer(LocalContext.current.resources)
+ GestureTutorialScreen(screenConfig, recognizer, onDoneButtonClicked, onBack)
+}
+
+@Composable
+private fun rememberHomeGestureRecognizer(resources: Resources): GestureRecognizer {
+ val distance =
+ resources.getDimensionPixelSize(
+ com.android.internal.R.dimen.system_gestures_distance_threshold
)
- GestureTutorialScreen(screenConfig, gestureRecognizerProvider, onDoneButtonClicked, onBack)
+ return remember(distance) { HomeGestureRecognizer(distance) }
}
@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 3097a18..30a21bf 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
@@ -19,13 +19,13 @@
import android.content.res.Resources
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
+import androidx.compose.ui.platform.LocalContext
import com.airbnb.lottie.compose.rememberLottieDynamicProperties
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.GestureRecognizer
-import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState
import com.android.systemui.touchpad.tutorial.ui.gesture.RecentAppsGestureRecognizer
@Composable
@@ -46,26 +46,18 @@
successResId = R.raw.trackpad_recent_apps_success,
),
)
- val gestureRecognizerProvider =
- object : GestureRecognizerProvider {
- @Composable
- override fun rememberGestureRecognizer(
- resources: Resources,
- gestureStateChangedCallback: (GestureState) -> Unit,
- ): GestureRecognizer {
- val distanceThresholdPx =
- resources.getDimensionPixelSize(
- com.android.internal.R.dimen.system_gestures_distance_threshold
- )
- val velocityThresholdPxPerMs =
- resources.getDimension(R.dimen.touchpad_recent_apps_gesture_velocity_threshold)
- return remember(distanceThresholdPx, velocityThresholdPxPerMs) {
- RecentAppsGestureRecognizer(distanceThresholdPx, velocityThresholdPxPerMs)
- .also { it.addGestureStateCallback(gestureStateChangedCallback) }
- }
- }
- }
- GestureTutorialScreen(screenConfig, gestureRecognizerProvider, onDoneButtonClicked, onBack)
+ val recognizer = rememberRecentAppsGestureRecognizer(LocalContext.current.resources)
+ GestureTutorialScreen(screenConfig, recognizer, onDoneButtonClicked, onBack)
+}
+
+@Composable
+private fun rememberRecentAppsGestureRecognizer(resources: Resources): GestureRecognizer {
+ val distance =
+ resources.getDimensionPixelSize(
+ com.android.internal.R.dimen.system_gestures_distance_threshold
+ )
+ val velocity = resources.getDimension(R.dimen.touchpad_recent_apps_gesture_velocity_threshold)
+ return remember(distance, velocity) { RecentAppsGestureRecognizer(distance, velocity) }
}
@Composable