summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/res/drawable/touchpad_tutorial_apps_icon.xml25
-rw-r--r--packages/SystemUI/res/values/strings.xml13
-rw-r--r--packages/SystemUI/src/com/android/systemui/touchpad/tutorial/TouchpadTutorialModule.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/SwitchAppsGestureTutorialScreen.kt88
-rw-r--r--packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/SwitchAppsGestureRecognizer.kt39
-rw-r--r--packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt17
-rw-r--r--packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/SwitchAppsGestureRecognizerProvider.kt35
-rw-r--r--packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/SwitchAppsGestureScreenViewModel.kt45
-rw-r--r--packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/TouchpadTutorialViewModel.kt5
10 files changed, 297 insertions, 6 deletions
diff --git a/packages/SystemUI/res/drawable/touchpad_tutorial_apps_icon.xml b/packages/SystemUI/res/drawable/touchpad_tutorial_apps_icon.xml
new file mode 100644
index 000000000000..5f9d4212e440
--- /dev/null
+++ b/packages/SystemUI/res/drawable/touchpad_tutorial_apps_icon.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ Copyright (C) 2025 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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="24dp"
+ android:width="24dp"
+ android:autoMirrored="true"
+ android:viewportHeight="960"
+ android:viewportWidth="960">
+ <path android:fillColor="@android:color/white"
+ android:pathData="M240,800q-33,0 -56.5,-23.5T160,720q0,-33 23.5,-56.5T240,640q33,0 56.5,23.5T320,720q0,33 -23.5,56.5T240,800ZM480,800q-33,0 -56.5,-23.5T400,720q0,-33 23.5,-56.5T480,640q33,0 56.5,23.5T560,720q0,33 -23.5,56.5T480,800ZM720,800q-33,0 -56.5,-23.5T640,720q0,-33 23.5,-56.5T720,640q33,0 56.5,23.5T800,720q0,33 -23.5,56.5T720,800ZM240,560q-33,0 -56.5,-23.5T160,480q0,-33 23.5,-56.5T240,400q33,0 56.5,23.5T320,480q0,33 -23.5,56.5T240,560ZM480,560q-33,0 -56.5,-23.5T400,480q0,-33 23.5,-56.5T480,400q33,0 56.5,23.5T560,480q0,33 -23.5,56.5T480,560ZM720,560q-33,0 -56.5,-23.5T640,480q0,-33 23.5,-56.5T720,400q33,0 56.5,23.5T800,480q0,33 -23.5,56.5T720,560ZM240,320q-33,0 -56.5,-23.5T160,240q0,-33 23.5,-56.5T240,160q33,0 56.5,23.5T320,240q0,33 -23.5,56.5T240,320ZM480,320q-33,0 -56.5,-23.5T400,240q0,-33 23.5,-56.5T480,160q33,0 56.5,23.5T560,240q0,33 -23.5,56.5T480,320ZM720,320q-33,0 -56.5,-23.5T640,240q0,-33 23.5,-56.5T720,160q33,0 56.5,23.5T800,240q0,33 -23.5,56.5T720,320Z"/>
+</vector>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index f2c648cb3ab0..414d3f1d17d5 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -3954,6 +3954,8 @@
<string name="touchpad_tutorial_home_gesture_button">Go home</string>
<!-- Label for button opening tutorial for "view recent apps" gesture on touchpad [CHAR LIMIT=NONE] -->
<string name="touchpad_tutorial_recent_apps_gesture_button">View recent apps</string>
+ <!-- Label for button opening tutorial for "switch apps" gesture on touchpad [CHAR LIMIT=NONE] -->
+ <string name="touchpad_tutorial_switch_apps_gesture_button">Switch apps</string>
<!-- Label for button finishing touchpad tutorial [CHAR LIMIT=NONE] -->
<string name="touchpad_tutorial_done_button">Done</string>
<!-- Screen title after gesture was not done correctly [CHAR LIMIT=NONE] -->
@@ -3991,6 +3993,17 @@
<string name="touchpad_recent_apps_gesture_success_body">You completed the view recent apps gesture.</string>
<!-- Text shown to the user after recent gesture was not done correctly [CHAR LIMIT=NONE] -->
<string name="touchpad_recent_gesture_error_body">To view recent apps, swipe up and hold using three fingers on your touchpad</string>
+ <!-- SWITCH APPS GESTURE -->
+ <!-- Touchpad switch apps gesture action name in tutorial [CHAR LIMIT=NONE] -->
+ <string name="touchpad_switch_apps_gesture_action_title">Switch apps</string>
+ <!-- Touchpad switch apps gesture guidance in gestures tutorial [CHAR LIMIT=NONE] -->
+ <string name="touchpad_switch_apps_gesture_guidance">Swipe left or right using four fingers on your touchpad</string>
+ <!-- Screen title after switch apps gesture was done successfully [CHAR LIMIT=NONE] -->
+ <string name="touchpad_switch_apps_gesture_success_title">Great job!</string>
+ <!-- Text shown to the user after they complete switch apps gesture tutorial [CHAR LIMIT=NONE] -->
+ <string name="touchpad_switch_apps_gesture_success_body">You completed the switch apps gesture.</string>
+ <!-- Text shown to the user after switch gesture was not done correctly [CHAR LIMIT=NONE] -->
+ <string name="touchpad_switch_gesture_error_body">Swipe left or right using four fingers on your touchpad to switch apps</string>
<!-- KEYBOARD TUTORIAL-->
<!-- Action key tutorial title [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/TouchpadTutorialModule.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/TouchpadTutorialModule.kt
index c43f31beb5bc..a2125c8f0955 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/TouchpadTutorialModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/TouchpadTutorialModule.kt
@@ -39,6 +39,8 @@ import com.android.systemui.touchpad.tutorial.ui.viewmodel.HomeGestureRecognizer
import com.android.systemui.touchpad.tutorial.ui.viewmodel.HomeGestureScreenViewModel
import com.android.systemui.touchpad.tutorial.ui.viewmodel.RecentAppsGestureRecognizerProvider
import com.android.systemui.touchpad.tutorial.ui.viewmodel.RecentAppsGestureScreenViewModel
+import com.android.systemui.touchpad.tutorial.ui.viewmodel.SwitchAppsGestureRecognizerProvider
+import com.android.systemui.touchpad.tutorial.ui.viewmodel.SwitchAppsGestureScreenViewModel
import dagger.Binds
import dagger.Module
import dagger.Provides
@@ -69,6 +71,14 @@ interface TouchpadTutorialModule {
}
@Provides
+ fun switchAppsViewModel(
+ recognizerProvider: SwitchAppsGestureRecognizerProvider,
+ adapterFactory: GestureRecognizerAdapter.Factory,
+ ): SwitchAppsGestureScreenViewModel {
+ return SwitchAppsGestureScreenViewModel(adapterFactory.create(recognizerProvider))
+ }
+
+ @Provides
fun recentAppsViewModel(
recognizerProvider: RecentAppsGestureRecognizerProvider,
adapterFactory: GestureRecognizerAdapter.Factory,
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/SwitchAppsGestureTutorialScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/SwitchAppsGestureTutorialScreen.kt
new file mode 100644
index 000000000000..3bb0dd779613
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/SwitchAppsGestureTutorialScreen.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2025 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.composable
+
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+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.viewmodel.EasterEggGestureViewModel
+import com.android.systemui.touchpad.tutorial.ui.viewmodel.SwitchAppsGestureScreenViewModel
+
+@Composable
+fun SwitchAppsGestureTutorialScreen(
+ viewModel: SwitchAppsGestureScreenViewModel,
+ easterEggGestureViewModel: EasterEggGestureViewModel,
+ onDoneButtonClicked: () -> Unit,
+ onBack: () -> Unit,
+) {
+ val screenConfig =
+ TutorialScreenConfig(
+ colors = rememberScreenColors(),
+ strings =
+ TutorialScreenConfig.Strings(
+ titleResId = R.string.touchpad_switch_apps_gesture_action_title,
+ bodyResId = R.string.touchpad_switch_apps_gesture_guidance,
+ titleSuccessResId = R.string.touchpad_switch_apps_gesture_success_title,
+ bodySuccessResId = R.string.touchpad_switch_apps_gesture_success_body,
+ titleErrorResId = R.string.gesture_error_title,
+ bodyErrorResId = R.string.touchpad_switch_gesture_error_body,
+ ),
+ // TODO: replace animation
+ animations = TutorialScreenConfig.Animations(educationResId = R.raw.trackpad_back_edu),
+ )
+ GestureTutorialScreen(
+ screenConfig = screenConfig,
+ tutorialStateFlow = viewModel.tutorialState,
+ motionEventConsumer = {
+ easterEggGestureViewModel.accept(it)
+ viewModel.handleEvent(it)
+ },
+ easterEggTriggeredFlow = easterEggGestureViewModel.easterEggTriggered,
+ onEasterEggFinished = easterEggGestureViewModel::onEasterEggFinished,
+ onDoneButtonClicked = onDoneButtonClicked,
+ onBack = onBack,
+ )
+}
+
+@Composable
+private fun rememberScreenColors(): TutorialScreenConfig.Colors {
+ val onTertiary = MaterialTheme.colorScheme.onTertiary
+ val onTertiaryFixed = LocalAndroidColorScheme.current.onTertiaryFixed
+ val onTertiaryFixedVariant = LocalAndroidColorScheme.current.onTertiaryFixedVariant
+ val tertiaryFixedDim = LocalAndroidColorScheme.current.tertiaryFixedDim
+ val dynamicProperties =
+ rememberLottieDynamicProperties(
+ rememberColorFilterProperty(".tertiaryFixedDim", tertiaryFixedDim),
+ rememberColorFilterProperty(".onTertiaryFixed", onTertiaryFixed),
+ rememberColorFilterProperty(".onTertiary", onTertiary),
+ rememberColorFilterProperty(".onTertiaryFixedVariant", onTertiaryFixedVariant),
+ )
+ val screenColors =
+ remember(dynamicProperties) {
+ TutorialScreenConfig.Colors(
+ background = onTertiaryFixed,
+ title = tertiaryFixedDim,
+ animationColors = dynamicProperties,
+ )
+ }
+ return screenColors
+}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt
index c8a58400069e..69b7e892a380 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt
@@ -61,6 +61,7 @@ fun TutorialSelectionScreen(
onBackTutorialClicked: () -> Unit,
onHomeTutorialClicked: () -> Unit,
onRecentAppsTutorialClicked: () -> Unit,
+ onSwitchAppsTutorialClicked: () -> Unit,
onDoneButtonClicked: () -> Unit,
lastSelectedScreen: Screen,
) {
@@ -86,6 +87,7 @@ fun TutorialSelectionScreen(
onBackTutorialClicked = onBackTutorialClicked,
onHomeTutorialClicked = onHomeTutorialClicked,
onRecentAppsTutorialClicked = onRecentAppsTutorialClicked,
+ onSwitchAppsTutorialClicked = onSwitchAppsTutorialClicked,
modifier = Modifier.weight(1f).padding(60.dp),
lastSelectedScreen,
)
@@ -95,6 +97,7 @@ fun TutorialSelectionScreen(
onBackTutorialClicked = onBackTutorialClicked,
onHomeTutorialClicked = onHomeTutorialClicked,
onRecentAppsTutorialClicked = onRecentAppsTutorialClicked,
+ onSwitchAppsTutorialClicked = onSwitchAppsTutorialClicked,
modifier = Modifier.weight(1f).padding(60.dp),
lastSelectedScreen,
)
@@ -113,6 +116,7 @@ private fun HorizontalSelectionButtons(
onBackTutorialClicked: () -> Unit,
onHomeTutorialClicked: () -> Unit,
onRecentAppsTutorialClicked: () -> Unit,
+ onSwitchAppsTutorialClicked: () -> Unit,
modifier: Modifier = Modifier,
lastSelectedScreen: Screen,
) {
@@ -121,10 +125,11 @@ private fun HorizontalSelectionButtons(
verticalAlignment = Alignment.CenterVertically,
modifier = modifier,
) {
- ThreeTutorialButtons(
+ FourTutorialButtons(
onBackTutorialClicked,
onHomeTutorialClicked,
onRecentAppsTutorialClicked,
+ onSwitchAppsTutorialClicked,
modifier = Modifier.weight(1f).fillMaxSize(),
lastSelectedScreen,
)
@@ -136,6 +141,7 @@ private fun VerticalSelectionButtons(
onBackTutorialClicked: () -> Unit,
onHomeTutorialClicked: () -> Unit,
onRecentAppsTutorialClicked: () -> Unit,
+ onSwitchAppsTutorialClicked: () -> Unit,
modifier: Modifier = Modifier,
lastSelectedScreen: Screen,
) {
@@ -144,10 +150,11 @@ private fun VerticalSelectionButtons(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = modifier,
) {
- ThreeTutorialButtons(
+ FourTutorialButtons(
onBackTutorialClicked,
onHomeTutorialClicked,
onRecentAppsTutorialClicked,
+ onSwitchAppsTutorialClicked,
modifier = Modifier.weight(1f).fillMaxSize(),
lastSelectedScreen,
)
@@ -155,21 +162,24 @@ private fun VerticalSelectionButtons(
}
@Composable
-private fun ThreeTutorialButtons(
+private fun FourTutorialButtons(
onBackTutorialClicked: () -> Unit,
onHomeTutorialClicked: () -> Unit,
onRecentAppsTutorialClicked: () -> Unit,
+ onSwitchAppsTutorialClicked: () -> Unit,
modifier: Modifier = Modifier,
lastSelectedScreen: Screen,
) {
val homeFocusRequester = remember { FocusRequester() }
val backFocusRequester = remember { FocusRequester() }
val recentAppsFocusRequester = remember { FocusRequester() }
+ val switchAppsFocusRequester = remember { FocusRequester() }
LaunchedEffect(Unit) {
when (lastSelectedScreen) {
Screen.HOME_GESTURE -> homeFocusRequester.requestFocus()
Screen.BACK_GESTURE -> backFocusRequester.requestFocus()
Screen.RECENT_APPS_GESTURE -> recentAppsFocusRequester.requestFocus()
+ Screen.SWITCH_APPS_GESTURE -> switchAppsFocusRequester.requestFocus()
else -> {} // No-Op.
}
}
@@ -197,6 +207,14 @@ private fun ThreeTutorialButtons(
backgroundColor = MaterialTheme.colorScheme.secondary,
modifier = modifier.focusRequester(recentAppsFocusRequester).focusable(),
)
+ TutorialButton(
+ text = stringResource(R.string.touchpad_tutorial_switch_apps_gesture_button),
+ icon = ImageVector.vectorResource(id = R.drawable.touchpad_tutorial_apps_icon),
+ iconColor = MaterialTheme.colorScheme.primary,
+ onClick = onSwitchAppsTutorialClicked,
+ backgroundColor = MaterialTheme.colorScheme.onPrimary,
+ modifier = modifier.focusRequester(switchAppsFocusRequester).focusable(),
+ )
}
@Composable
@@ -227,7 +245,7 @@ private fun TutorialButton(
tint = iconColor,
)
Spacer(modifier = Modifier.height(16.dp))
- Text(text = text, style = MaterialTheme.typography.headlineLarge)
+ Text(text = text, style = MaterialTheme.typography.headlineLarge, color = iconColor)
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/SwitchAppsGestureRecognizer.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/SwitchAppsGestureRecognizer.kt
new file mode 100644
index 000000000000..470048bd3b20
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/SwitchAppsGestureRecognizer.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2025 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 android.view.MotionEvent
+
+// TODO: javadoc
+class SwitchAppsGestureRecognizer(private val gestureDistanceThresholdPx: Int) : GestureRecognizer {
+
+ private val distanceTracker = DistanceTracker()
+ private var gestureStateChangedCallback: (GestureState) -> Unit = {}
+
+ override fun addGestureStateCallback(callback: (GestureState) -> Unit) {
+ gestureStateChangedCallback = callback
+ }
+
+ override fun clearGestureStateCallback() {
+ gestureStateChangedCallback = {}
+ }
+
+ // TODO: recognizer logic
+ override fun accept(event: MotionEvent) {
+ if (!isMultifingerTouchpadSwipe(event)) return
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt
index 3264300ed908..0a139125afa2 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt
@@ -37,6 +37,7 @@ import com.android.systemui.res.R
import com.android.systemui.touchpad.tutorial.ui.composable.BackGestureTutorialScreen
import com.android.systemui.touchpad.tutorial.ui.composable.HomeGestureTutorialScreen
import com.android.systemui.touchpad.tutorial.ui.composable.RecentAppsGestureTutorialScreen
+import com.android.systemui.touchpad.tutorial.ui.composable.SwitchAppsGestureTutorialScreen
import com.android.systemui.touchpad.tutorial.ui.composable.TutorialSelectionScreen
import com.android.systemui.touchpad.tutorial.ui.viewmodel.BackGestureScreenViewModel
import com.android.systemui.touchpad.tutorial.ui.viewmodel.EasterEggGestureViewModel
@@ -45,7 +46,9 @@ import com.android.systemui.touchpad.tutorial.ui.viewmodel.RecentAppsGestureScre
import com.android.systemui.touchpad.tutorial.ui.viewmodel.Screen.BACK_GESTURE
import com.android.systemui.touchpad.tutorial.ui.viewmodel.Screen.HOME_GESTURE
import com.android.systemui.touchpad.tutorial.ui.viewmodel.Screen.RECENT_APPS_GESTURE
+import com.android.systemui.touchpad.tutorial.ui.viewmodel.Screen.SWITCH_APPS_GESTURE
import com.android.systemui.touchpad.tutorial.ui.viewmodel.Screen.TUTORIAL_SELECTION
+import com.android.systemui.touchpad.tutorial.ui.viewmodel.SwitchAppsGestureScreenViewModel
import com.android.systemui.touchpad.tutorial.ui.viewmodel.TouchpadTutorialViewModel
import javax.inject.Inject
@@ -58,6 +61,7 @@ constructor(
private val backGestureViewModel: BackGestureScreenViewModel,
private val homeGestureViewModel: HomeGestureScreenViewModel,
private val recentAppsGestureViewModel: RecentAppsGestureScreenViewModel,
+ private val switchAppsGestureScreenViewModel: SwitchAppsGestureScreenViewModel,
private val easterEggGestureViewModel: EasterEggGestureViewModel,
) : ComponentActivity() {
@@ -75,6 +79,7 @@ constructor(
backGestureViewModel,
homeGestureViewModel,
recentAppsGestureViewModel,
+ switchAppsGestureScreenViewModel,
easterEggGestureViewModel,
closeTutorial = ::finishTutorial,
)
@@ -108,6 +113,7 @@ fun TouchpadTutorialScreen(
backGestureViewModel: BackGestureScreenViewModel,
homeGestureViewModel: HomeGestureScreenViewModel,
recentAppsGestureViewModel: RecentAppsGestureScreenViewModel,
+ switchAppsGestureScreenViewModel: SwitchAppsGestureScreenViewModel,
easterEggGestureViewModel: EasterEggGestureViewModel,
closeTutorial: () -> Unit,
) {
@@ -128,6 +134,10 @@ fun TouchpadTutorialScreen(
lastSelectedScreen = RECENT_APPS_GESTURE
vm.goTo(RECENT_APPS_GESTURE)
},
+ onSwitchAppsTutorialClicked = {
+ lastSelectedScreen = SWITCH_APPS_GESTURE
+ vm.goTo(SWITCH_APPS_GESTURE)
+ },
onDoneButtonClicked = closeTutorial,
lastSelectedScreen,
)
@@ -152,5 +162,12 @@ fun TouchpadTutorialScreen(
onDoneButtonClicked = { vm.goTo(TUTORIAL_SELECTION) },
onBack = { vm.goTo(TUTORIAL_SELECTION) },
)
+ SWITCH_APPS_GESTURE ->
+ SwitchAppsGestureTutorialScreen(
+ switchAppsGestureScreenViewModel,
+ easterEggGestureViewModel,
+ onDoneButtonClicked = { vm.goTo(SWITCH_APPS_GESTURE) },
+ onBack = { vm.goTo(TUTORIAL_SELECTION) },
+ )
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/SwitchAppsGestureRecognizerProvider.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/SwitchAppsGestureRecognizerProvider.kt
new file mode 100644
index 000000000000..b1e163b55377
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/SwitchAppsGestureRecognizerProvider.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2025 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.viewmodel
+
+import com.android.systemui.touchpad.tutorial.ui.gesture.GestureRecognizer
+import com.android.systemui.touchpad.tutorial.ui.gesture.SwitchAppsGestureRecognizer
+import com.android.systemui.touchpad.tutorial.ui.gesture.VelocityTracker
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
+
+class SwitchAppsGestureRecognizerProvider
+@Inject
+constructor(val resources: TouchpadGestureResources, val velocityTracker: VelocityTracker) :
+ GestureRecognizerProvider {
+
+ override val recognizer: Flow<GestureRecognizer> =
+ resources.distanceThreshold().map {
+ SwitchAppsGestureRecognizer(gestureDistanceThresholdPx = it)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/SwitchAppsGestureScreenViewModel.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/SwitchAppsGestureScreenViewModel.kt
new file mode 100644
index 000000000000..6593db49745d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/SwitchAppsGestureScreenViewModel.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2025 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.viewmodel
+
+import android.view.MotionEvent
+import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState
+import com.android.systemui.res.R
+import com.android.systemui.touchpad.tutorial.ui.gesture.handleTouchpadMotionEvent
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
+
+class SwitchAppsGestureScreenViewModel(private val gestureRecognizer: GestureRecognizerAdapter) :
+ TouchpadTutorialScreenViewModel {
+
+ // TODO: replace with correct markers and resource
+ override val tutorialState: Flow<TutorialActionState> =
+ gestureRecognizer.gestureState
+ .map {
+ it to
+ TutorialAnimationProperties(
+ progressStartMarker = "drag with gesture",
+ progressEndMarker = "onPause",
+ successAnimation = R.raw.trackpad_recent_apps_success,
+ )
+ }
+ .mapToTutorialState()
+
+ override fun handleEvent(event: MotionEvent): Boolean {
+ return gestureRecognizer.handleTouchpadMotionEvent(event)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/TouchpadTutorialViewModel.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/TouchpadTutorialViewModel.kt
index c56dcf3bf062..c6d5e7ad0a71 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/TouchpadTutorialViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/TouchpadTutorialViewModel.kt
@@ -27,7 +27,7 @@ import kotlinx.coroutines.flow.StateFlow
class TouchpadTutorialViewModel(
private val gesturesInteractor: TouchpadGesturesInteractor,
- private val logger: InputDeviceTutorialLogger
+ private val logger: InputDeviceTutorialLogger,
) : ViewModel() {
private val _screen = MutableStateFlow(Screen.TUTORIAL_SELECTION)
@@ -50,7 +50,7 @@ class TouchpadTutorialViewModel(
@Inject
constructor(
private val gesturesInteractor: TouchpadGesturesInteractor,
- private val logger: InputDeviceTutorialLogger
+ private val logger: InputDeviceTutorialLogger,
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
@@ -65,4 +65,5 @@ enum class Screen {
BACK_GESTURE,
HOME_GESTURE,
RECENT_APPS_GESTURE,
+ SWITCH_APPS_GESTURE,
}