Merge changes Ifc4e989b,I51bda79d into main
* changes:
Tutorial correctly handling META key event
Adding logger for touchpad and keyboard tutorials
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/InputDeviceTutorialLogger.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/InputDeviceTutorialLogger.kt
new file mode 100644
index 0000000..9525174
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/InputDeviceTutorialLogger.kt
@@ -0,0 +1,56 @@
+/*
+ * 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
+
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.core.LogLevel
+import com.android.systemui.log.dagger.InputDeviceTutorialLog
+import com.android.systemui.touchpad.tutorial.ui.viewmodel.Screen
+import com.google.errorprone.annotations.CompileTimeConstant
+import javax.inject.Inject
+
+private const val TAG = "InputDeviceTutorial"
+
+class InputDeviceTutorialLogger
+@Inject
+constructor(@InputDeviceTutorialLog private val buffer: LogBuffer) {
+
+ fun log(@CompileTimeConstant s: String) {
+ buffer.log(TAG, LogLevel.INFO, message = s)
+ }
+
+ fun logGoingToScreen(screen: Screen, context: TutorialContext) {
+ buffer.log(
+ TAG,
+ LogLevel.INFO,
+ {
+ str1 = screen.toString()
+ str2 = context.string
+ },
+ { "Emitting new screen $str1 in $str2" }
+ )
+ }
+
+ fun logCloseTutorial(context: TutorialContext) {
+ buffer.log(TAG, LogLevel.INFO, { str1 = context.string }, { "Closing $str1" })
+ }
+
+ enum class TutorialContext(val string: String) {
+ KEYBOARD_TOUCHPAD_TUTORIAL("keyboard touchpad tutorial"),
+ TOUCHPAD_TUTORIAL("touchpad tutorial"),
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionKeyTutorialScreen.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionKeyTutorialScreen.kt
index c5b0ca7..6bc640d 100644
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionKeyTutorialScreen.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionKeyTutorialScreen.kt
@@ -17,15 +17,19 @@
package com.android.systemui.inputdevice.tutorial.ui.composable
import androidx.activity.compose.BackHandler
+import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.KeyEvent
import androidx.compose.ui.input.key.KeyEventType
@@ -46,18 +50,27 @@
BackHandler(onBack = onBack)
val screenConfig = buildScreenConfig()
var actionState by remember { mutableStateOf(NOT_STARTED) }
+ val focusRequester = remember { FocusRequester() }
Box(
modifier =
- Modifier.fillMaxSize().onKeyEvent { keyEvent: KeyEvent ->
- // temporary before we can access Action/Meta key
- if (keyEvent.key == Key.AltLeft && keyEvent.type == KeyEventType.KeyUp) {
- actionState = FINISHED
+ Modifier.fillMaxSize()
+ .onKeyEvent { keyEvent: KeyEvent ->
+ if (keyEvent.key == Key.MetaLeft && keyEvent.type == KeyEventType.KeyUp) {
+ actionState = FINISHED
+ }
+ true
}
- true
- }
+ .focusRequester(focusRequester)
+ .focusable()
) {
ActionTutorialContent(actionState, onDoneButtonClicked, screenConfig)
}
+ LaunchedEffect(Unit) {
+ // we need to request focus on main container so it can handle all key events immediately
+ // when it's open. Otherwise user needs to press non-modifier key before modifier key can
+ // be handled as nothing is focused
+ focusRequester.requestFocus()
+ }
}
@Composable
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/view/KeyboardTouchpadTutorialActivity.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/view/KeyboardTouchpadTutorialActivity.kt
index 34ecc95..8debe79 100644
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/view/KeyboardTouchpadTutorialActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/view/KeyboardTouchpadTutorialActivity.kt
@@ -68,6 +68,7 @@
enableEdgeToEdge()
// required to handle 3+ fingers on touchpad
window.addPrivateFlags(WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY)
+ window.addPrivateFlags(WindowManager.LayoutParams.PRIVATE_FLAG_ALLOW_ACTION_KEY_EVENTS)
lifecycle.addObserver(vm)
lifecycleScope.launch {
vm.closeActivity.collect { finish ->
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/InputDeviceTutorialLog.kt b/packages/SystemUI/src/com/android/systemui/log/dagger/InputDeviceTutorialLog.kt
new file mode 100644
index 0000000..a788279
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/InputDeviceTutorialLog.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.log.dagger
+
+import javax.inject.Qualifier
+
+/** A [com.android.systemui.log.LogBuffer] for input device tutorial. */
+@Qualifier
+@MustBeDocumented
+@Retention(AnnotationRetention.RUNTIME)
+annotation class InputDeviceTutorialLog
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index 40bb8e1..5cae58a 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -660,6 +660,14 @@
return factory.create("KeyboardLog", 50);
}
+ /** Provides a {@link LogBuffer} for the input devices tutorial. */
+ @Provides
+ @SysUISingleton
+ @InputDeviceTutorialLog
+ public static LogBuffer provideInputDeviceTutorialLogBuffer(LogBufferFactory factory) {
+ return factory.create("InputDeviceTutorialLog", 50);
+ }
+
/** Provides a {@link LogBuffer} for {@link PackageChangeRepository} */
@Provides
@SysUISingleton
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 238e8a1..3fa3f63 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/TouchpadTutorialModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/TouchpadTutorialModule.kt
@@ -20,6 +20,7 @@
import androidx.compose.runtime.Composable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.inputdevice.tutorial.InputDeviceTutorialLogger
import com.android.systemui.inputdevice.tutorial.TouchpadTutorialScreensProvider
import com.android.systemui.model.SysUiState
import com.android.systemui.settings.DisplayTracker
@@ -53,9 +54,10 @@
fun touchpadGesturesInteractor(
sysUiState: SysUiState,
displayTracker: DisplayTracker,
- @Background backgroundScope: CoroutineScope
+ @Background backgroundScope: CoroutineScope,
+ logger: InputDeviceTutorialLogger,
): TouchpadGesturesInteractor {
- return TouchpadGesturesInteractor(sysUiState, displayTracker, backgroundScope)
+ return TouchpadGesturesInteractor(sysUiState, displayTracker, backgroundScope, logger)
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/domain/interactor/TouchpadGesturesInteractor.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/domain/interactor/TouchpadGesturesInteractor.kt
index df95232..1a41987 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/domain/interactor/TouchpadGesturesInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/domain/interactor/TouchpadGesturesInteractor.kt
@@ -16,6 +16,7 @@
package com.android.systemui.touchpad.tutorial.domain.interactor
+import com.android.systemui.inputdevice.tutorial.InputDeviceTutorialLogger
import com.android.systemui.model.SysUiState
import com.android.systemui.settings.DisplayTracker
import com.android.systemui.shared.system.QuickStepContract
@@ -25,13 +26,16 @@
class TouchpadGesturesInteractor(
private val sysUiState: SysUiState,
private val displayTracker: DisplayTracker,
- private val backgroundScope: CoroutineScope
+ private val backgroundScope: CoroutineScope,
+ private val logger: InputDeviceTutorialLogger,
) {
fun disableGestures() {
+ logger.log("Disabling touchpad gestures across the system")
setGesturesState(disabled = true)
}
fun enableGestures() {
+ logger.log("Enabling touchpad gestures across the system")
setGesturesState(disabled = 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 256c5b5..821b51a 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
@@ -27,6 +27,8 @@
import androidx.lifecycle.Lifecycle.State.STARTED
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.theme.PlatformTheme
+import com.android.systemui.inputdevice.tutorial.InputDeviceTutorialLogger
+import com.android.systemui.inputdevice.tutorial.InputDeviceTutorialLogger.TutorialContext
import com.android.systemui.inputdevice.tutorial.ui.composable.ActionKeyTutorialScreen
import com.android.systemui.touchpad.tutorial.ui.composable.BackGestureTutorialScreen
import com.android.systemui.touchpad.tutorial.ui.composable.HomeGestureTutorialScreen
@@ -42,6 +44,7 @@
@Inject
constructor(
private val viewModelFactory: TouchpadTutorialViewModel.Factory,
+ private val logger: InputDeviceTutorialLogger,
) : ComponentActivity() {
private val vm by viewModels<TouchpadTutorialViewModel>(factoryProducer = { viewModelFactory })
@@ -49,9 +52,17 @@
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
- setContent { PlatformTheme { TouchpadTutorialScreen(vm) { finish() } } }
+ setContent {
+ PlatformTheme { TouchpadTutorialScreen(vm, closeTutorial = ::finishTutorial) }
+ }
// required to handle 3+ fingers on touchpad
window.addPrivateFlags(WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY)
+ window.addPrivateFlags(WindowManager.LayoutParams.PRIVATE_FLAG_ALLOW_ACTION_KEY_EVENTS)
+ }
+
+ private fun finishTutorial() {
+ logger.logCloseTutorial(TutorialContext.TOUCHPAD_TUTORIAL)
+ finish()
}
override fun onResume() {
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 d3aeaa7..43266ad 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
@@ -18,18 +18,23 @@
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
+import com.android.systemui.inputdevice.tutorial.InputDeviceTutorialLogger
+import com.android.systemui.inputdevice.tutorial.InputDeviceTutorialLogger.TutorialContext
import com.android.systemui.touchpad.tutorial.domain.interactor.TouchpadGesturesInteractor
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
-class TouchpadTutorialViewModel(private val gesturesInteractor: TouchpadGesturesInteractor) :
- ViewModel() {
+class TouchpadTutorialViewModel(
+ private val gesturesInteractor: TouchpadGesturesInteractor,
+ private val logger: InputDeviceTutorialLogger
+) : ViewModel() {
private val _screen = MutableStateFlow(Screen.TUTORIAL_SELECTION)
val screen: StateFlow<Screen> = _screen
fun goTo(screen: Screen) {
+ logger.logGoingToScreen(screen, TutorialContext.TOUCHPAD_TUTORIAL)
_screen.value = screen
}
@@ -41,12 +46,16 @@
gesturesInteractor.enableGestures()
}
- class Factory @Inject constructor(private val gesturesInteractor: TouchpadGesturesInteractor) :
- ViewModelProvider.Factory {
+ class Factory
+ @Inject
+ constructor(
+ private val gesturesInteractor: TouchpadGesturesInteractor,
+ private val logger: InputDeviceTutorialLogger
+ ) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
- return TouchpadTutorialViewModel(gesturesInteractor) as T
+ return TouchpadTutorialViewModel(gesturesInteractor, logger) as T
}
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/TouchpadTutorialViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/TouchpadTutorialViewModelTest.kt
index c705cea..89e8895 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/TouchpadTutorialViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/TouchpadTutorialViewModelTest.kt
@@ -19,6 +19,7 @@
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.model.sysUiState
import com.android.systemui.settings.displayTracker
import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED
@@ -41,7 +42,13 @@
private val sysUiState = kosmos.sysUiState
private val viewModel =
TouchpadTutorialViewModel(
- TouchpadGesturesInteractor(sysUiState, kosmos.displayTracker, testScope.backgroundScope)
+ TouchpadGesturesInteractor(
+ sysUiState,
+ kosmos.displayTracker,
+ testScope.backgroundScope,
+ kosmos.inputDeviceTutorialLogger
+ ),
+ kosmos.inputDeviceTutorialLogger
)
@Test
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/inputdevice/tutorial/InputDeviceTutorialKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/inputdevice/tutorial/InputDeviceTutorialKosmos.kt
new file mode 100644
index 0000000..827f0d2
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/inputdevice/tutorial/InputDeviceTutorialKosmos.kt
@@ -0,0 +1,23 @@
+/*
+ * 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
+
+import com.android.systemui.kosmos.Kosmos
+import org.mockito.kotlin.mock
+
+var Kosmos.inputDeviceTutorialLogger: InputDeviceTutorialLogger by
+ Kosmos.Fixture { mock<InputDeviceTutorialLogger>() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/touchpad/tutorial/TouchpadTutorialKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/touchpad/tutorial/TouchpadTutorialKosmos.kt
index f502df0..ee9a4d2 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/touchpad/tutorial/TouchpadTutorialKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/touchpad/tutorial/TouchpadTutorialKosmos.kt
@@ -16,6 +16,7 @@
package com.android.systemui.touchpad.tutorial
+import com.android.systemui.inputdevice.tutorial.inputDeviceTutorialLogger
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testScope
import com.android.systemui.model.sysUiState
@@ -24,5 +25,10 @@
var Kosmos.touchpadGesturesInteractor: TouchpadGesturesInteractor by
Kosmos.Fixture {
- TouchpadGesturesInteractor(sysUiState, displayTracker, testScope.backgroundScope)
+ TouchpadGesturesInteractor(
+ sysUiState,
+ displayTracker,
+ testScope.backgroundScope,
+ inputDeviceTutorialLogger
+ )
}