Merge changes from topic "yukawa-b66498367" into pi-dev

am: c8b967a5de

Change-Id: Ib731bddebe7f93fd40034f67eab7f99f016f687f
This commit is contained in:
Yohei Yukawa
2018-03-12 02:19:14 +00:00
committed by android-build-merger
9 changed files with 102 additions and 448 deletions

View File

@@ -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);

View File

@@ -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.
*

View File

@@ -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);
}
}

View File

@@ -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 + "}";
}
}

View File

@@ -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,

View File

@@ -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";

View File

@@ -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

View File

@@ -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.
*

View File

@@ -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) {