diff options
7 files changed, 298 insertions, 185 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepositoryTest.kt index f04540426fc1..0d32b7fb1b3e 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepositoryTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepositoryTest.kt @@ -18,36 +18,31 @@ package com.android.systemui.keyboard.shortcut.data.repository import android.content.Context import android.content.Context.INPUT_SERVICE -import android.hardware.input.InputGestureData -import android.hardware.input.InputGestureData.createKeyTrigger -import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS +import android.hardware.input.InputManager.CUSTOM_INPUT_GESTURE_RESULT_SUCCESS import android.hardware.input.fakeInputManager import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags -import android.view.KeyEvent.KEYCODE_A import android.view.KeyEvent.KEYCODE_SLASH -import android.view.KeyEvent.META_ALT_ON import android.view.KeyEvent.META_CAPS_LOCK_ON -import android.view.KeyEvent.META_CTRL_ON -import android.view.KeyEvent.META_FUNCTION_ON -import android.view.KeyEvent.META_META_LEFT_ON import android.view.KeyEvent.META_META_ON -import android.view.KeyEvent.META_SHIFT_ON -import android.view.KeyEvent.META_SHIFT_RIGHT_ON -import android.view.KeyEvent.META_SYM_ON import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.hardware.input.Flags.FLAG_ENABLE_CUSTOMIZABLE_INPUT_GESTURES import com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.keyboard.shared.model.ShortcutCustomizationRequestResult import com.android.systemui.keyboard.shortcut.customShortcutCategoriesRepository +import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.ALL_SUPPORTED_MODIFIERS +import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.allAppsInputGestureData import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.allCustomizableInputGesturesWithSimpleShortcutCombinations import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.customizableInputGestureWithUnknownKeyGestureType import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.expectedShortcutCategoriesWithSimpleShortcutCombination +import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.goHomeInputGestureData +import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.standardAddCustomShortcutRequestInfo +import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.standardDeleteCustomShortcutRequestInfo +import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.standardKeyCombination import com.android.systemui.keyboard.shortcut.shared.model.KeyCombination -import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType -import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCustomizationRequestInfo import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey import com.android.systemui.keyboard.shortcut.shortcutHelperTestHelper import com.android.systemui.kosmos.testScope @@ -74,24 +69,21 @@ class CustomShortcutCategoriesRepositoryTest : SysuiTestCase() { it.userTracker = FakeUserTracker(onCreateCurrentUserContext = { mockUserContext }) } - private val fakeInputManager = kosmos.fakeInputManager + private val inputManager = kosmos.fakeInputManager.inputManager private val testScope = kosmos.testScope private val helper = kosmos.shortcutHelperTestHelper private val repo = kosmos.customShortcutCategoriesRepository @Before fun setup() { - whenever(mockUserContext.getSystemService(INPUT_SERVICE)) - .thenReturn(fakeInputManager.inputManager) + whenever(mockUserContext.getSystemService(INPUT_SERVICE)).thenReturn(inputManager) } @Test @EnableFlags(FLAG_ENABLE_CUSTOMIZABLE_INPUT_GESTURES, FLAG_USE_KEY_GESTURE_EVENT_HANDLER) fun categories_emitsCorrectlyConvertedShortcutCategories() { testScope.runTest { - whenever( - fakeInputManager.inputManager.getCustomInputGestures(/* filter= */ anyOrNull()) - ) + whenever(inputManager.getCustomInputGestures(/* filter= */ anyOrNull())) .thenReturn(allCustomizableInputGesturesWithSimpleShortcutCombinations) helper.toggle(deviceId = 123) @@ -106,9 +98,7 @@ class CustomShortcutCategoriesRepositoryTest : SysuiTestCase() { @DisableFlags(FLAG_ENABLE_CUSTOMIZABLE_INPUT_GESTURES, FLAG_USE_KEY_GESTURE_EVENT_HANDLER) fun categories_emitsEmptyListWhenFlagIsDisabled() { testScope.runTest { - whenever( - fakeInputManager.inputManager.getCustomInputGestures(/* filter= */ anyOrNull()) - ) + whenever(inputManager.getCustomInputGestures(/* filter= */ anyOrNull())) .thenReturn(allCustomizableInputGesturesWithSimpleShortcutCombinations) helper.toggle(deviceId = 123) @@ -122,9 +112,7 @@ class CustomShortcutCategoriesRepositoryTest : SysuiTestCase() { @EnableFlags(FLAG_ENABLE_CUSTOMIZABLE_INPUT_GESTURES, FLAG_USE_KEY_GESTURE_EVENT_HANDLER) fun categories_ignoresUnknownKeyGestureTypes() { testScope.runTest { - whenever( - fakeInputManager.inputManager.getCustomInputGestures(/* filter= */ anyOrNull()) - ) + whenever(inputManager.getCustomInputGestures(/* filter= */ anyOrNull())) .thenReturn(customizableInputGestureWithUnknownKeyGestureType) helper.toggle(deviceId = 123) @@ -151,7 +139,7 @@ class CustomShortcutCategoriesRepositoryTest : SysuiTestCase() { helper.toggle(deviceId = 123) val pressedKeys by collectLastValue(repo.pressedKeys) repo.updateUserKeyCombination( - KeyCombination(modifiers = allSupportedModifiers, keyCode = null) + KeyCombination(modifiers = ALL_SUPPORTED_MODIFIERS, keyCode = null) ) assertThat(pressedKeys) @@ -199,11 +187,11 @@ class CustomShortcutCategoriesRepositoryTest : SysuiTestCase() { @Test fun shortcutBeingCustomized_updatedOnCustomizationRequested() { testScope.runTest { - repo.onCustomizationRequested(standardCustomizationRequestInfo) + repo.onCustomizationRequested(standardAddCustomShortcutRequestInfo) val shortcutBeingCustomized = repo.getShortcutBeingCustomized() - assertThat(shortcutBeingCustomized).isEqualTo(standardCustomizationRequestInfo) + assertThat(shortcutBeingCustomized).isEqualTo(standardAddCustomShortcutRequestInfo) } } @@ -223,7 +211,7 @@ class CustomShortcutCategoriesRepositoryTest : SysuiTestCase() { fun buildInputGestureDataForShortcutBeingCustomized_noKeyCombinationSelected_returnsNull() { testScope.runTest { helper.toggle(deviceId = 123) - repo.onCustomizationRequested(standardCustomizationRequestInfo) + repo.onCustomizationRequested(standardAddCustomShortcutRequestInfo) val inputGestureData = repo.buildInputGestureDataForShortcutBeingCustomized() @@ -235,46 +223,32 @@ class CustomShortcutCategoriesRepositoryTest : SysuiTestCase() { fun buildInputGestureDataForShortcutBeingCustomized_successfullyBuildInputGestureData() { testScope.runTest { helper.toggle(deviceId = 123) - repo.onCustomizationRequested(standardCustomizationRequestInfo) + repo.onCustomizationRequested(standardAddCustomShortcutRequestInfo) repo.updateUserKeyCombination(standardKeyCombination) val inputGestureData = repo.buildInputGestureDataForShortcutBeingCustomized() // using toString as we're testing for only structural equality not referential. // inputGestureData is a java class and isEqual Tests for referential equality // as well which would cause this assert to fail - assertThat(inputGestureData.toString()).isEqualTo(standardInputGestureData.toString()) + assertThat(inputGestureData.toString()).isEqualTo(allAppsInputGestureData.toString()) } } - private val standardCustomizationRequestInfo = - ShortcutCustomizationRequestInfo.Add( - label = "Open apps list", - categoryType = ShortcutCategoryType.System, - subCategoryLabel = "System controls", - ) - - private val standardKeyCombination = - KeyCombination( - modifiers = META_META_ON or META_SHIFT_ON or META_META_LEFT_ON or META_SHIFT_RIGHT_ON, - keyCode = KEYCODE_A, - ) - - private val allSupportedModifiers = - META_META_ON or - META_CTRL_ON or - META_FUNCTION_ON or - META_SHIFT_ON or - META_ALT_ON or - META_SYM_ON - - private val standardInputGestureData = - InputGestureData.Builder() - .setKeyGestureType(KEY_GESTURE_TYPE_ALL_APPS) - .setTrigger( - createKeyTrigger( - /* keycode = */ standardKeyCombination.keyCode!!, - /* modifierState = */ standardKeyCombination.modifiers and allSupportedModifiers, - ) - ) - .build() + @Test + @EnableFlags(FLAG_ENABLE_CUSTOMIZABLE_INPUT_GESTURES, FLAG_USE_KEY_GESTURE_EVENT_HANDLER) + fun deleteShortcut_successfullyRetrievesGestureDataAndDeletesShortcut() { + testScope.runTest { + whenever(inputManager.getCustomInputGestures(anyOrNull())) + .thenReturn(listOf(allAppsInputGestureData, goHomeInputGestureData)) + whenever(inputManager.removeCustomInputGesture(allAppsInputGestureData)) + .thenReturn(CUSTOM_INPUT_GESTURE_RESULT_SUCCESS) + + helper.toggle(deviceId = 123) + repo.onCustomizationRequested(standardDeleteCustomShortcutRequestInfo) + + val result = repo.deleteShortcutCurrentlyBeingCustomized() + + assertThat(result).isEqualTo(ShortcutCustomizationRequestResult.SUCCESS) + } + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt index a1e7ef4ac5a3..8466eab2aca6 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt @@ -19,9 +19,23 @@ package com.android.systemui.keyboard.shortcut.data.source import android.hardware.input.InputGestureData import android.hardware.input.InputGestureData.createKeyTrigger import android.hardware.input.KeyGestureEvent +import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS +import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_HOME +import android.os.SystemClock import android.view.KeyEvent +import android.view.KeyEvent.ACTION_DOWN +import android.view.KeyEvent.KEYCODE_A +import android.view.KeyEvent.META_ALT_ON +import android.view.KeyEvent.META_CTRL_ON +import android.view.KeyEvent.META_FUNCTION_ON +import android.view.KeyEvent.META_META_LEFT_ON +import android.view.KeyEvent.META_META_ON +import android.view.KeyEvent.META_SHIFT_ON +import android.view.KeyEvent.META_SHIFT_RIGHT_ON +import android.view.KeyEvent.META_SYM_ON import android.view.KeyboardShortcutGroup import android.view.KeyboardShortcutInfo +import com.android.systemui.keyboard.shortcut.shared.model.KeyCombination import com.android.systemui.keyboard.shortcut.shared.model.Shortcut import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType @@ -29,9 +43,11 @@ import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType. import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.MultiTasking import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.System import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCommand +import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCustomizationRequestInfo import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey import com.android.systemui.keyboard.shortcut.shared.model.ShortcutSubCategory import com.android.systemui.keyboard.shortcut.shared.model.shortcut +import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCustomizationUiState import com.android.systemui.res.R object TestShortcuts { @@ -525,4 +541,110 @@ object TestShortcuts { keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER ), ) + + val standardAddCustomShortcutRequestInfo = + ShortcutCustomizationRequestInfo.Add( + label = "Open apps list", + categoryType = System, + subCategoryLabel = "System controls", + ) + + val standardDeleteCustomShortcutRequestInfo = + ShortcutCustomizationRequestInfo.Delete( + label = "Open apps list", + categoryType = System, + subCategoryLabel = "System controls", + ) + + val standardKeyCombination = + KeyCombination( + modifiers = META_META_ON or META_SHIFT_ON or META_META_LEFT_ON or META_SHIFT_RIGHT_ON, + keyCode = KEYCODE_A, + ) + + const val ALL_SUPPORTED_MODIFIERS = + META_META_ON or + META_CTRL_ON or + META_FUNCTION_ON or + META_SHIFT_ON or + META_ALT_ON or + META_SYM_ON + + val allAppsInputGestureData: InputGestureData = + InputGestureData.Builder() + .setKeyGestureType(KEY_GESTURE_TYPE_ALL_APPS) + .setTrigger( + createKeyTrigger( + /* keycode = */ standardKeyCombination.keyCode!!, + /* modifierState = */ standardKeyCombination.modifiers and + ALL_SUPPORTED_MODIFIERS, + ) + ) + .build() + + val goHomeInputGestureData: InputGestureData = + InputGestureData.Builder() + .setKeyGestureType(KEY_GESTURE_TYPE_HOME) + .setTrigger( + createKeyTrigger( + /* keycode = */ standardKeyCombination.keyCode!!, + /* modifierState = */ standardKeyCombination.modifiers and + ALL_SUPPORTED_MODIFIERS, + ) + ) + .build() + + val expectedStandardDeleteShortcutUiState = + ShortcutCustomizationUiState.DeleteShortcutDialog(isDialogShowing = false) + + val keyDownEventWithoutActionKeyPressed = + androidx.compose.ui.input.key.KeyEvent( + android.view.KeyEvent( + /* downTime = */ SystemClock.uptimeMillis(), + /* eventTime = */ SystemClock.uptimeMillis(), + /* action = */ ACTION_DOWN, + /* code = */ KEYCODE_A, + /* repeat = */ 0, + /* metaState = */ META_CTRL_ON, + ) + ) + + val keyDownEventWithActionKeyPressed = + androidx.compose.ui.input.key.KeyEvent( + android.view.KeyEvent( + /* downTime = */ SystemClock.uptimeMillis(), + /* eventTime = */ SystemClock.uptimeMillis(), + /* action = */ ACTION_DOWN, + /* code = */ KEYCODE_A, + /* repeat = */ 0, + /* metaState = */ META_CTRL_ON or META_META_ON, + ) + ) + + val keyUpEventWithActionKeyPressed = + androidx.compose.ui.input.key.KeyEvent( + android.view.KeyEvent( + /* downTime = */ SystemClock.uptimeMillis(), + /* eventTime = */ SystemClock.uptimeMillis(), + /* action = */ ACTION_DOWN, + /* code = */ KEYCODE_A, + /* repeat = */ 0, + /* metaState = */ 0, + ) + ) + + val standardAddShortcutRequest = + ShortcutCustomizationRequestInfo.Add( + label = "Standard shortcut", + categoryType = ShortcutCategoryType.System, + subCategoryLabel = "Standard subcategory", + ) + + val expectedStandardAddShortcutUiState = + ShortcutCustomizationUiState.AddShortcutDialog( + shortcutLabel = "Standard shortcut", + defaultCustomShortcutModifierKey = + ShortcutKey.Icon.ResIdIcon(R.drawable.ic_ksh_key_meta), + isDialogShowing = false, + ) } diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepository.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepository.kt index 99cafd3daacb..321fd57d3e8b 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepository.kt @@ -28,6 +28,7 @@ import android.hardware.input.InputManager.CUSTOM_INPUT_GESTURE_RESULT_ERROR_RES import android.hardware.input.InputManager.CUSTOM_INPUT_GESTURE_RESULT_SUCCESS import android.hardware.input.InputSettings import android.hardware.input.KeyGestureEvent +import android.hardware.input.KeyGestureEvent.KeyGestureType import android.util.Log import androidx.annotation.VisibleForTesting import androidx.compose.runtime.mutableStateOf @@ -44,6 +45,8 @@ import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCustomization import com.android.systemui.keyboard.shortcut.shared.model.ShortcutHelperState.Active import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey import com.android.systemui.settings.UserTracker +import javax.inject.Inject +import kotlin.coroutines.CoroutineContext import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow @@ -52,8 +55,6 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.withContext -import javax.inject.Inject -import kotlin.coroutines.CoroutineContext @SysUISingleton class CustomShortcutCategoriesRepository @@ -65,7 +66,7 @@ constructor( @Background private val bgCoroutineContext: CoroutineContext, private val shortcutCategoriesUtils: ShortcutCategoriesUtils, private val context: Context, - private val inputGestureMaps: InputGestureMaps + private val inputGestureMaps: InputGestureMaps, ) : ShortcutCategoriesRepository { private val userContext: Context @@ -130,9 +131,7 @@ constructor( emptyList() } else { val customInputGesturesForUser: List<InputGestureData> = - if (InputSettings.isCustomizableInputGesturesFeatureFlagEnabled()) { - inputManager.getCustomInputGestures(/* filter= */ null) - } else emptyList() + getCustomInputGestures() val sources = toInternalGroupSources(customInputGesturesForUser) val supportedKeyCodes = shortcutCategoriesUtils.fetchSupportedKeyCodes( @@ -173,16 +172,20 @@ constructor( .addKeyGestureTypeFromShortcutLabel() .addTriggerFromSelectedKeyCombination() .build() - // TODO(b/379648200) add app launch data for application categories shortcut after - // dynamic - // label/icon mapping implementation + // TODO(b/379648200) add app launch data after dynamic label/icon mapping implementation } catch (e: IllegalArgumentException) { Log.w(TAG, "could not add custom shortcut: $e") return null } } - suspend fun confirmAndSetShortcutCurrentlyBeingCustomized(): ShortcutCustomizationRequestResult { + private fun retrieveInputGestureDataForShortcutBeingDeleted(): InputGestureData? { + val keyGestureType = getKeyGestureTypeFromShortcutBeingDeletedLabel() + return getCustomInputGestures().firstOrNull { it.action.keyGestureType() == keyGestureType } + } + + suspend fun confirmAndSetShortcutCurrentlyBeingCustomized(): + ShortcutCustomizationRequestResult { return withContext(bgCoroutineContext) { val inputGestureData = buildInputGestureDataForShortcutBeingCustomized() @@ -201,24 +204,79 @@ constructor( } } + suspend fun deleteShortcutCurrentlyBeingCustomized(): + ShortcutCustomizationRequestResult { + return withContext(bgCoroutineContext) { + val inputGestureData = + retrieveInputGestureDataForShortcutBeingDeleted() + ?: return@withContext ShortcutCustomizationRequestResult.ERROR_OTHER + return@withContext when ( + val result = inputManager.removeCustomInputGesture(inputGestureData) + ) { + CUSTOM_INPUT_GESTURE_RESULT_SUCCESS -> ShortcutCustomizationRequestResult.SUCCESS + else -> { + Log.w( + TAG, + "Attempted to delete shortcut being customized " + + "${_shortcutBeingCustomized.value} but ran into an error. InputGestureData" + + " = $inputGestureData, error code: $result", + ) + ShortcutCustomizationRequestResult.ERROR_OTHER + } + } + } + } + + private fun getCustomInputGestures(): List<InputGestureData> { + return if (InputSettings.isCustomizableInputGesturesFeatureFlagEnabled()) { + inputManager.getCustomInputGestures(/* filter= */ InputGestureData.Filter.KEY) + } else emptyList() + } + private fun Builder.addKeyGestureTypeFromShortcutLabel(): Builder { + val keyGestureType = getKeyGestureTypeFromShortcutBeingCustomizedLabel() + + if (keyGestureType == null) { + Log.w( + TAG, + "Could not find KeyGestureType for shortcut ${_shortcutBeingCustomized.value}", + ) + return this + } + + return setKeyGestureType(keyGestureType) + } + + @KeyGestureType + private fun getKeyGestureTypeFromShortcutBeingCustomizedLabel(): Int? { val shortcutBeingCustomized = getShortcutBeingCustomized() as? ShortcutCustomizationRequestInfo.Add if (shortcutBeingCustomized == null) { - Log.w(TAG, "User requested to set shortcut but shortcut being customized is null") - return this + Log.w( + TAG, + "Requested key gesture type from label but shortcut being customized is null", + ) + return null } - val keyGestureType = - inputGestureMaps.shortcutLabelToKeyGestureTypeMap[shortcutBeingCustomized.label] + return inputGestureMaps.shortcutLabelToKeyGestureTypeMap[shortcutBeingCustomized.label] + } - if (keyGestureType == null) { - Log.w(TAG, "Could not find KeyGestureType for shortcut $shortcutBeingCustomized") - return this + @KeyGestureType + private fun getKeyGestureTypeFromShortcutBeingDeletedLabel(): Int? { + val shortcutBeingCustomized = + getShortcutBeingCustomized() as? ShortcutCustomizationRequestInfo.Delete + + if (shortcutBeingCustomized == null) { + Log.w( + TAG, + "Requested key gesture type from label but shortcut being customized is null", + ) + return null } - return setKeyGestureType(keyGestureType) + return inputGestureMaps.shortcutLabelToKeyGestureTypeMap[shortcutBeingCustomized.label] } private fun Builder.addTriggerFromSelectedKeyCombination(): Builder { @@ -227,7 +285,7 @@ constructor( Log.w( TAG, "User requested to set shortcut but selected key combination is " + - "$selectedKeyCombination", + "$selectedKeyCombination", ) return this } @@ -235,8 +293,7 @@ constructor( return setTrigger( createKeyTrigger( /* keycode = */ selectedKeyCombination.keyCode, - /* modifierState = */ - shortcutCategoriesUtils.removeUnsupportedModifiers( + /* modifierState = */ shortcutCategoriesUtils.removeUnsupportedModifiers( selectedKeyCombination.modifiers ), ) @@ -256,10 +313,8 @@ constructor( val keyTrigger = gestureData.trigger as KeyTrigger val keyGestureType = gestureData.action.keyGestureType() fetchGroupLabelByGestureType(keyGestureType)?.let { groupLabel -> - toInternalKeyboardShortcutInfo( - keyGestureType, - keyTrigger - )?.let { internalKeyboardShortcutInfo -> + toInternalKeyboardShortcutInfo(keyGestureType, keyTrigger)?.let { + internalKeyboardShortcutInfo -> val group = InternalKeyboardShortcutGroup( label = groupLabel, diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutCustomizationInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutCustomizationInteractor.kt index f4e2f05379bb..7743c53c6900 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutCustomizationInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutCustomizationInteractor.kt @@ -41,7 +41,13 @@ constructor(private val customShortcutRepository: CustomShortcutCategoriesReposi customShortcutRepository.onCustomizationRequested(requestInfo) } - suspend fun confirmAndSetShortcutCurrentlyBeingCustomized(): ShortcutCustomizationRequestResult { + suspend fun confirmAndSetShortcutCurrentlyBeingCustomized(): + ShortcutCustomizationRequestResult { return customShortcutRepository.confirmAndSetShortcutCurrentlyBeingCustomized() } + + suspend fun deleteShortcutCurrentlyBeingCustomized(): + ShortcutCustomizationRequestResult { + return customShortcutRepository.deleteShortcutCurrentlyBeingCustomized() + } } diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt index 67caadba0d45..f28618bb8cf4 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt @@ -73,22 +73,17 @@ constructor( return dialogFactory.create(dialogDelegate = ShortcutCustomizationDialogDelegate()) { dialog -> val uiState by - viewModel.shortcutCustomizationUiState.collectAsStateWithLifecycle( - initialValue = ShortcutCustomizationUiState.Inactive - ) + viewModel.shortcutCustomizationUiState.collectAsStateWithLifecycle( + initialValue = ShortcutCustomizationUiState.Inactive + ) val coroutineScope = rememberCoroutineScope() ShortcutCustomizationDialog( uiState = uiState, - modifier = Modifier - .width(364.dp) - .wrapContentHeight() - .padding(vertical = 24.dp), + modifier = Modifier.width(364.dp).wrapContentHeight().padding(vertical = 24.dp), onKeyPress = { viewModel.onKeyPressed(it) }, onCancel = { dialog.dismiss() }, - onConfirmSetShortcut = { - coroutineScope.launch { viewModel.onSetShortcut() } - }, - onConfirmDeleteShortcut = { viewModel.onDeleteShortcut() }, + onConfirmSetShortcut = { coroutineScope.launch { viewModel.onSetShortcut() } }, + onConfirmDeleteShortcut = { coroutineScope.launch { viewModel.deleteShortcutCurrentlyBeingCustomized() } }, ) dialog.setOnDismissListener { viewModel.onDialogDismissed() } diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt index 869682742043..b467bb481443 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt @@ -79,8 +79,7 @@ constructor( } is ShortcutCustomizationRequestInfo.Delete -> { - _shortcutCustomizationUiState.value = - DeleteShortcutDialog(isDialogShowing = false) + _shortcutCustomizationUiState.value = DeleteShortcutDialog(isDialogShowing = false) shortcutCustomizationInteractor.onCustomizationRequested(requestInfo) } } @@ -134,17 +133,23 @@ constructor( } } - fun onDeleteShortcut() { - // TODO(b/373631984) not yet implemented + suspend fun deleteShortcutCurrentlyBeingCustomized() { + val result = + shortcutCustomizationInteractor.deleteShortcutCurrentlyBeingCustomized() + + _shortcutCustomizationUiState.update { uiState -> + when (result) { + ShortcutCustomizationRequestResult.SUCCESS -> ShortcutCustomizationUiState.Inactive + else -> uiState + } + } } private fun getUiStateWithErrorMessage( uiState: ShortcutCustomizationUiState, errorMessage: String, ): ShortcutCustomizationUiState { - return (uiState as? AddShortcutDialog)?.copy( - errorMessage = errorMessage - ) ?: uiState + return (uiState as? AddShortcutDialog)?.copy(errorMessage = errorMessage) ?: uiState } private fun updatePressedKeys(keyEvent: KeyEvent) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt index f706cf6980e1..d0ce34c2d68d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt @@ -23,18 +23,20 @@ import android.hardware.input.InputManager.CUSTOM_INPUT_GESTURE_RESULT_ERROR_OTH import android.hardware.input.InputManager.CUSTOM_INPUT_GESTURE_RESULT_ERROR_RESERVED_GESTURE import android.hardware.input.InputManager.CUSTOM_INPUT_GESTURE_RESULT_SUCCESS import android.hardware.input.fakeInputManager -import android.os.SystemClock -import android.view.KeyEvent.ACTION_DOWN -import android.view.KeyEvent.KEYCODE_A -import android.view.KeyEvent.META_CTRL_ON -import android.view.KeyEvent.META_META_ON -import androidx.compose.ui.input.key.KeyEvent import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue -import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType -import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCustomizationRequestInfo +import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.allAppsInputGestureData +import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.expectedStandardAddShortcutUiState +import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.expectedStandardDeleteShortcutUiState +import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.goHomeInputGestureData +import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.keyDownEventWithActionKeyPressed +import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.keyDownEventWithoutActionKeyPressed +import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.keyUpEventWithActionKeyPressed +import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.standardAddCustomShortcutRequestInfo +import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.standardAddShortcutRequest +import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.standardDeleteCustomShortcutRequestInfo import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey import com.android.systemui.keyboard.shortcut.shortcutCustomizationViewModelFactory import com.android.systemui.keyboard.shortcut.shortcutHelperTestHelper @@ -97,7 +99,7 @@ class ShortcutCustomizationViewModelTest : SysuiTestCase() { @Test fun uiState_correctlyUpdatedWhenDeleteShortcutCustomizationIsRequested() { testScope.runTest { - viewModel.onShortcutCustomizationRequested(standardDeleteShortcutRequest) + viewModel.onShortcutCustomizationRequested(standardDeleteCustomShortcutRequestInfo) val uiState by collectLastValue(viewModel.shortcutCustomizationUiState) assertThat(uiState).isEqualTo(expectedStandardDeleteShortcutUiState) @@ -120,7 +122,7 @@ class ShortcutCustomizationViewModelTest : SysuiTestCase() { fun uiState_consumedOnDeleteDialogShown() { testScope.runTest { val uiState by collectLastValue(viewModel.shortcutCustomizationUiState) - viewModel.onShortcutCustomizationRequested(standardDeleteShortcutRequest) + viewModel.onShortcutCustomizationRequested(standardDeleteCustomShortcutRequestInfo) viewModel.onDialogShown() assertThat( @@ -168,7 +170,7 @@ class ShortcutCustomizationViewModelTest : SysuiTestCase() { fun uiState_errorMessage_isEmptyByDefault() { testScope.runTest { val uiState by collectLastValue(viewModel.shortcutCustomizationUiState) - viewModel.onShortcutCustomizationRequested(allAppsShortcutCustomizationRequest) + viewModel.onShortcutCustomizationRequested(standardAddCustomShortcutRequestInfo) viewModel.onDialogShown() assertThat((uiState as ShortcutCustomizationUiState.AddShortcutDialog).errorMessage) @@ -227,6 +229,21 @@ class ShortcutCustomizationViewModelTest : SysuiTestCase() { } @Test + fun uiState_becomesInactiveAfterSuccessfullyDeletingShortcut() { + testScope.runTest { + val uiState by collectLastValue(viewModel.shortcutCustomizationUiState) + whenever(inputManager.getCustomInputGestures(any())) + .thenReturn(listOf(goHomeInputGestureData, allAppsInputGestureData)) + whenever(inputManager.removeCustomInputGesture(any())) + .thenReturn(CUSTOM_INPUT_GESTURE_RESULT_SUCCESS) + + openDeleteShortcutDialogAndDeleteShortcut() + + assertThat(uiState).isEqualTo(ShortcutCustomizationUiState.Inactive) + } + } + + @Test fun onKeyPressed_handlesKeyEvents_whereActionKeyIsAlsoPressed() { testScope.runTest { viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest) @@ -281,7 +298,7 @@ class ShortcutCustomizationViewModelTest : SysuiTestCase() { } private suspend fun openAddShortcutDialogAndSetShortcut() { - viewModel.onShortcutCustomizationRequested(allAppsShortcutCustomizationRequest) + viewModel.onShortcutCustomizationRequested(standardAddCustomShortcutRequestInfo) viewModel.onDialogShown() viewModel.onKeyPressed(keyDownEventWithActionKeyPressed) @@ -290,71 +307,10 @@ class ShortcutCustomizationViewModelTest : SysuiTestCase() { viewModel.onSetShortcut() } - private val keyDownEventWithoutActionKeyPressed = - KeyEvent( - android.view.KeyEvent( - /* downTime = */ SystemClock.uptimeMillis(), - /* eventTime = */ SystemClock.uptimeMillis(), - /* action = */ ACTION_DOWN, - /* code = */ KEYCODE_A, - /* repeat = */ 0, - /* metaState = */ META_CTRL_ON, - ) - ) - - private val keyDownEventWithActionKeyPressed = - KeyEvent( - android.view.KeyEvent( - /* downTime = */ SystemClock.uptimeMillis(), - /* eventTime = */ SystemClock.uptimeMillis(), - /* action = */ ACTION_DOWN, - /* code = */ KEYCODE_A, - /* repeat = */ 0, - /* metaState = */ META_CTRL_ON or META_META_ON, - ) - ) - - private val keyUpEventWithActionKeyPressed = - KeyEvent( - android.view.KeyEvent( - /* downTime = */ SystemClock.uptimeMillis(), - /* eventTime = */ SystemClock.uptimeMillis(), - /* action = */ ACTION_DOWN, - /* code = */ KEYCODE_A, - /* repeat = */ 0, - /* metaState = */ 0, - ) - ) - - private val standardAddShortcutRequest = - ShortcutCustomizationRequestInfo.Add( - label = "Standard shortcut", - categoryType = ShortcutCategoryType.System, - subCategoryLabel = "Standard subcategory", - ) - - private val standardDeleteShortcutRequest = - ShortcutCustomizationRequestInfo.Delete( - label = "Standard shortcut", - categoryType = ShortcutCategoryType.System, - subCategoryLabel = "Standard subcategory", - ) - - private val allAppsShortcutCustomizationRequest = - ShortcutCustomizationRequestInfo.Add( - label = "Open apps list", - categoryType = ShortcutCategoryType.System, - subCategoryLabel = "System controls", - ) - - private val expectedStandardAddShortcutUiState = - ShortcutCustomizationUiState.AddShortcutDialog( - shortcutLabel = "Standard shortcut", - defaultCustomShortcutModifierKey = - ShortcutKey.Icon.ResIdIcon(R.drawable.ic_ksh_key_meta), - isDialogShowing = false, - ) - - private val expectedStandardDeleteShortcutUiState = - ShortcutCustomizationUiState.DeleteShortcutDialog(isDialogShowing = false) + private suspend fun openDeleteShortcutDialogAndDeleteShortcut() { + viewModel.onShortcutCustomizationRequested(standardDeleteCustomShortcutRequestInfo) + viewModel.onDialogShown() + + viewModel.deleteShortcutCurrentlyBeingCustomized() + } } |