Merge changes from topic "yukawa-b66498367" into pi-dev
am: c8b967a5de
Change-Id: Ib731bddebe7f93fd40034f67eab7f99f016f687f
This commit is contained in:
@@ -26,8 +26,6 @@ import android.os.IBinder;
|
||||
import android.view.InputDevice;
|
||||
import android.view.InputEvent;
|
||||
import android.view.PointerIcon;
|
||||
import android.view.inputmethod.InputMethodInfo;
|
||||
import android.view.inputmethod.InputMethodSubtype;
|
||||
|
||||
/** @hide */
|
||||
interface IInputManager {
|
||||
@@ -67,11 +65,6 @@ interface IInputManager {
|
||||
String keyboardLayoutDescriptor);
|
||||
void removeKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier,
|
||||
String keyboardLayoutDescriptor);
|
||||
KeyboardLayout getKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier,
|
||||
in InputMethodInfo imeInfo, in InputMethodSubtype imeSubtype);
|
||||
void setKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier,
|
||||
in InputMethodInfo imeInfo, in InputMethodSubtype imeSubtype,
|
||||
String keyboardLayoutDescriptor);
|
||||
|
||||
// Registers an input devices changed listener.
|
||||
void registerInputDevicesChangedListener(IInputDevicesChangedListener listener);
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package android.hardware.input;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SdkConstant;
|
||||
import android.annotation.SdkConstant.SdkConstantType;
|
||||
import android.annotation.SystemService;
|
||||
@@ -43,8 +42,6 @@ import android.view.InputDevice;
|
||||
import android.view.InputEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.PointerIcon;
|
||||
import android.view.inputmethod.InputMethodInfo;
|
||||
import android.view.inputmethod.InputMethodSubtype;
|
||||
|
||||
import com.android.internal.os.SomeArgs;
|
||||
|
||||
@@ -703,52 +700,6 @@ public final class InputManager {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the keyboard layout for the specified input device and IME subtype.
|
||||
*
|
||||
* @param identifier The identifier for the input device.
|
||||
* @param inputMethodInfo The input method.
|
||||
* @param inputMethodSubtype The input method subtype. {@code null} if this input method does
|
||||
* not support any subtype.
|
||||
*
|
||||
* @return The associated {@link KeyboardLayout}, or null if one has not been set.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@Nullable
|
||||
public KeyboardLayout getKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
|
||||
InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype inputMethodSubtype) {
|
||||
try {
|
||||
return mIm.getKeyboardLayoutForInputDevice(
|
||||
identifier, inputMethodInfo, inputMethodSubtype);
|
||||
} catch (RemoteException ex) {
|
||||
throw ex.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the keyboard layout for the specified input device and IME subtype pair.
|
||||
*
|
||||
* @param identifier The identifier for the input device.
|
||||
* @param inputMethodInfo The input method with which to associate the keyboard layout.
|
||||
* @param inputMethodSubtype The input method subtype which which to associate the keyboard
|
||||
* layout. {@code null} if this input method does not support any subtype.
|
||||
* @param keyboardLayoutDescriptor The descriptor of the keyboard layout to set
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public void setKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
|
||||
InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype inputMethodSubtype,
|
||||
String keyboardLayoutDescriptor) {
|
||||
try {
|
||||
mIm.setKeyboardLayoutForInputDevice(identifier, inputMethodInfo,
|
||||
inputMethodSubtype, keyboardLayoutDescriptor);
|
||||
} catch (RemoteException ex) {
|
||||
throw ex.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the TouchCalibration applied to the specified input device's coordinates.
|
||||
*
|
||||
|
||||
@@ -123,10 +123,4 @@ public class TouchCalibration implements Parcelable {
|
||||
Float.floatToIntBits(mYScale) ^
|
||||
Float.floatToIntBits(mYOffset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("[%f, %f, %f, %f, %f, %f]",
|
||||
mXScale, mXYMix, mXOffset, mYXMix, mYScale, mYOffset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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.internal.inputmethod;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
import android.view.inputmethod.InputMethodInfo;
|
||||
import android.view.inputmethod.InputMethodSubtype;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class InputMethodSubtypeHandle {
|
||||
private final String mInputMethodId;
|
||||
private final int mSubtypeId;
|
||||
|
||||
public InputMethodSubtypeHandle(InputMethodInfo info, @Nullable InputMethodSubtype subtype) {
|
||||
mInputMethodId = info.getId();
|
||||
if (subtype != null) {
|
||||
mSubtypeId = subtype.hashCode();
|
||||
} else {
|
||||
mSubtypeId = InputMethodUtils.NOT_A_SUBTYPE_ID;
|
||||
}
|
||||
}
|
||||
|
||||
public InputMethodSubtypeHandle(String inputMethodId, int subtypeId) {
|
||||
mInputMethodId = inputMethodId;
|
||||
mSubtypeId = subtypeId;
|
||||
}
|
||||
|
||||
public String getInputMethodId() {
|
||||
return mInputMethodId;
|
||||
}
|
||||
|
||||
public int getSubtypeId() {
|
||||
return mSubtypeId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == null || !(o instanceof InputMethodSubtypeHandle)) {
|
||||
return false;
|
||||
}
|
||||
InputMethodSubtypeHandle other = (InputMethodSubtypeHandle) o;
|
||||
return TextUtils.equals(mInputMethodId, other.getInputMethodId())
|
||||
&& mSubtypeId == other.getSubtypeId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(mInputMethodId) * 31 + mSubtypeId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "InputMethodSubtypeHandle{mInputMethodId=" + mInputMethodId
|
||||
+ ", mSubtypeId=" + mSubtypeId + "}";
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,6 @@ import android.os.LocaleList;
|
||||
import android.os.ShellCallback;
|
||||
import android.util.Log;
|
||||
import android.view.Display;
|
||||
import com.android.internal.inputmethod.InputMethodSubtypeHandle;
|
||||
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
|
||||
import com.android.internal.notification.SystemNotificationChannels;
|
||||
import com.android.internal.os.SomeArgs;
|
||||
@@ -79,8 +78,6 @@ import android.os.Message;
|
||||
import android.os.MessageQueue;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ResultReceiver;
|
||||
import android.os.ShellCommand;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.provider.Settings.SettingNotFoundException;
|
||||
@@ -101,6 +98,7 @@ import android.view.Surface;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.inputmethod.InputMethodInfo;
|
||||
import android.view.inputmethod.InputMethodSubtype;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileDescriptor;
|
||||
@@ -174,7 +172,8 @@ public class InputManagerService extends IInputManager.Stub
|
||||
private final ArrayList<InputDevice>
|
||||
mTempFullKeyboards = new ArrayList<InputDevice>(); // handler thread only
|
||||
private boolean mKeyboardLayoutNotificationShown;
|
||||
private InputMethodSubtypeHandle mCurrentImeHandle;
|
||||
private PendingIntent mKeyboardLayoutIntent;
|
||||
private Toast mSwitchedKeyboardLayoutToast;
|
||||
|
||||
// State for vibrator tokens.
|
||||
private Object mVibratorLock = new Object();
|
||||
@@ -1367,82 +1366,6 @@ public class InputManagerService extends IInputManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
@Nullable
|
||||
public KeyboardLayout getKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
|
||||
InputMethodInfo imeInfo, InputMethodSubtype imeSubtype) {
|
||||
InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(imeInfo, imeSubtype);
|
||||
String key = getLayoutDescriptor(identifier);
|
||||
final String keyboardLayoutDescriptor;
|
||||
synchronized (mDataStore) {
|
||||
keyboardLayoutDescriptor = mDataStore.getKeyboardLayout(key, handle);
|
||||
}
|
||||
|
||||
if (keyboardLayoutDescriptor == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final KeyboardLayout[] result = new KeyboardLayout[1];
|
||||
visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
|
||||
@Override
|
||||
public void visitKeyboardLayout(Resources resources,
|
||||
int keyboardLayoutResId, KeyboardLayout layout) {
|
||||
result[0] = layout;
|
||||
}
|
||||
});
|
||||
if (result[0] == null) {
|
||||
Slog.w(TAG, "Could not get keyboard layout with descriptor '"
|
||||
+ keyboardLayoutDescriptor + "'.");
|
||||
}
|
||||
return result[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
|
||||
InputMethodInfo imeInfo, InputMethodSubtype imeSubtype,
|
||||
String keyboardLayoutDescriptor) {
|
||||
if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
|
||||
"setKeyboardLayoutForInputDevice()")) {
|
||||
throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
|
||||
}
|
||||
if (keyboardLayoutDescriptor == null) {
|
||||
throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
|
||||
}
|
||||
if (imeInfo == null) {
|
||||
throw new IllegalArgumentException("imeInfo must not be null");
|
||||
}
|
||||
InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(imeInfo, imeSubtype);
|
||||
setKeyboardLayoutForInputDeviceInner(identifier, handle, keyboardLayoutDescriptor);
|
||||
}
|
||||
|
||||
private void setKeyboardLayoutForInputDeviceInner(InputDeviceIdentifier identifier,
|
||||
InputMethodSubtypeHandle imeHandle, String keyboardLayoutDescriptor) {
|
||||
String key = getLayoutDescriptor(identifier);
|
||||
synchronized (mDataStore) {
|
||||
try {
|
||||
if (mDataStore.setKeyboardLayout(key, imeHandle, keyboardLayoutDescriptor)) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Set keyboard layout " + keyboardLayoutDescriptor +
|
||||
" for subtype " + imeHandle + " and device " + identifier +
|
||||
" using key " + key);
|
||||
}
|
||||
if (imeHandle.equals(mCurrentImeHandle)) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Layout for current subtype changed, switching layout");
|
||||
}
|
||||
SomeArgs args = SomeArgs.obtain();
|
||||
args.arg1 = identifier;
|
||||
args.arg2 = imeHandle;
|
||||
mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, args).sendToTarget();
|
||||
}
|
||||
mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
|
||||
}
|
||||
} finally {
|
||||
mDataStore.saveIfNeeded();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
|
||||
String keyboardLayoutDescriptor) {
|
||||
@@ -1462,7 +1385,8 @@ public class InputManagerService extends IInputManager.Stub
|
||||
oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
|
||||
}
|
||||
if (mDataStore.addKeyboardLayout(key, keyboardLayoutDescriptor)
|
||||
&& !Objects.equals(oldLayout, mDataStore.getCurrentKeyboardLayout(key))) {
|
||||
&& !Objects.equals(oldLayout,
|
||||
mDataStore.getCurrentKeyboardLayout(key))) {
|
||||
mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
|
||||
}
|
||||
} finally {
|
||||
@@ -1512,44 +1436,45 @@ public class InputManagerService extends IInputManager.Stub
|
||||
Slog.i(TAG, "InputMethodSubtype changed: userId=" + userId
|
||||
+ " ime=" + inputMethodInfo + " subtype=" + subtype);
|
||||
}
|
||||
if (inputMethodInfo == null) {
|
||||
Slog.d(TAG, "No InputMethod is running, ignoring change");
|
||||
return;
|
||||
}
|
||||
if (subtype != null && !"keyboard".equals(subtype.getMode())) {
|
||||
Slog.d(TAG, "InputMethodSubtype changed to non-keyboard subtype, ignoring change");
|
||||
return;
|
||||
}
|
||||
InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(inputMethodInfo, subtype);
|
||||
if (!handle.equals(mCurrentImeHandle)) {
|
||||
mCurrentImeHandle = handle;
|
||||
handleSwitchKeyboardLayout(null, handle);
|
||||
}
|
||||
}
|
||||
|
||||
public void switchKeyboardLayout(int deviceId, int direction) {
|
||||
mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, deviceId, direction).sendToTarget();
|
||||
}
|
||||
|
||||
// Must be called on handler.
|
||||
private void handleSwitchKeyboardLayout(@Nullable InputDeviceIdentifier identifier,
|
||||
InputMethodSubtypeHandle handle) {
|
||||
synchronized (mInputDevicesLock) {
|
||||
for (InputDevice device : mInputDevices) {
|
||||
if (identifier != null && !device.getIdentifier().equals(identifier) ||
|
||||
!device.isFullKeyboard()) {
|
||||
continue;
|
||||
private void handleSwitchKeyboardLayout(int deviceId, int direction) {
|
||||
final InputDevice device = getInputDevice(deviceId);
|
||||
if (device != null) {
|
||||
final boolean changed;
|
||||
final String keyboardLayoutDescriptor;
|
||||
|
||||
String key = getLayoutDescriptor(device.getIdentifier());
|
||||
synchronized (mDataStore) {
|
||||
try {
|
||||
changed = mDataStore.switchKeyboardLayout(key, direction);
|
||||
keyboardLayoutDescriptor = mDataStore.getCurrentKeyboardLayout(
|
||||
key);
|
||||
} finally {
|
||||
mDataStore.saveIfNeeded();
|
||||
}
|
||||
String key = getLayoutDescriptor(device.getIdentifier());
|
||||
boolean changed = false;
|
||||
synchronized (mDataStore) {
|
||||
try {
|
||||
if (mDataStore.switchKeyboardLayout(key, handle)) {
|
||||
changed = true;
|
||||
}
|
||||
} finally {
|
||||
mDataStore.saveIfNeeded();
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
if (mSwitchedKeyboardLayoutToast != null) {
|
||||
mSwitchedKeyboardLayoutToast.cancel();
|
||||
mSwitchedKeyboardLayoutToast = null;
|
||||
}
|
||||
if (keyboardLayoutDescriptor != null) {
|
||||
KeyboardLayout keyboardLayout = getKeyboardLayout(keyboardLayoutDescriptor);
|
||||
if (keyboardLayout != null) {
|
||||
mSwitchedKeyboardLayoutToast = Toast.makeText(
|
||||
mContext, keyboardLayout.getLabel(), Toast.LENGTH_SHORT);
|
||||
mSwitchedKeyboardLayoutToast.show();
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
reloadKeyboardLayouts();
|
||||
}
|
||||
|
||||
reloadKeyboardLayouts();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1790,7 +1715,7 @@ public class InputManagerService extends IInputManager.Stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
|
||||
|
||||
pw.println("INPUT MANAGER (dumpsys input)\n");
|
||||
@@ -1798,49 +1723,8 @@ public class InputManagerService extends IInputManager.Stub
|
||||
if (dumpStr != null) {
|
||||
pw.println(dumpStr);
|
||||
}
|
||||
pw.println(" Keyboard Layouts:");
|
||||
visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
|
||||
@Override
|
||||
public void visitKeyboardLayout(Resources resources,
|
||||
int keyboardLayoutResId, KeyboardLayout layout) {
|
||||
pw.println(" \"" + layout + "\": " + layout.getDescriptor());
|
||||
}
|
||||
});
|
||||
pw.println();
|
||||
synchronized(mDataStore) {
|
||||
mDataStore.dump(pw, " ");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShellCommand(FileDescriptor in, FileDescriptor out,
|
||||
FileDescriptor err, String[] args, ShellCallback callback,
|
||||
ResultReceiver resultReceiver) {
|
||||
(new Shell()).exec(this, in, out, err, args, callback, resultReceiver);
|
||||
}
|
||||
|
||||
public int onShellCommand(Shell shell, String cmd) {
|
||||
if (TextUtils.isEmpty(cmd)) {
|
||||
shell.onHelp();
|
||||
return 1;
|
||||
}
|
||||
if (cmd.equals("setlayout")) {
|
||||
if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
|
||||
"onShellCommand()")) {
|
||||
throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
|
||||
}
|
||||
InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(
|
||||
shell.getNextArgRequired(), Integer.parseInt(shell.getNextArgRequired()));
|
||||
String descriptor = shell.getNextArgRequired();
|
||||
int vid = Integer.decode(shell.getNextArgRequired());
|
||||
int pid = Integer.decode(shell.getNextArgRequired());
|
||||
InputDeviceIdentifier id = new InputDeviceIdentifier(descriptor, vid, pid);
|
||||
setKeyboardLayoutForInputDeviceInner(id, handle, shell.getNextArgRequired());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
private boolean checkCallingPermission(String permission, String func) {
|
||||
// Quick check: if the calling permission is me, it's all okay.
|
||||
if (Binder.getCallingPid() == Process.myPid()) {
|
||||
@@ -2169,12 +2053,9 @@ public class InputManagerService extends IInputManager.Stub
|
||||
case MSG_DELIVER_INPUT_DEVICES_CHANGED:
|
||||
deliverInputDevicesChanged((InputDevice[])msg.obj);
|
||||
break;
|
||||
case MSG_SWITCH_KEYBOARD_LAYOUT: {
|
||||
SomeArgs args = (SomeArgs)msg.obj;
|
||||
handleSwitchKeyboardLayout((InputDeviceIdentifier)args.arg1,
|
||||
(InputMethodSubtypeHandle)args.arg2);
|
||||
case MSG_SWITCH_KEYBOARD_LAYOUT:
|
||||
handleSwitchKeyboardLayout(msg.arg1, msg.arg2);
|
||||
break;
|
||||
}
|
||||
case MSG_RELOAD_KEYBOARD_LAYOUTS:
|
||||
reloadKeyboardLayouts();
|
||||
break;
|
||||
@@ -2341,25 +2222,6 @@ public class InputManagerService extends IInputManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
private class Shell extends ShellCommand {
|
||||
@Override
|
||||
public int onCommand(String cmd) {
|
||||
return onShellCommand(this, cmd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHelp() {
|
||||
final PrintWriter pw = getOutPrintWriter();
|
||||
pw.println("Input manager commands:");
|
||||
pw.println(" help");
|
||||
pw.println(" Print this help text.");
|
||||
pw.println("");
|
||||
pw.println(" setlayout IME_ID IME_SUPTYPE_HASH_CODE"
|
||||
+ " DEVICE_DESCRIPTOR VENDOR_ID PRODUCT_ID KEYBOARD_DESCRIPTOR");
|
||||
pw.println(" Sets a keyboard layout for a given IME subtype and input device pair");
|
||||
}
|
||||
}
|
||||
|
||||
private final class LocalService extends InputManagerInternal {
|
||||
@Override
|
||||
public void setDisplayViewports(DisplayViewport defaultViewport,
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package com.android.server.input;
|
||||
|
||||
import com.android.internal.inputmethod.InputMethodSubtypeHandle;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.internal.util.FastXmlSerializer;
|
||||
import com.android.internal.util.XmlUtils;
|
||||
@@ -28,8 +27,6 @@ import org.xmlpull.v1.XmlSerializer;
|
||||
import android.annotation.Nullable;
|
||||
import android.view.Surface;
|
||||
import android.hardware.input.TouchCalibration;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.AtomicFile;
|
||||
import android.util.Slog;
|
||||
import android.util.Xml;
|
||||
@@ -41,13 +38,10 @@ import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
@@ -139,26 +133,9 @@ final class PersistentDataStore {
|
||||
}
|
||||
return state.getKeyboardLayouts();
|
||||
}
|
||||
public String getKeyboardLayout(String inputDeviceDescriptor,
|
||||
InputMethodSubtypeHandle imeHandle) {
|
||||
InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, false);
|
||||
if (state == null) {
|
||||
return null;
|
||||
}
|
||||
return state.getKeyboardLayout(imeHandle);
|
||||
}
|
||||
|
||||
public boolean setKeyboardLayout(String inputDeviceDescriptor,
|
||||
InputMethodSubtypeHandle imeHandle, String keyboardLayoutDescriptor) {
|
||||
InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, true);
|
||||
if (state.setKeyboardLayout(imeHandle, keyboardLayoutDescriptor)) {
|
||||
setDirty();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean addKeyboardLayout(String inputDeviceDescriptor, String keyboardLayoutDescriptor) {
|
||||
public boolean addKeyboardLayout(String inputDeviceDescriptor,
|
||||
String keyboardLayoutDescriptor) {
|
||||
InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, true);
|
||||
if (state.addKeyboardLayout(keyboardLayoutDescriptor)) {
|
||||
setDirty();
|
||||
@@ -177,10 +154,9 @@ final class PersistentDataStore {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean switchKeyboardLayout(String inputDeviceDescriptor,
|
||||
InputMethodSubtypeHandle imeHandle) {
|
||||
public boolean switchKeyboardLayout(String inputDeviceDescriptor, int direction) {
|
||||
InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, false);
|
||||
if (state != null && state.switchKeyboardLayout(imeHandle)) {
|
||||
if (state != null && state.switchKeyboardLayout(direction)) {
|
||||
setDirty();
|
||||
return true;
|
||||
}
|
||||
@@ -327,18 +303,6 @@ final class PersistentDataStore {
|
||||
serializer.endDocument();
|
||||
}
|
||||
|
||||
public void dump(PrintWriter pw, String prefix) {
|
||||
pw.println(prefix + "PersistentDataStore");
|
||||
pw.println(prefix + " mLoaded=" + mLoaded);
|
||||
pw.println(prefix + " mDirty=" + mDirty);
|
||||
pw.println(prefix + " InputDeviceStates:");
|
||||
int i = 0;
|
||||
for (Map.Entry<String, InputDeviceState> entry : mInputDevices.entrySet()) {
|
||||
pw.println(prefix + " " + i++ + ": " + entry.getKey());
|
||||
entry.getValue().dump(pw, prefix + " ");
|
||||
}
|
||||
}
|
||||
|
||||
private static final class InputDeviceState {
|
||||
private static final String[] CALIBRATION_NAME = { "x_scale",
|
||||
"x_ymix", "x_offset", "y_xmix", "y_scale", "y_offset" };
|
||||
@@ -346,8 +310,7 @@ final class PersistentDataStore {
|
||||
private TouchCalibration[] mTouchCalibration = new TouchCalibration[4];
|
||||
@Nullable
|
||||
private String mCurrentKeyboardLayout;
|
||||
private List<String> mUnassociatedKeyboardLayouts = new ArrayList<>();
|
||||
private ArrayMap<InputMethodSubtypeHandle, String> mKeyboardLayouts = new ArrayMap<>();
|
||||
private ArrayList<String> mKeyboardLayouts = new ArrayList<String>();
|
||||
|
||||
public TouchCalibration getTouchCalibration(int surfaceRotation) {
|
||||
try {
|
||||
@@ -386,34 +349,18 @@ final class PersistentDataStore {
|
||||
}
|
||||
|
||||
public String[] getKeyboardLayouts() {
|
||||
if (mUnassociatedKeyboardLayouts.isEmpty()) {
|
||||
if (mKeyboardLayouts.isEmpty()) {
|
||||
return (String[])ArrayUtils.emptyArray(String.class);
|
||||
}
|
||||
return mUnassociatedKeyboardLayouts.toArray(
|
||||
new String[mUnassociatedKeyboardLayouts.size()]);
|
||||
}
|
||||
|
||||
public String getKeyboardLayout(InputMethodSubtypeHandle handle) {
|
||||
return mKeyboardLayouts.get(handle);
|
||||
}
|
||||
|
||||
public boolean setKeyboardLayout(InputMethodSubtypeHandle imeHandle,
|
||||
String keyboardLayout) {
|
||||
String existingLayout = mKeyboardLayouts.get(imeHandle);
|
||||
if (TextUtils.equals(existingLayout, keyboardLayout)) {
|
||||
return false;
|
||||
}
|
||||
mKeyboardLayouts.put(imeHandle, keyboardLayout);
|
||||
return true;
|
||||
return mKeyboardLayouts.toArray(new String[mKeyboardLayouts.size()]);
|
||||
}
|
||||
|
||||
public boolean addKeyboardLayout(String keyboardLayout) {
|
||||
int index = Collections.binarySearch(
|
||||
mUnassociatedKeyboardLayouts, keyboardLayout);
|
||||
int index = Collections.binarySearch(mKeyboardLayouts, keyboardLayout);
|
||||
if (index >= 0) {
|
||||
return false;
|
||||
}
|
||||
mUnassociatedKeyboardLayouts.add(-index - 1, keyboardLayout);
|
||||
mKeyboardLayouts.add(-index - 1, keyboardLayout);
|
||||
if (mCurrentKeyboardLayout == null) {
|
||||
mCurrentKeyboardLayout = keyboardLayout;
|
||||
}
|
||||
@@ -421,11 +368,11 @@ final class PersistentDataStore {
|
||||
}
|
||||
|
||||
public boolean removeKeyboardLayout(String keyboardLayout) {
|
||||
int index = Collections.binarySearch(mUnassociatedKeyboardLayouts, keyboardLayout);
|
||||
int index = Collections.binarySearch(mKeyboardLayouts, keyboardLayout);
|
||||
if (index < 0) {
|
||||
return false;
|
||||
}
|
||||
mUnassociatedKeyboardLayouts.remove(index);
|
||||
mKeyboardLayouts.remove(index);
|
||||
updateCurrentKeyboardLayoutIfRemoved(keyboardLayout, index);
|
||||
return true;
|
||||
}
|
||||
@@ -433,34 +380,41 @@ final class PersistentDataStore {
|
||||
private void updateCurrentKeyboardLayoutIfRemoved(
|
||||
String removedKeyboardLayout, int removedIndex) {
|
||||
if (Objects.equals(mCurrentKeyboardLayout, removedKeyboardLayout)) {
|
||||
if (!mUnassociatedKeyboardLayouts.isEmpty()) {
|
||||
if (!mKeyboardLayouts.isEmpty()) {
|
||||
int index = removedIndex;
|
||||
if (index == mUnassociatedKeyboardLayouts.size()) {
|
||||
if (index == mKeyboardLayouts.size()) {
|
||||
index = 0;
|
||||
}
|
||||
mCurrentKeyboardLayout = mUnassociatedKeyboardLayouts.get(index);
|
||||
mCurrentKeyboardLayout = mKeyboardLayouts.get(index);
|
||||
} else {
|
||||
mCurrentKeyboardLayout = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean switchKeyboardLayout(InputMethodSubtypeHandle imeHandle) {
|
||||
final String layout = mKeyboardLayouts.get(imeHandle);
|
||||
if (!TextUtils.equals(mCurrentKeyboardLayout, layout)) {
|
||||
mCurrentKeyboardLayout = layout;
|
||||
return true;
|
||||
public boolean switchKeyboardLayout(int direction) {
|
||||
final int size = mKeyboardLayouts.size();
|
||||
if (size < 2) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
int index = Collections.binarySearch(mKeyboardLayouts, mCurrentKeyboardLayout);
|
||||
assert index >= 0;
|
||||
if (direction > 0) {
|
||||
index = (index + 1) % size;
|
||||
} else {
|
||||
index = (index + size - 1) % size;
|
||||
}
|
||||
mCurrentKeyboardLayout = mKeyboardLayouts.get(index);
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean removeUninstalledKeyboardLayouts(Set<String> availableKeyboardLayouts) {
|
||||
boolean changed = false;
|
||||
for (int i = mUnassociatedKeyboardLayouts.size(); i-- > 0; ) {
|
||||
String keyboardLayout = mUnassociatedKeyboardLayouts.get(i);
|
||||
for (int i = mKeyboardLayouts.size(); i-- > 0; ) {
|
||||
String keyboardLayout = mKeyboardLayouts.get(i);
|
||||
if (!availableKeyboardLayouts.contains(keyboardLayout)) {
|
||||
Slog.i(TAG, "Removing uninstalled keyboard layout " + keyboardLayout);
|
||||
mUnassociatedKeyboardLayouts.remove(i);
|
||||
mKeyboardLayouts.remove(i);
|
||||
updateCurrentKeyboardLayoutIfRemoved(keyboardLayout, i);
|
||||
changed = true;
|
||||
}
|
||||
@@ -478,8 +432,13 @@ final class PersistentDataStore {
|
||||
throw new XmlPullParserException(
|
||||
"Missing descriptor attribute on keyboard-layout.");
|
||||
}
|
||||
|
||||
String current = parser.getAttributeValue(null, "current");
|
||||
if (mKeyboardLayouts.contains(descriptor)) {
|
||||
throw new XmlPullParserException(
|
||||
"Found duplicate keyboard layout.");
|
||||
}
|
||||
|
||||
mKeyboardLayouts.add(descriptor);
|
||||
if (current != null && current.equals("true")) {
|
||||
if (mCurrentKeyboardLayout != null) {
|
||||
throw new XmlPullParserException(
|
||||
@@ -487,32 +446,6 @@ final class PersistentDataStore {
|
||||
}
|
||||
mCurrentKeyboardLayout = descriptor;
|
||||
}
|
||||
|
||||
String inputMethodId = parser.getAttributeValue(null, "input-method-id");
|
||||
String inputMethodSubtypeId =
|
||||
parser.getAttributeValue(null, "input-method-subtype-id");
|
||||
if (inputMethodId == null && inputMethodSubtypeId != null
|
||||
|| inputMethodId != null && inputMethodSubtypeId == null) {
|
||||
throw new XmlPullParserException(
|
||||
"Found an incomplete input method description");
|
||||
}
|
||||
|
||||
if (inputMethodSubtypeId != null) {
|
||||
InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(
|
||||
inputMethodId, Integer.parseInt(inputMethodSubtypeId));
|
||||
if (mKeyboardLayouts.containsKey(handle)) {
|
||||
throw new XmlPullParserException(
|
||||
"Found duplicate subtype to keyboard layout mapping: "
|
||||
+ handle);
|
||||
}
|
||||
mKeyboardLayouts.put(handle, descriptor);
|
||||
} else {
|
||||
if (mUnassociatedKeyboardLayouts.contains(descriptor)) {
|
||||
throw new XmlPullParserException(
|
||||
"Found duplicate unassociated keyboard layout: " + descriptor);
|
||||
}
|
||||
mUnassociatedKeyboardLayouts.add(descriptor);
|
||||
}
|
||||
} else if (parser.getName().equals("calibration")) {
|
||||
String format = parser.getAttributeValue(null, "format");
|
||||
String rotation = parser.getAttributeValue(null, "rotation");
|
||||
@@ -563,31 +496,19 @@ final class PersistentDataStore {
|
||||
}
|
||||
|
||||
// Maintain invariant that layouts are sorted.
|
||||
Collections.sort(mUnassociatedKeyboardLayouts);
|
||||
Collections.sort(mKeyboardLayouts);
|
||||
|
||||
// Maintain invariant that there is always a current keyboard layout unless
|
||||
// there are none installed.
|
||||
if (mCurrentKeyboardLayout == null && !mUnassociatedKeyboardLayouts.isEmpty()) {
|
||||
mCurrentKeyboardLayout = mUnassociatedKeyboardLayouts.get(0);
|
||||
if (mCurrentKeyboardLayout == null && !mKeyboardLayouts.isEmpty()) {
|
||||
mCurrentKeyboardLayout = mKeyboardLayouts.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
public void saveToXml(XmlSerializer serializer) throws IOException {
|
||||
for (String layout : mUnassociatedKeyboardLayouts) {
|
||||
for (String layout : mKeyboardLayouts) {
|
||||
serializer.startTag(null, "keyboard-layout");
|
||||
serializer.attribute(null, "descriptor", layout);
|
||||
serializer.endTag(null, "keyboard-layout");
|
||||
}
|
||||
|
||||
final int N = mKeyboardLayouts.size();
|
||||
for (int i = 0; i < N; i++) {
|
||||
final InputMethodSubtypeHandle handle = mKeyboardLayouts.keyAt(i);
|
||||
final String layout = mKeyboardLayouts.valueAt(i);
|
||||
serializer.startTag(null, "keyboard-layout");
|
||||
serializer.attribute(null, "descriptor", layout);
|
||||
serializer.attribute(null, "input-method-id", handle.getInputMethodId());
|
||||
serializer.attribute(null, "input-method-subtype-id",
|
||||
Integer.toString(handle.getSubtypeId()));
|
||||
if (layout.equals(mCurrentKeyboardLayout)) {
|
||||
serializer.attribute(null, "current", "true");
|
||||
}
|
||||
@@ -612,22 +533,6 @@ final class PersistentDataStore {
|
||||
}
|
||||
}
|
||||
|
||||
private void dump(final PrintWriter pw, final String prefix) {
|
||||
pw.println(prefix + "CurrentKeyboardLayout=" + mCurrentKeyboardLayout);
|
||||
pw.println(prefix + "UnassociatedKeyboardLayouts=" + mUnassociatedKeyboardLayouts);
|
||||
pw.println(prefix + "TouchCalibration=" + Arrays.toString(mTouchCalibration));
|
||||
pw.println(prefix + "Subtype to Layout Mappings:");
|
||||
final int N = mKeyboardLayouts.size();
|
||||
if (N != 0) {
|
||||
for (int i = 0; i < N; i++) {
|
||||
pw.println(prefix + " " + mKeyboardLayouts.keyAt(i) + ": "
|
||||
+ mKeyboardLayouts.valueAt(i));
|
||||
}
|
||||
} else {
|
||||
pw.println(prefix + " <none>");
|
||||
}
|
||||
}
|
||||
|
||||
private static String surfaceRotationToString(int surfaceRotation) {
|
||||
switch (surfaceRotation) {
|
||||
case Surface.ROTATION_0: return "0";
|
||||
|
||||
@@ -3880,6 +3880,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
hideRecentApps(true, false);
|
||||
}
|
||||
|
||||
// Handle keyboard layout switching.
|
||||
// TODO: Deprecate this behavior when we fully migrate to IME subtype-based layout rotation.
|
||||
if (down && repeatCount == 0 && keyCode == KeyEvent.KEYCODE_SPACE
|
||||
&& ((metaState & KeyEvent.META_CTRL_MASK) != 0)) {
|
||||
int direction = (metaState & KeyEvent.META_SHIFT_MASK) != 0 ? -1 : 1;
|
||||
mWindowManagerFuncs.switchKeyboardLayout(event.getDeviceId(), direction);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Handle input method switching.
|
||||
if (down && repeatCount == 0
|
||||
&& (keyCode == KeyEvent.KEYCODE_LANGUAGE_SWITCH
|
||||
|
||||
@@ -544,6 +544,12 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
|
||||
*/
|
||||
public int getCameraLensCoverState();
|
||||
|
||||
/**
|
||||
* Switch the keyboard layout for the given device.
|
||||
* Direction should be +1 or -1 to go to the next or previous keyboard layout.
|
||||
*/
|
||||
public void switchKeyboardLayout(int deviceId, int direction);
|
||||
|
||||
/**
|
||||
* Switch the input method, to be precise, input method subtype.
|
||||
*
|
||||
|
||||
@@ -3178,6 +3178,12 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
// Called by window manager policy. Not exposed externally.
|
||||
@Override
|
||||
public void switchKeyboardLayout(int deviceId, int direction) {
|
||||
mInputManager.switchKeyboardLayout(deviceId, direction);
|
||||
}
|
||||
|
||||
// Called by window manager policy. Not exposed externally.
|
||||
@Override
|
||||
public void switchInputMethod(boolean forwardDirection) {
|
||||
|
||||
Reference in New Issue
Block a user