Loading packages/SystemUI/res/values/strings.xml +4 −0 Original line number Diff line number Diff line Loading @@ -3827,6 +3827,10 @@ assigning a new custom key combination to a shortcut in shortcut helper. The helper is a component that shows the user which keyboard shortcuts they can use. [CHAR LIMIT=NONE] --> <string name="shortcut_helper_customize_dialog_error_message">Key combination already in use. Try another key.</string> <!-- Plus sign, used in keyboard shortcut helper to combine keys for shortcut. E.g. Ctrl + A The helper is a component that shows the user which keyboard shortcuts they can use. [CHAR LIMIT=NONE] --> <string name="shortcut_helper_plus_symbol">+</string> <!-- Keyboard touchpad tutorial scheduler--> Loading packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt +13 −3 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.systemui.keyboard.shortcut.ui import android.app.Dialog import android.view.WindowManager.LayoutParams.PRIVATE_FLAG_ALLOW_ACTION_KEY_EVENTS import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.wrapContentHeight Loading @@ -33,6 +34,7 @@ import com.android.systemui.statusbar.phone.SystemUIDialogFactory import com.android.systemui.statusbar.phone.create import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import kotlinx.coroutines.awaitCancellation class ShortcutCustomizationDialogStarter @AssistedInject Loading @@ -57,6 +59,7 @@ constructor( dialog = null } } awaitCancellation() } fun onShortcutCustomizationRequested(requestInfo: ShortcutCustomizationRequestInfo) { Loading @@ -66,14 +69,21 @@ constructor( private fun createAddShortcutDialog(): Dialog { return dialogFactory.create(dialogDelegate = ShortcutCustomizationDialogDelegate()) { dialog -> val uiState by viewModel.shortcutCustomizationUiState.collectAsStateWithLifecycle() val uiState by viewModel.shortcutCustomizationUiState.collectAsStateWithLifecycle( initialValue = ShortcutCustomizationUiState.Inactive ) AssignNewShortcutDialog( uiState = uiState, modifier = Modifier.width(364.dp).wrapContentHeight().padding(vertical = 24.dp), onKeyPress = { viewModel.onKeyPressed(it) }, onCancel = { dialog.dismiss() }, ) dialog.setOnDismissListener { viewModel.onAddShortcutDialogDismissed() } dialog.setOnDismissListener { viewModel.onDialogDismissed() } // By default, apps cannot intercept action key. The system always handles it. This // flag is needed to enable customisation dialog window to intercept action key dialog.window?.addPrivateFlags(PRIVATE_FLAG_ALLOW_ACTION_KEY_EVENTS) } } Loading packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt +82 −18 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding Loading @@ -39,18 +40,22 @@ import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.graphics.Color import androidx.compose.ui.input.key.KeyEvent import androidx.compose.ui.input.key.onPreviewKeyEvent import androidx.compose.ui.input.key.onKeyEvent import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.android.compose.ui.graphics.painter.rememberDrawablePainter import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCustomizationUiState import com.android.systemui.res.R Loading Loading @@ -81,15 +86,16 @@ fun AssignNewShortcutDialog( SelectedKeyCombinationContainer( shouldShowErrorMessage = uiState.shouldShowErrorMessage, onKeyPress = onKeyPress, pressedKeys = uiState.pressedKeys, ) KeyCombinationAlreadyInUseErrorMessage(uiState.shouldShowErrorMessage) DialogButtons(onCancel, isValidKeyCombination = uiState.isValidKeyCombination) DialogButtons(onCancel, isSetShortcutButtonEnabled = uiState.pressedKeys.isNotEmpty()) } } } @Composable fun DialogButtons(onCancel: () -> Unit, isValidKeyCombination: Boolean) { fun DialogButtons(onCancel: () -> Unit, isSetShortcutButtonEnabled: Boolean) { Row( modifier = Modifier.padding(top = 24.dp, start = 24.dp, end = 24.dp) Loading @@ -113,7 +119,7 @@ fun DialogButtons(onCancel: () -> Unit, isValidKeyCombination: Boolean) { contentColor = MaterialTheme.colorScheme.onPrimary, text = stringResource(R.string.shortcut_helper_customize_dialog_set_shortcut_button_label), enabled = isValidKeyCombination, enabled = isSetShortcutButtonEnabled, ) } } Loading @@ -137,10 +143,9 @@ fun KeyCombinationAlreadyInUseErrorMessage(shouldShowErrorMessage: Boolean) { @Composable fun SelectedKeyCombinationContainer( keyCombination: String = stringResource(R.string.shortcut_helper_add_shortcut_dialog_placeholder), shouldShowErrorMessage: Boolean, onKeyPress: (KeyEvent) -> Boolean, pressedKeys: List<ShortcutKey>, ) { val interactionSource = remember { MutableInteractionSource() } val isFocused by interactionSource.collectIsFocusedAsState() Loading @@ -148,6 +153,9 @@ fun SelectedKeyCombinationContainer( if (!isFocused) MaterialTheme.colorScheme.outline else if (shouldShowErrorMessage) MaterialTheme.colorScheme.error else MaterialTheme.colorScheme.primary val focusRequester = remember { FocusRequester() } LaunchedEffect(Unit) { focusRequester.requestFocus() } ClickableShortcutSurface( onClick = {}, Loading @@ -157,22 +165,19 @@ fun SelectedKeyCombinationContainer( Modifier.padding(all = 16.dp) .sizeIn(minWidth = 332.dp, minHeight = 56.dp) .border(width = 2.dp, color = outlineColor, shape = RoundedCornerShape(50.dp)) .onPreviewKeyEvent { onKeyPress(it) }, .onKeyEvent { onKeyPress(it) } .focusRequester(focusRequester), interactionSource = interactionSource, ) { Row( modifier = Modifier.padding(start = 24.dp, top = 16.dp, end = 16.dp, bottom = 16.dp), verticalAlignment = Alignment.CenterVertically, ) { Text( text = keyCombination, style = MaterialTheme.typography.headlineSmall, fontSize = 16.sp, lineHeight = 24.sp, fontWeight = FontWeight.W500, color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.width(252.dp), ) if (pressedKeys.isEmpty()) { PressKeyPrompt() } else { PressedKeysTextContainer(pressedKeys) } Spacer(modifier = Modifier.weight(1f)) if (shouldShowErrorMessage) { Icon( Loading @@ -186,6 +191,67 @@ fun SelectedKeyCombinationContainer( } } @Composable private fun RowScope.PressedKeysTextContainer(pressedKeys: List<ShortcutKey>) { pressedKeys.forEachIndexed { keyIndex, key -> if (keyIndex > 0) { ShortcutKeySeparator() } if (key is ShortcutKey.Text) { ShortcutTextKey(key) } else if (key is ShortcutKey.Icon) { ShortcutIconKey(key) } } } @Composable private fun ShortcutKeySeparator() { Text( text = stringResource(id = R.string.shortcut_helper_plus_symbol), style = MaterialTheme.typography.titleSmall, fontSize = 16.sp, lineHeight = 24.sp, color = MaterialTheme.colorScheme.onSurfaceVariant, ) } @Composable private fun RowScope.ShortcutIconKey(key: ShortcutKey.Icon) { Icon( painter = when (key) { is ShortcutKey.Icon.ResIdIcon -> painterResource(key.drawableResId) is ShortcutKey.Icon.DrawableIcon -> rememberDrawablePainter(drawable = key.drawable) }, contentDescription = null, modifier = Modifier.align(Alignment.CenterVertically).height(24.dp), tint = MaterialTheme.colorScheme.onSurfaceVariant, ) } @Composable private fun PressKeyPrompt() { Text( text = stringResource(id = R.string.shortcut_helper_add_shortcut_dialog_placeholder), style = MaterialTheme.typography.titleSmall, fontSize = 16.sp, lineHeight = 24.sp, color = MaterialTheme.colorScheme.onSurfaceVariant, ) } @Composable private fun ShortcutTextKey(key: ShortcutKey.Text) { Text( text = key.value, style = MaterialTheme.typography.titleSmall, fontSize = 16.sp, lineHeight = 24.sp, color = MaterialTheme.colorScheme.onSurfaceVariant, ) } @Composable private fun Title(title: String, modifier: Modifier = Modifier) { Text( Loading @@ -203,8 +269,6 @@ private fun Description(modifier: Modifier = Modifier) { Text( text = stringResource(id = R.string.shortcut_helper_customize_mode_sub_title), style = MaterialTheme.typography.bodyMedium, fontSize = 14.sp, lineHeight = 20.sp, modifier = modifier.wrapContentSize(Alignment.Center), color = MaterialTheme.colorScheme.onSurfaceVariant, ) Loading packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCustomizationUiState.kt +1 −1 Original line number Diff line number Diff line Loading @@ -22,9 +22,9 @@ sealed interface ShortcutCustomizationUiState { data class AddShortcutDialog( val shortcutLabel: String, val shouldShowErrorMessage: Boolean, val isValidKeyCombination: Boolean, val defaultCustomShortcutModifierKey: ShortcutKey.Icon.ResIdIcon, val isDialogShowing: Boolean, val pressedKeys: List<ShortcutKey> = emptyList(), ) : ShortcutCustomizationUiState data object Inactive : ShortcutCustomizationUiState Loading packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt +57 −5 Original line number Diff line number Diff line Loading @@ -17,14 +17,22 @@ package com.android.systemui.keyboard.shortcut.ui.viewmodel import androidx.compose.runtime.mutableStateOf import androidx.compose.ui.input.key.Key import androidx.compose.ui.input.key.KeyEvent import androidx.compose.ui.input.key.KeyEventType import androidx.compose.ui.input.key.isMetaPressed import androidx.compose.ui.input.key.key import androidx.compose.ui.input.key.nativeKeyCode import androidx.compose.ui.input.key.type import com.android.systemui.keyboard.shortcut.domain.interactor.ShortcutCustomizationInteractor import com.android.systemui.keyboard.shortcut.shared.model.KeyCombination import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCustomizationRequestInfo import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCustomizationUiState import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.update class ShortcutCustomizationViewModel Loading @@ -35,7 +43,21 @@ constructor(private val shortcutCustomizationInteractor: ShortcutCustomizationIn private val _shortcutCustomizationUiState = MutableStateFlow<ShortcutCustomizationUiState>(ShortcutCustomizationUiState.Inactive) val shortcutCustomizationUiState = _shortcutCustomizationUiState.asStateFlow() val shortcutCustomizationUiState = shortcutCustomizationInteractor.pressedKeys .map { keys -> // Note that Action Key is excluded as it's already displayed on the UI keys.filter { it != shortcutCustomizationInteractor.getDefaultCustomShortcutModifierKey() } } .combine(_shortcutCustomizationUiState) { keys, uiState -> if (uiState is ShortcutCustomizationUiState.AddShortcutDialog) { uiState.copy(pressedKeys = keys) } else { uiState } } fun onShortcutCustomizationRequested(requestInfo: ShortcutCustomizationRequestInfo) { when (requestInfo) { Loading @@ -44,10 +66,10 @@ constructor(private val shortcutCustomizationInteractor: ShortcutCustomizationIn ShortcutCustomizationUiState.AddShortcutDialog( shortcutLabel = requestInfo.label, shouldShowErrorMessage = false, isValidKeyCombination = false, defaultCustomShortcutModifierKey = shortcutCustomizationInteractor.getDefaultCustomShortcutModifierKey(), isDialogShowing = false, pressedKeys = emptyList(), ) _shortcutBeingCustomized.value = requestInfo } Loading @@ -62,18 +84,48 @@ constructor(private val shortcutCustomizationInteractor: ShortcutCustomizationIn } } fun onAddShortcutDialogDismissed() { fun onDialogDismissed() { _shortcutBeingCustomized.value = null _shortcutCustomizationUiState.value = ShortcutCustomizationUiState.Inactive shortcutCustomizationInteractor.updateUserSelectedKeyCombination(null) } fun onKeyPressed(keyEvent: KeyEvent): Boolean { // TODO Not yet implemented b/373638584 if ((keyEvent.isMetaPressed && keyEvent.type == KeyEventType.KeyDown)) { updatePressedKeys(keyEvent) return true } return false } private fun updatePressedKeys(keyEvent: KeyEvent) { val isModifier = SUPPORTED_MODIFIERS.contains(keyEvent.key) val keyCombination = KeyCombination( modifiers = keyEvent.nativeKeyEvent.modifiers, keyCode = if (!isModifier) keyEvent.key.nativeKeyCode else null, ) shortcutCustomizationInteractor.updateUserSelectedKeyCombination(keyCombination) } @AssistedFactory interface Factory { fun create(): ShortcutCustomizationViewModel } companion object { private val SUPPORTED_MODIFIERS = listOf( Key.MetaLeft, Key.MetaRight, Key.CtrlRight, Key.CtrlLeft, Key.AltLeft, Key.AltRight, Key.ShiftLeft, Key.ShiftRight, Key.Function, Key.Symbol, ) } } Loading
packages/SystemUI/res/values/strings.xml +4 −0 Original line number Diff line number Diff line Loading @@ -3827,6 +3827,10 @@ assigning a new custom key combination to a shortcut in shortcut helper. The helper is a component that shows the user which keyboard shortcuts they can use. [CHAR LIMIT=NONE] --> <string name="shortcut_helper_customize_dialog_error_message">Key combination already in use. Try another key.</string> <!-- Plus sign, used in keyboard shortcut helper to combine keys for shortcut. E.g. Ctrl + A The helper is a component that shows the user which keyboard shortcuts they can use. [CHAR LIMIT=NONE] --> <string name="shortcut_helper_plus_symbol">+</string> <!-- Keyboard touchpad tutorial scheduler--> Loading
packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt +13 −3 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.systemui.keyboard.shortcut.ui import android.app.Dialog import android.view.WindowManager.LayoutParams.PRIVATE_FLAG_ALLOW_ACTION_KEY_EVENTS import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.wrapContentHeight Loading @@ -33,6 +34,7 @@ import com.android.systemui.statusbar.phone.SystemUIDialogFactory import com.android.systemui.statusbar.phone.create import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import kotlinx.coroutines.awaitCancellation class ShortcutCustomizationDialogStarter @AssistedInject Loading @@ -57,6 +59,7 @@ constructor( dialog = null } } awaitCancellation() } fun onShortcutCustomizationRequested(requestInfo: ShortcutCustomizationRequestInfo) { Loading @@ -66,14 +69,21 @@ constructor( private fun createAddShortcutDialog(): Dialog { return dialogFactory.create(dialogDelegate = ShortcutCustomizationDialogDelegate()) { dialog -> val uiState by viewModel.shortcutCustomizationUiState.collectAsStateWithLifecycle() val uiState by viewModel.shortcutCustomizationUiState.collectAsStateWithLifecycle( initialValue = ShortcutCustomizationUiState.Inactive ) AssignNewShortcutDialog( uiState = uiState, modifier = Modifier.width(364.dp).wrapContentHeight().padding(vertical = 24.dp), onKeyPress = { viewModel.onKeyPressed(it) }, onCancel = { dialog.dismiss() }, ) dialog.setOnDismissListener { viewModel.onAddShortcutDialogDismissed() } dialog.setOnDismissListener { viewModel.onDialogDismissed() } // By default, apps cannot intercept action key. The system always handles it. This // flag is needed to enable customisation dialog window to intercept action key dialog.window?.addPrivateFlags(PRIVATE_FLAG_ALLOW_ACTION_KEY_EVENTS) } } Loading
packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt +82 −18 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding Loading @@ -39,18 +40,22 @@ import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.graphics.Color import androidx.compose.ui.input.key.KeyEvent import androidx.compose.ui.input.key.onPreviewKeyEvent import androidx.compose.ui.input.key.onKeyEvent import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.android.compose.ui.graphics.painter.rememberDrawablePainter import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCustomizationUiState import com.android.systemui.res.R Loading Loading @@ -81,15 +86,16 @@ fun AssignNewShortcutDialog( SelectedKeyCombinationContainer( shouldShowErrorMessage = uiState.shouldShowErrorMessage, onKeyPress = onKeyPress, pressedKeys = uiState.pressedKeys, ) KeyCombinationAlreadyInUseErrorMessage(uiState.shouldShowErrorMessage) DialogButtons(onCancel, isValidKeyCombination = uiState.isValidKeyCombination) DialogButtons(onCancel, isSetShortcutButtonEnabled = uiState.pressedKeys.isNotEmpty()) } } } @Composable fun DialogButtons(onCancel: () -> Unit, isValidKeyCombination: Boolean) { fun DialogButtons(onCancel: () -> Unit, isSetShortcutButtonEnabled: Boolean) { Row( modifier = Modifier.padding(top = 24.dp, start = 24.dp, end = 24.dp) Loading @@ -113,7 +119,7 @@ fun DialogButtons(onCancel: () -> Unit, isValidKeyCombination: Boolean) { contentColor = MaterialTheme.colorScheme.onPrimary, text = stringResource(R.string.shortcut_helper_customize_dialog_set_shortcut_button_label), enabled = isValidKeyCombination, enabled = isSetShortcutButtonEnabled, ) } } Loading @@ -137,10 +143,9 @@ fun KeyCombinationAlreadyInUseErrorMessage(shouldShowErrorMessage: Boolean) { @Composable fun SelectedKeyCombinationContainer( keyCombination: String = stringResource(R.string.shortcut_helper_add_shortcut_dialog_placeholder), shouldShowErrorMessage: Boolean, onKeyPress: (KeyEvent) -> Boolean, pressedKeys: List<ShortcutKey>, ) { val interactionSource = remember { MutableInteractionSource() } val isFocused by interactionSource.collectIsFocusedAsState() Loading @@ -148,6 +153,9 @@ fun SelectedKeyCombinationContainer( if (!isFocused) MaterialTheme.colorScheme.outline else if (shouldShowErrorMessage) MaterialTheme.colorScheme.error else MaterialTheme.colorScheme.primary val focusRequester = remember { FocusRequester() } LaunchedEffect(Unit) { focusRequester.requestFocus() } ClickableShortcutSurface( onClick = {}, Loading @@ -157,22 +165,19 @@ fun SelectedKeyCombinationContainer( Modifier.padding(all = 16.dp) .sizeIn(minWidth = 332.dp, minHeight = 56.dp) .border(width = 2.dp, color = outlineColor, shape = RoundedCornerShape(50.dp)) .onPreviewKeyEvent { onKeyPress(it) }, .onKeyEvent { onKeyPress(it) } .focusRequester(focusRequester), interactionSource = interactionSource, ) { Row( modifier = Modifier.padding(start = 24.dp, top = 16.dp, end = 16.dp, bottom = 16.dp), verticalAlignment = Alignment.CenterVertically, ) { Text( text = keyCombination, style = MaterialTheme.typography.headlineSmall, fontSize = 16.sp, lineHeight = 24.sp, fontWeight = FontWeight.W500, color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.width(252.dp), ) if (pressedKeys.isEmpty()) { PressKeyPrompt() } else { PressedKeysTextContainer(pressedKeys) } Spacer(modifier = Modifier.weight(1f)) if (shouldShowErrorMessage) { Icon( Loading @@ -186,6 +191,67 @@ fun SelectedKeyCombinationContainer( } } @Composable private fun RowScope.PressedKeysTextContainer(pressedKeys: List<ShortcutKey>) { pressedKeys.forEachIndexed { keyIndex, key -> if (keyIndex > 0) { ShortcutKeySeparator() } if (key is ShortcutKey.Text) { ShortcutTextKey(key) } else if (key is ShortcutKey.Icon) { ShortcutIconKey(key) } } } @Composable private fun ShortcutKeySeparator() { Text( text = stringResource(id = R.string.shortcut_helper_plus_symbol), style = MaterialTheme.typography.titleSmall, fontSize = 16.sp, lineHeight = 24.sp, color = MaterialTheme.colorScheme.onSurfaceVariant, ) } @Composable private fun RowScope.ShortcutIconKey(key: ShortcutKey.Icon) { Icon( painter = when (key) { is ShortcutKey.Icon.ResIdIcon -> painterResource(key.drawableResId) is ShortcutKey.Icon.DrawableIcon -> rememberDrawablePainter(drawable = key.drawable) }, contentDescription = null, modifier = Modifier.align(Alignment.CenterVertically).height(24.dp), tint = MaterialTheme.colorScheme.onSurfaceVariant, ) } @Composable private fun PressKeyPrompt() { Text( text = stringResource(id = R.string.shortcut_helper_add_shortcut_dialog_placeholder), style = MaterialTheme.typography.titleSmall, fontSize = 16.sp, lineHeight = 24.sp, color = MaterialTheme.colorScheme.onSurfaceVariant, ) } @Composable private fun ShortcutTextKey(key: ShortcutKey.Text) { Text( text = key.value, style = MaterialTheme.typography.titleSmall, fontSize = 16.sp, lineHeight = 24.sp, color = MaterialTheme.colorScheme.onSurfaceVariant, ) } @Composable private fun Title(title: String, modifier: Modifier = Modifier) { Text( Loading @@ -203,8 +269,6 @@ private fun Description(modifier: Modifier = Modifier) { Text( text = stringResource(id = R.string.shortcut_helper_customize_mode_sub_title), style = MaterialTheme.typography.bodyMedium, fontSize = 14.sp, lineHeight = 20.sp, modifier = modifier.wrapContentSize(Alignment.Center), color = MaterialTheme.colorScheme.onSurfaceVariant, ) Loading
packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCustomizationUiState.kt +1 −1 Original line number Diff line number Diff line Loading @@ -22,9 +22,9 @@ sealed interface ShortcutCustomizationUiState { data class AddShortcutDialog( val shortcutLabel: String, val shouldShowErrorMessage: Boolean, val isValidKeyCombination: Boolean, val defaultCustomShortcutModifierKey: ShortcutKey.Icon.ResIdIcon, val isDialogShowing: Boolean, val pressedKeys: List<ShortcutKey> = emptyList(), ) : ShortcutCustomizationUiState data object Inactive : ShortcutCustomizationUiState Loading
packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt +57 −5 Original line number Diff line number Diff line Loading @@ -17,14 +17,22 @@ package com.android.systemui.keyboard.shortcut.ui.viewmodel import androidx.compose.runtime.mutableStateOf import androidx.compose.ui.input.key.Key import androidx.compose.ui.input.key.KeyEvent import androidx.compose.ui.input.key.KeyEventType import androidx.compose.ui.input.key.isMetaPressed import androidx.compose.ui.input.key.key import androidx.compose.ui.input.key.nativeKeyCode import androidx.compose.ui.input.key.type import com.android.systemui.keyboard.shortcut.domain.interactor.ShortcutCustomizationInteractor import com.android.systemui.keyboard.shortcut.shared.model.KeyCombination import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCustomizationRequestInfo import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCustomizationUiState import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.update class ShortcutCustomizationViewModel Loading @@ -35,7 +43,21 @@ constructor(private val shortcutCustomizationInteractor: ShortcutCustomizationIn private val _shortcutCustomizationUiState = MutableStateFlow<ShortcutCustomizationUiState>(ShortcutCustomizationUiState.Inactive) val shortcutCustomizationUiState = _shortcutCustomizationUiState.asStateFlow() val shortcutCustomizationUiState = shortcutCustomizationInteractor.pressedKeys .map { keys -> // Note that Action Key is excluded as it's already displayed on the UI keys.filter { it != shortcutCustomizationInteractor.getDefaultCustomShortcutModifierKey() } } .combine(_shortcutCustomizationUiState) { keys, uiState -> if (uiState is ShortcutCustomizationUiState.AddShortcutDialog) { uiState.copy(pressedKeys = keys) } else { uiState } } fun onShortcutCustomizationRequested(requestInfo: ShortcutCustomizationRequestInfo) { when (requestInfo) { Loading @@ -44,10 +66,10 @@ constructor(private val shortcutCustomizationInteractor: ShortcutCustomizationIn ShortcutCustomizationUiState.AddShortcutDialog( shortcutLabel = requestInfo.label, shouldShowErrorMessage = false, isValidKeyCombination = false, defaultCustomShortcutModifierKey = shortcutCustomizationInteractor.getDefaultCustomShortcutModifierKey(), isDialogShowing = false, pressedKeys = emptyList(), ) _shortcutBeingCustomized.value = requestInfo } Loading @@ -62,18 +84,48 @@ constructor(private val shortcutCustomizationInteractor: ShortcutCustomizationIn } } fun onAddShortcutDialogDismissed() { fun onDialogDismissed() { _shortcutBeingCustomized.value = null _shortcutCustomizationUiState.value = ShortcutCustomizationUiState.Inactive shortcutCustomizationInteractor.updateUserSelectedKeyCombination(null) } fun onKeyPressed(keyEvent: KeyEvent): Boolean { // TODO Not yet implemented b/373638584 if ((keyEvent.isMetaPressed && keyEvent.type == KeyEventType.KeyDown)) { updatePressedKeys(keyEvent) return true } return false } private fun updatePressedKeys(keyEvent: KeyEvent) { val isModifier = SUPPORTED_MODIFIERS.contains(keyEvent.key) val keyCombination = KeyCombination( modifiers = keyEvent.nativeKeyEvent.modifiers, keyCode = if (!isModifier) keyEvent.key.nativeKeyCode else null, ) shortcutCustomizationInteractor.updateUserSelectedKeyCombination(keyCombination) } @AssistedFactory interface Factory { fun create(): ShortcutCustomizationViewModel } companion object { private val SUPPORTED_MODIFIERS = listOf( Key.MetaLeft, Key.MetaRight, Key.CtrlRight, Key.CtrlLeft, Key.AltLeft, Key.AltRight, Key.ShiftLeft, Key.ShiftRight, Key.Function, Key.Symbol, ) } }