Loading packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepository.kt +82 −4 Original line number Original line Diff line number Diff line Loading @@ -16,11 +16,23 @@ package com.android.systemui.keyboard.shortcut.data.repository package com.android.systemui.keyboard.shortcut.data.repository import android.view.KeyEvent import android.view.KeyboardShortcutGroup import android.view.KeyboardShortcutInfo import android.view.WindowManager import android.view.WindowManager.KeyboardShortcutsReceiver import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyboard.shortcut.data.source.MultitaskingShortcutsSource import com.android.systemui.keyboard.shortcut.data.source.MultitaskingShortcutsSource import com.android.systemui.keyboard.shortcut.data.source.SystemShortcutsSource import com.android.systemui.keyboard.shortcut.data.source.SystemShortcutsSource 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.ShortcutCategory import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCommand import com.android.systemui.keyboard.shortcut.shared.model.ShortcutHelperState.Active import com.android.systemui.keyboard.shortcut.shared.model.shortcutCategory import javax.inject.Inject import javax.inject.Inject import kotlinx.coroutines.flow.map import kotlinx.coroutines.suspendCancellableCoroutine @SysUISingleton @SysUISingleton class ShortcutHelperCategoriesRepository class ShortcutHelperCategoriesRepository Loading @@ -28,11 +40,77 @@ class ShortcutHelperCategoriesRepository constructor( constructor( private val systemShortcutsSource: SystemShortcutsSource, private val systemShortcutsSource: SystemShortcutsSource, private val multitaskingShortcutsSource: MultitaskingShortcutsSource, private val multitaskingShortcutsSource: MultitaskingShortcutsSource, private val windowManager: WindowManager, shortcutHelperStateRepository: ShortcutHelperStateRepository ) { ) { fun systemShortcutsCategory(): ShortcutCategory = val systemShortcutsCategory = systemShortcutsSource.systemShortcutsCategory() shortcutHelperStateRepository.state.map { if (it is Active) systemShortcutsSource.systemShortcutsCategory() else null } val multitaskingShortcutsCategory = shortcutHelperStateRepository.state.map { if (it is Active) multitaskingShortcutsSource.multitaskingShortcutCategory() else null } fun multitaskingShortcutsCategory(): ShortcutCategory = val imeShortcutsCategory = multitaskingShortcutsSource.multitaskingShortcutCategory() shortcutHelperStateRepository.state.map { if (it is Active) retrieveImeShortcuts(it.deviceId) else null } private suspend fun retrieveImeShortcuts(deviceId: Int): ShortcutCategory { return suspendCancellableCoroutine { continuation -> val shortcutsReceiver = KeyboardShortcutsReceiver { shortcutGroups -> continuation.resumeWith(Result.success(toShortcutCategory(shortcutGroups))) } windowManager.requestImeKeyboardShortcuts(shortcutsReceiver, deviceId) } } private fun toShortcutCategory(shortcutGroups: List<KeyboardShortcutGroup>) = shortcutCategory(ShortcutCategoryType.IME) { shortcutGroups.map { shortcutGroup -> subCategory(shortcutGroup.label.toString(), toShortcuts(shortcutGroup.items)) } } private fun toShortcuts(infoList: List<KeyboardShortcutInfo>) = infoList.mapNotNull { toShortcut(it) } private fun toShortcut(shortcutInfo: KeyboardShortcutInfo): Shortcut? { val shortcutCommand = toShortcutCommand(shortcutInfo) return if (shortcutCommand == null) null else Shortcut(label = shortcutInfo.label!!.toString(), commands = listOf(shortcutCommand)) } private fun toShortcutCommand(info: KeyboardShortcutInfo): ShortcutCommand? { val keyCodes = mutableListOf<Int>() var remainingModifiers = info.modifiers SUPPORTED_MODIFIERS.forEach { supportedModifier -> if ((supportedModifier and remainingModifiers) != 0) { keyCodes += supportedModifier // "Remove" the modifier from the remaining modifiers remainingModifiers = remainingModifiers and supportedModifier.inv() } } if (remainingModifiers != 0) { // There is a remaining modifier we don't support return null } keyCodes += info.keycode return ShortcutCommand(keyCodes) } companion object { private val SUPPORTED_MODIFIERS = listOf( KeyEvent.META_META_ON, KeyEvent.META_CTRL_ON, KeyEvent.META_ALT_ON, KeyEvent.META_SHIFT_ON, KeyEvent.META_SYM_ON, KeyEvent.META_FUNCTION_ON ) } } } packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractor.kt +38 −12 Original line number Original line Diff line number Diff line Loading @@ -18,30 +18,56 @@ package com.android.systemui.keyboard.shortcut.domain.interactor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperCategoriesRepository import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperCategoriesRepository import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperStateRepository 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.ShortcutCategory import com.android.systemui.keyboard.shortcut.shared.model.ShortcutHelperState import com.android.systemui.keyboard.shortcut.shared.model.ShortcutSubCategory import javax.inject.Inject import javax.inject.Inject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map @SysUISingleton @SysUISingleton class ShortcutHelperCategoriesInteractor class ShortcutHelperCategoriesInteractor @Inject @Inject constructor( constructor( stateRepository: ShortcutHelperStateRepository, categoriesRepository: ShortcutHelperCategoriesRepository, categoriesRepository: ShortcutHelperCategoriesRepository, ) { ) { private val systemsShortcutCategory = categoriesRepository.systemShortcutsCategory private val multitaskingShortcutsCategory = categoriesRepository.multitaskingShortcutsCategory private val imeShortcutsCategory = categoriesRepository.imeShortcutsCategory.map { groupSubCategoriesInCategory(it) } val shortcutCategories: Flow<List<ShortcutCategory>> = val shortcutCategories: Flow<List<ShortcutCategory>> = stateRepository.state.map { state -> combine(systemsShortcutCategory, multitaskingShortcutsCategory, imeShortcutsCategory) { when (state) { shortcutCategories -> is ShortcutHelperState.Active -> shortcutCategories.filterNotNull() listOf( } categoriesRepository.systemShortcutsCategory(), categoriesRepository.multitaskingShortcutsCategory() private fun groupSubCategoriesInCategory( shortcutCategory: ShortcutCategory? ): ShortcutCategory? { if (shortcutCategory == null) { return null } val subCategoriesWithGroupedShortcuts = shortcutCategory.subCategories.map { ShortcutSubCategory( label = it.label, shortcuts = groupShortcutsInSubcategory(it.shortcuts) ) ) is ShortcutHelperState.Inactive -> emptyList() } } return ShortcutCategory( type = shortcutCategory.type, subCategories = subCategoriesWithGroupedShortcuts ) } private fun groupShortcutsInSubcategory(shortcuts: List<Shortcut>) = shortcuts .groupBy { it.label } .entries .map { (commonLabel, groupedShortcuts) -> Shortcut(label = commonLabel, commands = groupedShortcuts.flatMap { it.commands }) } } } } packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperStateInteractor.kt +2 −1 Original line number Original line Diff line number Diff line Loading @@ -26,6 +26,7 @@ import com.android.systemui.shared.system.QuickStepContract import javax.inject.Inject import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import kotlinx.coroutines.launch @SysUISingleton @SysUISingleton Loading @@ -38,7 +39,7 @@ constructor( private val repository: ShortcutHelperStateRepository private val repository: ShortcutHelperStateRepository ) { ) { val state: Flow<ShortcutHelperState> = repository.state val state: Flow<ShortcutHelperState> = repository.state.asStateFlow() fun onViewClosed() { fun onViewClosed() { repository.hide() repository.hide() Loading packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCategory.kt +1 −0 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.systemui.keyboard.shortcut.shared.model enum class ShortcutCategoryType { enum class ShortcutCategoryType { SYSTEM, SYSTEM, MULTI_TASKING, MULTI_TASKING, IME } } data class ShortcutCategory( data class ShortcutCategory( Loading packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepositoryTest.kt 0 → 100644 +130 −0 Original line number Original line 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. */ package com.android.systemui.keyboard.shortcut.data.repository import android.view.KeyEvent import android.view.KeyboardShortcutGroup import android.view.KeyboardShortcutInfo 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.Shortcut import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCommand import com.android.systemui.keyboard.shortcut.shared.model.shortcutCategory import com.android.systemui.keyboard.shortcut.shortcutHelperCategoriesRepository import com.android.systemui.keyboard.shortcut.shortcutHelperTestHelper import com.android.systemui.kosmos.testDispatcher import com.android.systemui.kosmos.testScope import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) class ShortcutHelperCategoriesRepositoryTest : SysuiTestCase() { @OptIn(ExperimentalCoroutinesApi::class) private val kosmos = testKosmos().also { it.testDispatcher = UnconfinedTestDispatcher() } private val repo = kosmos.shortcutHelperCategoriesRepository private val helper = kosmos.shortcutHelperTestHelper private val testScope = kosmos.testScope @Test fun stateActive_imeShortcuts_shortcutInfoCorrectlyConverted() = testScope.runTest { helper.setImeShortcuts(imeShortcutsGroupWithPreviousLanguageSwitchShortcut) val imeShortcutCategory by collectLastValue(repo.imeShortcutsCategory) helper.showFromActivity() assertThat(imeShortcutCategory) .isEqualTo(expectedImeShortcutCategoryWithPreviousLanguageSwitchShortcut) } @Test fun stateActive_imeShortcuts_discardUnsupportedShortcutInfoModifiers() = testScope.runTest { helper.setImeShortcuts(imeShortcutsGroupWithUnsupportedShortcutModifiers) val imeShortcutCategory by collectLastValue(repo.imeShortcutsCategory) helper.showFromActivity() assertThat(imeShortcutCategory) .isEqualTo(expectedImeShortcutCategoryWithDiscardedUnsupportedShortcuts) } private val switchToPreviousLanguageCommand = ShortcutCommand( listOf(KeyEvent.META_CTRL_ON, KeyEvent.META_SHIFT_ON, KeyEvent.KEYCODE_SPACE) ) private val expectedImeShortcutCategoryWithDiscardedUnsupportedShortcuts = shortcutCategory(ShortcutCategoryType.IME) { subCategory("input", emptyList()) } private val switchToPreviousLanguageKeyboardShortcutInfo = KeyboardShortcutInfo( /* label = */ "switch to previous language", /* keycode = */ switchToPreviousLanguageCommand.keyCodes[2], /* modifiers = */ switchToPreviousLanguageCommand.keyCodes[0] or switchToPreviousLanguageCommand.keyCodes[1], ) private val expectedImeShortcutCategoryWithPreviousLanguageSwitchShortcut = shortcutCategory(ShortcutCategoryType.IME) { subCategory( "input", listOf( Shortcut( switchToPreviousLanguageKeyboardShortcutInfo.label!!.toString(), listOf(switchToPreviousLanguageCommand) ) ) ) } private val imeShortcutsGroupWithPreviousLanguageSwitchShortcut = listOf( KeyboardShortcutGroup( "input", listOf( switchToPreviousLanguageKeyboardShortcutInfo, ) ) ) private val shortcutInfoWithUnsupportedModifier = KeyboardShortcutInfo( /* label = */ "unsupported shortcut", /* keycode = */ KeyEvent.KEYCODE_SPACE, /* modifiers = */ 32 ) private val imeShortcutsGroupWithUnsupportedShortcutModifiers = listOf( KeyboardShortcutGroup( "input", listOf( shortcutInfoWithUnsupportedModifier, ) ) ) } Loading
packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepository.kt +82 −4 Original line number Original line Diff line number Diff line Loading @@ -16,11 +16,23 @@ package com.android.systemui.keyboard.shortcut.data.repository package com.android.systemui.keyboard.shortcut.data.repository import android.view.KeyEvent import android.view.KeyboardShortcutGroup import android.view.KeyboardShortcutInfo import android.view.WindowManager import android.view.WindowManager.KeyboardShortcutsReceiver import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyboard.shortcut.data.source.MultitaskingShortcutsSource import com.android.systemui.keyboard.shortcut.data.source.MultitaskingShortcutsSource import com.android.systemui.keyboard.shortcut.data.source.SystemShortcutsSource import com.android.systemui.keyboard.shortcut.data.source.SystemShortcutsSource 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.ShortcutCategory import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCommand import com.android.systemui.keyboard.shortcut.shared.model.ShortcutHelperState.Active import com.android.systemui.keyboard.shortcut.shared.model.shortcutCategory import javax.inject.Inject import javax.inject.Inject import kotlinx.coroutines.flow.map import kotlinx.coroutines.suspendCancellableCoroutine @SysUISingleton @SysUISingleton class ShortcutHelperCategoriesRepository class ShortcutHelperCategoriesRepository Loading @@ -28,11 +40,77 @@ class ShortcutHelperCategoriesRepository constructor( constructor( private val systemShortcutsSource: SystemShortcutsSource, private val systemShortcutsSource: SystemShortcutsSource, private val multitaskingShortcutsSource: MultitaskingShortcutsSource, private val multitaskingShortcutsSource: MultitaskingShortcutsSource, private val windowManager: WindowManager, shortcutHelperStateRepository: ShortcutHelperStateRepository ) { ) { fun systemShortcutsCategory(): ShortcutCategory = val systemShortcutsCategory = systemShortcutsSource.systemShortcutsCategory() shortcutHelperStateRepository.state.map { if (it is Active) systemShortcutsSource.systemShortcutsCategory() else null } val multitaskingShortcutsCategory = shortcutHelperStateRepository.state.map { if (it is Active) multitaskingShortcutsSource.multitaskingShortcutCategory() else null } fun multitaskingShortcutsCategory(): ShortcutCategory = val imeShortcutsCategory = multitaskingShortcutsSource.multitaskingShortcutCategory() shortcutHelperStateRepository.state.map { if (it is Active) retrieveImeShortcuts(it.deviceId) else null } private suspend fun retrieveImeShortcuts(deviceId: Int): ShortcutCategory { return suspendCancellableCoroutine { continuation -> val shortcutsReceiver = KeyboardShortcutsReceiver { shortcutGroups -> continuation.resumeWith(Result.success(toShortcutCategory(shortcutGroups))) } windowManager.requestImeKeyboardShortcuts(shortcutsReceiver, deviceId) } } private fun toShortcutCategory(shortcutGroups: List<KeyboardShortcutGroup>) = shortcutCategory(ShortcutCategoryType.IME) { shortcutGroups.map { shortcutGroup -> subCategory(shortcutGroup.label.toString(), toShortcuts(shortcutGroup.items)) } } private fun toShortcuts(infoList: List<KeyboardShortcutInfo>) = infoList.mapNotNull { toShortcut(it) } private fun toShortcut(shortcutInfo: KeyboardShortcutInfo): Shortcut? { val shortcutCommand = toShortcutCommand(shortcutInfo) return if (shortcutCommand == null) null else Shortcut(label = shortcutInfo.label!!.toString(), commands = listOf(shortcutCommand)) } private fun toShortcutCommand(info: KeyboardShortcutInfo): ShortcutCommand? { val keyCodes = mutableListOf<Int>() var remainingModifiers = info.modifiers SUPPORTED_MODIFIERS.forEach { supportedModifier -> if ((supportedModifier and remainingModifiers) != 0) { keyCodes += supportedModifier // "Remove" the modifier from the remaining modifiers remainingModifiers = remainingModifiers and supportedModifier.inv() } } if (remainingModifiers != 0) { // There is a remaining modifier we don't support return null } keyCodes += info.keycode return ShortcutCommand(keyCodes) } companion object { private val SUPPORTED_MODIFIERS = listOf( KeyEvent.META_META_ON, KeyEvent.META_CTRL_ON, KeyEvent.META_ALT_ON, KeyEvent.META_SHIFT_ON, KeyEvent.META_SYM_ON, KeyEvent.META_FUNCTION_ON ) } } }
packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractor.kt +38 −12 Original line number Original line Diff line number Diff line Loading @@ -18,30 +18,56 @@ package com.android.systemui.keyboard.shortcut.domain.interactor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperCategoriesRepository import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperCategoriesRepository import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperStateRepository 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.ShortcutCategory import com.android.systemui.keyboard.shortcut.shared.model.ShortcutHelperState import com.android.systemui.keyboard.shortcut.shared.model.ShortcutSubCategory import javax.inject.Inject import javax.inject.Inject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map @SysUISingleton @SysUISingleton class ShortcutHelperCategoriesInteractor class ShortcutHelperCategoriesInteractor @Inject @Inject constructor( constructor( stateRepository: ShortcutHelperStateRepository, categoriesRepository: ShortcutHelperCategoriesRepository, categoriesRepository: ShortcutHelperCategoriesRepository, ) { ) { private val systemsShortcutCategory = categoriesRepository.systemShortcutsCategory private val multitaskingShortcutsCategory = categoriesRepository.multitaskingShortcutsCategory private val imeShortcutsCategory = categoriesRepository.imeShortcutsCategory.map { groupSubCategoriesInCategory(it) } val shortcutCategories: Flow<List<ShortcutCategory>> = val shortcutCategories: Flow<List<ShortcutCategory>> = stateRepository.state.map { state -> combine(systemsShortcutCategory, multitaskingShortcutsCategory, imeShortcutsCategory) { when (state) { shortcutCategories -> is ShortcutHelperState.Active -> shortcutCategories.filterNotNull() listOf( } categoriesRepository.systemShortcutsCategory(), categoriesRepository.multitaskingShortcutsCategory() private fun groupSubCategoriesInCategory( shortcutCategory: ShortcutCategory? ): ShortcutCategory? { if (shortcutCategory == null) { return null } val subCategoriesWithGroupedShortcuts = shortcutCategory.subCategories.map { ShortcutSubCategory( label = it.label, shortcuts = groupShortcutsInSubcategory(it.shortcuts) ) ) is ShortcutHelperState.Inactive -> emptyList() } } return ShortcutCategory( type = shortcutCategory.type, subCategories = subCategoriesWithGroupedShortcuts ) } private fun groupShortcutsInSubcategory(shortcuts: List<Shortcut>) = shortcuts .groupBy { it.label } .entries .map { (commonLabel, groupedShortcuts) -> Shortcut(label = commonLabel, commands = groupedShortcuts.flatMap { it.commands }) } } } }
packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperStateInteractor.kt +2 −1 Original line number Original line Diff line number Diff line Loading @@ -26,6 +26,7 @@ import com.android.systemui.shared.system.QuickStepContract import javax.inject.Inject import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import kotlinx.coroutines.launch @SysUISingleton @SysUISingleton Loading @@ -38,7 +39,7 @@ constructor( private val repository: ShortcutHelperStateRepository private val repository: ShortcutHelperStateRepository ) { ) { val state: Flow<ShortcutHelperState> = repository.state val state: Flow<ShortcutHelperState> = repository.state.asStateFlow() fun onViewClosed() { fun onViewClosed() { repository.hide() repository.hide() Loading
packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCategory.kt +1 −0 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.systemui.keyboard.shortcut.shared.model enum class ShortcutCategoryType { enum class ShortcutCategoryType { SYSTEM, SYSTEM, MULTI_TASKING, MULTI_TASKING, IME } } data class ShortcutCategory( data class ShortcutCategory( Loading
packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepositoryTest.kt 0 → 100644 +130 −0 Original line number Original line 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. */ package com.android.systemui.keyboard.shortcut.data.repository import android.view.KeyEvent import android.view.KeyboardShortcutGroup import android.view.KeyboardShortcutInfo 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.Shortcut import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCommand import com.android.systemui.keyboard.shortcut.shared.model.shortcutCategory import com.android.systemui.keyboard.shortcut.shortcutHelperCategoriesRepository import com.android.systemui.keyboard.shortcut.shortcutHelperTestHelper import com.android.systemui.kosmos.testDispatcher import com.android.systemui.kosmos.testScope import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) class ShortcutHelperCategoriesRepositoryTest : SysuiTestCase() { @OptIn(ExperimentalCoroutinesApi::class) private val kosmos = testKosmos().also { it.testDispatcher = UnconfinedTestDispatcher() } private val repo = kosmos.shortcutHelperCategoriesRepository private val helper = kosmos.shortcutHelperTestHelper private val testScope = kosmos.testScope @Test fun stateActive_imeShortcuts_shortcutInfoCorrectlyConverted() = testScope.runTest { helper.setImeShortcuts(imeShortcutsGroupWithPreviousLanguageSwitchShortcut) val imeShortcutCategory by collectLastValue(repo.imeShortcutsCategory) helper.showFromActivity() assertThat(imeShortcutCategory) .isEqualTo(expectedImeShortcutCategoryWithPreviousLanguageSwitchShortcut) } @Test fun stateActive_imeShortcuts_discardUnsupportedShortcutInfoModifiers() = testScope.runTest { helper.setImeShortcuts(imeShortcutsGroupWithUnsupportedShortcutModifiers) val imeShortcutCategory by collectLastValue(repo.imeShortcutsCategory) helper.showFromActivity() assertThat(imeShortcutCategory) .isEqualTo(expectedImeShortcutCategoryWithDiscardedUnsupportedShortcuts) } private val switchToPreviousLanguageCommand = ShortcutCommand( listOf(KeyEvent.META_CTRL_ON, KeyEvent.META_SHIFT_ON, KeyEvent.KEYCODE_SPACE) ) private val expectedImeShortcutCategoryWithDiscardedUnsupportedShortcuts = shortcutCategory(ShortcutCategoryType.IME) { subCategory("input", emptyList()) } private val switchToPreviousLanguageKeyboardShortcutInfo = KeyboardShortcutInfo( /* label = */ "switch to previous language", /* keycode = */ switchToPreviousLanguageCommand.keyCodes[2], /* modifiers = */ switchToPreviousLanguageCommand.keyCodes[0] or switchToPreviousLanguageCommand.keyCodes[1], ) private val expectedImeShortcutCategoryWithPreviousLanguageSwitchShortcut = shortcutCategory(ShortcutCategoryType.IME) { subCategory( "input", listOf( Shortcut( switchToPreviousLanguageKeyboardShortcutInfo.label!!.toString(), listOf(switchToPreviousLanguageCommand) ) ) ) } private val imeShortcutsGroupWithPreviousLanguageSwitchShortcut = listOf( KeyboardShortcutGroup( "input", listOf( switchToPreviousLanguageKeyboardShortcutInfo, ) ) ) private val shortcutInfoWithUnsupportedModifier = KeyboardShortcutInfo( /* label = */ "unsupported shortcut", /* keycode = */ KeyEvent.KEYCODE_SPACE, /* modifiers = */ 32 ) private val imeShortcutsGroupWithUnsupportedShortcutModifiers = listOf( KeyboardShortcutGroup( "input", listOf( shortcutInfoWithUnsupportedModifier, ) ) ) }