summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/hardware/input/IInputManager.aidl6
-rw-r--r--core/java/android/hardware/input/InputManagerGlobal.java39
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java9
-rw-r--r--services/core/java/com/android/server/input/KeyboardLayoutManager.java35
-rw-r--r--tests/Input/src/com/android/server/input/KeyboardLayoutManagerTests.kt37
5 files changed, 121 insertions, 5 deletions
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index 2bb28a1b6b0b..7fc7e4d81afa 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -106,6 +106,12 @@ interface IInputManager {
@EnforcePermission("SET_KEYBOARD_LAYOUT")
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = "
+ "android.Manifest.permission.SET_KEYBOARD_LAYOUT)")
+ void setKeyboardLayoutOverrideForInputDevice(in InputDeviceIdentifier identifier,
+ String keyboardLayoutDescriptor);
+
+ @EnforcePermission("SET_KEYBOARD_LAYOUT")
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = "
+ + "android.Manifest.permission.SET_KEYBOARD_LAYOUT)")
void setKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier, int userId,
in InputMethodInfo imeInfo, in InputMethodSubtype imeSubtype,
String keyboardLayoutDescriptor);
diff --git a/core/java/android/hardware/input/InputManagerGlobal.java b/core/java/android/hardware/input/InputManagerGlobal.java
index 3ef90e4b8a5f..e79416162fc2 100644
--- a/core/java/android/hardware/input/InputManagerGlobal.java
+++ b/core/java/android/hardware/input/InputManagerGlobal.java
@@ -57,6 +57,8 @@ import android.view.InputMonitor;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.PointerIcon;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodSubtype;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -1256,6 +1258,43 @@ public final class InputManagerGlobal {
}
/**
+ * Sets the keyboard layout override for the specified input device. This will set the
+ * keyboard layout as the default for the input device irrespective of the underlying IME
+ * configuration.
+ *
+ * <p>
+ * Prefer using {@link InputManager#setKeyboardLayoutForInputDevice(InputDeviceIdentifier, int,
+ * InputMethodInfo, InputMethodSubtype, String)} for normal use cases.
+ * </p><p>
+ * This method is to be used only for special cases where we knowingly want to set a
+ * particular keyboard layout for a keyboard, ignoring the IME configuration. e.g. Setting a
+ * default layout for an Android Emulator where we know the preferred H/W keyboard layout.
+ * </p><p>
+ * NOTE: This may affect the typing experience if the layout isn't compatible with the IME
+ * configuration.
+ * </p><p>
+ * NOTE: User can still change the keyboard layout configuration from the settings page.
+ * </p>
+ *
+ * @param identifier The identifier for the input device.
+ * @param keyboardLayoutDescriptor The keyboard layout descriptor to use.
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.SET_KEYBOARD_LAYOUT)
+ public void setKeyboardLayoutOverrideForInputDevice(@NonNull InputDeviceIdentifier identifier,
+ @NonNull String keyboardLayoutDescriptor) {
+ Objects.requireNonNull(identifier, "identifier should not be null");
+ Objects.requireNonNull(keyboardLayoutDescriptor,
+ "keyboardLayoutDescriptor should not be null");
+ try {
+ mIm.setKeyboardLayoutOverrideForInputDevice(identifier, keyboardLayoutDescriptor);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* TODO(b/330517633): Cleanup the unsupported API
*/
@NonNull
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 2ba35d6a70d2..4e03e86dfe36 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -1261,6 +1261,15 @@ public class InputManagerService extends IInputManager.Stub
@EnforcePermission(Manifest.permission.SET_KEYBOARD_LAYOUT)
@Override // Binder call
+ public void setKeyboardLayoutOverrideForInputDevice(InputDeviceIdentifier identifier,
+ String keyboardLayoutDescriptor) {
+ super.setKeyboardLayoutOverrideForInputDevice_enforcePermission();
+ mKeyboardLayoutManager.setKeyboardLayoutOverrideForInputDevice(identifier,
+ keyboardLayoutDescriptor);
+ }
+
+ @EnforcePermission(Manifest.permission.SET_KEYBOARD_LAYOUT)
+ @Override // Binder call
public void setKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
@UserIdInt int userId, @NonNull InputMethodInfo imeInfo,
@Nullable InputMethodSubtype imeSubtype, String keyboardLayoutDescriptor) {
diff --git a/services/core/java/com/android/server/input/KeyboardLayoutManager.java b/services/core/java/com/android/server/input/KeyboardLayoutManager.java
index 1d1a178ff20b..b8ce86b7c98c 100644
--- a/services/core/java/com/android/server/input/KeyboardLayoutManager.java
+++ b/services/core/java/com/android/server/input/KeyboardLayoutManager.java
@@ -113,6 +113,7 @@ class KeyboardLayoutManager implements InputManager.InputDeviceListener {
private static final int MSG_UPDATE_EXISTING_DEVICES = 1;
private static final int MSG_RELOAD_KEYBOARD_LAYOUTS = 2;
private static final int MSG_UPDATE_KEYBOARD_LAYOUTS = 3;
+ private static final String GLOBAL_OVERRIDE_KEY = "GLOBAL_OVERRIDE_KEY";
private final Context mContext;
private final NativeInputManagerService mNative;
@@ -508,26 +509,44 @@ class KeyboardLayoutManager implements InputManager.InputDeviceListener {
}
@AnyThread
+ public void setKeyboardLayoutOverrideForInputDevice(InputDeviceIdentifier identifier,
+ String keyboardLayoutDescriptor) {
+ InputDevice inputDevice = getInputDevice(identifier);
+ if (inputDevice == null || inputDevice.isVirtual() || !inputDevice.isFullKeyboard()) {
+ return;
+ }
+ KeyboardIdentifier keyboardIdentifier = new KeyboardIdentifier(inputDevice);
+ setKeyboardLayoutForInputDeviceInternal(keyboardIdentifier, GLOBAL_OVERRIDE_KEY,
+ keyboardLayoutDescriptor);
+ }
+
+ @AnyThread
public void setKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
@UserIdInt int userId, @NonNull InputMethodInfo imeInfo,
@Nullable InputMethodSubtype imeSubtype,
String keyboardLayoutDescriptor) {
- Objects.requireNonNull(keyboardLayoutDescriptor,
- "keyboardLayoutDescriptor must not be null");
InputDevice inputDevice = getInputDevice(identifier);
if (inputDevice == null || inputDevice.isVirtual() || !inputDevice.isFullKeyboard()) {
return;
}
KeyboardIdentifier keyboardIdentifier = new KeyboardIdentifier(inputDevice);
- String layoutKey = new LayoutKey(keyboardIdentifier,
+ final String datastoreKey = new LayoutKey(keyboardIdentifier,
new ImeInfo(userId, imeInfo, imeSubtype)).toString();
+ setKeyboardLayoutForInputDeviceInternal(keyboardIdentifier, datastoreKey,
+ keyboardLayoutDescriptor);
+ }
+
+ private void setKeyboardLayoutForInputDeviceInternal(KeyboardIdentifier identifier,
+ String datastoreKey, String keyboardLayoutDescriptor) {
+ Objects.requireNonNull(keyboardLayoutDescriptor,
+ "keyboardLayoutDescriptor must not be null");
synchronized (mDataStore) {
try {
- if (mDataStore.setKeyboardLayout(keyboardIdentifier.toString(), layoutKey,
+ if (mDataStore.setKeyboardLayout(identifier.toString(), datastoreKey,
keyboardLayoutDescriptor)) {
if (DEBUG) {
Slog.d(TAG, "setKeyboardLayoutForInputDevice() " + identifier
- + " key: " + layoutKey
+ + " key: " + datastoreKey
+ " keyboardLayoutDescriptor: " + keyboardLayoutDescriptor);
}
mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
@@ -635,6 +654,12 @@ class KeyboardLayoutManager implements InputManager.InputDeviceListener {
if (layout != null) {
return new KeyboardLayoutSelectionResult(layout, LAYOUT_SELECTION_CRITERIA_USER);
}
+
+ layout = mDataStore.getKeyboardLayout(keyboardIdentifier.toString(),
+ GLOBAL_OVERRIDE_KEY);
+ if (layout != null) {
+ return new KeyboardLayoutSelectionResult(layout, LAYOUT_SELECTION_CRITERIA_DEVICE);
+ }
}
synchronized (mKeyboardLayoutCache) {
diff --git a/tests/Input/src/com/android/server/input/KeyboardLayoutManagerTests.kt b/tests/Input/src/com/android/server/input/KeyboardLayoutManagerTests.kt
index d6654cceb458..4440a839caef 100644
--- a/tests/Input/src/com/android/server/input/KeyboardLayoutManagerTests.kt
+++ b/tests/Input/src/com/android/server/input/KeyboardLayoutManagerTests.kt
@@ -28,6 +28,8 @@ import android.hardware.input.InputManager
import android.hardware.input.InputManagerGlobal
import android.hardware.input.KeyboardLayout
import android.hardware.input.KeyboardLayoutSelectionResult
+import android.hardware.input.KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_DEVICE
+import android.hardware.input.KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_USER
import android.icu.util.ULocale
import android.os.Bundle
import android.os.test.TestLooper
@@ -281,6 +283,41 @@ class KeyboardLayoutManagerTests {
}
@Test
+ fun testGetSetKeyboardLayoutOverrideForInputDevice() {
+ val imeSubtype = createImeSubtype()
+
+ keyboardLayoutManager.setKeyboardLayoutOverrideForInputDevice(
+ keyboardDevice.identifier,
+ ENGLISH_UK_LAYOUT_DESCRIPTOR
+ )
+ var result =
+ keyboardLayoutManager.getKeyboardLayoutForInputDevice(
+ keyboardDevice.identifier, USER_ID, imeInfo, imeSubtype
+ )
+ assertEquals(LAYOUT_SELECTION_CRITERIA_DEVICE, result.selectionCriteria)
+ assertEquals(
+ "getKeyboardLayoutForInputDevice API should return the set layout",
+ ENGLISH_UK_LAYOUT_DESCRIPTOR,
+ result.layoutDescriptor
+ )
+
+ // This should replace the overriding layout set above
+ keyboardLayoutManager.setKeyboardLayoutForInputDevice(
+ keyboardDevice.identifier, USER_ID, imeInfo, imeSubtype,
+ ENGLISH_US_LAYOUT_DESCRIPTOR
+ )
+ result = keyboardLayoutManager.getKeyboardLayoutForInputDevice(
+ keyboardDevice.identifier, USER_ID, imeInfo, imeSubtype
+ )
+ assertEquals(LAYOUT_SELECTION_CRITERIA_USER, result.selectionCriteria)
+ assertEquals(
+ "getKeyboardLayoutForInputDevice API should return the user set layout",
+ ENGLISH_US_LAYOUT_DESCRIPTOR,
+ result.layoutDescriptor
+ )
+ }
+
+ @Test
fun testGetKeyboardLayoutListForInputDevice() {
// Check Layouts for "hi-Latn". It should return all 'Latn' keyboard layouts
var keyboardLayouts =