Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e575477a authored by Josh's avatar Josh
Browse files

Added Tests for custom shortcut registration logic

+ refactored code to make classes more testable.

Test: CustomShortcutCategoriesRepositoryTest
Test: ShortcutCustomizationViewModelTest
Flag: com.android.systemui.keyboard_shortcut_helper_shortcut_customizer
Fix: 373631227

Change-Id: Icbcf21a3b4bf4e2f52e7dcb09264e287b2882e8f
parent 373ae848
Loading
Loading
Loading
Loading
+82 −0
Original line number Diff line number Diff line
@@ -18,16 +18,22 @@ 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.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
@@ -40,6 +46,8 @@ import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.allCusto
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.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
@@ -188,6 +196,69 @@ class CustomShortcutCategoriesRepositoryTest : SysuiTestCase() {
        }
    }

    @Test
    fun shortcutBeingCustomized_updatedOnCustomizationRequested() {
        testScope.runTest {
            repo.onCustomizationRequested(standardCustomizationRequestInfo)

            val shortcutBeingCustomized = repo.getShortcutBeingCustomized()

            assertThat(shortcutBeingCustomized).isEqualTo(standardCustomizationRequestInfo)
        }
    }

    @Test
    fun buildInputGestureDataForShortcutBeingCustomized_noShortcutBeingCustomized_returnsNull() {
        testScope.runTest {
            helper.toggle(deviceId = 123)
            repo.updateUserKeyCombination(standardKeyCombination)

            val inputGestureData = repo.buildInputGestureDataForShortcutBeingCustomized()

            assertThat(inputGestureData).isNull()
        }
    }

    @Test
    fun buildInputGestureDataForShortcutBeingCustomized_noKeyCombinationSelected_returnsNull() {
        testScope.runTest {
            helper.toggle(deviceId = 123)
            repo.onCustomizationRequested(standardCustomizationRequestInfo)

            val inputGestureData = repo.buildInputGestureDataForShortcutBeingCustomized()

            assertThat(inputGestureData).isNull()
        }
    }

    @Test
    fun buildInputGestureDataForShortcutBeingCustomized_successfullyBuildInputGestureData() {
        testScope.runTest {
            helper.toggle(deviceId = 123)
            repo.onCustomizationRequested(standardCustomizationRequestInfo)
            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())
        }
    }

    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
@@ -195,4 +266,15 @@ class CustomShortcutCategoriesRepositoryTest : SysuiTestCase() {
            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()
}
+2 −3
Original line number Diff line number Diff line
@@ -3817,18 +3817,17 @@
    <!-- Error message displayed when the user select a key combination that is already in use while
         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>
    <string name="shortcut_customizer_key_combination_in_use_error_message">Key combination already in use. Try another key.</string>
    <!-- Generic error message displayed when the user selected key combination cannot be used as
         custom keyboard shortcut in shortcut helper. The helper is a component that shows the user
         which keyboard shortcuts they can use and allows users to customize their keyboard
         shortcuts. [CHAR LIMIT=NONE] -->
    <string name="shortcut_helper_customize_generic_error_message">Shortcut cannot be set.</string>
    <string name="shortcut_customizer_generic_error_message">Shortcut cannot be set.</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-->
    <!-- Notification title for launching keyboard tutorial [CHAR_LIMIT=100] -->
    <string name="launch_keyboard_tutorial_notification_title">Navigate using your keyboard</string>
+1 −3
Original line number Diff line number Diff line
@@ -18,8 +18,6 @@ package com.android.systemui.keyboard.shared.model

enum class ShortcutCustomizationRequestResult {
    SUCCESS,
    ERROR_ALREADY_EXISTS,
    ERROR_DOES_NOT_EXIST,
    ERROR_RESERVED_SHORTCUT,
    ERROR_RESERVED_COMBINATION,
    ERROR_OTHER,
}
+36 −27
Original line number Diff line number Diff line
@@ -24,12 +24,12 @@ import android.hardware.input.InputGestureData.KeyTrigger
import android.hardware.input.InputGestureData.createKeyTrigger
import android.hardware.input.InputManager
import android.hardware.input.InputManager.CUSTOM_INPUT_GESTURE_RESULT_ERROR_ALREADY_EXISTS
import android.hardware.input.InputManager.CUSTOM_INPUT_GESTURE_RESULT_ERROR_DOES_NOT_EXIST
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.InputSettings
import android.hardware.input.KeyGestureEvent
import android.util.Log
import androidx.annotation.VisibleForTesting
import androidx.compose.runtime.mutableStateOf
import com.android.systemui.Flags.shortcutHelperKeyGlyph
import com.android.systemui.dagger.SysUISingleton
@@ -166,40 +166,44 @@ constructor(
        _shortcutBeingCustomized.value = requestInfo
    }

    @VisibleForTesting
    fun buildInputGestureDataForShortcutBeingCustomized(): InputGestureData? {
        try {
            return Builder()
                .addKeyGestureTypeFromShortcutLabel()
                .addTriggerFromSelectedKeyCombination()
                .build()
            // TODO(b/379648200) add app launch data for application categories shortcut after
            // dynamic
            // label/icon mapping implementation
        } catch (e: IllegalArgumentException) {
            Log.w(TAG, "could not add custom shortcut: $e")
            return null
        }
    }

    suspend fun confirmAndSetShortcutCurrentlyBeingCustomized(): ShortcutCustomizationRequestResult {
        return withContext(bgCoroutineContext) {
            val builder =
                Builder().addKeyGestureTypeFromShortcutLabel()
                    .addTriggerFromSelectedKeyCombination()
            val inputGestureData =
                buildInputGestureDataForShortcutBeingCustomized()
                    ?: return@withContext ShortcutCustomizationRequestResult.ERROR_OTHER

            // TODO(b/379648200) add app launch data for application categories shortcut after dynamic
            // label mapping implementation
            try {
                val inputGestureData = builder.build()
                val result = inputManager.addCustomInputGesture(inputGestureData)
                return@withContext when (result) {
            return@withContext when (inputManager.addCustomInputGesture(inputGestureData)) {
                CUSTOM_INPUT_GESTURE_RESULT_SUCCESS -> ShortcutCustomizationRequestResult.SUCCESS
                CUSTOM_INPUT_GESTURE_RESULT_ERROR_ALREADY_EXISTS ->
                        ShortcutCustomizationRequestResult.ERROR_ALREADY_EXISTS

                    CUSTOM_INPUT_GESTURE_RESULT_ERROR_DOES_NOT_EXIST ->
                        ShortcutCustomizationRequestResult.ERROR_DOES_NOT_EXIST
                    ShortcutCustomizationRequestResult.ERROR_RESERVED_COMBINATION

                CUSTOM_INPUT_GESTURE_RESULT_ERROR_RESERVED_GESTURE ->
                        ShortcutCustomizationRequestResult.ERROR_RESERVED_SHORTCUT
                    ShortcutCustomizationRequestResult.ERROR_RESERVED_COMBINATION

                else -> ShortcutCustomizationRequestResult.ERROR_OTHER
            }
            } catch (e: IllegalArgumentException) {
                Log.w(TAG, "could not add custom shortcut: $e")
                return@withContext ShortcutCustomizationRequestResult.ERROR_OTHER
            }
        }
    }

    private fun Builder.addKeyGestureTypeFromShortcutLabel(): Builder {
        val shortcutBeingCustomized =
            _shortcutBeingCustomized.value as? ShortcutCustomizationRequestInfo.Add
            getShortcutBeingCustomized() as? ShortcutCustomizationRequestInfo.Add

        if (shortcutBeingCustomized == null) {
            Log.w(TAG, "User requested to set shortcut but shortcut being customized is null")
@@ -239,6 +243,11 @@ constructor(
        )
    }

    @VisibleForTesting
    fun getShortcutBeingCustomized(): ShortcutCustomizationRequestInfo? {
        return _shortcutBeingCustomized.value
    }

    private fun toInternalGroupSources(
        inputGestures: List<InputGestureData>
    ): List<InternalGroupsSource> {
+3 −21
Original line number Diff line number Diff line
@@ -106,38 +106,20 @@ constructor(
        _shortcutCustomizationUiState.update { uiState ->
            when (result) {
                ShortcutCustomizationRequestResult.SUCCESS -> ShortcutCustomizationUiState.Inactive
                ShortcutCustomizationRequestResult.ERROR_ALREADY_EXISTS -> {
                ShortcutCustomizationRequestResult.ERROR_RESERVED_COMBINATION -> {
                    getUiStateWithErrorMessage(
                        uiState = uiState,
                        errorMessage =
                            context.getString(
                                R.string.shortcut_helper_customize_dialog_error_message
                                R.string.shortcut_customizer_key_combination_in_use_error_message
                            ),
                    )
                }
                ShortcutCustomizationRequestResult.ERROR_DOES_NOT_EXIST ->
                    getUiStateWithErrorMessage(
                        uiState = uiState,
                        errorMessage =
                            context.getString(
                                R.string.shortcut_helper_customize_generic_error_message
                            ),
                    )
                ShortcutCustomizationRequestResult.ERROR_RESERVED_SHORTCUT ->
                    getUiStateWithErrorMessage(
                        uiState = uiState,
                        errorMessage =
                            context.getString(
                                R.string.shortcut_helper_customize_dialog_error_message
                            ),
                    )
                ShortcutCustomizationRequestResult.ERROR_OTHER ->
                    getUiStateWithErrorMessage(
                        uiState = uiState,
                        errorMessage =
                            context.getString(
                                R.string.shortcut_helper_customize_generic_error_message
                            ),
                            context.getString(R.string.shortcut_customizer_generic_error_message),
                    )
            }
        }
Loading