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

Commit 0f1123b5 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "[Custom Key Glyph] Retrieve key glyph in Shortcut Helper" into main

parents 703e9559 515afbe8
Loading
Loading
Loading
Loading
+114 −0
Original line number Diff line number Diff line
@@ -16,7 +16,11 @@

package com.android.systemui.keyboard.shortcut.data.repository

import android.graphics.drawable.Drawable
import android.hardware.input.KeyGlyphMap
import android.hardware.input.fakeInputManager
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.view.KeyEvent.KEYCODE_1
import android.view.KeyEvent.KEYCODE_A
import android.view.KeyEvent.KEYCODE_B
@@ -26,10 +30,12 @@ import android.view.KeyEvent.KEYCODE_E
import android.view.KeyEvent.KEYCODE_F
import android.view.KeyEvent.KEYCODE_G
import android.view.KeyEvent.META_FUNCTION_ON
import android.view.KeyEvent.META_META_ON
import android.view.KeyboardShortcutGroup
import android.view.KeyboardShortcutInfo
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.Flags.FLAG_SHORTCUT_HELPER_KEY_GLYPH
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyboard.shortcut.data.source.FakeKeyboardShortcutGroupsSource
@@ -49,6 +55,7 @@ import com.android.systemui.keyboard.shortcut.shortcutHelperSystemShortcutsSourc
import com.android.systemui.keyboard.shortcut.shortcutHelperTestHelper
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
import com.android.systemui.res.R
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -57,6 +64,9 @@ import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mockito.mock
import org.mockito.kotlin.whenever

@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@@ -187,6 +197,79 @@ class ShortcutHelperCategoriesRepositoryTest : SysuiTestCase() {
                )
        }

    @EnableFlags(FLAG_SHORTCUT_HELPER_KEY_GLYPH)
    @Test
    fun modifierMappedToCustomDrawableWhenKeyGlyphMapExists() =
        testScope.runTest {
            val metaDrawable = mock(Drawable::class.java)
            val keyGlyph = mock(KeyGlyphMap::class.java)
            whenever(keyGlyph.getDrawableForModifierState(context, META_META_ON))
                .thenReturn(metaDrawable)
            whenever(kosmos.fakeInputManager.inputManager.getKeyGlyphMap(anyInt()))
                .thenReturn(keyGlyph)
            fakeSystemSource.setGroups(simpleGroup(simpleShortcutInfo(KEYCODE_1, META_META_ON)))
            helper.toggle(deviceId = 123)

            val categories by collectLastValue(repo.categories)
            val systemCategory = categories?.firstOrNull { it.type == ShortcutCategoryType.System }

            val expectedCategory =
                ShortcutCategory(
                    type = ShortcutCategoryType.System,
                    simpleSubCategory(
                        simpleDrawableModifierShortcut("1", modifierDrawable = metaDrawable)
                    ),
                )

            assertThat(systemCategory).isEqualTo(expectedCategory)
        }

    @EnableFlags(FLAG_SHORTCUT_HELPER_KEY_GLYPH)
    @Test
    fun modifierMappedToDefaultDrawableWhenNoKeyGlyphMapExists() =
        testScope.runTest {
            fakeSystemSource.setGroups(simpleGroup(simpleShortcutInfo(KEYCODE_1, META_META_ON)))
            helper.toggle(deviceId = 123)

            val categories by collectLastValue(repo.categories)
            val systemCategory = categories?.firstOrNull { it.type == ShortcutCategoryType.System }

            val expectedCategory =
                ShortcutCategory(
                    type = ShortcutCategoryType.System,
                    simpleSubCategory(
                        simpleResIdModifierShortcut("1", modifierResId = R.drawable.ic_ksh_key_meta)
                    ),
                )
            assertThat(systemCategory).isEqualTo(expectedCategory)
        }

    @DisableFlags(FLAG_SHORTCUT_HELPER_KEY_GLYPH)
    @Test
    fun modifierMappedToDefaultDrawableWhenKeyGlyphDisabled() =
        testScope.runTest {
            val metaDrawable = mock(Drawable::class.java)
            val keyGlyph = mock(KeyGlyphMap::class.java)
            whenever(keyGlyph.getDrawableForModifierState(context, META_META_ON))
                .thenReturn(metaDrawable)
            whenever(kosmos.fakeInputManager.inputManager.getKeyGlyphMap(anyInt()))
                .thenReturn(keyGlyph)
            fakeSystemSource.setGroups(simpleGroup(simpleShortcutInfo(KEYCODE_1, META_META_ON)))
            helper.toggle(deviceId = 123)

            val categories by collectLastValue(repo.categories)
            val systemCategory = categories?.firstOrNull { it.type == ShortcutCategoryType.System }

            val expectedCategory =
                ShortcutCategory(
                    type = ShortcutCategoryType.System,
                    simpleSubCategory(
                        simpleResIdModifierShortcut("1", modifierResId = R.drawable.ic_ksh_key_meta)
                    ),
                )
            assertThat(systemCategory).isEqualTo(expectedCategory)
        }

    private fun simpleSubCategory(vararg shortcuts: Shortcut) =
        ShortcutSubCategory(simpleGroupLabel, shortcuts.asList())

@@ -196,6 +279,37 @@ class ShortcutHelperCategoriesRepositoryTest : SysuiTestCase() {
            commands = listOf(ShortcutCommand(keys.map { ShortcutKey.Text(it) })),
        )

    private fun simpleDrawableModifierShortcut(
        vararg keys: String,
        modifierDrawable: Drawable,
    ): Shortcut {
        val keyShortcuts = keys.map { ShortcutKey.Text(it) }
        return Shortcut(
            label = simpleShortcutLabel,
            commands =
                listOf(
                    ShortcutCommand(
                        listOf(ShortcutKey.Icon.DrawableIcon(drawable = modifierDrawable)) +
                            keyShortcuts
                    )
                ),
        )
    }

    private fun simpleResIdModifierShortcut(vararg keys: String, modifierResId: Int): Shortcut {
        val keyShortcuts = keys.map { ShortcutKey.Text(it) }
        return Shortcut(
            label = simpleShortcutLabel,
            commands =
                listOf(
                    ShortcutCommand(
                        listOf(ShortcutKey.Icon.ResIdIcon(drawableResId = modifierResId)) +
                            keyShortcuts
                    )
                ),
        )
    }

    private fun simpleGroup(vararg shortcuts: KeyboardShortcutInfo) =
        KeyboardShortcutGroup(simpleGroupLabel, shortcuts.asList())

+31 −7
Original line number Diff line number Diff line
@@ -19,12 +19,14 @@ package com.android.systemui.keyboard.shortcut.data.repository
import android.content.Context
import android.graphics.drawable.Icon
import android.hardware.input.InputManager
import android.hardware.input.KeyGlyphMap
import android.util.Log
import android.view.InputDevice
import android.view.KeyCharacterMap
import android.view.KeyEvent
import android.view.KeyboardShortcutGroup
import android.view.KeyboardShortcutInfo
import com.android.systemui.Flags.shortcutHelperKeyGlyph
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.keyboard.shortcut.data.source.KeyboardShortcutGroupsSource
@@ -142,7 +144,10 @@ constructor(
        return if (type == null) {
            null
        } else {
            val keyGlyphMap =
                if (shortcutHelperKeyGlyph()) inputManager.getKeyGlyphMap(inputDevice.id) else null
            toShortcutCategory(
                keyGlyphMap,
                inputDevice.keyCharacterMap,
                type,
                groups,
@@ -163,6 +168,7 @@ constructor(
    }

    private fun toShortcutCategory(
        keyGlyphMap: KeyGlyphMap?,
        keyCharacterMap: KeyCharacterMap,
        type: ShortcutCategoryType,
        shortcutGroups: List<KeyboardShortcutGroup>,
@@ -175,6 +181,7 @@ constructor(
                    ShortcutSubCategory(
                        shortcutGroup.label.toString(),
                        toShortcuts(
                            keyGlyphMap,
                            keyCharacterMap,
                            shortcutGroup.items,
                            keepIcons,
@@ -192,6 +199,7 @@ constructor(
    }

    private fun toShortcuts(
        keyGlyphMap: KeyGlyphMap?,
        keyCharacterMap: KeyCharacterMap,
        infoList: List<KeyboardShortcutInfo>,
        keepIcons: Boolean,
@@ -203,14 +211,16 @@ constructor(
                // keycode, or they could have a baseCharacter instead of a keycode.
                it.keycode == KeyEvent.KEYCODE_UNKNOWN || supportedKeyCodes.contains(it.keycode)
            }
            .mapNotNull { toShortcut(keyCharacterMap, it, keepIcons) }
            .mapNotNull { toShortcut(keyGlyphMap, keyCharacterMap, it, keepIcons) }

    private fun toShortcut(
        keyGlyphMap: KeyGlyphMap?,
        keyCharacterMap: KeyCharacterMap,
        shortcutInfo: KeyboardShortcutInfo,
        keepIcon: Boolean,
    ): Shortcut? {
        val shortcutCommand = toShortcutCommand(keyCharacterMap, shortcutInfo) ?: return null
        val shortcutCommand =
            toShortcutCommand(keyGlyphMap, keyCharacterMap, shortcutInfo) ?: return null
        return Shortcut(
            label = shortcutInfo.label!!.toString(),
            icon = toShortcutIcon(keepIcon, shortcutInfo),
@@ -235,6 +245,7 @@ constructor(
    }

    private fun toShortcutCommand(
        keyGlyphMap: KeyGlyphMap?,
        keyCharacterMap: KeyCharacterMap,
        info: KeyboardShortcutInfo,
    ): ShortcutCommand? {
@@ -242,7 +253,7 @@ constructor(
        var remainingModifiers = info.modifiers
        SUPPORTED_MODIFIERS.forEach { supportedModifier ->
            if ((supportedModifier and remainingModifiers) != 0) {
                keys += toShortcutModifierKey(supportedModifier) ?: return null
                keys += toShortcutModifierKey(keyGlyphMap, supportedModifier) ?: return null
                // "Remove" the modifier from the remaining modifiers
                remainingModifiers = remainingModifiers and supportedModifier.inv()
            }
@@ -253,7 +264,9 @@ constructor(
            return null
        }
        if (info.keycode != 0 || info.baseCharacter > Char.MIN_VALUE) {
            keys += toShortcutKey(keyCharacterMap, info.keycode, info.baseCharacter) ?: return null
            keys +=
                toShortcutKey(keyGlyphMap, keyCharacterMap, info.keycode, info.baseCharacter)
                    ?: return null
        }
        if (keys.isEmpty()) {
            Log.wtf(TAG, "No keys for $info")
@@ -262,10 +275,15 @@ constructor(
        return ShortcutCommand(keys)
    }

    private fun toShortcutModifierKey(modifierMask: Int): ShortcutKey? {
    private fun toShortcutModifierKey(keyGlyphMap: KeyGlyphMap?, modifierMask: Int): ShortcutKey? {
        val modifierDrawable = keyGlyphMap?.getDrawableForModifierState(context, modifierMask)
        if (modifierDrawable != null) {
            return ShortcutKey.Icon.DrawableIcon(drawable = modifierDrawable)
        }

        val iconResId = ShortcutHelperKeys.keyIcons[modifierMask]
        if (iconResId != null) {
            return ShortcutKey.Icon(iconResId)
            return ShortcutKey.Icon.ResIdIcon(iconResId)
        }

        val modifierLabel = ShortcutHelperKeys.modifierLabels[modifierMask]
@@ -277,13 +295,19 @@ constructor(
    }

    private fun toShortcutKey(
        keyGlyphMap: KeyGlyphMap?,
        keyCharacterMap: KeyCharacterMap,
        keyCode: Int,
        baseCharacter: Char = Char.MIN_VALUE,
    ): ShortcutKey? {
        val keycodeDrawable = keyGlyphMap?.getDrawableForKeycode(context, keyCode)
        if (keycodeDrawable != null) {
            return ShortcutKey.Icon.DrawableIcon(drawable = keycodeDrawable)
        }

        val iconResId = ShortcutHelperKeys.keyIcons[keyCode]
        if (iconResId != null) {
            return ShortcutKey.Icon(iconResId)
            return ShortcutKey.Icon.ResIdIcon(iconResId)
        }
        if (baseCharacter > Char.MIN_VALUE) {
            return ShortcutKey.Text(baseCharacter.uppercase())
+1 −1
Original line number Diff line number Diff line
@@ -28,7 +28,7 @@ class ShortcutCommandBuilder {
    }

    fun key(@DrawableRes drawableResId: Int) {
        keys += ShortcutKey.Icon(drawableResId)
        keys += ShortcutKey.Icon.ResIdIcon(drawableResId)
    }

    fun build() = ShortcutCommand(keys)
+6 −1
Original line number Diff line number Diff line
@@ -16,10 +16,15 @@

package com.android.systemui.keyboard.shortcut.shared.model

import android.graphics.drawable.Drawable
import androidx.annotation.DrawableRes

sealed interface ShortcutKey {
    data class Text(val value: String) : ShortcutKey

    data class Icon(@DrawableRes val drawableResId: Int) : ShortcutKey
    sealed interface Icon : ShortcutKey {
        data class ResIdIcon(@DrawableRes val drawableResId: Int) : Icon

        data class DrawableIcon(val drawable: Drawable) : Icon
    }
}
+5 −1
Original line number Diff line number Diff line
@@ -647,7 +647,11 @@ private fun BoxScope.ShortcutTextKey(key: ShortcutKey.Text) {
@Composable
private fun BoxScope.ShortcutIconKey(key: ShortcutKey.Icon) {
    Icon(
        painter = painterResource(key.drawableResId),
        painter =
            when (key) {
                is ShortcutKey.Icon.ResIdIcon -> painterResource(key.drawableResId)
                is ShortcutKey.Icon.DrawableIcon -> rememberDrawablePainter(drawable = key.drawable)
            },
        contentDescription = null,
        modifier = Modifier.align(Alignment.Center).padding(6.dp),
    )