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

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

Merge changes I09c162e3,I4af5b80f into main

* changes:
  Shortcut Helper - Add "back", "home", and "recents" keys in system shortcuts
  Shortcut Helper - Filter shortcut commands containing unsupported keys
parents 724e8774 2121faff
Loading
Loading
Loading
Loading
+24 −0
Original line number Diff line number Diff line
<!--
  ~ 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.
  -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportHeight="960"
    android:viewportWidth="960">
    <path
        android:fillColor="#000"
        android:pathData="M640,760L200,480L640,200L640,760ZM560,480L560,480L560,480ZM560,614L560,346L350,480L560,614Z" />
</vector>
 No newline at end of file
+24 −0
Original line number Diff line number Diff line
<!--
  ~ 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.
  -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="960"
    android:viewportHeight="960">
    <path
        android:fillColor="#000"
        android:pathData="M200,840Q167,840 143.5,816.5Q120,793 120,760L120,200Q120,167 143.5,143.5Q167,120 200,120L760,120Q793,120 816.5,143.5Q840,167 840,200L840,760Q840,793 816.5,816.5Q793,840 760,840L200,840ZM200,760L760,760Q760,760 760,760Q760,760 760,760L760,200Q760,200 760,200Q760,200 760,200L200,200Q200,200 200,200Q200,200 200,200L200,760Q200,760 200,760Q200,760 200,760Z"/>
</vector>
+24 −0
Original line number Diff line number Diff line
<!--
  ~ 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.
  -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="960"
    android:viewportHeight="960">
    <path
        android:fillColor="#000"
        android:pathData="M480,880Q397,880 324,848.5Q251,817 197,763Q143,709 111.5,636Q80,563 80,480Q80,397 111.5,324Q143,251 197,197Q251,143 324,111.5Q397,80 480,80Q563,80 636,111.5Q709,143 763,197Q817,251 848.5,324Q880,397 880,480Q880,563 848.5,636Q817,709 763,763Q709,817 636,848.5Q563,880 480,880ZM480,800Q614,800 707,707Q800,614 800,480Q800,346 707,253Q614,160 480,160Q346,160 253,253Q160,346 160,480Q160,614 253,707Q346,800 480,800ZM480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Z"/>
</vector>
+92 −50
Original line number Diff line number Diff line
@@ -71,6 +71,35 @@ constructor(
    stateRepository: ShortcutHelperStateRepository
) {

    private val sources =
        listOf(
            InternalGroupsSource(
                source = systemShortcutsSource,
                isTrusted = true,
                typeProvider = { System }
            ),
            InternalGroupsSource(
                source = multitaskingShortcutsSource,
                isTrusted = true,
                typeProvider = { MultiTasking }
            ),
            InternalGroupsSource(
                source = appCategoriesShortcutsSource,
                isTrusted = true,
                typeProvider = { AppCategories }
            ),
            InternalGroupsSource(
                source = inputShortcutsSource,
                isTrusted = false,
                typeProvider = { InputMethodEditor }
            ),
            InternalGroupsSource(
                source = currentAppShortcutsSource,
                isTrusted = false,
                typeProvider = { groups -> getCurrentAppShortcutCategoryType(groups) }
            ),
        )

    private val activeInputDevice =
        stateRepository.state.map {
            if (it is Active) {
@@ -82,67 +111,43 @@ constructor(

    val categories: Flow<List<ShortcutCategory>> =
        activeInputDevice
            .map {
                if (it == null) {
            .map { inputDevice ->
                if (inputDevice == null) {
                    return@map emptyList()
                }
                return@map listOfNotNull(
                    fetchSystemShortcuts(it),
                    fetchMultiTaskingShortcuts(it),
                    fetchAppCategoriesShortcuts(it),
                    fetchImeShortcuts(it),
                    fetchCurrentAppShortcuts(it),
                val groupsFromAllSources = sources.map { it.source.shortcutGroups(inputDevice.id) }
                val supportedKeyCodes = fetchSupportedKeyCodes(inputDevice.id, groupsFromAllSources)
                return@map sources.mapIndexedNotNull { index, internalGroupsSource ->
                    fetchShortcutCategory(
                        internalGroupsSource,
                        groupsFromAllSources[index],
                        inputDevice,
                        supportedKeyCodes,
                    )
                }
            }
            .stateIn(
                scope = backgroundScope,
                started = SharingStarted.Lazily,
                initialValue = emptyList(),
            )

    private suspend fun fetchSystemShortcuts(inputDevice: InputDevice) =
        toShortcutCategory(
            inputDevice.keyCharacterMap,
            System,
            systemShortcutsSource.shortcutGroups(inputDevice.id),
            keepIcons = true,
        )

    private suspend fun fetchMultiTaskingShortcuts(inputDevice: InputDevice) =
        toShortcutCategory(
            inputDevice.keyCharacterMap,
            MultiTasking,
            multitaskingShortcutsSource.shortcutGroups(inputDevice.id),
            keepIcons = true,
        )

    private suspend fun fetchAppCategoriesShortcuts(inputDevice: InputDevice) =
        toShortcutCategory(
            inputDevice.keyCharacterMap,
            AppCategories,
            appCategoriesShortcutsSource.shortcutGroups(inputDevice.id),
            keepIcons = true,
        )

    private suspend fun fetchImeShortcuts(inputDevice: InputDevice) =
        toShortcutCategory(
            inputDevice.keyCharacterMap,
            InputMethodEditor,
            inputShortcutsSource.shortcutGroups(inputDevice.id),
            keepIcons = false,
        )

    private suspend fun fetchCurrentAppShortcuts(inputDevice: InputDevice): ShortcutCategory? {
        val shortcutGroups = currentAppShortcutsSource.shortcutGroups(inputDevice.id)
        val categoryType = getCurrentAppShortcutCategoryType(shortcutGroups)
        return if (categoryType == null) {
    private fun fetchShortcutCategory(
        internalGroupsSource: InternalGroupsSource,
        groups: List<KeyboardShortcutGroup>,
        inputDevice: InputDevice,
        supportedKeyCodes: Set<Int>,
    ): ShortcutCategory? {
        val type = internalGroupsSource.typeProvider(groups)
        return if (type == null) {
            null
        } else {
            toShortcutCategory(
                inputDevice.keyCharacterMap,
                categoryType,
                shortcutGroups,
                keepIcons = false
                type,
                groups,
                internalGroupsSource.isTrusted,
                supportedKeyCodes,
            )
        }
    }
@@ -162,13 +167,19 @@ constructor(
        type: ShortcutCategoryType,
        shortcutGroups: List<KeyboardShortcutGroup>,
        keepIcons: Boolean,
        supportedKeyCodes: Set<Int>,
    ): ShortcutCategory? {
        val subCategories =
            shortcutGroups
                .map { shortcutGroup ->
                    ShortcutSubCategory(
                        shortcutGroup.label.toString(),
                        toShortcuts(keyCharacterMap, shortcutGroup.items, keepIcons)
                        toShortcuts(
                            keyCharacterMap,
                            shortcutGroup.items,
                            keepIcons,
                            supportedKeyCodes,
                        )
                    )
                }
                .filter { it.shortcuts.isNotEmpty() }
@@ -184,7 +195,15 @@ constructor(
        keyCharacterMap: KeyCharacterMap,
        infoList: List<KeyboardShortcutInfo>,
        keepIcons: Boolean,
    ) = infoList.mapNotNull { toShortcut(keyCharacterMap, it, keepIcons) }
        supportedKeyCodes: Set<Int>,
    ) =
        infoList
            .filter {
                // Allow KEYCODE_UNKNOWN (0) because shortcuts can have just modifiers and no
                // 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) }

    private fun toShortcut(
        keyCharacterMap: KeyCharacterMap,
@@ -268,6 +287,29 @@ constructor(
        return null
    }

    private suspend fun fetchSupportedKeyCodes(
        deviceId: Int,
        groupsFromAllSources: List<List<KeyboardShortcutGroup>>
    ): Set<Int> =
        withContext(backgroundDispatcher) {
            val allUsedKeyCodes =
                groupsFromAllSources
                    .flatMap { groups -> groups.flatMap { group -> group.items } }
                    .map { info -> info.keycode }
                    .distinct()
            val keyCodesSupported =
                inputManager.deviceHasKeys(deviceId, allUsedKeyCodes.toIntArray())
            return@withContext allUsedKeyCodes
                .filterIndexed { index, _ -> keyCodesSupported[index] }
                .toSet()
        }

    private class InternalGroupsSource(
        val source: KeyboardShortcutGroupsSource,
        val isTrusted: Boolean,
        val typeProvider: (groups: List<KeyboardShortcutGroup>) -> ShortcutCategoryType?,
    )

    companion object {
        private const val TAG = "SHCategoriesRepo"

+4 −0
Original line number Diff line number Diff line
@@ -98,6 +98,7 @@ import android.view.KeyEvent.KEYCODE_NUM_LOCK
import android.view.KeyEvent.KEYCODE_PAGE_DOWN
import android.view.KeyEvent.KEYCODE_PAGE_UP
import android.view.KeyEvent.KEYCODE_PERIOD
import android.view.KeyEvent.KEYCODE_RECENT_APPS
import android.view.KeyEvent.KEYCODE_SCROLL_LOCK
import android.view.KeyEvent.KEYCODE_SHIFT_LEFT
import android.view.KeyEvent.KEYCODE_SHIFT_RIGHT
@@ -118,6 +119,9 @@ object ShortcutHelperKeys {
    val keyIcons =
        mapOf(
            META_META_ON to R.drawable.ic_ksh_key_meta,
            KEYCODE_BACK to R.drawable.ic_arrow_back_2,
            KEYCODE_HOME to R.drawable.ic_radio_button_unchecked,
            KEYCODE_RECENT_APPS to R.drawable.ic_check_box_outline_blank,
        )

    val specialKeyLabels =
Loading