Maintain keyboard configuration and reload layouts if changed
Virtual keyboard creation logic involves 2 steps: - Create a uinput device - Updating associated layout info It is possible that when onInputDeviceAdded() occurs layout info is not correctly set. So, everytime we get onInputDeviceChanged() callback and onImeInfoChanged() callback there is a possibility that keyboard layout needs to be reconfigured. So, keep track of current configuration and call reload() when a new layouts needs to be set. Test: atest VirtualKeyboardLayoutTest Bug: 277778640 Change-Id: I998009d394a2103bf5afb37a622094dd771162d8
This commit is contained in:
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.server.input;
|
||||
|
||||
import android.annotation.AnyThread;
|
||||
import android.annotation.MainThread;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.UserIdInt;
|
||||
@@ -99,6 +101,7 @@ 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;
|
||||
@@ -108,16 +111,17 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
private final Handler mHandler;
|
||||
|
||||
// Connected keyboards with associated keyboard layouts (either auto-detected or manually
|
||||
// selected layout). If the mapped value is null/empty, it means that no layout has been
|
||||
// configured for the keyboard and user might need to manually configure it from the Settings.
|
||||
private final SparseArray<Set<String>> mConfiguredKeyboards = new SparseArray<>();
|
||||
// selected layout).
|
||||
private final SparseArray<KeyboardConfiguration> mConfiguredKeyboards = new SparseArray<>();
|
||||
private Toast mSwitchedKeyboardLayoutToast;
|
||||
|
||||
// This cache stores "best-matched" layouts so that we don't need to run the matching
|
||||
// algorithm repeatedly.
|
||||
@GuardedBy("mKeyboardLayoutCache")
|
||||
private final Map<String, String> mKeyboardLayoutCache = new ArrayMap<>();
|
||||
private final Object mImeInfoLock = new Object();
|
||||
@Nullable
|
||||
@GuardedBy("mImeInfoLock")
|
||||
private ImeInfo mCurrentImeInfo;
|
||||
|
||||
KeyboardLayoutManager(Context context, NativeInputManagerService nativeService,
|
||||
@@ -155,26 +159,32 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
}
|
||||
|
||||
@Override
|
||||
@MainThread
|
||||
public void onInputDeviceAdded(int deviceId) {
|
||||
onInputDeviceChanged(deviceId);
|
||||
if (useNewSettingsUi()) {
|
||||
// Force native callback to set up keyboard layout overlay for newly added keyboards
|
||||
reloadKeyboardLayouts();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@MainThread
|
||||
public void onInputDeviceRemoved(int deviceId) {
|
||||
mConfiguredKeyboards.remove(deviceId);
|
||||
maybeUpdateNotification();
|
||||
}
|
||||
|
||||
@Override
|
||||
@MainThread
|
||||
public void onInputDeviceChanged(int deviceId) {
|
||||
final InputDevice inputDevice = getInputDevice(deviceId);
|
||||
if (inputDevice == null || inputDevice.isVirtual() || !inputDevice.isFullKeyboard()) {
|
||||
return;
|
||||
}
|
||||
KeyboardConfiguration config = mConfiguredKeyboards.get(deviceId);
|
||||
if (config == null) {
|
||||
config = new KeyboardConfiguration();
|
||||
mConfiguredKeyboards.put(deviceId, config);
|
||||
}
|
||||
|
||||
boolean needToShowNotification = false;
|
||||
if (!useNewSettingsUi()) {
|
||||
synchronized (mDataStore) {
|
||||
String layout = getCurrentKeyboardLayoutForInputDevice(inputDevice.getIdentifier());
|
||||
@@ -182,54 +192,66 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
layout = getDefaultKeyboardLayout(inputDevice);
|
||||
if (layout != null) {
|
||||
setCurrentKeyboardLayoutForInputDevice(inputDevice.getIdentifier(), layout);
|
||||
} else {
|
||||
mConfiguredKeyboards.put(inputDevice.getId(), new HashSet<>());
|
||||
}
|
||||
}
|
||||
config.setCurrentLayout(layout);
|
||||
if (layout == null) {
|
||||
// In old settings show notification always until user manually selects a
|
||||
// layout in the settings.
|
||||
needToShowNotification = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
final InputDeviceIdentifier identifier = inputDevice.getIdentifier();
|
||||
final String key = getLayoutDescriptor(identifier);
|
||||
Set<String> selectedLayouts = new HashSet<>();
|
||||
boolean needToShowMissingLayoutNotification = false;
|
||||
for (ImeInfo imeInfo : getImeInfoListForLayoutMapping()) {
|
||||
// Check if the layout has been previously configured
|
||||
String layout = getKeyboardLayoutForInputDeviceInternal(identifier,
|
||||
new ImeInfo(imeInfo.mUserId, imeInfo.mImeSubtypeHandle,
|
||||
imeInfo.mImeSubtype));
|
||||
if (layout == null) {
|
||||
needToShowMissingLayoutNotification = true;
|
||||
continue;
|
||||
// If even one layout not configured properly, we need to ask user to configure
|
||||
// the keyboard properly from the Settings.
|
||||
selectedLayouts.clear();
|
||||
break;
|
||||
}
|
||||
selectedLayouts.add(layout);
|
||||
}
|
||||
|
||||
if (needToShowMissingLayoutNotification) {
|
||||
// If even one layout not configured properly we will show configuration
|
||||
// notification allowing user to set the keyboard layout.
|
||||
selectedLayouts.clear();
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG,
|
||||
"Layouts selected for input device: " + identifier + " -> selectedLayouts: "
|
||||
+ selectedLayouts);
|
||||
}
|
||||
mConfiguredKeyboards.set(inputDevice.getId(), selectedLayouts);
|
||||
|
||||
config.setConfiguredLayouts(selectedLayouts);
|
||||
|
||||
// Update current layout: If there is a change then need to reload.
|
||||
synchronized (mImeInfoLock) {
|
||||
String layout = getKeyboardLayoutForInputDeviceInternal(
|
||||
inputDevice.getIdentifier(), mCurrentImeInfo);
|
||||
if (!Objects.equals(layout, config.getCurrentLayout())) {
|
||||
config.setCurrentLayout(layout);
|
||||
mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (mDataStore) {
|
||||
try {
|
||||
if (!mDataStore.setSelectedKeyboardLayouts(key, selectedLayouts)) {
|
||||
// No need to show the notification only if layout selection didn't change
|
||||
if (mDataStore.setSelectedKeyboardLayouts(key, selectedLayouts)) {
|
||||
// Need to show the notification only if layout selection changed
|
||||
// from the previous configuration
|
||||
return;
|
||||
needToShowNotification = true;
|
||||
}
|
||||
} finally {
|
||||
mDataStore.saveIfNeeded();
|
||||
}
|
||||
}
|
||||
}
|
||||
maybeUpdateNotification();
|
||||
if (needToShowNotification) {
|
||||
maybeUpdateNotification();
|
||||
}
|
||||
}
|
||||
|
||||
private String getDefaultKeyboardLayout(final InputDevice inputDevice) {
|
||||
@@ -323,12 +345,14 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
reloadKeyboardLayouts();
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
public KeyboardLayout[] getKeyboardLayouts() {
|
||||
final ArrayList<KeyboardLayout> list = new ArrayList<>();
|
||||
visitAllKeyboardLayouts((resources, keyboardLayoutResId, layout) -> list.add(layout));
|
||||
return list.toArray(new KeyboardLayout[0]);
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
public KeyboardLayout[] getKeyboardLayoutsForInputDevice(
|
||||
final InputDeviceIdentifier identifier) {
|
||||
if (useNewSettingsUi()) {
|
||||
@@ -375,6 +399,7 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
KeyboardLayout[]::new);
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@Nullable
|
||||
public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) {
|
||||
Objects.requireNonNull(keyboardLayoutDescriptor,
|
||||
@@ -543,6 +568,7 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
return key.toString();
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@Nullable
|
||||
public String getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier) {
|
||||
if (useNewSettingsUi()) {
|
||||
@@ -566,6 +592,7 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
}
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
public void setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
|
||||
String keyboardLayoutDescriptor) {
|
||||
if (useNewSettingsUi()) {
|
||||
@@ -592,6 +619,7 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
}
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
public String[] getEnabledKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) {
|
||||
if (useNewSettingsUi()) {
|
||||
Slog.e(TAG, "getEnabledKeyboardLayoutsForInputDevice API not supported");
|
||||
@@ -608,6 +636,7 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
}
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
|
||||
String keyboardLayoutDescriptor) {
|
||||
if (useNewSettingsUi()) {
|
||||
@@ -635,6 +664,7 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
}
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
public void removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
|
||||
String keyboardLayoutDescriptor) {
|
||||
if (useNewSettingsUi()) {
|
||||
@@ -667,6 +697,7 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
}
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
public void switchKeyboardLayout(int deviceId, int direction) {
|
||||
if (useNewSettingsUi()) {
|
||||
Slog.e(TAG, "switchKeyboardLayout API not supported");
|
||||
@@ -675,7 +706,7 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, deviceId, direction).sendToTarget();
|
||||
}
|
||||
|
||||
// Must be called on handler.
|
||||
@MainThread
|
||||
private void handleSwitchKeyboardLayout(int deviceId, int direction) {
|
||||
final InputDevice device = getInputDevice(deviceId);
|
||||
if (device != null) {
|
||||
@@ -713,23 +744,14 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@AnyThread
|
||||
public String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier) {
|
||||
String keyboardLayoutDescriptor;
|
||||
if (useNewSettingsUi()) {
|
||||
InputDevice inputDevice = getInputDevice(identifier);
|
||||
if (inputDevice == null) {
|
||||
// getKeyboardLayoutOverlay() called before input device added completely. Need
|
||||
// to wait till the device is added which will call reloadKeyboardLayouts()
|
||||
return null;
|
||||
synchronized (mImeInfoLock) {
|
||||
keyboardLayoutDescriptor = getKeyboardLayoutForInputDeviceInternal(identifier,
|
||||
mCurrentImeInfo);
|
||||
}
|
||||
if (mCurrentImeInfo == null) {
|
||||
// Haven't received onInputMethodSubtypeChanged() callback from IMMS. Will reload
|
||||
// keyboard layouts once we receive the callback.
|
||||
return null;
|
||||
}
|
||||
|
||||
keyboardLayoutDescriptor = getKeyboardLayoutForInputDeviceInternal(identifier,
|
||||
mCurrentImeInfo);
|
||||
} else {
|
||||
keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice(identifier);
|
||||
}
|
||||
@@ -755,6 +777,7 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
return result;
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@Nullable
|
||||
public String getKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
|
||||
@UserIdInt int userId, @NonNull InputMethodInfo imeInfo,
|
||||
@@ -773,6 +796,7 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
return layout;
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
public void setKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
|
||||
@UserIdInt int userId, @NonNull InputMethodInfo imeInfo,
|
||||
@Nullable InputMethodSubtype imeSubtype,
|
||||
@@ -783,8 +807,8 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
}
|
||||
Objects.requireNonNull(keyboardLayoutDescriptor,
|
||||
"keyboardLayoutDescriptor must not be null");
|
||||
String key = createLayoutKey(identifier, userId,
|
||||
InputMethodSubtypeHandle.of(imeInfo, imeSubtype));
|
||||
String key = createLayoutKey(identifier,
|
||||
new ImeInfo(userId, InputMethodSubtypeHandle.of(imeInfo, imeSubtype), imeSubtype));
|
||||
synchronized (mDataStore) {
|
||||
try {
|
||||
// Key for storing into data store = <device descriptor>,<userId>,<subtypeHandle>
|
||||
@@ -803,6 +827,7 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
}
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
public KeyboardLayout[] getKeyboardLayoutListForInputDevice(InputDeviceIdentifier identifier,
|
||||
@UserIdInt int userId, @NonNull InputMethodInfo imeInfo,
|
||||
@Nullable InputMethodSubtype imeSubtype) {
|
||||
@@ -815,8 +840,8 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
}
|
||||
|
||||
private KeyboardLayout[] getKeyboardLayoutListForInputDeviceInternal(
|
||||
InputDeviceIdentifier identifier, ImeInfo imeInfo) {
|
||||
String key = createLayoutKey(identifier, imeInfo.mUserId, imeInfo.mImeSubtypeHandle);
|
||||
InputDeviceIdentifier identifier, @Nullable ImeInfo imeInfo) {
|
||||
String key = createLayoutKey(identifier, imeInfo);
|
||||
|
||||
// Fetch user selected layout and always include it in layout list.
|
||||
String userSelectedLayout;
|
||||
@@ -826,7 +851,7 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
|
||||
final ArrayList<KeyboardLayout> potentialLayouts = new ArrayList<>();
|
||||
String imeLanguageTag;
|
||||
if (imeInfo.mImeSubtype == null) {
|
||||
if (imeInfo == null || imeInfo.mImeSubtype == null) {
|
||||
imeLanguageTag = "";
|
||||
} else {
|
||||
ULocale imeLocale = imeInfo.mImeSubtype.getPhysicalKeyboardHintLanguageTag();
|
||||
@@ -866,6 +891,7 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
return potentialLayouts.toArray(new KeyboardLayout[0]);
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
public void onInputMethodSubtypeChanged(@UserIdInt int userId,
|
||||
@Nullable InputMethodSubtypeHandle subtypeHandle,
|
||||
@Nullable InputMethodSubtype subtype) {
|
||||
@@ -879,25 +905,45 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (mCurrentImeInfo == null || !subtypeHandle.equals(mCurrentImeInfo.mImeSubtypeHandle)
|
||||
|| mCurrentImeInfo.mUserId != userId) {
|
||||
mCurrentImeInfo = new ImeInfo(userId, subtypeHandle, subtype);
|
||||
mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "InputMethodSubtype changed: userId=" + userId
|
||||
+ " subtypeHandle=" + subtypeHandle);
|
||||
synchronized (mImeInfoLock) {
|
||||
if (mCurrentImeInfo == null || !subtypeHandle.equals(mCurrentImeInfo.mImeSubtypeHandle)
|
||||
|| mCurrentImeInfo.mUserId != userId) {
|
||||
mCurrentImeInfo = new ImeInfo(userId, subtypeHandle, subtype);
|
||||
mHandler.sendEmptyMessage(MSG_CURRENT_IME_INFO_CHANGED);
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "InputMethodSubtype changed: userId=" + userId
|
||||
+ " subtypeHandle=" + subtypeHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@MainThread
|
||||
private void onCurrentImeInfoChanged() {
|
||||
synchronized (mImeInfoLock) {
|
||||
for (int i = 0; i < mConfiguredKeyboards.size(); i++) {
|
||||
InputDevice inputDevice = Objects.requireNonNull(
|
||||
getInputDevice(mConfiguredKeyboards.keyAt(i)));
|
||||
String layout = getKeyboardLayoutForInputDeviceInternal(inputDevice.getIdentifier(),
|
||||
mCurrentImeInfo);
|
||||
KeyboardConfiguration config = mConfiguredKeyboards.valueAt(i);
|
||||
if (!Objects.equals(layout, config.getCurrentLayout())) {
|
||||
config.setCurrentLayout(layout);
|
||||
mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String getKeyboardLayoutForInputDeviceInternal(InputDeviceIdentifier identifier,
|
||||
ImeInfo imeInfo) {
|
||||
@Nullable ImeInfo imeInfo) {
|
||||
InputDevice inputDevice = getInputDevice(identifier);
|
||||
if (inputDevice == null || inputDevice.isVirtual() || !inputDevice.isFullKeyboard()) {
|
||||
return null;
|
||||
}
|
||||
String key = createLayoutKey(identifier, imeInfo.mUserId, imeInfo.mImeSubtypeHandle);
|
||||
String key = createLayoutKey(identifier, imeInfo);
|
||||
String layout;
|
||||
synchronized (mDataStore) {
|
||||
layout = mDataStore.getKeyboardLayout(getLayoutDescriptor(identifier), key);
|
||||
@@ -923,11 +969,7 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
|
||||
@Nullable
|
||||
private static String getDefaultKeyboardLayoutBasedOnImeInfo(InputDevice inputDevice,
|
||||
ImeInfo imeInfo, KeyboardLayout[] layoutList) {
|
||||
if (imeInfo.mImeSubtypeHandle == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable ImeInfo imeInfo, KeyboardLayout[] layoutList) {
|
||||
Arrays.sort(layoutList);
|
||||
|
||||
// Check <VendorID, ProductID> matching for explicitly declared custom KCM files.
|
||||
@@ -961,12 +1003,12 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
}
|
||||
}
|
||||
|
||||
InputMethodSubtype subtype = imeInfo.mImeSubtype;
|
||||
// Can't auto select layout based on IME if subtype or language tag is null
|
||||
if (subtype == null) {
|
||||
if (imeInfo == null || imeInfo.mImeSubtypeHandle == null || imeInfo.mImeSubtype == null) {
|
||||
// Can't auto select layout based on IME info is null
|
||||
return null;
|
||||
}
|
||||
|
||||
InputMethodSubtype subtype = imeInfo.mImeSubtype;
|
||||
// Check layout type, language tag information from IME for matching
|
||||
ULocale pkLocale = subtype.getPhysicalKeyboardHintLanguageTag();
|
||||
String pkLanguageTag =
|
||||
@@ -1043,6 +1085,7 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
mNative.reloadKeyboardLayouts();
|
||||
}
|
||||
|
||||
@MainThread
|
||||
private void maybeUpdateNotification() {
|
||||
if (mConfiguredKeyboards.size() == 0) {
|
||||
hideKeyboardLayoutNotification();
|
||||
@@ -1051,7 +1094,7 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
for (int i = 0; i < mConfiguredKeyboards.size(); i++) {
|
||||
// If we have a keyboard with no selected layouts, we should always show missing
|
||||
// layout notification even if there are other keyboards that are configured properly.
|
||||
if (mConfiguredKeyboards.valueAt(i).isEmpty()) {
|
||||
if (!mConfiguredKeyboards.valueAt(i).hasConfiguredLayouts()) {
|
||||
showMissingKeyboardLayoutNotification();
|
||||
return;
|
||||
}
|
||||
@@ -1059,7 +1102,7 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
showConfiguredKeyboardLayoutNotification();
|
||||
}
|
||||
|
||||
// Must be called on handler.
|
||||
@MainThread
|
||||
private void showMissingKeyboardLayoutNotification() {
|
||||
final Resources r = mContext.getResources();
|
||||
final String missingKeyboardLayoutNotificationContent = r.getString(
|
||||
@@ -1084,6 +1127,7 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
}
|
||||
}
|
||||
|
||||
@MainThread
|
||||
private void showKeyboardLayoutNotification(@NonNull String intentTitle,
|
||||
@NonNull String intentContent, @Nullable InputDevice targetDevice) {
|
||||
final NotificationManager notificationManager = mContext.getSystemService(
|
||||
@@ -1119,7 +1163,7 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
notification, UserHandle.ALL);
|
||||
}
|
||||
|
||||
// Must be called on handler.
|
||||
@MainThread
|
||||
private void hideKeyboardLayoutNotification() {
|
||||
NotificationManager notificationManager = mContext.getSystemService(
|
||||
NotificationManager.class);
|
||||
@@ -1132,6 +1176,7 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
UserHandle.ALL);
|
||||
}
|
||||
|
||||
@MainThread
|
||||
private void showConfiguredKeyboardLayoutNotification() {
|
||||
final Resources r = mContext.getResources();
|
||||
|
||||
@@ -1144,8 +1189,8 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
}
|
||||
|
||||
final InputDevice inputDevice = getInputDevice(mConfiguredKeyboards.keyAt(0));
|
||||
final Set<String> selectedLayouts = mConfiguredKeyboards.valueAt(0);
|
||||
if (inputDevice == null || selectedLayouts == null || selectedLayouts.isEmpty()) {
|
||||
final KeyboardConfiguration config = mConfiguredKeyboards.valueAt(0);
|
||||
if (inputDevice == null || !config.hasConfiguredLayouts()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1153,10 +1198,11 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
r.getString(
|
||||
R.string.keyboard_layout_notification_selected_title,
|
||||
inputDevice.getName()),
|
||||
createConfiguredNotificationText(mContext, selectedLayouts),
|
||||
createConfiguredNotificationText(mContext, config.getConfiguredLayouts()),
|
||||
inputDevice);
|
||||
}
|
||||
|
||||
@MainThread
|
||||
private String createConfiguredNotificationText(@NonNull Context context,
|
||||
@NonNull Set<String> selectedLayouts) {
|
||||
final Resources r = context.getResources();
|
||||
@@ -1199,6 +1245,9 @@ 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;
|
||||
}
|
||||
@@ -1252,11 +1301,13 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
return imeInfoList;
|
||||
}
|
||||
|
||||
private String createLayoutKey(InputDeviceIdentifier identifier, int userId,
|
||||
@NonNull InputMethodSubtypeHandle subtypeHandle) {
|
||||
Objects.requireNonNull(subtypeHandle, "subtypeHandle must not be null");
|
||||
return "layoutDescriptor:" + getLayoutDescriptor(identifier) + ",userId:" + userId
|
||||
+ ",subtypeHandle:" + subtypeHandle.toStringHandle();
|
||||
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,
|
||||
@@ -1350,6 +1401,39 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
|
||||
}
|
||||
}
|
||||
|
||||
private static class KeyboardConfiguration {
|
||||
// If null or empty, it means no layout is configured for the device. And user needs to
|
||||
// manually set up the device.
|
||||
@Nullable
|
||||
private Set<String> mConfiguredLayouts;
|
||||
|
||||
// If null, it means no layout is selected for the device.
|
||||
@Nullable
|
||||
private String mCurrentLayout;
|
||||
|
||||
private boolean hasConfiguredLayouts() {
|
||||
return mConfiguredLayouts != null && !mConfiguredLayouts.isEmpty();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Set<String> getConfiguredLayouts() {
|
||||
return mConfiguredLayouts;
|
||||
}
|
||||
|
||||
private void setConfiguredLayouts(Set<String> configuredLayouts) {
|
||||
mConfiguredLayouts = configuredLayouts;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String getCurrentLayout() {
|
||||
return mCurrentLayout;
|
||||
}
|
||||
|
||||
private void setCurrentLayout(String currentLayout) {
|
||||
mCurrentLayout = currentLayout;
|
||||
}
|
||||
}
|
||||
|
||||
private interface KeyboardLayoutVisitor {
|
||||
void visitKeyboardLayout(Resources resources,
|
||||
int keyboardLayoutResId, KeyboardLayout layout);
|
||||
|
||||
Reference in New Issue
Block a user