Merge "Handle layout selection before onInputDeviceAdded()" into main
This commit is contained in:
committed by
Android (Google) Code Review
commit
73a9932a92
@@ -3527,6 +3527,8 @@ package android.view {
|
||||
method @RequiresPermission("android.permission.DISABLE_INPUT_DEVICE") public void disable();
|
||||
method @RequiresPermission("android.permission.DISABLE_INPUT_DEVICE") public void enable();
|
||||
method @NonNull public android.hardware.input.InputDeviceIdentifier getIdentifier();
|
||||
method @Nullable public String getKeyboardLanguageTag();
|
||||
method @Nullable public String getKeyboardLayoutType();
|
||||
}
|
||||
|
||||
public abstract class InputEvent implements android.os.Parcelable {
|
||||
|
||||
@@ -958,6 +958,7 @@ public final class InputDevice implements Parcelable {
|
||||
* @hide
|
||||
*/
|
||||
@Nullable
|
||||
@TestApi
|
||||
public String getKeyboardLanguageTag() {
|
||||
return mKeyboardLanguageTag;
|
||||
}
|
||||
@@ -968,6 +969,7 @@ public final class InputDevice implements Parcelable {
|
||||
* @hide
|
||||
*/
|
||||
@Nullable
|
||||
@TestApi
|
||||
public String getKeyboardLayoutType() {
|
||||
return mKeyboardLayoutType;
|
||||
}
|
||||
|
||||
@@ -2725,11 +2725,12 @@ public class InputManagerService extends IInputManager.Stub
|
||||
|
||||
// Native callback.
|
||||
@SuppressWarnings("unused")
|
||||
private String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier) {
|
||||
private String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier, String languageTag,
|
||||
String layoutType) {
|
||||
if (!mSystemReady) {
|
||||
return null;
|
||||
}
|
||||
return mKeyboardLayoutManager.getKeyboardLayoutOverlay(identifier);
|
||||
return mKeyboardLayoutManager.getKeyboardLayoutOverlay(identifier, languageTag, layoutType);
|
||||
}
|
||||
|
||||
@EnforcePermission(Manifest.permission.REMAP_MODIFIER_KEYS)
|
||||
|
||||
@@ -25,6 +25,7 @@ import android.annotation.AnyThread;
|
||||
import android.annotation.MainThread;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
@@ -109,7 +110,6 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
private static final int MSG_SWITCH_KEYBOARD_LAYOUT = 2;
|
||||
private static final int MSG_RELOAD_KEYBOARD_LAYOUTS = 3;
|
||||
private static final int MSG_UPDATE_KEYBOARD_LAYOUTS = 4;
|
||||
private static final int MSG_CURRENT_IME_INFO_CHANGED = 5;
|
||||
|
||||
private final Context mContext;
|
||||
private final NativeInputManagerService mNative;
|
||||
@@ -186,6 +186,7 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
if (inputDevice == null || inputDevice.isVirtual() || !inputDevice.isFullKeyboard()) {
|
||||
return;
|
||||
}
|
||||
final KeyboardIdentifier keyboardIdentifier = new KeyboardIdentifier(inputDevice);
|
||||
KeyboardConfiguration config = mConfiguredKeyboards.get(deviceId);
|
||||
if (config == null) {
|
||||
config = new KeyboardConfiguration();
|
||||
@@ -202,8 +203,6 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
setCurrentKeyboardLayoutForInputDevice(inputDevice.getIdentifier(), layout);
|
||||
}
|
||||
}
|
||||
config.setCurrentLayout(
|
||||
new KeyboardLayoutInfo(layout, LAYOUT_SELECTION_CRITERIA_USER));
|
||||
if (layout == null) {
|
||||
// In old settings show notification always until user manually selects a
|
||||
// layout in the settings.
|
||||
@@ -211,16 +210,14 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
final InputDeviceIdentifier identifier = inputDevice.getIdentifier();
|
||||
final String key = getLayoutDescriptor(identifier);
|
||||
Set<String> selectedLayouts = new HashSet<>();
|
||||
List<ImeInfo> imeInfoList = getImeInfoListForLayoutMapping();
|
||||
List<KeyboardLayoutInfo> layoutInfoList = new ArrayList<>();
|
||||
boolean hasMissingLayout = false;
|
||||
for (ImeInfo imeInfo : imeInfoList) {
|
||||
// Check if the layout has been previously configured
|
||||
KeyboardLayoutInfo layoutInfo = getKeyboardLayoutForInputDeviceInternal(identifier,
|
||||
imeInfo);
|
||||
KeyboardLayoutInfo layoutInfo = getKeyboardLayoutForInputDeviceInternal(
|
||||
keyboardIdentifier, imeInfo);
|
||||
boolean noLayoutFound = layoutInfo == null || layoutInfo.mDescriptor == null;
|
||||
if (!noLayoutFound) {
|
||||
selectedLayouts.add(layoutInfo.mDescriptor);
|
||||
@@ -231,8 +228,8 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG,
|
||||
"Layouts selected for input device: " + identifier + " -> selectedLayouts: "
|
||||
+ selectedLayouts);
|
||||
"Layouts selected for input device: " + keyboardIdentifier
|
||||
+ " -> selectedLayouts: " + selectedLayouts);
|
||||
}
|
||||
|
||||
// If even one layout not configured properly, we need to ask user to configure
|
||||
@@ -243,18 +240,9 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
|
||||
config.setConfiguredLayouts(selectedLayouts);
|
||||
|
||||
// Update current layout: If there is a change then need to reload.
|
||||
synchronized (mImeInfoLock) {
|
||||
KeyboardLayoutInfo layoutInfo = getKeyboardLayoutForInputDeviceInternal(
|
||||
inputDevice.getIdentifier(), mCurrentImeInfo);
|
||||
if (!Objects.equals(layoutInfo, config.getCurrentLayout())) {
|
||||
config.setCurrentLayout(layoutInfo);
|
||||
mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (mDataStore) {
|
||||
try {
|
||||
final String key = keyboardIdentifier.toString();
|
||||
boolean isFirstConfiguration = !mDataStore.hasInputDeviceEntry(key);
|
||||
if (mDataStore.setSelectedKeyboardLayouts(key, selectedLayouts)) {
|
||||
// Need to show the notification only if layout selection changed
|
||||
@@ -563,35 +551,6 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
return LocaleList.forLanguageTags(languageTags.replace('|', ','));
|
||||
}
|
||||
|
||||
private String getLayoutDescriptor(@NonNull InputDeviceIdentifier identifier) {
|
||||
Objects.requireNonNull(identifier, "identifier must not be null");
|
||||
Objects.requireNonNull(identifier.getDescriptor(), "descriptor must not be null");
|
||||
|
||||
if (identifier.getVendorId() == 0 && identifier.getProductId() == 0) {
|
||||
return identifier.getDescriptor();
|
||||
}
|
||||
// If vendor id and product id is available, use it as keys. This allows us to have the
|
||||
// same setup for all keyboards with same product and vendor id. i.e. User can swap 2
|
||||
// identical keyboards and still get the same setup.
|
||||
StringBuilder key = new StringBuilder();
|
||||
key.append("vendor:").append(identifier.getVendorId()).append(",product:").append(
|
||||
identifier.getProductId());
|
||||
|
||||
if (useNewSettingsUi()) {
|
||||
InputDevice inputDevice = getInputDevice(identifier);
|
||||
Objects.requireNonNull(inputDevice, "Input device must not be null");
|
||||
// Some keyboards can have same product ID and vendor ID but different Keyboard info
|
||||
// like language tag and layout type.
|
||||
if (!TextUtils.isEmpty(inputDevice.getKeyboardLanguageTag())) {
|
||||
key.append(",languageTag:").append(inputDevice.getKeyboardLanguageTag());
|
||||
}
|
||||
if (!TextUtils.isEmpty(inputDevice.getKeyboardLayoutType())) {
|
||||
key.append(",layoutType:").append(inputDevice.getKeyboardLayoutType());
|
||||
}
|
||||
}
|
||||
return key.toString();
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@Nullable
|
||||
public String getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier) {
|
||||
@@ -599,7 +558,7 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
Slog.e(TAG, "getCurrentKeyboardLayoutForInputDevice API not supported");
|
||||
return null;
|
||||
}
|
||||
String key = getLayoutDescriptor(identifier);
|
||||
String key = new KeyboardIdentifier(identifier).toString();
|
||||
synchronized (mDataStore) {
|
||||
String layout;
|
||||
// try loading it using the layout descriptor if we have it
|
||||
@@ -626,7 +585,7 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
|
||||
Objects.requireNonNull(keyboardLayoutDescriptor,
|
||||
"keyboardLayoutDescriptor must not be null");
|
||||
String key = getLayoutDescriptor(identifier);
|
||||
String key = new KeyboardIdentifier(identifier).toString();
|
||||
synchronized (mDataStore) {
|
||||
try {
|
||||
if (mDataStore.setCurrentKeyboardLayout(key, keyboardLayoutDescriptor)) {
|
||||
@@ -649,7 +608,7 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
Slog.e(TAG, "getEnabledKeyboardLayoutsForInputDevice API not supported");
|
||||
return new String[0];
|
||||
}
|
||||
String key = getLayoutDescriptor(identifier);
|
||||
String key = new KeyboardIdentifier(identifier).toString();
|
||||
synchronized (mDataStore) {
|
||||
String[] layouts = mDataStore.getKeyboardLayouts(key);
|
||||
if ((layouts == null || layouts.length == 0)
|
||||
@@ -670,7 +629,7 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
Objects.requireNonNull(keyboardLayoutDescriptor,
|
||||
"keyboardLayoutDescriptor must not be null");
|
||||
|
||||
String key = getLayoutDescriptor(identifier);
|
||||
String key = new KeyboardIdentifier(identifier).toString();
|
||||
synchronized (mDataStore) {
|
||||
try {
|
||||
String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
|
||||
@@ -698,7 +657,7 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
Objects.requireNonNull(keyboardLayoutDescriptor,
|
||||
"keyboardLayoutDescriptor must not be null");
|
||||
|
||||
String key = getLayoutDescriptor(identifier);
|
||||
String key = new KeyboardIdentifier(identifier).toString();
|
||||
synchronized (mDataStore) {
|
||||
try {
|
||||
String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
|
||||
@@ -737,7 +696,7 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
final boolean changed;
|
||||
final String keyboardLayoutDescriptor;
|
||||
|
||||
String key = getLayoutDescriptor(device.getIdentifier());
|
||||
String key = new KeyboardIdentifier(device.getIdentifier()).toString();
|
||||
synchronized (mDataStore) {
|
||||
try {
|
||||
changed = mDataStore.switchKeyboardLayout(key, direction);
|
||||
@@ -769,11 +728,13 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
|
||||
@Nullable
|
||||
@AnyThread
|
||||
public String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier) {
|
||||
public String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier, String languageTag,
|
||||
String layoutType) {
|
||||
String keyboardLayoutDescriptor;
|
||||
if (useNewSettingsUi()) {
|
||||
synchronized (mImeInfoLock) {
|
||||
KeyboardLayoutInfo layoutInfo = getKeyboardLayoutForInputDeviceInternal(identifier,
|
||||
KeyboardLayoutInfo layoutInfo = getKeyboardLayoutForInputDeviceInternal(
|
||||
new KeyboardIdentifier(identifier, languageTag, layoutType),
|
||||
mCurrentImeInfo);
|
||||
keyboardLayoutDescriptor = layoutInfo == null ? null : layoutInfo.mDescriptor;
|
||||
}
|
||||
@@ -811,12 +772,16 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
Slog.e(TAG, "getKeyboardLayoutForInputDevice() API not supported");
|
||||
return null;
|
||||
}
|
||||
InputMethodSubtypeHandle subtypeHandle = InputMethodSubtypeHandle.of(imeInfo, imeSubtype);
|
||||
KeyboardLayoutInfo layoutInfo = getKeyboardLayoutForInputDeviceInternal(identifier,
|
||||
new ImeInfo(userId, subtypeHandle, imeSubtype));
|
||||
InputDevice inputDevice = getInputDevice(identifier);
|
||||
if (inputDevice == null || inputDevice.isVirtual() || !inputDevice.isFullKeyboard()) {
|
||||
return null;
|
||||
}
|
||||
KeyboardIdentifier keyboardIdentifier = new KeyboardIdentifier(inputDevice);
|
||||
KeyboardLayoutInfo layoutInfo = getKeyboardLayoutForInputDeviceInternal(
|
||||
keyboardIdentifier, new ImeInfo(userId, imeInfo, imeSubtype));
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "getKeyboardLayoutForInputDevice() " + identifier.toString() + ", userId : "
|
||||
+ userId + ", subtypeHandle = " + subtypeHandle + " -> " + layoutInfo);
|
||||
+ userId + ", subtype = " + imeSubtype + " -> " + layoutInfo);
|
||||
}
|
||||
return layoutInfo != null ? layoutInfo.mDescriptor : null;
|
||||
}
|
||||
@@ -832,16 +797,20 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
}
|
||||
Objects.requireNonNull(keyboardLayoutDescriptor,
|
||||
"keyboardLayoutDescriptor must not be null");
|
||||
String key = createLayoutKey(identifier,
|
||||
new ImeInfo(userId, InputMethodSubtypeHandle.of(imeInfo, imeSubtype), imeSubtype));
|
||||
InputDevice inputDevice = getInputDevice(identifier);
|
||||
if (inputDevice == null || inputDevice.isVirtual() || !inputDevice.isFullKeyboard()) {
|
||||
return;
|
||||
}
|
||||
KeyboardIdentifier keyboardIdentifier = new KeyboardIdentifier(inputDevice);
|
||||
String layoutKey = new LayoutKey(keyboardIdentifier,
|
||||
new ImeInfo(userId, imeInfo, imeSubtype)).toString();
|
||||
synchronized (mDataStore) {
|
||||
try {
|
||||
// Key for storing into data store = <device descriptor>,<userId>,<subtypeHandle>
|
||||
if (mDataStore.setKeyboardLayout(getLayoutDescriptor(identifier), key,
|
||||
if (mDataStore.setKeyboardLayout(keyboardIdentifier.toString(), layoutKey,
|
||||
keyboardLayoutDescriptor)) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "setKeyboardLayoutForInputDevice() " + identifier
|
||||
+ " key: " + key
|
||||
+ " key: " + layoutKey
|
||||
+ " keyboardLayoutDescriptor: " + keyboardLayoutDescriptor);
|
||||
}
|
||||
mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
|
||||
@@ -860,18 +829,23 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
Slog.e(TAG, "getKeyboardLayoutListForInputDevice() API not supported");
|
||||
return new KeyboardLayout[0];
|
||||
}
|
||||
return getKeyboardLayoutListForInputDeviceInternal(identifier, new ImeInfo(userId,
|
||||
InputMethodSubtypeHandle.of(imeInfo, imeSubtype), imeSubtype));
|
||||
InputDevice inputDevice = getInputDevice(identifier);
|
||||
if (inputDevice == null || inputDevice.isVirtual() || !inputDevice.isFullKeyboard()) {
|
||||
return new KeyboardLayout[0];
|
||||
}
|
||||
return getKeyboardLayoutListForInputDeviceInternal(new KeyboardIdentifier(inputDevice),
|
||||
new ImeInfo(userId, imeInfo, imeSubtype));
|
||||
}
|
||||
|
||||
private KeyboardLayout[] getKeyboardLayoutListForInputDeviceInternal(
|
||||
InputDeviceIdentifier identifier, @Nullable ImeInfo imeInfo) {
|
||||
String key = createLayoutKey(identifier, imeInfo);
|
||||
KeyboardIdentifier keyboardIdentifier, @Nullable ImeInfo imeInfo) {
|
||||
String layoutKey = new LayoutKey(keyboardIdentifier, imeInfo).toString();
|
||||
|
||||
// Fetch user selected layout and always include it in layout list.
|
||||
String userSelectedLayout;
|
||||
synchronized (mDataStore) {
|
||||
userSelectedLayout = mDataStore.getKeyboardLayout(getLayoutDescriptor(identifier), key);
|
||||
userSelectedLayout = mDataStore.getKeyboardLayout(keyboardIdentifier.toString(),
|
||||
layoutKey);
|
||||
}
|
||||
|
||||
final ArrayList<KeyboardLayout> potentialLayouts = new ArrayList<>();
|
||||
@@ -894,8 +868,8 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
// devices that have special layouts we assume there's a reason that the generic
|
||||
// layouts don't work for them, so we don't want to return them since it's likely
|
||||
// to result in a poor user experience.
|
||||
if (layout.getVendorId() == identifier.getVendorId()
|
||||
&& layout.getProductId() == identifier.getProductId()) {
|
||||
if (layout.getVendorId() == keyboardIdentifier.mIdentifier.getVendorId()
|
||||
&& layout.getProductId() == keyboardIdentifier.mIdentifier.getProductId()) {
|
||||
if (!mDeviceSpecificLayoutAvailable) {
|
||||
mDeviceSpecificLayoutAvailable = true;
|
||||
potentialLayouts.clear();
|
||||
@@ -934,7 +908,7 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
if (mCurrentImeInfo == null || !subtypeHandle.equals(mCurrentImeInfo.mImeSubtypeHandle)
|
||||
|| mCurrentImeInfo.mUserId != userId) {
|
||||
mCurrentImeInfo = new ImeInfo(userId, subtypeHandle, subtype);
|
||||
mHandler.sendEmptyMessage(MSG_CURRENT_IME_INFO_CHANGED);
|
||||
mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "InputMethodSubtype changed: userId=" + userId
|
||||
+ " subtypeHandle=" + subtypeHandle);
|
||||
@@ -943,34 +917,12 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
}
|
||||
}
|
||||
|
||||
@MainThread
|
||||
private void onCurrentImeInfoChanged() {
|
||||
synchronized (mImeInfoLock) {
|
||||
for (int i = 0; i < mConfiguredKeyboards.size(); i++) {
|
||||
InputDevice inputDevice = Objects.requireNonNull(
|
||||
getInputDevice(mConfiguredKeyboards.keyAt(i)));
|
||||
KeyboardLayoutInfo layoutInfo = getKeyboardLayoutForInputDeviceInternal(
|
||||
inputDevice.getIdentifier(), mCurrentImeInfo);
|
||||
KeyboardConfiguration config = mConfiguredKeyboards.valueAt(i);
|
||||
if (!Objects.equals(layoutInfo, config.getCurrentLayout())) {
|
||||
config.setCurrentLayout(layoutInfo);
|
||||
mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private KeyboardLayoutInfo getKeyboardLayoutForInputDeviceInternal(
|
||||
InputDeviceIdentifier identifier, @Nullable ImeInfo imeInfo) {
|
||||
InputDevice inputDevice = getInputDevice(identifier);
|
||||
if (inputDevice == null || inputDevice.isVirtual() || !inputDevice.isFullKeyboard()) {
|
||||
return null;
|
||||
}
|
||||
String key = createLayoutKey(identifier, imeInfo);
|
||||
KeyboardIdentifier keyboardIdentifier, @Nullable ImeInfo imeInfo) {
|
||||
String layoutKey = new LayoutKey(keyboardIdentifier, imeInfo).toString();
|
||||
synchronized (mDataStore) {
|
||||
String layout = mDataStore.getKeyboardLayout(getLayoutDescriptor(identifier), key);
|
||||
String layout = mDataStore.getKeyboardLayout(keyboardIdentifier.toString(), layoutKey);
|
||||
if (layout != null) {
|
||||
return new KeyboardLayoutInfo(layout, LAYOUT_SELECTION_CRITERIA_USER);
|
||||
}
|
||||
@@ -978,16 +930,17 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
|
||||
synchronized (mKeyboardLayoutCache) {
|
||||
// Check Auto-selected layout cache to see if layout had been previously selected
|
||||
if (mKeyboardLayoutCache.containsKey(key)) {
|
||||
return mKeyboardLayoutCache.get(key);
|
||||
if (mKeyboardLayoutCache.containsKey(layoutKey)) {
|
||||
return mKeyboardLayoutCache.get(layoutKey);
|
||||
} else {
|
||||
// NOTE: This list is already filtered based on IME Script code
|
||||
KeyboardLayout[] layoutList = getKeyboardLayoutListForInputDeviceInternal(
|
||||
identifier, imeInfo);
|
||||
keyboardIdentifier, imeInfo);
|
||||
// Call auto-matching algorithm to find the best matching layout
|
||||
KeyboardLayoutInfo layoutInfo =
|
||||
getDefaultKeyboardLayoutBasedOnImeInfo(inputDevice, imeInfo, layoutList);
|
||||
mKeyboardLayoutCache.put(key, layoutInfo);
|
||||
getDefaultKeyboardLayoutBasedOnImeInfo(keyboardIdentifier, imeInfo,
|
||||
layoutList);
|
||||
mKeyboardLayoutCache.put(layoutKey, layoutInfo);
|
||||
return layoutInfo;
|
||||
}
|
||||
}
|
||||
@@ -995,17 +948,18 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
|
||||
@Nullable
|
||||
private static KeyboardLayoutInfo getDefaultKeyboardLayoutBasedOnImeInfo(
|
||||
InputDevice inputDevice, @Nullable ImeInfo imeInfo, KeyboardLayout[] layoutList) {
|
||||
KeyboardIdentifier keyboardIdentifier, @Nullable ImeInfo imeInfo,
|
||||
KeyboardLayout[] layoutList) {
|
||||
Arrays.sort(layoutList);
|
||||
|
||||
// Check <VendorID, ProductID> matching for explicitly declared custom KCM files.
|
||||
for (KeyboardLayout layout : layoutList) {
|
||||
if (layout.getVendorId() == inputDevice.getVendorId()
|
||||
&& layout.getProductId() == inputDevice.getProductId()) {
|
||||
if (layout.getVendorId() == keyboardIdentifier.mIdentifier.getVendorId()
|
||||
&& layout.getProductId() == keyboardIdentifier.mIdentifier.getProductId()) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG,
|
||||
"getDefaultKeyboardLayoutBasedOnImeInfo() : Layout found based on "
|
||||
+ "vendor and product Ids. " + inputDevice.getIdentifier()
|
||||
+ "vendor and product Ids. " + keyboardIdentifier
|
||||
+ " : " + layout.getDescriptor());
|
||||
}
|
||||
return new KeyboardLayoutInfo(layout.getDescriptor(),
|
||||
@@ -1014,17 +968,17 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
}
|
||||
|
||||
// Check layout type, language tag information from InputDevice for matching
|
||||
String inputLanguageTag = inputDevice.getKeyboardLanguageTag();
|
||||
String inputLanguageTag = keyboardIdentifier.mLanguageTag;
|
||||
if (inputLanguageTag != null) {
|
||||
String layoutDesc = getMatchingLayoutForProvidedLanguageTagAndLayoutType(layoutList,
|
||||
inputLanguageTag, inputDevice.getKeyboardLayoutType());
|
||||
inputLanguageTag, keyboardIdentifier.mLayoutType);
|
||||
|
||||
if (layoutDesc != null) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG,
|
||||
"getDefaultKeyboardLayoutBasedOnImeInfo() : Layout found based on "
|
||||
+ "HW information (Language tag and Layout type). "
|
||||
+ inputDevice.getIdentifier() + " : " + layoutDesc);
|
||||
+ keyboardIdentifier + " : " + layoutDesc);
|
||||
}
|
||||
return new KeyboardLayoutInfo(layoutDesc, LAYOUT_SELECTION_CRITERIA_DEVICE);
|
||||
}
|
||||
@@ -1045,7 +999,7 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG,
|
||||
"getDefaultKeyboardLayoutBasedOnImeInfo() : Layout found based on "
|
||||
+ "IME locale matching. " + inputDevice.getIdentifier() + " : "
|
||||
+ "IME locale matching. " + keyboardIdentifier + " : "
|
||||
+ layoutDesc);
|
||||
}
|
||||
if (layoutDesc != null) {
|
||||
@@ -1105,7 +1059,7 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
}
|
||||
}
|
||||
return layoutMatchingLanguageAndCountry != null
|
||||
? layoutMatchingLanguageAndCountry : layoutMatchingLanguage;
|
||||
? layoutMatchingLanguageAndCountry : layoutMatchingLanguage;
|
||||
}
|
||||
|
||||
private void reloadKeyboardLayouts() {
|
||||
@@ -1297,9 +1251,6 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
case MSG_UPDATE_KEYBOARD_LAYOUTS:
|
||||
updateKeyboardLayouts();
|
||||
return true;
|
||||
case MSG_CURRENT_IME_INFO_CHANGED:
|
||||
onCurrentImeInfoChanged();
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -1322,6 +1273,7 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
identifier.getDescriptor()) : null;
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
private List<ImeInfo> getImeInfoListForLayoutMapping() {
|
||||
List<ImeInfo> imeInfoList = new ArrayList<>();
|
||||
UserManager userManager = Objects.requireNonNull(
|
||||
@@ -1337,31 +1289,20 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
int userId = userHandle.getIdentifier();
|
||||
for (InputMethodInfo imeInfo :
|
||||
inputMethodManagerInternal.getEnabledInputMethodListAsUser(
|
||||
userId)) {
|
||||
userId)) {
|
||||
for (InputMethodSubtype imeSubtype :
|
||||
inputMethodManager.getEnabledInputMethodSubtypeList(
|
||||
imeInfo, true /* allowsImplicitlyEnabledSubtypes */)) {
|
||||
if (!imeSubtype.isSuitableForPhysicalKeyboardLayoutMapping()) {
|
||||
continue;
|
||||
}
|
||||
imeInfoList.add(
|
||||
new ImeInfo(userId, InputMethodSubtypeHandle.of(imeInfo, imeSubtype),
|
||||
imeSubtype));
|
||||
imeInfoList.add(new ImeInfo(userId, imeInfo, imeSubtype));
|
||||
}
|
||||
}
|
||||
}
|
||||
return imeInfoList;
|
||||
}
|
||||
|
||||
private String createLayoutKey(InputDeviceIdentifier identifier, @Nullable ImeInfo imeInfo) {
|
||||
if (imeInfo == null) {
|
||||
return getLayoutDescriptor(identifier);
|
||||
}
|
||||
Objects.requireNonNull(imeInfo.mImeSubtypeHandle, "subtypeHandle must not be null");
|
||||
return "layoutDescriptor:" + getLayoutDescriptor(identifier) + ",userId:" + imeInfo.mUserId
|
||||
+ ",subtypeHandle:" + imeInfo.mImeSubtypeHandle.toStringHandle();
|
||||
}
|
||||
|
||||
private static boolean isLayoutCompatibleWithLanguageTag(KeyboardLayout layout,
|
||||
@NonNull String languageTag) {
|
||||
LocaleList layoutLocales = layout.getLocales();
|
||||
@@ -1451,6 +1392,11 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
mImeSubtypeHandle = imeSubtypeHandle;
|
||||
mImeSubtype = imeSubtype;
|
||||
}
|
||||
|
||||
ImeInfo(@UserIdInt int userId, @NonNull InputMethodInfo imeInfo,
|
||||
@Nullable InputMethodSubtype imeSubtype) {
|
||||
this(userId, InputMethodSubtypeHandle.of(imeInfo, imeSubtype), imeSubtype);
|
||||
}
|
||||
}
|
||||
|
||||
private static class KeyboardConfiguration {
|
||||
@@ -1459,10 +1405,6 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
@Nullable
|
||||
private Set<String> mConfiguredLayouts;
|
||||
|
||||
// If null, it means no layout is selected for the device.
|
||||
@Nullable
|
||||
private KeyboardLayoutInfo mCurrentLayout;
|
||||
|
||||
private boolean hasConfiguredLayouts() {
|
||||
return mConfiguredLayouts != null && !mConfiguredLayouts.isEmpty();
|
||||
}
|
||||
@@ -1475,15 +1417,6 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
private void setConfiguredLayouts(Set<String> configuredLayouts) {
|
||||
mConfiguredLayouts = configuredLayouts;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private KeyboardLayoutInfo getCurrentLayout() {
|
||||
return mCurrentLayout;
|
||||
}
|
||||
|
||||
private void setCurrentLayout(KeyboardLayoutInfo currentLayout) {
|
||||
mCurrentLayout = currentLayout;
|
||||
}
|
||||
}
|
||||
|
||||
private static class KeyboardLayoutInfo {
|
||||
@@ -1517,4 +1450,88 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
void visitKeyboardLayout(Resources resources,
|
||||
int keyboardLayoutResId, KeyboardLayout layout);
|
||||
}
|
||||
|
||||
private static class KeyboardIdentifier {
|
||||
@NonNull
|
||||
private final InputDeviceIdentifier mIdentifier;
|
||||
@Nullable
|
||||
private final String mLanguageTag;
|
||||
@Nullable
|
||||
private final String mLayoutType;
|
||||
|
||||
// NOTE: Use this only for old settings UI where we don't use language tag and layout
|
||||
// type to determine the KCM file.
|
||||
private KeyboardIdentifier(@NonNull InputDeviceIdentifier inputDeviceIdentifier) {
|
||||
this(inputDeviceIdentifier, null, null);
|
||||
}
|
||||
|
||||
private KeyboardIdentifier(@NonNull InputDevice inputDevice) {
|
||||
this(inputDevice.getIdentifier(), inputDevice.getKeyboardLanguageTag(),
|
||||
inputDevice.getKeyboardLayoutType());
|
||||
}
|
||||
|
||||
private KeyboardIdentifier(@NonNull InputDeviceIdentifier identifier,
|
||||
@Nullable String languageTag, @Nullable String layoutType) {
|
||||
Objects.requireNonNull(identifier, "identifier must not be null");
|
||||
Objects.requireNonNull(identifier.getDescriptor(), "descriptor must not be null");
|
||||
mIdentifier = identifier;
|
||||
mLanguageTag = languageTag;
|
||||
mLayoutType = layoutType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (mIdentifier.getVendorId() == 0 && mIdentifier.getProductId() == 0) {
|
||||
return mIdentifier.getDescriptor();
|
||||
}
|
||||
// If vendor id and product id is available, use it as keys. This allows us to have the
|
||||
// same setup for all keyboards with same product and vendor id. i.e. User can swap 2
|
||||
// identical keyboards and still get the same setup.
|
||||
StringBuilder key = new StringBuilder();
|
||||
key.append("vendor:").append(mIdentifier.getVendorId()).append(",product:").append(
|
||||
mIdentifier.getProductId());
|
||||
|
||||
// Some keyboards can have same product ID and vendor ID but different Keyboard info
|
||||
// like language tag and layout type.
|
||||
if (!TextUtils.isEmpty(mLanguageTag)) {
|
||||
key.append(",languageTag:").append(mLanguageTag);
|
||||
}
|
||||
if (!TextUtils.isEmpty(mLayoutType)) {
|
||||
key.append(",layoutType:").append(mLayoutType);
|
||||
}
|
||||
return key.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private static class LayoutKey {
|
||||
|
||||
private final KeyboardIdentifier mKeyboardIdentifier;
|
||||
@Nullable
|
||||
private final ImeInfo mImeInfo;
|
||||
|
||||
private LayoutKey(KeyboardIdentifier keyboardIdentifier, @Nullable ImeInfo imeInfo) {
|
||||
mKeyboardIdentifier = keyboardIdentifier;
|
||||
mImeInfo = imeInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (mImeInfo == null) {
|
||||
return mKeyboardIdentifier.toString();
|
||||
}
|
||||
Objects.requireNonNull(mImeInfo.mImeSubtypeHandle, "subtypeHandle must not be null");
|
||||
return "layoutDescriptor:" + mKeyboardIdentifier + ",userId:" + mImeInfo.mUserId
|
||||
+ ",subtypeHandle:" + mImeInfo.mImeSubtypeHandle.toStringHandle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,7 +313,8 @@ public:
|
||||
std::shared_ptr<PointerControllerInterface> obtainPointerController(int32_t deviceId) override;
|
||||
void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) override;
|
||||
std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay(
|
||||
const InputDeviceIdentifier& identifier) override;
|
||||
const InputDeviceIdentifier& identifier,
|
||||
const std::optional<KeyboardLayoutInfo> keyboardLayoutInfo) override;
|
||||
std::string getDeviceAlias(const InputDeviceIdentifier& identifier) override;
|
||||
TouchAffineTransformation getTouchAffineTransformation(const std::string& inputDeviceDescriptor,
|
||||
ui::Rotation surfaceRotation) override;
|
||||
@@ -779,17 +780,32 @@ void NativeInputManager::notifyInputDevicesChanged(const std::vector<InputDevice
|
||||
}
|
||||
|
||||
std::shared_ptr<KeyCharacterMap> NativeInputManager::getKeyboardLayoutOverlay(
|
||||
const InputDeviceIdentifier& identifier) {
|
||||
const InputDeviceIdentifier& identifier,
|
||||
const std::optional<KeyboardLayoutInfo> keyboardLayoutInfo) {
|
||||
ATRACE_CALL();
|
||||
JNIEnv* env = jniEnv();
|
||||
|
||||
std::shared_ptr<KeyCharacterMap> result;
|
||||
ScopedLocalRef<jstring> descriptor(env, env->NewStringUTF(identifier.descriptor.c_str()));
|
||||
ScopedLocalRef<jstring> languageTag(env,
|
||||
keyboardLayoutInfo
|
||||
? env->NewStringUTF(
|
||||
keyboardLayoutInfo->languageTag.c_str())
|
||||
: nullptr);
|
||||
ScopedLocalRef<jstring> layoutType(env,
|
||||
keyboardLayoutInfo
|
||||
? env->NewStringUTF(
|
||||
keyboardLayoutInfo->layoutType.c_str())
|
||||
: nullptr);
|
||||
ScopedLocalRef<jobject> identifierObj(env, env->NewObject(gInputDeviceIdentifierInfo.clazz,
|
||||
gInputDeviceIdentifierInfo.constructor, descriptor.get(),
|
||||
identifier.vendor, identifier.product));
|
||||
ScopedLocalRef<jobjectArray> arrayObj(env, jobjectArray(env->CallObjectMethod(mServiceObj,
|
||||
gServiceClassInfo.getKeyboardLayoutOverlay, identifierObj.get())));
|
||||
ScopedLocalRef<jobjectArray>
|
||||
arrayObj(env,
|
||||
jobjectArray(env->CallObjectMethod(mServiceObj,
|
||||
gServiceClassInfo.getKeyboardLayoutOverlay,
|
||||
identifierObj.get(), languageTag.get(),
|
||||
layoutType.get())));
|
||||
if (arrayObj.get()) {
|
||||
ScopedLocalRef<jstring> filenameObj(env,
|
||||
jstring(env->GetObjectArrayElement(arrayObj.get(), 0)));
|
||||
@@ -2803,9 +2819,9 @@ int register_android_server_InputManager(JNIEnv* env) {
|
||||
GET_METHOD_ID(gServiceClassInfo.getPointerIcon, clazz,
|
||||
"getPointerIcon", "(I)Landroid/view/PointerIcon;");
|
||||
|
||||
GET_METHOD_ID(gServiceClassInfo.getKeyboardLayoutOverlay, clazz,
|
||||
"getKeyboardLayoutOverlay",
|
||||
"(Landroid/hardware/input/InputDeviceIdentifier;)[Ljava/lang/String;");
|
||||
GET_METHOD_ID(gServiceClassInfo.getKeyboardLayoutOverlay, clazz, "getKeyboardLayoutOverlay",
|
||||
"(Landroid/hardware/input/InputDeviceIdentifier;Ljava/lang/String;Ljava/lang/"
|
||||
"String;)[Ljava/lang/String;");
|
||||
|
||||
GET_METHOD_ID(gServiceClassInfo.getDeviceAlias, clazz,
|
||||
"getDeviceAlias", "(Ljava/lang/String;)Ljava/lang/String;");
|
||||
|
||||
Reference in New Issue
Block a user