summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/BackGestureScreenViewModelTest.kt24
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/EasterEggGestureViewModelTest.kt9
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/HomeGestureScreenViewModelTest.kt20
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/RecentAppsGestureScreenViewModelTest.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/touchpad/tutorial/TouchpadTutorialModule.kt40
-rw-r--r--packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadEventsFilter.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/BackGestureRecognizerProvider.kt32
-rw-r--r--packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/BackGestureScreenViewModel.kt33
-rw-r--r--packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/EasterEggGestureViewModel.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/EasterEggRecognizerProvider.kt (renamed from packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/GestureFlowAdapter.kt)16
-rw-r--r--packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/GestureRecognizerAdapter.kt72
-rw-r--r--packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/GestureRecognizerProvider.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/HomeGestureRecognizerProvider.kt47
-rw-r--r--packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/HomeGestureScreenViewModel.kt63
-rw-r--r--packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/RecentAppsGestureRecognizerProvider.kt49
-rw-r--r--packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/RecentAppsGestureScreenViewModel.kt67
-rw-r--r--packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/TouchpadGestureResources.kt46
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/touchpad/ui/gesture/TouchpadGestureResourcesKosmos.kt25
19 files changed, 432 insertions, 174 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/BackGestureScreenViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/BackGestureScreenViewModelTest.kt
index 79c1f9fcf517..4aec88e8497b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/BackGestureScreenViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/BackGestureScreenViewModelTest.kt
@@ -16,12 +16,13 @@
package com.android.systemui.touchpad.tutorial.ui.viewmodel
+import android.content.res.mockResources
import android.view.MotionEvent
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
-import com.android.systemui.common.ui.domain.interactor.configurationInteractor
+import com.android.systemui.inputdevice.tutorial.inputDeviceTutorialLogger
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.collectLastValue
import com.android.systemui.kosmos.runTest
@@ -34,18 +35,27 @@ import com.android.systemui.touchpad.tutorial.ui.composable.GestureUiState.Finis
import com.android.systemui.touchpad.tutorial.ui.composable.GestureUiState.InProgress
import com.android.systemui.touchpad.tutorial.ui.gesture.MultiFingerGesture.Companion.SWIPE_DISTANCE
import com.android.systemui.touchpad.tutorial.ui.gesture.ThreeFingerGesture
+import com.android.systemui.touchpad.ui.gesture.touchpadGestureResources
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.kotlin.whenever
@SmallTest
@RunWith(AndroidJUnit4::class)
class BackGestureScreenViewModelTest : SysuiTestCase() {
private val kosmos = testKosmos()
+ private val resources = kosmos.mockResources
private val fakeConfigRepository = kosmos.fakeConfigurationRepository
- private val viewModel = BackGestureScreenViewModel(kosmos.configurationInteractor)
+ private val viewModel =
+ BackGestureScreenViewModel(
+ GestureRecognizerAdapter(
+ BackGestureRecognizerProvider(kosmos.touchpadGestureResources),
+ kosmos.inputDeviceTutorialLogger,
+ )
+ )
@Before
fun before() {
@@ -115,10 +125,12 @@ class BackGestureScreenViewModelTest : SysuiTestCase() {
}
private fun setThresholdResource(threshold: Float) {
- fakeConfigRepository.setDimensionPixelSize(
- R.dimen.touchpad_tutorial_gestures_distance_threshold,
- (threshold).toInt(),
- )
+ whenever(
+ resources.getDimensionPixelSize(
+ R.dimen.touchpad_tutorial_gestures_distance_threshold
+ )
+ )
+ .thenReturn(threshold.toInt())
fakeConfigRepository.onAnyConfigurationChange()
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/EasterEggGestureViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/EasterEggGestureViewModelTest.kt
index 4af374287c62..8bd796b5c851 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/EasterEggGestureViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/EasterEggGestureViewModelTest.kt
@@ -20,6 +20,7 @@ import android.view.MotionEvent
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.inputdevice.tutorial.inputDeviceTutorialLogger
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.collectLastValue
import com.android.systemui.kosmos.runTest
@@ -36,7 +37,13 @@ import org.junit.runner.RunWith
class EasterEggGestureViewModelTest : SysuiTestCase() {
private val kosmos = testKosmos()
- private val viewModel = EasterEggGestureViewModel()
+ private val viewModel =
+ EasterEggGestureViewModel(
+ GestureRecognizerAdapter(
+ EasterEggRecognizerProvider(),
+ kosmos.inputDeviceTutorialLogger,
+ )
+ )
@Before
fun before() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/HomeGestureScreenViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/HomeGestureScreenViewModelTest.kt
index 4dfd01a91f17..65a995dcd043 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/HomeGestureScreenViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/HomeGestureScreenViewModelTest.kt
@@ -22,7 +22,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
-import com.android.systemui.common.ui.domain.interactor.configurationInteractor
+import com.android.systemui.inputdevice.tutorial.inputDeviceTutorialLogger
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.collectLastValue
import com.android.systemui.kosmos.runTest
@@ -37,6 +37,7 @@ import com.android.systemui.touchpad.tutorial.ui.gesture.MultiFingerGesture.Comp
import com.android.systemui.touchpad.tutorial.ui.gesture.ThreeFingerGesture
import com.android.systemui.touchpad.tutorial.ui.gesture.Velocity
import com.android.systemui.touchpad.ui.gesture.fakeVelocityTracker
+import com.android.systemui.touchpad.ui.gesture.touchpadGestureResources
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
@@ -59,7 +60,12 @@ class HomeGestureScreenViewModelTest : SysuiTestCase() {
private val resources = kosmos.mockResources
private val viewModel =
- HomeGestureScreenViewModel(kosmos.configurationInteractor, resources, fakeVelocityTracker)
+ HomeGestureScreenViewModel(
+ GestureRecognizerAdapter(
+ HomeGestureRecognizerProvider(kosmos.touchpadGestureResources, fakeVelocityTracker),
+ kosmos.inputDeviceTutorialLogger,
+ )
+ )
@Before
fun before() {
@@ -126,10 +132,12 @@ class HomeGestureScreenViewModelTest : SysuiTestCase() {
}
private fun setDistanceThreshold(threshold: Float) {
- fakeConfigRepository.setDimensionPixelSize(
- R.dimen.touchpad_tutorial_gestures_distance_threshold,
- (threshold).toInt(),
- )
+ whenever(
+ resources.getDimensionPixelSize(
+ R.dimen.touchpad_tutorial_gestures_distance_threshold
+ )
+ )
+ .thenReturn(threshold.toInt())
fakeConfigRepository.onAnyConfigurationChange()
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/RecentAppsGestureScreenViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/RecentAppsGestureScreenViewModelTest.kt
index 66bf778a754b..1bc60b67095e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/RecentAppsGestureScreenViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/RecentAppsGestureScreenViewModelTest.kt
@@ -22,7 +22,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
-import com.android.systemui.common.ui.domain.interactor.configurationInteractor
+import com.android.systemui.inputdevice.tutorial.inputDeviceTutorialLogger
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.collectLastValue
import com.android.systemui.kosmos.runTest
@@ -37,6 +37,7 @@ import com.android.systemui.touchpad.tutorial.ui.gesture.MultiFingerGesture.Comp
import com.android.systemui.touchpad.tutorial.ui.gesture.ThreeFingerGesture
import com.android.systemui.touchpad.tutorial.ui.gesture.Velocity
import com.android.systemui.touchpad.ui.gesture.fakeVelocityTracker
+import com.android.systemui.touchpad.ui.gesture.touchpadGestureResources
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
@@ -60,9 +61,13 @@ class RecentAppsGestureScreenViewModelTest : SysuiTestCase() {
private val viewModel =
RecentAppsGestureScreenViewModel(
- kosmos.configurationInteractor,
- resources,
- fakeVelocityTracker,
+ GestureRecognizerAdapter(
+ RecentAppsGestureRecognizerProvider(
+ kosmos.touchpadGestureResources,
+ fakeVelocityTracker,
+ ),
+ kosmos.inputDeviceTutorialLogger,
+ )
)
@Before
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 a6c066500054..c43f31beb5bc 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/TouchpadTutorialModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/TouchpadTutorialModule.kt
@@ -30,9 +30,15 @@ import com.android.systemui.touchpad.tutorial.ui.composable.HomeGestureTutorialS
import com.android.systemui.touchpad.tutorial.ui.gesture.VelocityTracker
import com.android.systemui.touchpad.tutorial.ui.gesture.VerticalVelocityTracker
import com.android.systemui.touchpad.tutorial.ui.view.TouchpadTutorialActivity
+import com.android.systemui.touchpad.tutorial.ui.viewmodel.BackGestureRecognizerProvider
import com.android.systemui.touchpad.tutorial.ui.viewmodel.BackGestureScreenViewModel
import com.android.systemui.touchpad.tutorial.ui.viewmodel.EasterEggGestureViewModel
+import com.android.systemui.touchpad.tutorial.ui.viewmodel.EasterEggRecognizerProvider
+import com.android.systemui.touchpad.tutorial.ui.viewmodel.GestureRecognizerAdapter
+import com.android.systemui.touchpad.tutorial.ui.viewmodel.HomeGestureRecognizerProvider
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 dagger.Binds
import dagger.Module
import dagger.Provides
@@ -53,14 +59,46 @@ interface TouchpadTutorialModule {
fun touchpadScreensProvider(
backGestureScreenViewModel: BackGestureScreenViewModel,
homeGestureScreenViewModel: HomeGestureScreenViewModel,
+ easterEggGestureViewModel: EasterEggGestureViewModel,
): TouchpadTutorialScreensProvider {
return ScreensProvider(
backGestureScreenViewModel,
homeGestureScreenViewModel,
- EasterEggGestureViewModel(),
+ easterEggGestureViewModel,
)
}
+ @Provides
+ fun recentAppsViewModel(
+ recognizerProvider: RecentAppsGestureRecognizerProvider,
+ adapterFactory: GestureRecognizerAdapter.Factory,
+ ): RecentAppsGestureScreenViewModel {
+ return RecentAppsGestureScreenViewModel(adapterFactory.create(recognizerProvider))
+ }
+
+ @Provides
+ fun backViewModel(
+ recognizerProvider: BackGestureRecognizerProvider,
+ adapterFactory: GestureRecognizerAdapter.Factory,
+ ): BackGestureScreenViewModel {
+ return BackGestureScreenViewModel(adapterFactory.create(recognizerProvider))
+ }
+
+ @Provides
+ fun homeViewModel(
+ recognizerProvider: HomeGestureRecognizerProvider,
+ adapterFactory: GestureRecognizerAdapter.Factory,
+ ): HomeGestureScreenViewModel {
+ return HomeGestureScreenViewModel(adapterFactory.create(recognizerProvider))
+ }
+
+ @Provides
+ fun easterEggViewModel(
+ adapterFactory: GestureRecognizerAdapter.Factory
+ ): EasterEggGestureViewModel {
+ return EasterEggGestureViewModel(adapterFactory.create(EasterEggRecognizerProvider()))
+ }
+
@SysUISingleton
@Provides
fun touchpadGesturesInteractor(
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadEventsFilter.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadEventsFilter.kt
index bddeb0b25ec2..b4b8ff0a3949 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadEventsFilter.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadEventsFilter.kt
@@ -20,6 +20,7 @@ import android.view.InputDevice
import android.view.MotionEvent
import android.view.MotionEvent.ACTION_DOWN
import android.view.MotionEvent.BUTTON_PRIMARY
+import com.android.systemui.touchpad.tutorial.ui.viewmodel.GestureRecognizerAdapter
object TouchpadEventsFilter {
@@ -42,3 +43,12 @@ fun GestureRecognizer.handleTouchpadMotionEvent(event: MotionEvent): Boolean {
false
}
}
+
+fun GestureRecognizerAdapter.handleTouchpadMotionEvent(event: MotionEvent): Boolean {
+ return if (TouchpadEventsFilter.isTouchpadAndNonClickEvent(event)) {
+ this.accept(event)
+ true
+ } else {
+ false
+ }
+}
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 cefe382a299c..3264300ed908 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
@@ -58,6 +58,7 @@ constructor(
private val backGestureViewModel: BackGestureScreenViewModel,
private val homeGestureViewModel: HomeGestureScreenViewModel,
private val recentAppsGestureViewModel: RecentAppsGestureScreenViewModel,
+ private val easterEggGestureViewModel: EasterEggGestureViewModel,
) : ComponentActivity() {
private val tutorialViewModel by
@@ -74,7 +75,7 @@ constructor(
backGestureViewModel,
homeGestureViewModel,
recentAppsGestureViewModel,
- EasterEggGestureViewModel(),
+ easterEggGestureViewModel,
closeTutorial = ::finishTutorial,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/BackGestureRecognizerProvider.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/BackGestureRecognizerProvider.kt
new file mode 100644
index 000000000000..b089882e9cf8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/BackGestureRecognizerProvider.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.systemui.touchpad.tutorial.ui.viewmodel
+
+import com.android.systemui.touchpad.tutorial.ui.gesture.BackGestureRecognizer
+import com.android.systemui.touchpad.tutorial.ui.gesture.GestureRecognizer
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
+
+class BackGestureRecognizerProvider @Inject constructor(val resources: TouchpadGestureResources) :
+ GestureRecognizerProvider {
+
+ override val recognizer: Flow<GestureRecognizer> =
+ resources.distanceThreshold().map { distance ->
+ BackGestureRecognizer(gestureDistanceThresholdPx = distance)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/BackGestureScreenViewModel.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/BackGestureScreenViewModel.kt
index 93e8d313edcf..8e53669a7841 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/BackGestureScreenViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/BackGestureScreenViewModel.kt
@@ -17,47 +17,26 @@
package com.android.systemui.touchpad.tutorial.ui.viewmodel
import android.view.MotionEvent
-import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
import com.android.systemui.res.R
import com.android.systemui.touchpad.tutorial.ui.composable.GestureUiState
import com.android.systemui.touchpad.tutorial.ui.composable.toGestureUiState
-import com.android.systemui.touchpad.tutorial.ui.gesture.BackGestureRecognizer
import com.android.systemui.touchpad.tutorial.ui.gesture.GestureDirection
-import com.android.systemui.touchpad.tutorial.ui.gesture.GestureFlowAdapter
import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState
import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.InProgress
import com.android.systemui.touchpad.tutorial.ui.gesture.handleTouchpadMotionEvent
import com.android.systemui.util.kotlin.pairwiseBy
-import javax.inject.Inject
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.flatMapLatest
-class BackGestureScreenViewModel
-@Inject
-constructor(configurationInteractor: ConfigurationInteractor) : TouchpadTutorialScreenViewModel {
+class BackGestureScreenViewModel(val gestureRecognizer: GestureRecognizerAdapter) :
+ TouchpadTutorialScreenViewModel {
- private var recognizer: BackGestureRecognizer? = null
-
- private val distanceThreshold: Flow<Int> =
- configurationInteractor
- .dimensionPixelSize(R.dimen.touchpad_tutorial_gestures_distance_threshold)
- .distinctUntilChanged()
-
- @OptIn(ExperimentalCoroutinesApi::class)
override val gestureUiState: Flow<GestureUiState> =
- distanceThreshold
- .flatMapLatest {
- recognizer = BackGestureRecognizer(gestureDistanceThresholdPx = it)
- GestureFlowAdapter(recognizer!!).gestureStateAsFlow
- }
- .pairwiseBy(GestureState.NotStarted) { previous, current ->
- toGestureUiState(current, previous)
- }
+ gestureRecognizer.gestureState.pairwiseBy(GestureState.NotStarted) { previous, current ->
+ toGestureUiState(current, previous)
+ }
override fun handleEvent(event: MotionEvent): Boolean {
- return recognizer?.handleTouchpadMotionEvent(event) ?: false
+ return gestureRecognizer.handleTouchpadMotionEvent(event)
}
private fun toGestureUiState(current: GestureState, previous: GestureState): GestureUiState {
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/EasterEggGestureViewModel.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/EasterEggGestureViewModel.kt
index 69cdab6108ab..9ca456dff58a 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/EasterEggGestureViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/EasterEggGestureViewModel.kt
@@ -17,8 +17,6 @@
package com.android.systemui.touchpad.tutorial.ui.viewmodel
import android.view.MotionEvent
-import com.android.systemui.touchpad.tutorial.ui.gesture.EasterEggGestureRecognizer
-import com.android.systemui.touchpad.tutorial.ui.gesture.GestureFlowAdapter
import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState
import com.android.systemui.touchpad.tutorial.ui.gesture.handleTouchpadMotionEvent
import java.util.function.Consumer
@@ -29,14 +27,10 @@ import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.receiveAsFlow
-class EasterEggGestureViewModel(
- private val gestureRecognizer: EasterEggGestureRecognizer = EasterEggGestureRecognizer()
-) : Consumer<MotionEvent> {
+class EasterEggGestureViewModel(val gestureRecognizer: GestureRecognizerAdapter) :
+ Consumer<MotionEvent> {
- private val gestureDone =
- GestureFlowAdapter(gestureRecognizer).gestureStateAsFlow.filter {
- it == GestureState.Finished
- }
+ private val gestureDone = gestureRecognizer.gestureState.filter { it == GestureState.Finished }
private val easterEggFinished = Channel<Unit>()
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/viewmodel/EasterEggRecognizerProvider.kt
index 23e31b0a9efd..c48ccb52ba0f 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/GestureFlowAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/EasterEggRecognizerProvider.kt
@@ -14,17 +14,15 @@
* limitations under the License.
*/
-package com.android.systemui.touchpad.tutorial.ui.gesture
+package com.android.systemui.touchpad.tutorial.ui.viewmodel
-import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
-import kotlinx.coroutines.channels.awaitClose
+import com.android.systemui.touchpad.tutorial.ui.gesture.EasterEggGestureRecognizer
+import com.android.systemui.touchpad.tutorial.ui.gesture.GestureRecognizer
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
-class GestureFlowAdapter(gestureRecognizer: GestureRecognizer) {
+class EasterEggRecognizerProvider : GestureRecognizerProvider {
- val gestureStateAsFlow: Flow<GestureState> = conflatedCallbackFlow {
- val callback: (GestureState) -> Unit = { trySend(it) }
- gestureRecognizer.addGestureStateCallback(callback)
- awaitClose { gestureRecognizer.clearGestureStateCallback() }
- }
+ override val recognizer: Flow<GestureRecognizer> =
+ MutableStateFlow(EasterEggGestureRecognizer())
}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/GestureRecognizerAdapter.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/GestureRecognizerAdapter.kt
new file mode 100644
index 000000000000..8e7375fa923b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/GestureRecognizerAdapter.kt
@@ -0,0 +1,72 @@
+/*
+ * 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.viewmodel
+
+import android.view.MotionEvent
+import com.android.systemui.inputdevice.tutorial.InputDeviceTutorialLogger
+import com.android.systemui.touchpad.tutorial.ui.gesture.GestureRecognizer
+import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState
+import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import java.util.function.Consumer
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flatMapLatest
+
+/**
+ * Adapter for [GestureRecognizer] exposing [GestureState] as Flow and ensuring that motion events
+ * are always handled by latest [GestureRecognizer].
+ */
+class GestureRecognizerAdapter
+@AssistedInject
+constructor(
+ @Assisted provider: GestureRecognizerProvider,
+ private val logger: InputDeviceTutorialLogger,
+) : Consumer<MotionEvent> {
+
+ private var gestureRecognizer: GestureRecognizer? = null
+
+ @OptIn(ExperimentalCoroutinesApi::class)
+ val gestureState: Flow<GestureState> =
+ provider.recognizer.flatMapLatest {
+ gestureRecognizer = it
+ gestureStateAsFlow(it)
+ }
+
+ override fun accept(event: MotionEvent) {
+ if (gestureRecognizer == null) {
+ logger.w("sending MotionEvent before gesture recognizer is initialized")
+ } else {
+ gestureRecognizer?.accept(event)
+ }
+ }
+
+ private fun gestureStateAsFlow(recognizer: GestureRecognizer): Flow<GestureState> =
+ conflatedCallbackFlow {
+ val callback: (GestureState) -> Unit = { trySend(it) }
+ recognizer.addGestureStateCallback(callback)
+ awaitClose { recognizer.clearGestureStateCallback() }
+ }
+
+ @AssistedFactory
+ interface Factory {
+ fun create(provider: GestureRecognizerProvider): GestureRecognizerAdapter
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/GestureRecognizerProvider.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/GestureRecognizerProvider.kt
new file mode 100644
index 000000000000..585bc0c425d0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/GestureRecognizerProvider.kt
@@ -0,0 +1,25 @@
+/*
+ * 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.viewmodel
+
+import com.android.systemui.touchpad.tutorial.ui.gesture.GestureRecognizer
+import kotlinx.coroutines.flow.Flow
+
+/** Observes state of the system and provides always up-to-date [GestureRecognizer] */
+interface GestureRecognizerProvider {
+ val recognizer: Flow<GestureRecognizer>
+}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/HomeGestureRecognizerProvider.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/HomeGestureRecognizerProvider.kt
new file mode 100644
index 000000000000..6d818a6a0398
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/HomeGestureRecognizerProvider.kt
@@ -0,0 +1,47 @@
+/*
+ * 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.viewmodel
+
+import com.android.systemui.res.R
+import com.android.systemui.touchpad.tutorial.ui.gesture.GestureRecognizer
+import com.android.systemui.touchpad.tutorial.ui.gesture.HomeGestureRecognizer
+import com.android.systemui.touchpad.tutorial.ui.gesture.VelocityTracker
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.map
+
+class HomeGestureRecognizerProvider
+@Inject
+constructor(val resources: TouchpadGestureResources, val velocityTracker: VelocityTracker) :
+ GestureRecognizerProvider {
+
+ override val recognizer: Flow<GestureRecognizer> =
+ resources
+ .distanceThreshold()
+ .combine(
+ resources.velocityThreshold(R.dimen.touchpad_home_gesture_velocity_threshold),
+ { distance, velocity -> distance to velocity },
+ )
+ .map { (distance, velocity) ->
+ HomeGestureRecognizer(
+ gestureDistanceThresholdPx = distance,
+ velocityThresholdPxPerMs = velocity,
+ velocityTracker = velocityTracker,
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/HomeGestureScreenViewModel.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/HomeGestureScreenViewModel.kt
index 9a817d810bba..9d6f568fa1b1 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/HomeGestureScreenViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/HomeGestureScreenViewModel.kt
@@ -16,70 +16,27 @@
package com.android.systemui.touchpad.tutorial.ui.viewmodel
-import android.content.res.Resources
import android.view.MotionEvent
-import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
-import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.res.R
import com.android.systemui.touchpad.tutorial.ui.composable.GestureUiState
import com.android.systemui.touchpad.tutorial.ui.composable.toGestureUiState
-import com.android.systemui.touchpad.tutorial.ui.gesture.GestureFlowAdapter
-import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState
-import com.android.systemui.touchpad.tutorial.ui.gesture.HomeGestureRecognizer
-import com.android.systemui.touchpad.tutorial.ui.gesture.VelocityTracker
-import com.android.systemui.touchpad.tutorial.ui.gesture.VerticalVelocityTracker
import com.android.systemui.touchpad.tutorial.ui.gesture.handleTouchpadMotionEvent
-import javax.inject.Inject
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.map
-class HomeGestureScreenViewModel
-@Inject
-constructor(
- val configurationInteractor: ConfigurationInteractor,
- @Main val resources: Resources,
- val velocityTracker: VelocityTracker = VerticalVelocityTracker(),
-) : TouchpadTutorialScreenViewModel {
+class HomeGestureScreenViewModel(private val gestureRecognizer: GestureRecognizerAdapter) :
+ TouchpadTutorialScreenViewModel {
- private var recognizer: HomeGestureRecognizer? = null
-
- private val distanceThreshold: Flow<Int> =
- configurationInteractor
- .dimensionPixelSize(R.dimen.touchpad_tutorial_gestures_distance_threshold)
- .distinctUntilChanged()
-
- private val velocityThreshold: Flow<Float> =
- configurationInteractor.onAnyConfigurationChange
- .map { resources.getDimension(R.dimen.touchpad_home_gesture_velocity_threshold) }
- .distinctUntilChanged()
-
- @OptIn(ExperimentalCoroutinesApi::class)
override val gestureUiState: Flow<GestureUiState> =
- distanceThreshold
- .combine(velocityThreshold, { distance, velocity -> distance to velocity })
- .flatMapLatest { (distance, velocity) ->
- recognizer =
- HomeGestureRecognizer(
- gestureDistanceThresholdPx = distance,
- velocityThresholdPxPerMs = velocity,
- velocityTracker = velocityTracker,
- )
- GestureFlowAdapter(recognizer!!).gestureStateAsFlow
- }
- .map { toGestureUiState(it) }
-
- private fun toGestureUiState(it: GestureState) =
- it.toGestureUiState(
- progressStartMarker = "drag with gesture",
- progressEndMarker = "release playback realtime",
- successAnimation = R.raw.trackpad_home_success,
- )
+ gestureRecognizer.gestureState.map {
+ it.toGestureUiState(
+ progressStartMarker = "drag with gesture",
+ progressEndMarker = "release playback realtime",
+ successAnimation = R.raw.trackpad_home_success,
+ )
+ }
override fun handleEvent(event: MotionEvent): Boolean {
- return recognizer?.handleTouchpadMotionEvent(event) ?: false
+ return gestureRecognizer.handleTouchpadMotionEvent(event)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/RecentAppsGestureRecognizerProvider.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/RecentAppsGestureRecognizerProvider.kt
new file mode 100644
index 000000000000..3e0b434036e5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/RecentAppsGestureRecognizerProvider.kt
@@ -0,0 +1,49 @@
+/*
+ * 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.viewmodel
+
+import com.android.systemui.res.R
+import com.android.systemui.touchpad.tutorial.ui.gesture.GestureRecognizer
+import com.android.systemui.touchpad.tutorial.ui.gesture.RecentAppsGestureRecognizer
+import com.android.systemui.touchpad.tutorial.ui.gesture.VelocityTracker
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.map
+
+class RecentAppsGestureRecognizerProvider
+@Inject
+constructor(val resources: TouchpadGestureResources, val velocityTracker: VelocityTracker) :
+ GestureRecognizerProvider {
+
+ override val recognizer: Flow<GestureRecognizer> =
+ resources
+ .distanceThreshold()
+ .combine(
+ resources.velocityThreshold(
+ R.dimen.touchpad_recent_apps_gesture_velocity_threshold
+ ),
+ { distance, velocity -> distance to velocity },
+ )
+ .map { (distance, velocity) ->
+ RecentAppsGestureRecognizer(
+ gestureDistanceThresholdPx = distance,
+ velocityThresholdPxPerMs = velocity,
+ velocityTracker = velocityTracker,
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/RecentAppsGestureScreenViewModel.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/RecentAppsGestureScreenViewModel.kt
index 8215078c346d..97528583277f 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/RecentAppsGestureScreenViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/RecentAppsGestureScreenViewModel.kt
@@ -16,74 +16,27 @@
package com.android.systemui.touchpad.tutorial.ui.viewmodel
-import android.content.res.Resources
import android.view.MotionEvent
-import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
-import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.res.R
import com.android.systemui.touchpad.tutorial.ui.composable.GestureUiState
import com.android.systemui.touchpad.tutorial.ui.composable.toGestureUiState
-import com.android.systemui.touchpad.tutorial.ui.gesture.GestureFlowAdapter
-import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState
-import com.android.systemui.touchpad.tutorial.ui.gesture.RecentAppsGestureRecognizer
-import com.android.systemui.touchpad.tutorial.ui.gesture.VelocityTracker
-import com.android.systemui.touchpad.tutorial.ui.gesture.VerticalVelocityTracker
import com.android.systemui.touchpad.tutorial.ui.gesture.handleTouchpadMotionEvent
-import javax.inject.Inject
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.map
-class RecentAppsGestureScreenViewModel
-@Inject
-constructor(
- configurationInteractor: ConfigurationInteractor,
- @Main private val resources: Resources,
- private val velocityTracker: VelocityTracker = VerticalVelocityTracker(),
-) : TouchpadTutorialScreenViewModel {
+class RecentAppsGestureScreenViewModel(private val gestureRecognizer: GestureRecognizerAdapter) :
+ TouchpadTutorialScreenViewModel {
- private var recognizer: RecentAppsGestureRecognizer? = null
-
- private val distanceThreshold: Flow<Int> =
- configurationInteractor.onAnyConfigurationChange
- .map {
- resources.getDimensionPixelSize(
- R.dimen.touchpad_tutorial_gestures_distance_threshold
- )
- }
- .distinctUntilChanged()
-
- private val velocityThreshold: Flow<Float> =
- configurationInteractor.onAnyConfigurationChange
- .map { resources.getDimension(R.dimen.touchpad_recent_apps_gesture_velocity_threshold) }
- .distinctUntilChanged()
-
- @OptIn(ExperimentalCoroutinesApi::class)
override val gestureUiState: Flow<GestureUiState> =
- distanceThreshold
- .combine(velocityThreshold, { distance, velocity -> distance to velocity })
- .flatMapLatest { (distance, velocity) ->
- recognizer =
- RecentAppsGestureRecognizer(
- gestureDistanceThresholdPx = distance,
- velocityThresholdPxPerMs = velocity,
- velocityTracker = velocityTracker,
- )
- GestureFlowAdapter(recognizer!!).gestureStateAsFlow
- }
- .map { toGestureUiState(it) }
-
- private fun toGestureUiState(it: GestureState) =
- it.toGestureUiState(
- progressStartMarker = "drag with gesture",
- progressEndMarker = "onPause",
- successAnimation = R.raw.trackpad_recent_apps_success,
- )
+ gestureRecognizer.gestureState.map {
+ it.toGestureUiState(
+ progressStartMarker = "drag with gesture",
+ progressEndMarker = "onPause",
+ successAnimation = R.raw.trackpad_recent_apps_success,
+ )
+ }
override fun handleEvent(event: MotionEvent): Boolean {
- return recognizer?.handleTouchpadMotionEvent(event) ?: false
+ return gestureRecognizer.handleTouchpadMotionEvent(event)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/TouchpadGestureResources.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/TouchpadGestureResources.kt
new file mode 100644
index 000000000000..3d99bd82d79e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/TouchpadGestureResources.kt
@@ -0,0 +1,46 @@
+/*
+ * 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.viewmodel
+
+import android.content.res.Resources
+import androidx.annotation.DimenRes
+import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.res.R
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.map
+
+class TouchpadGestureResources
+@Inject
+constructor(val configurationInteractor: ConfigurationInteractor, @Main val resources: Resources) {
+
+ fun distanceThreshold(): Flow<Int> =
+ configurationInteractor.onAnyConfigurationChange
+ .map {
+ resources.getDimensionPixelSize(
+ R.dimen.touchpad_tutorial_gestures_distance_threshold
+ )
+ }
+ .distinctUntilChanged()
+
+ fun velocityThreshold(@DimenRes resId: Int): Flow<Float> =
+ configurationInteractor.onAnyConfigurationChange
+ .map { resources.getDimension(resId) }
+ .distinctUntilChanged()
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/touchpad/ui/gesture/TouchpadGestureResourcesKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/touchpad/ui/gesture/TouchpadGestureResourcesKosmos.kt
new file mode 100644
index 000000000000..d795941f96aa
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/touchpad/ui/gesture/TouchpadGestureResourcesKosmos.kt
@@ -0,0 +1,25 @@
+/*
+ * 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.ui.gesture
+
+import android.content.res.mockResources
+import com.android.systemui.common.ui.domain.interactor.configurationInteractor
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.touchpad.tutorial.ui.viewmodel.TouchpadGestureResources
+
+var Kosmos.touchpadGestureResources: TouchpadGestureResources by
+ Kosmos.Fixture { TouchpadGestureResources(configurationInteractor, mockResources) }