diff options
6 files changed, 78 insertions, 259 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepository.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepository.kt index 49817b263583..495e8f322f00 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepository.kt @@ -233,7 +233,7 @@ constructor( Log.wtf(TAG, "Unsupported modifiers remaining: $remainingModifiers") return null } - if (info.keycode != 0) { + if (info.keycode != 0 || info.baseCharacter > Char.MIN_VALUE) { keys += toShortcutKey(keyCharacterMap, info.keycode, info.baseCharacter) ?: return null } if (keys.isEmpty()) { @@ -253,7 +253,7 @@ constructor( return ShortcutKey.Icon(iconResId) } if (baseCharacter > Char.MIN_VALUE) { - return ShortcutKey.Text(baseCharacter.toString()) + return ShortcutKey.Text(baseCharacter.uppercase()) } val specialKeyLabel = ShortcutHelperKeys.specialKeyLabels[keyCode] if (specialKeyLabel != null) { diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/AppCategoriesShortcutsSource.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/AppCategoriesShortcutsSource.kt index d7cb7db0f15b..d6c6d5b3a83c 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/AppCategoriesShortcutsSource.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/AppCategoriesShortcutsSource.kt @@ -16,92 +16,29 @@ package com.android.systemui.keyboard.shortcut.data.source -import android.content.Intent -import android.content.res.Resources -import android.view.KeyEvent import android.view.KeyboardShortcutGroup -import android.view.KeyboardShortcutInfo -import com.android.systemui.dagger.qualifiers.Main -import com.android.systemui.res.R -import com.android.systemui.util.icons.AppCategoryIconProvider +import android.view.WindowManager +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.keyboard.shortcut.extensions.copy import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.withContext class AppCategoriesShortcutsSource @Inject constructor( - private val appCategoryIconProvider: AppCategoryIconProvider, - @Main private val resources: Resources, + private val windowManager: WindowManager, + @Background private val backgroundDispatcher: CoroutineDispatcher, ) : KeyboardShortcutGroupsSource { - override suspend fun shortcutGroups(deviceId: Int) = - listOf( - KeyboardShortcutGroup( - /* label = */ resources.getString(R.string.keyboard_shortcut_group_applications), - /* items = */ shortcuts() - ) - ) - - private suspend fun shortcuts(): List<KeyboardShortcutInfo> = - listOfNotNull( - assistantAppShortcutInfo(), - appCategoryShortcutInfo( - Intent.CATEGORY_APP_BROWSER, - R.string.keyboard_shortcut_group_applications_browser, - KeyEvent.KEYCODE_B - ), - appCategoryShortcutInfo( - Intent.CATEGORY_APP_CONTACTS, - R.string.keyboard_shortcut_group_applications_contacts, - KeyEvent.KEYCODE_C - ), - appCategoryShortcutInfo( - Intent.CATEGORY_APP_EMAIL, - R.string.keyboard_shortcut_group_applications_email, - KeyEvent.KEYCODE_E - ), - appCategoryShortcutInfo( - Intent.CATEGORY_APP_CALENDAR, - R.string.keyboard_shortcut_group_applications_calendar, - KeyEvent.KEYCODE_K - ), - appCategoryShortcutInfo( - Intent.CATEGORY_APP_MAPS, - R.string.keyboard_shortcut_group_applications_maps, - KeyEvent.KEYCODE_M - ), - appCategoryShortcutInfo( - Intent.CATEGORY_APP_MUSIC, - R.string.keyboard_shortcut_group_applications_music, - KeyEvent.KEYCODE_P - ), - appCategoryShortcutInfo( - Intent.CATEGORY_APP_MESSAGING, - R.string.keyboard_shortcut_group_applications_sms, - KeyEvent.KEYCODE_S - ), - appCategoryShortcutInfo( - Intent.CATEGORY_APP_CALCULATOR, - R.string.keyboard_shortcut_group_applications_calculator, - KeyEvent.KEYCODE_U - ), - ) - .sortedBy { it.label!!.toString().lowercase() } - - private suspend fun assistantAppShortcutInfo(): KeyboardShortcutInfo? { - val assistantIcon = appCategoryIconProvider.assistantAppIcon() ?: return null - return KeyboardShortcutInfo( - /* label = */ resources.getString(R.string.keyboard_shortcut_group_applications_assist), - /* icon = */ assistantIcon, - /* keycode = */ KeyEvent.KEYCODE_A, - /* modifiers = */ KeyEvent.META_META_ON, - ) - } - - private suspend fun appCategoryShortcutInfo(category: String, labelResId: Int, keycode: Int) = - KeyboardShortcutInfo( - /* label = */ resources.getString(labelResId), - /* icon = */ appCategoryIconProvider.categoryAppIcon(category), - /* keycode = */ keycode, - /* modifiers = */ KeyEvent.META_META_ON, - ) + override suspend fun shortcutGroups(deviceId: Int): List<KeyboardShortcutGroup> = + withContext(backgroundDispatcher) { + val group = windowManager.getApplicationLaunchKeyboardShortcuts(deviceId) + return@withContext if (group == null) { + emptyList() + } else { + val sortedShortcutItems = group.items.sortedBy { it.label!!.toString().lowercase() } + listOf(group.copy(items = sortedShortcutItems)) + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/extensions/KeyboardShortcutGroupExtensions.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/extensions/KeyboardShortcutGroupExtensions.kt new file mode 100644 index 000000000000..3a120bdcc9c0 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/extensions/KeyboardShortcutGroupExtensions.kt @@ -0,0 +1,27 @@ +/* + * 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. + */ + +package com.android.systemui.keyboard.shortcut.extensions + +import android.view.KeyboardShortcutGroup +import android.view.KeyboardShortcutInfo + +fun KeyboardShortcutGroup.copy( + label: CharSequence = getLabel(), + items: List<KeyboardShortcutInfo> = getItems(), + isSystemGroup: Boolean = isSystemGroup(), + packageName: CharSequence? = getPackageName(), +) = KeyboardShortcutGroup(label, items, isSystemGroup).also { it.packageName = packageName } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/source/AppCategoriesShortcutsSourceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/source/AppCategoriesShortcutsSourceTest.kt index e49e2b4990b4..5d592087527c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/source/AppCategoriesShortcutsSourceTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/source/AppCategoriesShortcutsSourceTest.kt @@ -16,21 +16,17 @@ package com.android.systemui.keyboard.shortcut.data.source -import android.content.Intent.CATEGORY_APP_BROWSER -import android.content.Intent.CATEGORY_APP_CALCULATOR -import android.content.Intent.CATEGORY_APP_CALENDAR -import android.content.Intent.CATEGORY_APP_CONTACTS -import android.content.Intent.CATEGORY_APP_EMAIL -import android.content.Intent.CATEGORY_APP_MAPS -import android.content.Intent.CATEGORY_APP_MESSAGING -import android.content.Intent.CATEGORY_APP_MUSIC +import android.view.KeyEvent +import android.view.KeyboardShortcutGroup +import android.view.KeyboardShortcutInfo +import android.view.mockWindowManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase -import com.android.systemui.keyboard.shortcut.shortcutHelperAppCategoriesShortcutsSource +import com.android.systemui.kosmos.testDispatcher import com.android.systemui.kosmos.testScope import com.android.systemui.testKosmos -import com.android.systemui.util.icons.fakeAppCategoryIconProvider +import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.test.runTest import org.junit.Before @@ -43,185 +39,43 @@ class AppCategoriesShortcutsSourceTest : SysuiTestCase() { private val kosmos = testKosmos() private val testScope = kosmos.testScope - private val defaultAppIconsProvider = kosmos.fakeAppCategoryIconProvider - private val source = kosmos.shortcutHelperAppCategoriesShortcutsSource + private val mockWindowManager = kosmos.mockWindowManager + private val source = + AppCategoriesShortcutsSource(kosmos.mockWindowManager, kosmos.testDispatcher) + + private var appCategoriesGroup: KeyboardShortcutGroup? = null @Before fun setUp() { - categoryApps.forEach { categoryAppIcon -> - defaultAppIconsProvider.installCategoryApp( - categoryAppIcon.category, - categoryAppIcon.packageName, - categoryAppIcon.iconResId - ) - } + whenever(mockWindowManager.getApplicationLaunchKeyboardShortcuts(TEST_DEVICE_ID)) + .thenAnswer { appCategoriesGroup } } @Test - fun shortcutGroups_returnsSingleGroup() = - testScope.runTest { assertThat(source.shortcutGroups(TEST_DEVICE_ID)).hasSize(1) } - - @Test - fun shortcutGroups_hasAssistantIcon() = - testScope.runTest { - defaultAppIconsProvider.installAssistantApp(ASSISTANT_PACKAGE, ASSISTANT_ICON_RES_ID) - - val shortcuts = source.shortcutGroups(TEST_DEVICE_ID).first().items - - val shortcutInfo = shortcuts.first { it.label == "Assistant" } - - assertThat(shortcutInfo.icon!!.resPackage).isEqualTo(ASSISTANT_PACKAGE) - assertThat(shortcutInfo.icon!!.resId).isEqualTo(ASSISTANT_ICON_RES_ID) - } - - @Test - fun shortcutGroups_hasBrowserIcon() = - testScope.runTest { - val shortcuts = source.shortcutGroups(TEST_DEVICE_ID).first().items - - val shortcutInfo = shortcuts.first { it.label == "Browser" } - - assertThat(shortcutInfo.icon!!.resPackage).isEqualTo(BROWSER_PACKAGE) - assertThat(shortcutInfo.icon!!.resId).isEqualTo(BROWSER_ICON_RES_ID) - } - - @Test - fun shortcutGroups_hasContactsIcon() = - testScope.runTest { - val shortcuts = source.shortcutGroups(TEST_DEVICE_ID).first().items - - val shortcutInfo = shortcuts.first { it.label == "Contacts" } - - assertThat(shortcutInfo.icon!!.resPackage).isEqualTo(CONTACTS_PACKAGE) - assertThat(shortcutInfo.icon!!.resId).isEqualTo(CONTACTS_ICON_RES_ID) - } - - @Test - fun shortcutGroups_hasEmailIcon() = + fun shortcutGroups_nullResult_returnsEmptyList() = testScope.runTest { - val shortcuts = source.shortcutGroups(TEST_DEVICE_ID).first().items - - val shortcutInfo = shortcuts.first { it.label == "Email" } + appCategoriesGroup = null - assertThat(shortcutInfo.icon!!.resPackage).isEqualTo(EMAIL_PACKAGE) - assertThat(shortcutInfo.icon!!.resId).isEqualTo(EMAIL_ICON_RES_ID) + assertThat(source.shortcutGroups(TEST_DEVICE_ID)).isEmpty() } @Test - fun shortcutGroups_hasCalendarIcon() = + fun shortcutGroups_returnsSortedList() = testScope.runTest { - val shortcuts = source.shortcutGroups(TEST_DEVICE_ID).first().items - - val shortcutInfo = shortcuts.first { it.label == "Calendar" } + val testItems = + listOf( + KeyboardShortcutInfo("Info 2", KeyEvent.KEYCODE_E, KeyEvent.META_META_ON), + KeyboardShortcutInfo("Info 1", KeyEvent.KEYCODE_E, KeyEvent.META_META_ON), + KeyboardShortcutInfo("Info 3", KeyEvent.KEYCODE_E, KeyEvent.META_META_ON), + ) + appCategoriesGroup = KeyboardShortcutGroup("Test Group", testItems) - assertThat(shortcutInfo.icon!!.resPackage).isEqualTo(CALENDAR_PACKAGE) - assertThat(shortcutInfo.icon!!.resId).isEqualTo(CALENDAR_ICON_RES_ID) - } - - @Test - fun shortcutGroups_hasMapsIcon() = - testScope.runTest { val shortcuts = source.shortcutGroups(TEST_DEVICE_ID).first().items - - val shortcutInfo = shortcuts.first { it.label == "Maps" } - - assertThat(shortcutInfo.icon!!.resPackage).isEqualTo(MAPS_PACKAGE) - assertThat(shortcutInfo.icon!!.resId).isEqualTo(MAPS_ICON_RES_ID) + val shortcutLabels = shortcuts.map { it.label.toString() } + assertThat(shortcutLabels).containsExactly("Info 1", "Info 2", "Info 3").inOrder() } - @Test - fun shortcutGroups_hasMessagingIcon() = - testScope.runTest { - val shortcuts = source.shortcutGroups(TEST_DEVICE_ID).first().items - - val shortcutInfo = shortcuts.first { it.label == "SMS" } - - assertThat(shortcutInfo.icon!!.resPackage).isEqualTo(MESSAGING_PACKAGE) - assertThat(shortcutInfo.icon!!.resId).isEqualTo(MESSAGING_ICON_RES_ID) - } - - @Test - fun shortcutGroups_hasMusicIcon() = - testScope.runTest { - val shortcuts = source.shortcutGroups(TEST_DEVICE_ID).first().items - - val shortcutInfo = shortcuts.first { it.label == "Music" } - - assertThat(shortcutInfo.icon!!.resPackage).isEqualTo(MUSIC_PACKAGE) - assertThat(shortcutInfo.icon!!.resId).isEqualTo(MUSIC_ICON_RES_ID) - } - - @Test - fun shortcutGroups_hasCalculatorIcon() = - testScope.runTest { - val shortcuts = source.shortcutGroups(TEST_DEVICE_ID).first().items - - val shortcutInfo = shortcuts.first { it.label == "Calculator" } - - assertThat(shortcutInfo.icon!!.resPackage).isEqualTo(CALCULATOR_PACKAGE) - assertThat(shortcutInfo.icon!!.resId).isEqualTo(CALCULATOR_ICON_RES_ID) - } - - @Test - fun shortcutGroups_shortcutsSortedByLabelIgnoringCase() = - testScope.runTest { - val shortcuts = source.shortcutGroups(TEST_DEVICE_ID).first().items - - val shortcutLabels = shortcuts.map { it.label!!.toString() } - assertThat(shortcutLabels).isEqualTo(shortcutLabels.sortedBy { it.lowercase() }) - } - - @Test - fun shortcutGroups_noAssistantApp_excludesAssistantFromShortcuts() = - testScope.runTest { - val shortcutLabels = - source.shortcutGroups(TEST_DEVICE_ID).first().items.map { it.label!!.toString() } - - assertThat(shortcutLabels).doesNotContain("Assistant") - } - - private companion object { - private const val ASSISTANT_PACKAGE = "the.assistant.app" - private const val ASSISTANT_ICON_RES_ID = 123 - - private const val BROWSER_PACKAGE = "com.test.browser" - private const val BROWSER_ICON_RES_ID = 1 - - private const val CONTACTS_PACKAGE = "app.test.contacts" - private const val CONTACTS_ICON_RES_ID = 234 - - private const val EMAIL_PACKAGE = "email.app.test" - private const val EMAIL_ICON_RES_ID = 351 - - private const val CALENDAR_PACKAGE = "app.test.calendar" - private const val CALENDAR_ICON_RES_ID = 411 - - private const val MAPS_PACKAGE = "maps.app.package" - private const val MAPS_ICON_RES_ID = 999 - - private const val MUSIC_PACKAGE = "com.android.music" - private const val MUSIC_ICON_RES_ID = 101 - - private const val MESSAGING_PACKAGE = "my.sms.app" - private const val MESSAGING_ICON_RES_ID = 9191 - - private const val CALCULATOR_PACKAGE = "that.calculator.app" - private const val CALCULATOR_ICON_RES_ID = 314 - - private val categoryApps = - listOf( - CategoryApp(CATEGORY_APP_BROWSER, BROWSER_PACKAGE, BROWSER_ICON_RES_ID), - CategoryApp(CATEGORY_APP_CONTACTS, CONTACTS_PACKAGE, CONTACTS_ICON_RES_ID), - CategoryApp(CATEGORY_APP_EMAIL, EMAIL_PACKAGE, EMAIL_ICON_RES_ID), - CategoryApp(CATEGORY_APP_CALENDAR, CALENDAR_PACKAGE, CALENDAR_ICON_RES_ID), - CategoryApp(CATEGORY_APP_MAPS, MAPS_PACKAGE, MAPS_ICON_RES_ID), - CategoryApp(CATEGORY_APP_MUSIC, MUSIC_PACKAGE, MUSIC_ICON_RES_ID), - CategoryApp(CATEGORY_APP_MESSAGING, MESSAGING_PACKAGE, MESSAGING_ICON_RES_ID), - CategoryApp(CATEGORY_APP_CALCULATOR, CALCULATOR_PACKAGE, CALCULATOR_ICON_RES_ID), - ) - + companion object { private const val TEST_DEVICE_ID = 123 } - - private class CategoryApp(val category: String, val packageName: String, val iconResId: Int) } diff --git a/packages/SystemUI/tests/utils/src/android/view/WindowManagerKosmos.kt b/packages/SystemUI/tests/utils/src/android/view/WindowManagerKosmos.kt index 2a0559869c86..d5451ee8eb10 100644 --- a/packages/SystemUI/tests/utils/src/android/view/WindowManagerKosmos.kt +++ b/packages/SystemUI/tests/utils/src/android/view/WindowManagerKosmos.kt @@ -19,4 +19,6 @@ package android.view import com.android.systemui.kosmos.Kosmos import org.mockito.Mockito.mock -val Kosmos.windowManager by Kosmos.Fixture<WindowManager> { mock(WindowManager::class.java) } +val Kosmos.mockWindowManager: WindowManager by Kosmos.Fixture { mock(WindowManager::class.java) } + +var Kosmos.windowManager: WindowManager by Kosmos.Fixture { mockWindowManager } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt index 001b55b99919..c423b626b3a7 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt @@ -41,13 +41,12 @@ import com.android.systemui.kosmos.testDispatcher import com.android.systemui.kosmos.testScope import com.android.systemui.model.sysUiState import com.android.systemui.settings.displayTracker -import com.android.systemui.util.icons.fakeAppCategoryIconProvider var Kosmos.shortcutHelperAppCategoriesShortcutsSource: KeyboardShortcutGroupsSource by Kosmos.Fixture { AppCategoriesShortcutsSource( - fakeAppCategoryIconProvider, - mainResources, + windowManager, + testDispatcher, ) } |