Loading core/java/android/hardware/input/KeyGlyphMap.java +9 −0 Original line number Diff line number Diff line Loading @@ -158,6 +158,15 @@ public final class KeyGlyphMap implements Parcelable { return getDrawable(context, mModifierGlyphs.get(modifier, 0)); } /** * Provides the drawable resource for the glyph for a modifier state (e.g. META_META_ON). * Returns null if not available. */ @Nullable public Drawable getDrawableForModifierState(Context context, int modifierState) { return getDrawable(context, mModifierGlyphs.get(modifierState, 0)); } @Nullable private Drawable getDrawable(Context context, @DrawableRes int drawableRes) { PackageManager pm = context.getPackageManager(); Loading services/core/java/com/android/server/input/KeyboardGlyphManager.java +8 −6 Original line number Diff line number Diff line Loading @@ -149,17 +149,17 @@ public final class KeyboardGlyphManager implements InputManager.InputDeviceListe continue; } final ActivityInfo activityInfo = resolveInfo.activityInfo; KeyGlyphMapData data = getKeyboardGlyphMapsInPackage(pm, activityInfo); if (data == null) { List<KeyGlyphMapData> data = getKeyboardGlyphMapsInPackage(pm, activityInfo); if (data == null || data.isEmpty()) { continue; } glyphMaps.add(data); glyphMaps.addAll(data); } return glyphMaps; } @Nullable private KeyGlyphMapData getKeyboardGlyphMapsInPackage(PackageManager pm, private List<KeyGlyphMapData> getKeyboardGlyphMapsInPackage(PackageManager pm, @NonNull ActivityInfo receiver) { Bundle metaData = receiver.metaData; if (metaData == null) { Loading @@ -175,6 +175,7 @@ public final class KeyboardGlyphManager implements InputManager.InputDeviceListe try { Resources resources = pm.getResourcesForApplication(receiver.applicationInfo); List<KeyGlyphMapData> glyphMaps = new ArrayList<>(); try (XmlResourceParser parser = resources.getXml(configResId)) { XmlUtils.beginDocument(parser, TAG_KEYBOARD_GLYPH_MAPS); Loading @@ -193,13 +194,14 @@ public final class KeyboardGlyphManager implements InputManager.InputDeviceListe int vendor = a.getInt(R.styleable.KeyboardGlyphMap_vendorId, -1); int product = a.getInt(R.styleable.KeyboardGlyphMap_productId, -1); if (glyphMapRes != 0 && vendor != -1 && product != -1) { return new KeyGlyphMapData(receiver.packageName, receiver.name, glyphMapRes, vendor, product); glyphMaps.add(new KeyGlyphMapData(receiver.packageName, receiver.name, glyphMapRes, vendor, product)); } } finally { a.recycle(); } } return glyphMaps; } } catch (Exception ex) { Slog.w(TAG, "Could not parse keyboard glyph map resource from receiver " Loading tests/Input/res/xml/keyboard_glyph_maps.xml +4 −0 Original line number Diff line number Diff line Loading @@ -19,4 +19,8 @@ androidprv:glyphMap="@xml/test_glyph_map" androidprv:vendorId="0x1234" androidprv:productId="0x3456" /> <keyboard-glyph-map androidprv:glyphMap="@xml/test_glyph_map2" androidprv:vendorId="0x1235" androidprv:productId="0x3457" /> </keyboard-glyph-maps> No newline at end of file tests/Input/res/xml/test_glyph_map2.xml 0 → 100644 +33 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- ~ Copyright 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. --> <keyboard-glyph-map xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> <key-glyph androidprv:keycode="KEYCODE_BACK" androidprv:glyphDrawable="@drawable/test_key_drawable" /> <modifier-glyph androidprv:modifier="META" androidprv:glyphDrawable="@drawable/test_modifier_drawable" /> <function-row-key androidprv:keycode="KEYCODE_EMOJI_PICKER" /> <hardware-defined-shortcut androidprv:keycode="KEYCODE_1" androidprv:modifierState="FUNCTION" androidprv:outKeycode="KEYCODE_BACK" /> <hardware-defined-shortcut androidprv:keycode="KEYCODE_2" androidprv:modifierState="FUNCTION|META" androidprv:outKeycode="KEYCODE_HOME" /> </keyboard-glyph-map> No newline at end of file tests/Input/src/com/android/server/input/KeyboardGlyphManagerTests.kt +12 −1 Original line number Diff line number Diff line Loading @@ -59,6 +59,9 @@ class KeyboardGlyphManagerTests { const val DEVICE_ID = 1 const val VENDOR_ID = 0x1234 const val PRODUCT_ID = 0x3456 const val DEVICE_ID2 = 2 const val VENDOR_ID2 = 0x1235 const val PRODUCT_ID2 = 0x3457 const val PACKAGE_NAME = "KeyboardLayoutManagerTests" const val RECEIVER_NAME = "DummyReceiver" } Loading Loading @@ -96,8 +99,11 @@ class KeyboardGlyphManagerTests { .thenReturn(inputManager) keyboardDevice = createKeyboard(DEVICE_ID, VENDOR_ID, PRODUCT_ID, 0, "", "") Mockito.`when`(inputManagerRule.mock.inputDeviceIds).thenReturn(intArrayOf(DEVICE_ID)) Mockito.`when`(inputManagerRule.mock.inputDeviceIds).thenReturn(intArrayOf(DEVICE_ID, DEVICE_ID2)) Mockito.`when`(inputManagerRule.mock.getInputDevice(DEVICE_ID)).thenReturn(keyboardDevice) val keyboardDevice2 = createKeyboard(DEVICE_ID2, VENDOR_ID2, PRODUCT_ID2, 0, "", "") Mockito.`when`(inputManagerRule.mock.getInputDevice(DEVICE_ID2)).thenReturn(keyboardDevice2) } private fun setupBroadcastReceiver() { Loading Loading @@ -143,6 +149,10 @@ class KeyboardGlyphManagerTests { "Glyph map for test keyboard(deviceId=$DEVICE_ID) must exist", keyboardGlyphManager.getKeyGlyphMap(DEVICE_ID) ) assertNotNull( "Glyph map for test keyboard(deviceId=$DEVICE_ID2) must exist", keyboardGlyphManager.getKeyGlyphMap(DEVICE_ID2) ) assertNull( "Glyph map for non-existing keyboard must be null", keyboardGlyphManager.getKeyGlyphMap(-2) Loading @@ -158,6 +168,7 @@ class KeyboardGlyphManagerTests { assertNotNull(glyphMap.getDrawableForModifier(context, KeyEvent.KEYCODE_META_LEFT)) assertNotNull(glyphMap.getDrawableForModifier(context, KeyEvent.KEYCODE_META_RIGHT)) assertNotNull(glyphMap.getDrawableForModifierState(context, KeyEvent.META_META_ON)) val functionRowKeys = glyphMap.functionRowKeys assertEquals(1, functionRowKeys.size) Loading Loading
core/java/android/hardware/input/KeyGlyphMap.java +9 −0 Original line number Diff line number Diff line Loading @@ -158,6 +158,15 @@ public final class KeyGlyphMap implements Parcelable { return getDrawable(context, mModifierGlyphs.get(modifier, 0)); } /** * Provides the drawable resource for the glyph for a modifier state (e.g. META_META_ON). * Returns null if not available. */ @Nullable public Drawable getDrawableForModifierState(Context context, int modifierState) { return getDrawable(context, mModifierGlyphs.get(modifierState, 0)); } @Nullable private Drawable getDrawable(Context context, @DrawableRes int drawableRes) { PackageManager pm = context.getPackageManager(); Loading
services/core/java/com/android/server/input/KeyboardGlyphManager.java +8 −6 Original line number Diff line number Diff line Loading @@ -149,17 +149,17 @@ public final class KeyboardGlyphManager implements InputManager.InputDeviceListe continue; } final ActivityInfo activityInfo = resolveInfo.activityInfo; KeyGlyphMapData data = getKeyboardGlyphMapsInPackage(pm, activityInfo); if (data == null) { List<KeyGlyphMapData> data = getKeyboardGlyphMapsInPackage(pm, activityInfo); if (data == null || data.isEmpty()) { continue; } glyphMaps.add(data); glyphMaps.addAll(data); } return glyphMaps; } @Nullable private KeyGlyphMapData getKeyboardGlyphMapsInPackage(PackageManager pm, private List<KeyGlyphMapData> getKeyboardGlyphMapsInPackage(PackageManager pm, @NonNull ActivityInfo receiver) { Bundle metaData = receiver.metaData; if (metaData == null) { Loading @@ -175,6 +175,7 @@ public final class KeyboardGlyphManager implements InputManager.InputDeviceListe try { Resources resources = pm.getResourcesForApplication(receiver.applicationInfo); List<KeyGlyphMapData> glyphMaps = new ArrayList<>(); try (XmlResourceParser parser = resources.getXml(configResId)) { XmlUtils.beginDocument(parser, TAG_KEYBOARD_GLYPH_MAPS); Loading @@ -193,13 +194,14 @@ public final class KeyboardGlyphManager implements InputManager.InputDeviceListe int vendor = a.getInt(R.styleable.KeyboardGlyphMap_vendorId, -1); int product = a.getInt(R.styleable.KeyboardGlyphMap_productId, -1); if (glyphMapRes != 0 && vendor != -1 && product != -1) { return new KeyGlyphMapData(receiver.packageName, receiver.name, glyphMapRes, vendor, product); glyphMaps.add(new KeyGlyphMapData(receiver.packageName, receiver.name, glyphMapRes, vendor, product)); } } finally { a.recycle(); } } return glyphMaps; } } catch (Exception ex) { Slog.w(TAG, "Could not parse keyboard glyph map resource from receiver " Loading
tests/Input/res/xml/keyboard_glyph_maps.xml +4 −0 Original line number Diff line number Diff line Loading @@ -19,4 +19,8 @@ androidprv:glyphMap="@xml/test_glyph_map" androidprv:vendorId="0x1234" androidprv:productId="0x3456" /> <keyboard-glyph-map androidprv:glyphMap="@xml/test_glyph_map2" androidprv:vendorId="0x1235" androidprv:productId="0x3457" /> </keyboard-glyph-maps> No newline at end of file
tests/Input/res/xml/test_glyph_map2.xml 0 → 100644 +33 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- ~ Copyright 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. --> <keyboard-glyph-map xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> <key-glyph androidprv:keycode="KEYCODE_BACK" androidprv:glyphDrawable="@drawable/test_key_drawable" /> <modifier-glyph androidprv:modifier="META" androidprv:glyphDrawable="@drawable/test_modifier_drawable" /> <function-row-key androidprv:keycode="KEYCODE_EMOJI_PICKER" /> <hardware-defined-shortcut androidprv:keycode="KEYCODE_1" androidprv:modifierState="FUNCTION" androidprv:outKeycode="KEYCODE_BACK" /> <hardware-defined-shortcut androidprv:keycode="KEYCODE_2" androidprv:modifierState="FUNCTION|META" androidprv:outKeycode="KEYCODE_HOME" /> </keyboard-glyph-map> No newline at end of file
tests/Input/src/com/android/server/input/KeyboardGlyphManagerTests.kt +12 −1 Original line number Diff line number Diff line Loading @@ -59,6 +59,9 @@ class KeyboardGlyphManagerTests { const val DEVICE_ID = 1 const val VENDOR_ID = 0x1234 const val PRODUCT_ID = 0x3456 const val DEVICE_ID2 = 2 const val VENDOR_ID2 = 0x1235 const val PRODUCT_ID2 = 0x3457 const val PACKAGE_NAME = "KeyboardLayoutManagerTests" const val RECEIVER_NAME = "DummyReceiver" } Loading Loading @@ -96,8 +99,11 @@ class KeyboardGlyphManagerTests { .thenReturn(inputManager) keyboardDevice = createKeyboard(DEVICE_ID, VENDOR_ID, PRODUCT_ID, 0, "", "") Mockito.`when`(inputManagerRule.mock.inputDeviceIds).thenReturn(intArrayOf(DEVICE_ID)) Mockito.`when`(inputManagerRule.mock.inputDeviceIds).thenReturn(intArrayOf(DEVICE_ID, DEVICE_ID2)) Mockito.`when`(inputManagerRule.mock.getInputDevice(DEVICE_ID)).thenReturn(keyboardDevice) val keyboardDevice2 = createKeyboard(DEVICE_ID2, VENDOR_ID2, PRODUCT_ID2, 0, "", "") Mockito.`when`(inputManagerRule.mock.getInputDevice(DEVICE_ID2)).thenReturn(keyboardDevice2) } private fun setupBroadcastReceiver() { Loading Loading @@ -143,6 +149,10 @@ class KeyboardGlyphManagerTests { "Glyph map for test keyboard(deviceId=$DEVICE_ID) must exist", keyboardGlyphManager.getKeyGlyphMap(DEVICE_ID) ) assertNotNull( "Glyph map for test keyboard(deviceId=$DEVICE_ID2) must exist", keyboardGlyphManager.getKeyGlyphMap(DEVICE_ID2) ) assertNull( "Glyph map for non-existing keyboard must be null", keyboardGlyphManager.getKeyGlyphMap(-2) Loading @@ -158,6 +168,7 @@ class KeyboardGlyphManagerTests { assertNotNull(glyphMap.getDrawableForModifier(context, KeyEvent.KEYCODE_META_LEFT)) assertNotNull(glyphMap.getDrawableForModifier(context, KeyEvent.KEYCODE_META_RIGHT)) assertNotNull(glyphMap.getDrawableForModifierState(context, KeyEvent.META_META_ON)) val functionRowKeys = glyphMap.functionRowKeys assertEquals(1, functionRowKeys.size) Loading