• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.inputdevice.tutorial.ui.view
18 
19 import android.os.Bundle
20 import android.view.WindowManager
21 import androidx.activity.ComponentActivity
22 import androidx.activity.compose.setContent
23 import androidx.activity.enableEdgeToEdge
24 import androidx.activity.viewModels
25 import androidx.compose.runtime.Composable
26 import androidx.compose.runtime.getValue
27 import androidx.lifecycle.Lifecycle.State.STARTED
28 import androidx.lifecycle.compose.collectAsStateWithLifecycle
29 import androidx.lifecycle.lifecycleScope
30 import com.android.app.tracing.coroutines.launchTraced as launch
31 import com.android.compose.theme.PlatformTheme
32 import com.android.systemui.inputdevice.tutorial.InputDeviceTutorialLogger
33 import com.android.systemui.inputdevice.tutorial.InputDeviceTutorialLogger.TutorialContext
34 import com.android.systemui.inputdevice.tutorial.KeyboardTouchpadTutorialMetricsLogger
35 import com.android.systemui.inputdevice.tutorial.TouchpadTutorialScreensProvider
36 import com.android.systemui.inputdevice.tutorial.domain.interactor.TutorialSchedulerInteractor
37 import com.android.systemui.inputdevice.tutorial.domain.interactor.TutorialSchedulerInteractor.TutorialType
38 import com.android.systemui.inputdevice.tutorial.ui.composable.ActionKeyTutorialScreen
39 import com.android.systemui.inputdevice.tutorial.ui.viewmodel.KeyboardTouchpadTutorialViewModel
40 import com.android.systemui.inputdevice.tutorial.ui.viewmodel.KeyboardTouchpadTutorialViewModel.Factory.ViewModelFactoryAssistedProvider
41 import com.android.systemui.inputdevice.tutorial.ui.viewmodel.Screen.ACTION_KEY
42 import com.android.systemui.inputdevice.tutorial.ui.viewmodel.Screen.BACK_GESTURE
43 import com.android.systemui.inputdevice.tutorial.ui.viewmodel.Screen.HOME_GESTURE
44 import java.util.Optional
45 import javax.inject.Inject
46 
47 /**
48  * Activity for out of the box experience for keyboard and touchpad. Note that it's possible that
49  * either of them are actually not connected when this is launched
50  */
51 class KeyboardTouchpadTutorialActivity
52 @Inject
53 constructor(
54     private val viewModelFactoryAssistedProvider: ViewModelFactoryAssistedProvider,
55     private val touchpadTutorialScreensProvider: Optional<TouchpadTutorialScreensProvider>,
56     private val schedulerInteractor: TutorialSchedulerInteractor,
57     private val logger: InputDeviceTutorialLogger,
58     private val metricsLogger: KeyboardTouchpadTutorialMetricsLogger,
59 ) : ComponentActivity() {
60 
61     companion object {
62         const val INTENT_TUTORIAL_SCOPE_KEY = "tutorial_scope"
63         const val INTENT_TUTORIAL_SCOPE_TOUCHPAD = "touchpad"
64         const val INTENT_TUTORIAL_SCOPE_TOUCHPAD_BACK = "touchpad_back"
65         const val INTENT_TUTORIAL_SCOPE_TOUCHPAD_HOME = "touchpad_home"
66         const val INTENT_TUTORIAL_SCOPE_KEYBOARD = "keyboard"
67         const val INTENT_TUTORIAL_SCOPE_ALL = "all"
68 
69         const val INTENT_TUTORIAL_ENTRY_POINT_KEY = "entry_point"
70         const val INTENT_TUTORIAL_ENTRY_POINT_SCHEDULER = "scheduler"
71         const val INTENT_TUTORIAL_ENTRY_POINT_CONTEXTUAL_EDU = "contextual_edu"
72     }
73 
74     private val vm by
75         viewModels<KeyboardTouchpadTutorialViewModel>(
76             factoryProducer = {
77                 viewModelFactoryAssistedProvider.create(touchpadTutorialScreensProvider.isPresent)
78             }
79         )
80 
81     override fun onCreate(savedInstanceState: Bundle?) {
82         super.onCreate(savedInstanceState)
83         enableEdgeToEdge()
84         // required to handle 3+ fingers on touchpad
85         window.addPrivateFlags(WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY)
86         window.addPrivateFlags(WindowManager.LayoutParams.PRIVATE_FLAG_ALLOW_ACTION_KEY_EVENTS)
87         lifecycle.addObserver(vm)
88         lifecycleScope.launch {
89             vm.closeActivity.collect { finish ->
90                 if (finish) {
91                     logger.logCloseTutorial(TutorialContext.KEYBOARD_TOUCHPAD_TUTORIAL)
92                     finish()
93                 }
94             }
95         }
96         val entryPointExtra = intent.getStringExtra(INTENT_TUTORIAL_ENTRY_POINT_KEY)
97         val isAutoProceed =
98             if (entryPointExtra == null) true
99             else entryPointExtra.equals(INTENT_TUTORIAL_ENTRY_POINT_SCHEDULER)
100         val scopeExtra = intent.getStringExtra(INTENT_TUTORIAL_SCOPE_KEY)
101         val isScopeAll = INTENT_TUTORIAL_SCOPE_ALL.equals(scopeExtra)
102         setContent {
103             PlatformTheme {
104                 KeyboardTouchpadTutorialContainer(
105                     vm,
106                     touchpadTutorialScreensProvider,
107                     isAutoProceed,
108                     isScopeAll,
109                 )
110             }
111         }
112         if (savedInstanceState == null) {
113             logger.logOpenTutorial(TutorialContext.KEYBOARD_TOUCHPAD_TUTORIAL)
114 
115             val tutorialTypeExtra = intent.getStringExtra(INTENT_TUTORIAL_SCOPE_KEY)
116             metricsLogger.logPeripheralTutorialLaunched(entryPointExtra, tutorialTypeExtra)
117             // We only update launched info when the tutorial is triggered by the scheduler
118             if (INTENT_TUTORIAL_ENTRY_POINT_SCHEDULER.equals(entryPointExtra))
119                 updateLaunchInfo(tutorialTypeExtra)
120         }
121     }
122 
123     private fun updateLaunchInfo(tutorialTypeExtra: String?) {
124         val type =
125             when (tutorialTypeExtra) {
126                 INTENT_TUTORIAL_SCOPE_KEYBOARD -> TutorialType.KEYBOARD
127                 INTENT_TUTORIAL_SCOPE_TOUCHPAD -> TutorialType.TOUCHPAD
128                 INTENT_TUTORIAL_SCOPE_ALL -> TutorialType.BOTH
129                 else -> TutorialType.NONE
130             }
131         schedulerInteractor.updateLaunchInfo(type)
132     }
133 }
134 
135 @Composable
KeyboardTouchpadTutorialContainernull136 fun KeyboardTouchpadTutorialContainer(
137     vm: KeyboardTouchpadTutorialViewModel,
138     touchpadScreens: Optional<TouchpadTutorialScreensProvider>,
139     isAutoProceed: Boolean = false,
140     isScopeAll: Boolean = false,
141 ) {
142     val activeScreen by vm.screen.collectAsStateWithLifecycle(STARTED)
143     when (activeScreen) {
144         BACK_GESTURE ->
145             touchpadScreens
146                 .get()
147                 .BackGesture(
148                     onDoneButtonClicked = vm::onDoneButtonClicked,
149                     onBack = vm::onBack,
150                     onAutoProceed = if (isAutoProceed) vm::onAutoProceed else null,
151                 )
152         HOME_GESTURE ->
153             touchpadScreens
154                 .get()
155                 .HomeGesture(
156                     onDoneButtonClicked = vm::onDoneButtonClicked,
157                     onBack = vm::onBack,
158                     onAutoProceed = if (isScopeAll) vm::onAutoProceed else null,
159                 )
160         ACTION_KEY ->
161             ActionKeyTutorialScreen(
162                 onDoneButtonClicked = vm::onDoneButtonClicked,
163                 onBack = vm::onBack,
164             )
165     }
166 }
167