summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Brown <jeffbrown@google.com>2012-04-10 14:30:49 -0700
committerJeff Brown <jeffbrown@google.com>2012-04-10 18:23:58 -0700
commit9f25b7fdf216c9ef0bd2322cd223eeaf0d60f77f (patch)
treeb0b509a261874435cab3f5f1a727c02b399bd91c
parent54ae14749bc7f9e73cfda35a8b49f9efa80a77fb (diff)
downloadframeworks_base-9f25b7fdf216c9ef0bd2322cd223eeaf0d60f77f.zip
frameworks_base-9f25b7fdf216c9ef0bd2322cd223eeaf0d60f77f.tar.gz
frameworks_base-9f25b7fdf216c9ef0bd2322cd223eeaf0d60f77f.tar.bz2
Request key maps from input manager service.
Instead of each application loading the KeyCharacterMap from the file system, get them from the input manager service as part of the InputDevice object. Refactored InputManager to be a proper singleton instead of having a bunch of static methods. InputManager now maintains a cache of all InputDevice objects that it has loaded. Currently we never invalidate the cache which can cause InputDevice to return stale motion ranges if the device is reconfigured. This will be fixed in a future change. Added a fake InputDevice with ID -1 to represent the virtual keyboard. Change-Id: If7a695839ad0972317a5aab89e9d1e42ace28eb7
-rw-r--r--api/current.txt7
-rwxr-xr-xcmds/input/src/com/android/commands/input/Input.java6
-rw-r--r--core/java/android/app/ContextImpl.java6
-rw-r--r--core/java/android/app/Instrumentation.java8
-rw-r--r--core/java/android/hardware/input/IInputManager.aidl8
-rwxr-xr-xcore/java/android/hardware/input/InputManager.java363
-rw-r--r--core/java/android/hardware/input/KeyboardLayout.aidl19
-rw-r--r--core/java/android/hardware/input/KeyboardLayout.java91
-rwxr-xr-xcore/java/android/view/InputDevice.java112
-rw-r--r--core/java/android/view/KeyCharacterMap.java87
-rw-r--r--core/jni/Android.mk1
-rw-r--r--core/jni/AndroidRuntime.cpp6
-rw-r--r--core/jni/android_view_InputDevice.cpp97
-rw-r--r--core/jni/android_view_InputDevice.h31
-rw-r--r--core/jni/android_view_KeyCharacterMap.cpp139
-rw-r--r--core/jni/android_view_KeyCharacterMap.h32
-rw-r--r--core/res/AndroidManifest.xml7
-rwxr-xr-xcore/res/res/values/strings.xml6
-rw-r--r--include/androidfw/Input.h111
-rw-r--r--include/androidfw/InputDevice.h143
-rw-r--r--include/androidfw/KeyCharacterMap.h28
-rw-r--r--include/androidfw/KeyLayoutMap.h12
-rw-r--r--include/androidfw/Keyboard.h5
-rw-r--r--include/androidfw/VirtualKeyMap.h2
-rw-r--r--libs/androidfw/Android.mk1
-rw-r--r--libs/androidfw/Input.cpp174
-rw-r--r--libs/androidfw/InputDevice.cpp179
-rw-r--r--libs/androidfw/KeyCharacterMap.cpp98
-rw-r--r--libs/androidfw/KeyLayoutMap.cpp14
-rw-r--r--libs/androidfw/Keyboard.cpp14
-rw-r--r--native/android/input.cpp1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java3
-rw-r--r--services/input/EventHub.cpp114
-rw-r--r--services/input/EventHub.h30
-rw-r--r--services/input/InputReader.cpp28
-rw-r--r--services/input/tests/InputReader_test.cpp4
-rw-r--r--services/java/com/android/server/input/InputManagerService.java249
-rw-r--r--services/jni/com_android_server_input_InputManagerService.cpp83
-rw-r--r--tools/validatekeymaps/Main.cpp6
39 files changed, 1433 insertions, 892 deletions
diff --git a/api/current.txt b/api/current.txt
index 3b0b95b..35ae56b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -102,6 +102,7 @@ package android {
field public static final java.lang.String SET_ALWAYS_FINISH = "android.permission.SET_ALWAYS_FINISH";
field public static final java.lang.String SET_ANIMATION_SCALE = "android.permission.SET_ANIMATION_SCALE";
field public static final java.lang.String SET_DEBUG_APP = "android.permission.SET_DEBUG_APP";
+ field public static final java.lang.String SET_KEYBOARD_LAYOUT = "android.permission.SET_KEYBOARD_LAYOUT";
field public static final java.lang.String SET_ORIENTATION = "android.permission.SET_ORIENTATION";
field public static final java.lang.String SET_POINTER_SPEED = "android.permission.SET_POINTER_SPEED";
field public static final deprecated java.lang.String SET_PREFERRED_APPLICATIONS = "android.permission.SET_PREFERRED_APPLICATIONS";
@@ -22268,6 +22269,7 @@ package android.view {
method public java.util.List<android.view.InputDevice.MotionRange> getMotionRanges();
method public java.lang.String getName();
method public int getSources();
+ method public boolean isVirtual();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
field public static final int KEYBOARD_TYPE_ALPHABETIC = 2; // 0x2
@@ -22327,7 +22329,8 @@ package android.view {
method public abstract void onInputQueueDestroyed(android.view.InputQueue);
}
- public class KeyCharacterMap {
+ public class KeyCharacterMap implements android.os.Parcelable {
+ method public int describeContents();
method public static boolean deviceHasKey(int);
method public static boolean[] deviceHasKeys(int[]);
method public int get(int, int);
@@ -22342,10 +22345,12 @@ package android.view {
method public char getNumber(int);
method public boolean isPrintingKey(int);
method public static android.view.KeyCharacterMap load(int);
+ method public void writeToParcel(android.os.Parcel, int);
field public static final int ALPHA = 3; // 0x3
field public static final deprecated int BUILT_IN_KEYBOARD = 0; // 0x0
field public static final int COMBINING_ACCENT = -2147483648; // 0x80000000
field public static final int COMBINING_ACCENT_MASK = 2147483647; // 0x7fffffff
+ field public static final android.os.Parcelable.Creator CREATOR;
field public static final int FULL = 4; // 0x4
field public static final char HEX_INPUT = 61184; // 0xef00 '\uef00'
field public static final int MODIFIER_BEHAVIOR_CHORDED = 0; // 0x0
diff --git a/cmds/input/src/com/android/commands/input/Input.java b/cmds/input/src/com/android/commands/input/Input.java
index 3037881..fcf3c7e 100755
--- a/cmds/input/src/com/android/commands/input/Input.java
+++ b/cmds/input/src/com/android/commands/input/Input.java
@@ -145,13 +145,15 @@ public class Input {
private void injectKeyEvent(KeyEvent event) {
Log.i(TAG, "InjectKeyEvent: " + event);
- InputManager.injectInputEvent(event, InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
+ InputManager.getInstance().injectInputEvent(event,
+ InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
}
private void injectPointerEvent(MotionEvent event) {
event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
Log.i("Input", "InjectPointerEvent: " + event);
- InputManager.injectInputEvent(event, InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
+ InputManager.getInstance().injectInputEvent(event,
+ InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
}
private static final float lerp(float a, float b, float alpha) {
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index c5d7b91..138a88f 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -325,9 +325,9 @@ class ContextImpl extends Context {
return createDropBoxManager();
}});
- registerService(INPUT_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- return new InputManager(ctx);
+ registerService(INPUT_SERVICE, new StaticServiceFetcher() {
+ public Object createStaticService() {
+ return InputManager.getInstance();
}});
registerService(INPUT_METHOD_SERVICE, new ServiceFetcher() {
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index f955713..75c6e11 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -883,7 +883,7 @@ public class Instrumentation {
}
KeyEvent newEvent = new KeyEvent(downTime, eventTime, action, code, repeatCount, metaState,
deviceId, scancode, flags | KeyEvent.FLAG_FROM_SYSTEM, source);
- InputManager.injectInputEvent(newEvent,
+ InputManager.getInstance().injectInputEvent(newEvent,
InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
}
@@ -926,7 +926,8 @@ public class Instrumentation {
if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) == 0) {
event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
}
- InputManager.injectInputEvent(event, InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
+ InputManager.getInstance().injectInputEvent(event,
+ InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
}
/**
@@ -945,7 +946,8 @@ public class Instrumentation {
if ((event.getSource() & InputDevice.SOURCE_CLASS_TRACKBALL) == 0) {
event.setSource(InputDevice.SOURCE_TRACKBALL);
}
- InputManager.injectInputEvent(event, InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
+ InputManager.getInstance().injectInputEvent(event,
+ InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
}
/**
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index c2abce5..47e0d1e 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -16,6 +16,7 @@
package android.hardware.input;
+import android.hardware.input.KeyboardLayout;
import android.view.InputDevice;
import android.view.InputEvent;
@@ -34,4 +35,11 @@ interface IInputManager {
// Injects an input event into the system. To inject into windows owned by other
// applications, the caller must have the INJECT_EVENTS permission.
boolean injectInputEvent(in InputEvent ev, int mode);
+
+ // Keyboard layouts configuration.
+ KeyboardLayout[] getKeyboardLayouts();
+ KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor);
+ String getKeyboardLayoutForInputDevice(String inputDeviceDescriptor);
+ void setKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
+ String keyboardLayoutDescriptor);
}
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 5ead1f4..3b3c237 100755
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -16,37 +16,18 @@
package android.hardware.input;
-import com.android.internal.util.XmlUtils;
-
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
-import android.content.ComponentName;
import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.content.res.XmlResourceParser;
-import android.os.Bundle;
import android.os.IBinder;
-import android.os.Parcel;
-import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.util.Log;
+import android.util.SparseArray;
import android.view.InputDevice;
import android.view.InputEvent;
-import android.view.KeyCharacterMap;
-import android.view.KeyCharacterMap.UnavailableException;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
/**
* Provides information about input devices and available key layouts.
@@ -60,13 +41,10 @@ import java.util.List;
public final class InputManager {
private static final String TAG = "InputManager";
- private static final IInputManager sIm;
-
- private final Context mContext;
+ private static InputManager sInstance;
- // Used to simulate a persistent data store.
- // TODO: Replace with the real thing.
- private static final HashMap<String, String> mFakeRegistry = new HashMap<String, String>();
+ private final IInputManager mIm;
+ private final SparseArray<InputDevice> mInputDevices = new SparseArray<InputDevice>();
/**
* Broadcast Action: Query available keyboard layouts.
@@ -169,14 +147,25 @@ public final class InputManager {
*/
public static final int INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH = 2; // see InputDispatcher.h
- static {
- IBinder b = ServiceManager.getService(Context.INPUT_SERVICE);
- sIm = IInputManager.Stub.asInterface(b);
+ private InputManager(IInputManager im) {
+ mIm = im;
}
- /** @hide */
- public InputManager(Context context) {
- mContext = context;
+ /**
+ * Gets an instance of the input manager.
+ *
+ * @return The input manager instance.
+ *
+ * @hide
+ */
+ public static InputManager getInstance() {
+ synchronized (InputManager.class) {
+ if (sInstance == null) {
+ IBinder b = ServiceManager.getService(Context.INPUT_SERVICE);
+ sInstance = new InputManager(IInputManager.Stub.asInterface(b));
+ }
+ return sInstance;
+ }
}
/**
@@ -188,18 +177,16 @@ public final class InputManager {
* </p>
*
* @return A list of all supported keyboard layouts.
+ *
* @hide
*/
- public List<KeyboardLayout> getKeyboardLayouts() {
- ArrayList<KeyboardLayout> list = new ArrayList<KeyboardLayout>();
-
- final PackageManager pm = mContext.getPackageManager();
- Intent intent = new Intent(ACTION_QUERY_KEYBOARD_LAYOUTS);
- for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent,
- PackageManager.GET_META_DATA)) {
- loadKeyboardLayouts(pm, resolveInfo.activityInfo, list, null);
+ public KeyboardLayout[] getKeyboardLayouts() {
+ try {
+ return mIm.getKeyboardLayouts();
+ } catch (RemoteException ex) {
+ Log.w(TAG, "Could not get list of keyboard layout informations.", ex);
+ return new KeyboardLayout[0];
}
- return list;
}
/**
@@ -216,20 +203,10 @@ public final class InputManager {
throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
}
- KeyboardLayoutDescriptor d = parseKeyboardLayoutDescriptor(keyboardLayoutDescriptor);
- if (d == null) {
- return null;
- }
-
- final PackageManager pm = mContext.getPackageManager();
try {
- ActivityInfo receiver = pm.getReceiverInfo(
- new ComponentName(d.packageName, d.receiverName),
- PackageManager.GET_META_DATA);
- return loadKeyboardLayouts(pm, receiver, null, d.keyboardLayoutName);
- } catch (NameNotFoundException ex) {
- Log.w(TAG, "Could not load keyboard layout '" + d.keyboardLayoutName
- + "' from receiver " + d.packageName + "/" + d.receiverName, ex);
+ return mIm.getKeyboardLayout(keyboardLayoutDescriptor);
+ } catch (RemoteException ex) {
+ Log.w(TAG, "Could not get keyboard layout information.", ex);
return null;
}
}
@@ -243,12 +220,17 @@ public final class InputManager {
*
* @hide
*/
- public String getInputDeviceKeyboardLayoutDescriptor(String inputDeviceDescriptor) {
+ public String getKeyboardLayoutForInputDevice(String inputDeviceDescriptor) {
if (inputDeviceDescriptor == null) {
throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
}
- return mFakeRegistry.get(inputDeviceDescriptor);
+ try {
+ return mIm.getKeyboardLayoutForInputDevice(inputDeviceDescriptor);
+ } catch (RemoteException ex) {
+ Log.w(TAG, "Could not get keyboard layout for input device.", ex);
+ return null;
+ }
}
/**
@@ -264,92 +246,17 @@ public final class InputManager {
*
* @hide
*/
- public void setInputDeviceKeyboardLayoutDescriptor(String inputDeviceDescriptor,
+ public void setKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
String keyboardLayoutDescriptor) {
if (inputDeviceDescriptor == null) {
throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
}
- mFakeRegistry.put(inputDeviceDescriptor, keyboardLayoutDescriptor);
- }
-
- private KeyboardLayout loadKeyboardLayouts(
- PackageManager pm, ActivityInfo receiver,
- List<KeyboardLayout> list, String keyboardName) {
- Bundle metaData = receiver.metaData;
- if (metaData == null) {
- return null;
- }
-
- int configResId = metaData.getInt(META_DATA_KEYBOARD_LAYOUTS);
- if (configResId == 0) {
- Log.w(TAG, "Missing meta-data '" + META_DATA_KEYBOARD_LAYOUTS + "' on receiver "
- + receiver.packageName + "/" + receiver.name);
- return null;
- }
-
try {
- Resources resources = pm.getResourcesForApplication(receiver.applicationInfo);
- XmlResourceParser parser = resources.getXml(configResId);
- try {
- XmlUtils.beginDocument(parser, "keyboard-layouts");
-
- for (;;) {
- XmlUtils.nextElement(parser);
- String element = parser.getName();
- if (element == null) {
- break;
- }
- if (element.equals("keyboard-layout")) {
- TypedArray a = resources.obtainAttributes(
- parser, com.android.internal.R.styleable.KeyboardLayout);
- try {
- String name = a.getString(
- com.android.internal.R.styleable.KeyboardLayout_name);
- String label = a.getString(
- com.android.internal.R.styleable.KeyboardLayout_label);
- int kcmResId = a.getResourceId(
- com.android.internal.R.styleable.KeyboardLayout_kcm, 0);
- if (name == null || label == null || kcmResId == 0) {
- Log.w(TAG, "Missing required 'name', 'label' or 'kcm' "
- + "attributes in keyboard layout "
- + "resource from receiver "
- + receiver.packageName + "/" + receiver.name);
- } else {
- String descriptor = makeKeyboardLayoutDescriptor(
- receiver.packageName, receiver.name, name);
- KeyboardLayout c = new KeyboardLayout(
- descriptor, label, kcmResId);
- if (keyboardName != null && name.equals(keyboardName)) {
- return c;
- }
- if (list != null) {
- list.add(c);
- }
- }
- } finally {
- a.recycle();
- }
- } else {
- Log.w(TAG, "Skipping unrecognized element '" + element
- + "' in keyboard layout resource from receiver "
- + receiver.packageName + "/" + receiver.name);
- }
- }
- } finally {
- parser.close();
- }
- } catch (Exception ex) {
- Log.w(TAG, "Could not load keyboard layout resource from receiver "
- + receiver.packageName + "/" + receiver.name, ex);
- return null;
- }
- if (keyboardName != null) {
- Log.w(TAG, "Could not load keyboard layout '" + keyboardName
- + "' from receiver " + receiver.packageName + "/" + receiver.name
- + " because it was not declared in the keyboard layout resource.");
+ mIm.setKeyboardLayoutForInputDevice(inputDeviceDescriptor, keyboardLayoutDescriptor);
+ } catch (RemoteException ex) {
+ Log.w(TAG, "Could not set keyboard layout for input device.", ex);
}
- return null;
}
/**
@@ -359,15 +266,16 @@ public final class InputManager {
* speed set by {@link #tryPointerSpeed}.
* </p>
*
+ * @param context The application context.
* @return The pointer speed as a value between {@link #MIN_POINTER_SPEED} and
* {@link #MAX_POINTER_SPEED}, or the default value {@link #DEFAULT_POINTER_SPEED}.
*
* @hide
*/
- public int getPointerSpeed() {
+ public int getPointerSpeed(Context context) {
int speed = DEFAULT_POINTER_SPEED;
try {
- speed = Settings.System.getInt(mContext.getContentResolver(),
+ speed = Settings.System.getInt(context.getContentResolver(),
Settings.System.POINTER_SPEED);
} catch (SettingNotFoundException snfe) {
}
@@ -380,17 +288,18 @@ public final class InputManager {
* Requires {@link android.Manifest.permissions.WRITE_SETTINGS}.
* </p>
*
+ * @param context The application context.
* @param speed The pointer speed as a value between {@link #MIN_POINTER_SPEED} and
* {@link #MAX_POINTER_SPEED}, or the default value {@link #DEFAULT_POINTER_SPEED}.
*
* @hide
*/
- public void setPointerSpeed(int speed) {
+ public void setPointerSpeed(Context context, int speed) {
if (speed < MIN_POINTER_SPEED || speed > MAX_POINTER_SPEED) {
throw new IllegalArgumentException("speed out of range");
}
- Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.putInt(context.getContentResolver(),
Settings.System.POINTER_SPEED, speed);
}
@@ -411,7 +320,7 @@ public final class InputManager {
}
try {
- sIm.tryPointerSpeed(speed);
+ mIm.tryPointerSpeed(speed);
} catch (RemoteException ex) {
Log.w(TAG, "Could not set temporary pointer speed.", ex);
}
@@ -424,12 +333,27 @@ public final class InputManager {
*
* @hide
*/
- public static InputDevice getInputDevice(int id) {
+ public InputDevice getInputDevice(int id) {
+ synchronized (mInputDevices) {
+ InputDevice inputDevice = mInputDevices.get(id);
+ if (inputDevice != null) {
+ return inputDevice;
+ }
+ }
+ final InputDevice newInputDevice;
try {
- return sIm.getInputDevice(id);
+ newInputDevice = mIm.getInputDevice(id);
} catch (RemoteException ex) {
throw new RuntimeException("Could not get input device information.", ex);
}
+ synchronized (mInputDevices) {
+ InputDevice inputDevice = mInputDevices.get(id);
+ if (inputDevice != null) {
+ return inputDevice;
+ }
+ mInputDevices.put(id, newInputDevice);
+ return newInputDevice;
+ }
}
/**
@@ -438,9 +362,9 @@ public final class InputManager {
*
* @hide
*/
- public static int[] getInputDeviceIds() {
+ public int[] getInputDeviceIds() {
try {
- return sIm.getInputDeviceIds();
+ return mIm.getInputDeviceIds();
} catch (RemoteException ex) {
throw new RuntimeException("Could not get input device ids.", ex);
}
@@ -458,10 +382,10 @@ public final class InputManager {
*
* @hide
*/
- public static boolean[] deviceHasKeys(int[] keyCodes) {
+ public boolean[] deviceHasKeys(int[] keyCodes) {
boolean[] ret = new boolean[keyCodes.length];
try {
- sIm.hasKeys(-1, InputDevice.SOURCE_ANY, keyCodes, ret);
+ mIm.hasKeys(-1, InputDevice.SOURCE_ANY, keyCodes, ret);
} catch (RemoteException e) {
// no fallback; just return the empty array
}
@@ -489,7 +413,7 @@ public final class InputManager {
*
* @hide
*/
- public static boolean injectInputEvent(InputEvent event, int mode) {
+ public boolean injectInputEvent(InputEvent event, int mode) {
if (event == null) {
throw new IllegalArgumentException("event must not be null");
}
@@ -500,152 +424,9 @@ public final class InputManager {
}
try {
- return sIm.injectInputEvent(event, mode);
+ return mIm.injectInputEvent(event, mode);
} catch (RemoteException ex) {
return false;
}
}
-
- private static String makeKeyboardLayoutDescriptor(String packageName,
- String receiverName, String keyboardName) {
- return packageName + "/" + receiverName + "/" + keyboardName;
- }
-
- private static KeyboardLayoutDescriptor parseKeyboardLayoutDescriptor(String descriptor) {
- int pos = descriptor.indexOf('/');
- if (pos < 0 || pos + 1 == descriptor.length()) {
- return null;
- }
- int pos2 = descriptor.indexOf('/', pos + 1);
- if (pos2 < pos + 2 || pos2 + 1 == descriptor.length()) {
- return null;
- }
-
- KeyboardLayoutDescriptor result = new KeyboardLayoutDescriptor();
- result.packageName = descriptor.substring(0, pos);
- result.receiverName = descriptor.substring(pos + 1, pos2);
- result.keyboardLayoutName = descriptor.substring(pos2 + 1);
- return result;
- }
-
- /**
- * Describes a keyboard layout.
- *
- * @hide
- */
- public static final class KeyboardLayout implements Parcelable,
- Comparable<KeyboardLayout> {
- private final String mDescriptor;
- private final String mLabel;
- private final int mKeyCharacterMapResId;
-
- private KeyCharacterMap mKeyCharacterMap;
-
- public static final Parcelable.Creator<KeyboardLayout> CREATOR =
- new Parcelable.Creator<KeyboardLayout>() {
- public KeyboardLayout createFromParcel(Parcel source) {
- return new KeyboardLayout(source);
- }
- public KeyboardLayout[] newArray(int size) {
- return new KeyboardLayout[size];
- }
- };
-
- private KeyboardLayout(String descriptor,
- String label, int keyCharacterMapResId) {
- mDescriptor = descriptor;
- mLabel = label;
- mKeyCharacterMapResId = keyCharacterMapResId;
- }
-
- private KeyboardLayout(Parcel source) {
- mDescriptor = source.readString();
- mLabel = source.readString();
- mKeyCharacterMapResId = source.readInt();
- }
-
- /**
- * Gets the keyboard layout descriptor, which can be used to retrieve
- * the keyboard layout again later using
- * {@link InputManager#getKeyboardLayout(String)}.
- *
- * @return The keyboard layout descriptor.
- */
- public String getDescriptor() {
- return mDescriptor;
- }
-
- /**
- * Gets the keyboard layout descriptive label to show in the user interface.
- * @return The keyboard layout descriptive label.
- */
- public String getLabel() {
- return mLabel;
- }
-
- /**
- * Loads the key character map associated with the keyboard layout.
- *
- * @param pm The package manager.
- * @return The key character map, or null if it could not be loaded for any reason.
- */
- public KeyCharacterMap loadKeyCharacterMap(PackageManager pm) {
- if (pm == null) {
- throw new IllegalArgumentException("pm must not be null");
- }
-
- if (mKeyCharacterMap == null) {
- KeyboardLayoutDescriptor d = parseKeyboardLayoutDescriptor(mDescriptor);
- if (d == null) {
- Log.e(TAG, "Could not load key character map '" + mDescriptor
- + "' because the descriptor could not be parsed.");
- return null;
- }
-
- CharSequence cs = pm.getText(d.packageName, mKeyCharacterMapResId, null);
- if (cs == null) {
- Log.e(TAG, "Could not load key character map '" + mDescriptor
- + "' because its associated resource could not be loaded.");
- return null;
- }
-
- try {
- mKeyCharacterMap = KeyCharacterMap.load(cs);
- } catch (UnavailableException ex) {
- Log.e(TAG, "Could not load key character map '" + mDescriptor
- + "' due to an error while parsing.", ex);
- return null;
- }
- }
- return mKeyCharacterMap;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(mDescriptor);
- dest.writeString(mLabel);
- dest.writeInt(mKeyCharacterMapResId);
- }
-
- @Override
- public int compareTo(KeyboardLayout another) {
- return mLabel.compareToIgnoreCase(another.mLabel);
- }
-
- @Override
- public String toString() {
- return mLabel;
- }
- }
-
- private static final class KeyboardLayoutDescriptor {
- public String packageName;
- public String receiverName;
- public String keyboardLayoutName;
- }
}
diff --git a/core/java/android/hardware/input/KeyboardLayout.aidl b/core/java/android/hardware/input/KeyboardLayout.aidl
new file mode 100644
index 0000000..226e384
--- /dev/null
+++ b/core/java/android/hardware/input/KeyboardLayout.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2012 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 android.hardware.input;
+
+parcelable KeyboardLayout;
diff --git a/core/java/android/hardware/input/KeyboardLayout.java b/core/java/android/hardware/input/KeyboardLayout.java
new file mode 100644
index 0000000..e75a6dc
--- /dev/null
+++ b/core/java/android/hardware/input/KeyboardLayout.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2012 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 android.hardware.input;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Describes a keyboard layout.
+ *
+ * @hide
+ */
+public final class KeyboardLayout implements Parcelable,
+ Comparable<KeyboardLayout> {
+ private final String mDescriptor;
+ private final String mLabel;
+
+ public static final Parcelable.Creator<KeyboardLayout> CREATOR =
+ new Parcelable.Creator<KeyboardLayout>() {
+ public KeyboardLayout createFromParcel(Parcel source) {
+ return new KeyboardLayout(source);
+ }
+ public KeyboardLayout[] newArray(int size) {
+ return new KeyboardLayout[size];
+ }
+ };
+
+ public KeyboardLayout(String descriptor, String label) {
+ mDescriptor = descriptor;
+ mLabel = label;
+ }
+
+ private KeyboardLayout(Parcel source) {
+ mDescriptor = source.readString();
+ mLabel = source.readString();
+ }
+
+ /**
+ * Gets the keyboard layout descriptor, which can be used to retrieve
+ * the keyboard layout again later using
+ * {@link InputManager#getKeyboardLayout(String)}.
+ *
+ * @return The keyboard layout descriptor.
+ */
+ public String getDescriptor() {
+ return mDescriptor;
+ }
+
+ /**
+ * Gets the keyboard layout descriptive label to show in the user interface.
+ * @return The keyboard layout descriptive label.
+ */
+ public String getLabel() {
+ return mLabel;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mDescriptor);
+ dest.writeString(mLabel);
+ }
+
+ @Override
+ public int compareTo(KeyboardLayout another) {
+ return mLabel.compareToIgnoreCase(another.mLabel);
+ }
+
+ @Override
+ public String toString() {
+ return mLabel;
+ }
+} \ No newline at end of file
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index 6f8d09b..75b2c746 100755
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -39,13 +39,12 @@ import java.util.List;
* </p>
*/
public final class InputDevice implements Parcelable {
- private int mId;
- private String mName;
- private String mDescriptor;
- private int mSources;
- private int mKeyboardType;
- private String mKeyCharacterMapFile;
-
+ private final int mId;
+ private final String mName;
+ private final String mDescriptor;
+ private final int mSources;
+ private final int mKeyboardType;
+ private final KeyCharacterMap mKeyCharacterMap;
private final ArrayList<MotionRange> mMotionRanges = new ArrayList<MotionRange>();
/**
@@ -292,8 +291,43 @@ public final class InputDevice implements Parcelable {
*/
public static final int KEYBOARD_TYPE_ALPHABETIC = 2;
+ public static final Parcelable.Creator<InputDevice> CREATOR =
+ new Parcelable.Creator<InputDevice>() {
+ public InputDevice createFromParcel(Parcel in) {
+ return new InputDevice(in);
+ }
+ public InputDevice[] newArray(int size) {
+ return new InputDevice[size];
+ }
+ };
+
// Called by native code.
- private InputDevice() {
+ private InputDevice(int id, String name, String descriptor, int sources,
+ int keyboardType, KeyCharacterMap keyCharacterMap) {
+ mId = id;
+ mName = name;
+ mDescriptor = descriptor;
+ mSources = sources;
+ mKeyboardType = keyboardType;
+ mKeyCharacterMap = keyCharacterMap;
+ }
+
+ private InputDevice(Parcel in) {
+ mId = in.readInt();
+ mName = in.readString();
+ mDescriptor = in.readString();
+ mSources = in.readInt();
+ mKeyboardType = in.readInt();
+ mKeyCharacterMap = KeyCharacterMap.CREATOR.createFromParcel(in);
+
+ for (;;) {
+ int axis = in.readInt();
+ if (axis < 0) {
+ break;
+ }
+ addMotionRange(axis, in.readInt(),
+ in.readFloat(), in.readFloat(), in.readFloat(), in.readFloat());
+ }
}
/**
@@ -302,7 +336,7 @@ public final class InputDevice implements Parcelable {
* @return The input device or null if not found.
*/
public static InputDevice getDevice(int id) {
- return InputManager.getInputDevice(id);
+ return InputManager.getInstance().getInputDevice(id);
}
/**
@@ -310,7 +344,7 @@ public final class InputDevice implements Parcelable {
* @return The input device ids.
*/
public static int[] getDeviceIds() {
- return InputManager.getInputDeviceIds();
+ return InputManager.getInstance().getInputDeviceIds();
}
/**
@@ -356,6 +390,22 @@ public final class InputDevice implements Parcelable {
}
/**
+ * Returns true if the device is a virtual input device rather than a real one,
+ * such as the virtual keyboard (see {@link KeyCharacterMap#VIRTUAL_KEYBOARD}).
+ * <p>
+ * Virtual input devices are provided to implement system-level functionality
+ * and should not be seen or configured by users.
+ * </p>
+ *
+ * @return True if the device is virtual.
+ *
+ * @see KeyCharacterMap#VIRTUAL_KEYBOARD
+ */
+ public boolean isVirtual() {
+ return mId < 0;
+ }
+
+ /**
* Gets the name of this input device.
* @return The input device name.
*/
@@ -384,11 +434,7 @@ public final class InputDevice implements Parcelable {
* @return The key character map.
*/
public KeyCharacterMap getKeyCharacterMap() {
- return KeyCharacterMap.load(mId);
- }
-
- String getKeyCharacterMapFile() {
- return mKeyCharacterMapFile;
+ return mKeyCharacterMap;
}
/**
@@ -453,6 +499,7 @@ public final class InputDevice implements Parcelable {
return mMotionRanges;
}
+ // Called from native code.
private void addMotionRange(int axis, int source,
float min, float max, float flat, float fuzz) {
mMotionRanges.add(new MotionRange(axis, source, min, max, flat, fuzz));
@@ -545,37 +592,6 @@ public final class InputDevice implements Parcelable {
}
}
- public static final Parcelable.Creator<InputDevice> CREATOR
- = new Parcelable.Creator<InputDevice>() {
- public InputDevice createFromParcel(Parcel in) {
- InputDevice result = new InputDevice();
- result.readFromParcel(in);
- return result;
- }
-
- public InputDevice[] newArray(int size) {
- return new InputDevice[size];
- }
- };
-
- private void readFromParcel(Parcel in) {
- mId = in.readInt();
- mName = in.readString();
- mDescriptor = in.readString();
- mSources = in.readInt();
- mKeyboardType = in.readInt();
- mKeyCharacterMapFile = in.readString();
-
- for (;;) {
- int axis = in.readInt();
- if (axis < 0) {
- break;
- }
- addMotionRange(axis, in.readInt(),
- in.readFloat(), in.readFloat(), in.readFloat(), in.readFloat());
- }
- }
-
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeInt(mId);
@@ -583,7 +599,7 @@ public final class InputDevice implements Parcelable {
out.writeString(mDescriptor);
out.writeInt(mSources);
out.writeInt(mKeyboardType);
- out.writeString(mKeyCharacterMapFile);
+ mKeyCharacterMap.writeToParcel(out, flags);
final int numRanges = mMotionRanges.size();
for (int i = 0; i < numRanges; i++) {
@@ -623,8 +639,6 @@ public final class InputDevice implements Parcelable {
}
description.append("\n");
- description.append(" Key Character Map: ").append(mKeyCharacterMapFile).append("\n");
-
description.append(" Sources: 0x").append(Integer.toHexString(mSources)).append(" (");
appendSourceDescriptionIfApplicable(description, SOURCE_KEYBOARD, "keyboard");
appendSourceDescriptionIfApplicable(description, SOURCE_DPAD, "dpad");
diff --git a/core/java/android/view/KeyCharacterMap.java b/core/java/android/view/KeyCharacterMap.java
index b03f086..3d165ea 100644
--- a/core/java/android/view/KeyCharacterMap.java
+++ b/core/java/android/view/KeyCharacterMap.java
@@ -16,18 +16,21 @@
package android.view;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.text.method.MetaKeyKeyListener;
import android.util.AndroidRuntimeException;
import android.util.SparseIntArray;
import android.hardware.input.InputManager;
import android.util.SparseArray;
+import android.view.InputDevice.MotionRange;
import java.lang.Character;
/**
* Describes the keys provided by a keyboard device and their associated labels.
*/
-public class KeyCharacterMap {
+public class KeyCharacterMap implements Parcelable {
/**
* The id of the device's primary built in keyboard is always 0.
*
@@ -134,12 +137,20 @@ public class KeyCharacterMap {
*/
public static final int MODIFIER_BEHAVIOR_CHORDED_OR_TOGGLED = 1;
- private static SparseArray<KeyCharacterMap> sInstances = new SparseArray<KeyCharacterMap>();
+ public static final Parcelable.Creator<KeyCharacterMap> CREATOR =
+ new Parcelable.Creator<KeyCharacterMap>() {
+ public KeyCharacterMap createFromParcel(Parcel in) {
+ return new KeyCharacterMap(in);
+ }
+ public KeyCharacterMap[] newArray(int size) {
+ return new KeyCharacterMap[size];
+ }
+ };
- private final int mDeviceId;
private int mPtr;
- private static native int nativeLoad(String file);
+ private static native int nativeReadFromParcel(Parcel in);
+ private static native void nativeWriteToParcel(int ptr, Parcel out);
private static native void nativeDispose(int ptr);
private static native char nativeGetCharacter(int ptr, int keyCode, int metaState);
@@ -149,10 +160,20 @@ public class KeyCharacterMap {
private static native char nativeGetMatch(int ptr, int keyCode, char[] chars, int metaState);
private static native char nativeGetDisplayLabel(int ptr, int keyCode);
private static native int nativeGetKeyboardType(int ptr);
- private static native KeyEvent[] nativeGetEvents(int ptr, int deviceId, char[] chars);
+ private static native KeyEvent[] nativeGetEvents(int ptr, char[] chars);
+
+ private KeyCharacterMap(Parcel in) {
+ if (in == null) {
+ throw new IllegalArgumentException("parcel must not be null");
+ }
+ mPtr = nativeReadFromParcel(in);
+ if (mPtr == 0) {
+ throw new RuntimeException("Could not read KeyCharacterMap from parcel.");
+ }
+ }
- private KeyCharacterMap(int deviceId, int ptr) {
- mDeviceId = deviceId;
+ // Called from native
+ private KeyCharacterMap(int ptr) {
mPtr = ptr;
}
@@ -174,33 +195,16 @@ public class KeyCharacterMap {
* is missing from the system.
*/
public static KeyCharacterMap load(int deviceId) {
- synchronized (sInstances) {
- KeyCharacterMap map = sInstances.get(deviceId);
- if (map == null) {
- String kcm = null;
- if (deviceId != VIRTUAL_KEYBOARD) {
- InputDevice device = InputDevice.getDevice(deviceId);
- if (device != null) {
- kcm = device.getKeyCharacterMapFile();
- }
- }
- if (kcm == null || kcm.length() == 0) {
- kcm = "/system/usr/keychars/Virtual.kcm";
- }
- int ptr = nativeLoad(kcm); // might throw
- map = new KeyCharacterMap(deviceId, ptr);
- sInstances.put(deviceId, map);
+ final InputManager im = InputManager.getInstance();
+ InputDevice inputDevice = im.getInputDevice(deviceId);
+ if (inputDevice == null) {
+ inputDevice = im.getInputDevice(VIRTUAL_KEYBOARD);
+ if (inputDevice == null) {
+ throw new UnavailableException(
+ "Could not load key character map for device " + deviceId);
}
- return map;
}
- }
-
- /**
- * TODO implement this
- * @hide
- */
- public static KeyCharacterMap load(CharSequence contents) {
- return null;
+ return inputDevice.getKeyCharacterMap();
}
/**
@@ -437,7 +441,7 @@ public class KeyCharacterMap {
if (chars == null) {
throw new IllegalArgumentException("chars must not be null.");
}
- return nativeGetEvents(mPtr, mDeviceId, chars);
+ return nativeGetEvents(mPtr, chars);
}
/**
@@ -527,7 +531,7 @@ public class KeyCharacterMap {
* @return True if at least one attached keyboard supports the specified key code.
*/
public static boolean deviceHasKey(int keyCode) {
- return InputManager.deviceHasKeys(new int[] { keyCode })[0];
+ return InputManager.getInstance().deviceHasKeys(new int[] { keyCode })[0];
}
/**
@@ -541,7 +545,20 @@ public class KeyCharacterMap {
* at the same index in the key codes array.
*/
public static boolean[] deviceHasKeys(int[] keyCodes) {
- return InputManager.deviceHasKeys(keyCodes);
+ return InputManager.getInstance().deviceHasKeys(keyCodes);
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ if (out == null) {
+ throw new IllegalArgumentException("parcel must not be null");
+ }
+ nativeWriteToParcel(mPtr, out);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
}
/**
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index ec0fe00..523b2d5 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -48,6 +48,7 @@ LOCAL_SRC_FILES:= \
android_view_Surface.cpp \
android_view_TextureView.cpp \
android_view_InputChannel.cpp \
+ android_view_InputDevice.cpp \
android_view_InputEventReceiver.cpp \
android_view_KeyEvent.cpp \
android_view_KeyCharacterMap.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index e705c47..879b9d2 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -148,7 +148,6 @@ extern int register_android_net_TrafficStats(JNIEnv* env);
extern int register_android_net_wifi_WifiManager(JNIEnv* env);
extern int register_android_text_AndroidCharacter(JNIEnv *env);
extern int register_android_text_AndroidBidi(JNIEnv *env);
-extern int register_android_text_KeyCharacterMap(JNIEnv *env);
extern int register_android_opengl_classes(JNIEnv *env);
extern int register_android_bluetooth_HeadsetBase(JNIEnv* env);
extern int register_android_bluetooth_BluetoothAudioGateway(JNIEnv* env);
@@ -168,7 +167,9 @@ extern int register_android_app_backup_FullBackup(JNIEnv *env);
extern int register_android_app_ActivityThread(JNIEnv *env);
extern int register_android_app_NativeActivity(JNIEnv *env);
extern int register_android_view_InputChannel(JNIEnv* env);
+extern int register_android_view_InputDevice(JNIEnv* env);
extern int register_android_view_InputEventReceiver(JNIEnv* env);
+extern int register_android_view_KeyCharacterMap(JNIEnv *env);
extern int register_android_view_KeyEvent(JNIEnv* env);
extern int register_android_view_MotionEvent(JNIEnv* env);
extern int register_android_view_PointerIcon(JNIEnv* env);
@@ -1082,7 +1083,8 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_emoji_EmojiFactory),
REG_JNI(register_android_text_AndroidCharacter),
REG_JNI(register_android_text_AndroidBidi),
- REG_JNI(register_android_text_KeyCharacterMap),
+ REG_JNI(register_android_view_InputDevice),
+ REG_JNI(register_android_view_KeyCharacterMap),
REG_JNI(register_android_os_Process),
REG_JNI(register_android_os_SystemProperties),
REG_JNI(register_android_os_Binder),
diff --git a/core/jni/android_view_InputDevice.cpp b/core/jni/android_view_InputDevice.cpp
new file mode 100644
index 0000000..d7d476a
--- /dev/null
+++ b/core/jni/android_view_InputDevice.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include <androidfw/Input.h>
+
+#include <android_runtime/AndroidRuntime.h>
+#include <nativehelper/jni.h>
+#include <nativehelper/JNIHelp.h>
+
+#include <ScopedLocalRef.h>
+
+#include "android_view_InputDevice.h"
+#include "android_view_KeyCharacterMap.h"
+
+namespace android {
+
+static struct {
+ jclass clazz;
+
+ jmethodID ctor;
+ jmethodID addMotionRange;
+} gInputDeviceClassInfo;
+
+jobject android_view_InputDevice_create(JNIEnv* env, const InputDeviceInfo& deviceInfo) {
+ ScopedLocalRef<jstring> nameObj(env, env->NewStringUTF(deviceInfo.getName().string()));
+ if (!nameObj.get()) {
+ return NULL;
+ }
+
+ ScopedLocalRef<jstring> descriptorObj(env,
+ env->NewStringUTF(deviceInfo.getDescriptor().string()));
+ if (!descriptorObj.get()) {
+ return NULL;
+ }
+
+ ScopedLocalRef<jobject> kcmObj(env,
+ android_view_KeyCharacterMap_create(env, deviceInfo.getId(),
+ deviceInfo.getKeyCharacterMap()));
+ if (!kcmObj.get()) {
+ return NULL;
+ }
+
+ ScopedLocalRef<jobject> inputDeviceObj(env, env->NewObject(gInputDeviceClassInfo.clazz,
+ gInputDeviceClassInfo.ctor, deviceInfo.getId(), nameObj.get(),
+ descriptorObj.get(), deviceInfo.getSources(), deviceInfo.getKeyboardType(),
+ kcmObj.get()));
+
+ const Vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
+ for (size_t i = 0; i < ranges.size(); i++) {
+ const InputDeviceInfo::MotionRange& range = ranges.itemAt(i);
+ env->CallVoidMethod(inputDeviceObj.get(), gInputDeviceClassInfo.addMotionRange,
+ range.axis, range.source, range.min, range.max, range.flat, range.fuzz);
+ if (env->ExceptionCheck()) {
+ return NULL;
+ }
+ }
+
+ return env->NewLocalRef(inputDeviceObj.get());
+}
+
+
+#define FIND_CLASS(var, className) \
+ var = env->FindClass(className); \
+ LOG_FATAL_IF(! var, "Unable to find class " className);
+
+#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
+ var = env->GetMethodID(clazz, methodName, methodDescriptor); \
+ LOG_FATAL_IF(! var, "Unable to find method " methodName);
+
+int register_android_view_InputDevice(JNIEnv* env)
+{
+ FIND_CLASS(gInputDeviceClassInfo.clazz, "android/view/InputDevice");
+ gInputDeviceClassInfo.clazz = jclass(env->NewGlobalRef(gInputDeviceClassInfo.clazz));
+
+ GET_METHOD_ID(gInputDeviceClassInfo.ctor, gInputDeviceClassInfo.clazz,
+ "<init>", "(ILjava/lang/String;Ljava/lang/String;IILandroid/view/KeyCharacterMap;)V");
+
+ GET_METHOD_ID(gInputDeviceClassInfo.addMotionRange, gInputDeviceClassInfo.clazz,
+ "addMotionRange", "(IIFFFF)V");
+
+ return 0;
+}
+
+}; // namespace android
diff --git a/core/jni/android_view_InputDevice.h b/core/jni/android_view_InputDevice.h
new file mode 100644
index 0000000..78651ba
--- /dev/null
+++ b/core/jni/android_view_InputDevice.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#ifndef _ANDROID_VIEW_INPUTDEVICE_H
+#define _ANDROID_VIEW_INPUTDEVICE_H
+
+#include "jni.h"
+
+#include <androidfw/InputDevice.h>
+
+namespace android {
+
+/* Creates an InputDevice object from the given information. */
+extern jobject android_view_InputDevice_create(JNIEnv* env, const InputDeviceInfo& deviceInfo);
+
+} // namespace android
+
+#endif // _ANDROID_VIEW_INPUTDEVICE_H
diff --git a/core/jni/android_view_KeyCharacterMap.cpp b/core/jni/android_view_KeyCharacterMap.cpp
index 7245d9d..3e56a89 100644
--- a/core/jni/android_view_KeyCharacterMap.cpp
+++ b/core/jni/android_view_KeyCharacterMap.cpp
@@ -14,19 +14,27 @@
* limitations under the License.
*/
+#include <android_runtime/AndroidRuntime.h>
+
#include <androidfw/KeyCharacterMap.h>
#include <androidfw/Input.h>
+#include <binder/Parcel.h>
-#include <android_runtime/AndroidRuntime.h>
#include <nativehelper/jni.h>
#include <nativehelper/JNIHelp.h>
+#include "android_os_Parcel.h"
#include "android_view_KeyEvent.h"
namespace android {
static struct {
jclass clazz;
+ jmethodID ctor;
+} gKeyCharacterMapClassInfo;
+
+static struct {
+ jclass clazz;
} gKeyEventClassInfo;
static struct {
@@ -35,44 +43,87 @@ static struct {
} gFallbackActionClassInfo;
-static jint nativeLoad(JNIEnv *env, jobject clazz, jstring fileStr) {
- const char* file = env->GetStringUTFChars(fileStr, NULL);
-
- KeyCharacterMap* map;
- status_t status = KeyCharacterMap::load(String8(file), &map);
- jint result;
- if (status) {
- String8 msg;
- msg.appendFormat("Could not load key character map '%s' due to error %d. "
- "Refer to the log for details.", file, status);
- jniThrowException(env, "android/view/KeyCharacterMap$KeyCharacterMapUnavailableException",
- msg.string());
- result = 0;
- } else {
- result = reinterpret_cast<jint>(map);
+class NativeKeyCharacterMap {
+public:
+ NativeKeyCharacterMap(int32_t deviceId, const sp<KeyCharacterMap>& map) :
+ mDeviceId(deviceId), mMap(map) {
}
- env->ReleaseStringUTFChars(fileStr, file);
- return result;
+ ~NativeKeyCharacterMap() {
+ }
+
+ inline int32_t getDeviceId() const {
+ return mDeviceId;
+ }
+
+ inline const sp<KeyCharacterMap>& getMap() const {
+ return mMap;
+ }
+
+private:
+ int32_t mDeviceId;
+ sp<KeyCharacterMap> mMap;
+};
+
+
+jobject android_view_KeyCharacterMap_create(JNIEnv* env, int32_t deviceId,
+ const sp<KeyCharacterMap>& kcm) {
+ NativeKeyCharacterMap* map = new NativeKeyCharacterMap(deviceId,
+ kcm.get() ? kcm : KeyCharacterMap::empty());
+ if (!map) {
+ return NULL;
+ }
+
+ return env->NewObject(gKeyCharacterMapClassInfo.clazz, gKeyCharacterMapClassInfo.ctor,
+ reinterpret_cast<jint>(map));
+}
+
+static jint nativeReadFromParcel(JNIEnv *env, jobject clazz, jobject parcelObj) {
+ Parcel* parcel = parcelForJavaObject(env, parcelObj);
+ if (!parcel) {
+ return 0;
+ }
+
+ int32_t deviceId = parcel->readInt32();
+ if (parcel->errorCheck()) {
+ return 0;
+ }
+
+ sp<KeyCharacterMap> kcm = KeyCharacterMap::readFromParcel(parcel);
+ if (!kcm.get()) {
+ return 0;
+ }
+
+ NativeKeyCharacterMap* map = new NativeKeyCharacterMap(deviceId, kcm);
+ return reinterpret_cast<jint>(map);
+}
+
+static void nativeWriteToParcel(JNIEnv* env, jobject clazz, jint ptr, jobject parcelObj) {
+ NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr);
+ Parcel* parcel = parcelForJavaObject(env, parcelObj);
+ if (parcel) {
+ parcel->writeInt32(map->getDeviceId());
+ map->getMap()->writeToParcel(parcel);
+ }
}
static void nativeDispose(JNIEnv *env, jobject clazz, jint ptr) {
- KeyCharacterMap* map = reinterpret_cast<KeyCharacterMap*>(ptr);
+ NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr);
delete map;
}
static jchar nativeGetCharacter(JNIEnv *env, jobject clazz, jint ptr,
jint keyCode, jint metaState) {
- KeyCharacterMap* map = reinterpret_cast<KeyCharacterMap*>(ptr);
- return map->getCharacter(keyCode, metaState);
+ NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr);
+ return map->getMap()->getCharacter(keyCode, metaState);
}
static jboolean nativeGetFallbackAction(JNIEnv *env, jobject clazz, jint ptr, jint keyCode,
jint metaState, jobject fallbackActionObj) {
- KeyCharacterMap* map = reinterpret_cast<KeyCharacterMap*>(ptr);
+ NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr);
KeyCharacterMap::FallbackAction fallbackAction;
- bool result = map->getFallbackAction(keyCode, metaState, &fallbackAction);
+ bool result = map->getMap()->getFallbackAction(keyCode, metaState, &fallbackAction);
if (result) {
env->SetIntField(fallbackActionObj, gFallbackActionClassInfo.keyCode,
fallbackAction.keyCode);
@@ -83,13 +134,13 @@ static jboolean nativeGetFallbackAction(JNIEnv *env, jobject clazz, jint ptr, ji
}
static jchar nativeGetNumber(JNIEnv *env, jobject clazz, jint ptr, jint keyCode) {
- KeyCharacterMap* map = reinterpret_cast<KeyCharacterMap*>(ptr);
- return map->getNumber(keyCode);
+ NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr);
+ return map->getMap()->getNumber(keyCode);
}
static jchar nativeGetMatch(JNIEnv *env, jobject clazz, jint ptr, jint keyCode,
jcharArray charsArray, jint metaState) {
- KeyCharacterMap* map = reinterpret_cast<KeyCharacterMap*>(ptr);
+ NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr);
jsize numChars = env->GetArrayLength(charsArray);
jchar* chars = static_cast<jchar*>(env->GetPrimitiveArrayCritical(charsArray, NULL));
@@ -97,25 +148,25 @@ static jchar nativeGetMatch(JNIEnv *env, jobject clazz, jint ptr, jint keyCode,
return 0;
}
- char16_t result = map->getMatch(keyCode, chars, size_t(numChars), metaState);
+ char16_t result = map->getMap()->getMatch(keyCode, chars, size_t(numChars), metaState);
env->ReleasePrimitiveArrayCritical(charsArray, chars, JNI_ABORT);
return result;
}
static jchar nativeGetDisplayLabel(JNIEnv *env, jobject clazz, jint ptr, jint keyCode) {
- KeyCharacterMap* map = reinterpret_cast<KeyCharacterMap*>(ptr);
- return map->getDisplayLabel(keyCode);
+ NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr);
+ return map->getMap()->getDisplayLabel(keyCode);
}
static jint nativeGetKeyboardType(JNIEnv *env, jobject clazz, jint ptr) {
- KeyCharacterMap* map = reinterpret_cast<KeyCharacterMap*>(ptr);
- return map->getKeyboardType();
+ NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr);
+ return map->getMap()->getKeyboardType();
}
-static jobjectArray nativeGetEvents(JNIEnv *env, jobject clazz, jint ptr, jint deviceId,
+static jobjectArray nativeGetEvents(JNIEnv *env, jobject clazz, jint ptr,
jcharArray charsArray) {
- KeyCharacterMap* map = reinterpret_cast<KeyCharacterMap*>(ptr);
+ NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr);
jchar* chars = env->GetCharArrayElements(charsArray, NULL);
if (!chars) {
@@ -125,7 +176,7 @@ static jobjectArray nativeGetEvents(JNIEnv *env, jobject clazz, jint ptr, jint d
Vector<KeyEvent> events;
jobjectArray result = NULL;
- if (map->getEvents(deviceId, chars, size_t(numChars), events)) {
+ if (map->getMap()->getEvents(map->getDeviceId(), chars, size_t(numChars), events)) {
result = env->NewObjectArray(jsize(events.size()), gKeyEventClassInfo.clazz, NULL);
if (result) {
for (size_t i = 0; i < events.size(); i++) {
@@ -148,8 +199,10 @@ static jobjectArray nativeGetEvents(JNIEnv *env, jobject clazz, jint ptr, jint d
static JNINativeMethod g_methods[] = {
/* name, signature, funcPtr */
- { "nativeLoad", "(Ljava/lang/String;)I",
- (void*)nativeLoad },
+ { "nativeReadFromParcel", "(Landroid/os/Parcel;)I",
+ (void*)nativeReadFromParcel },
+ { "nativeWriteToParcel", "(ILandroid/os/Parcel;)V",
+ (void*)nativeWriteToParcel },
{ "nativeDispose", "(I)V",
(void*)nativeDispose },
{ "nativeGetCharacter", "(III)C",
@@ -164,7 +217,7 @@ static JNINativeMethod g_methods[] = {
(void*)nativeGetDisplayLabel },
{ "nativeGetKeyboardType", "(I)I",
(void*)nativeGetKeyboardType },
- { "nativeGetEvents", "(II[C)[Landroid/view/KeyEvent;",
+ { "nativeGetEvents", "(I[C)[Landroid/view/KeyEvent;",
(void*)nativeGetEvents },
};
@@ -172,12 +225,22 @@ static JNINativeMethod g_methods[] = {
var = env->FindClass(className); \
LOG_FATAL_IF(! var, "Unable to find class " className);
+#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
+ var = env->GetMethodID(clazz, methodName, methodDescriptor); \
+ LOG_FATAL_IF(! var, "Unable to find method " methodName);
+
#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
LOG_FATAL_IF(! var, "Unable to find field " fieldName);
-int register_android_text_KeyCharacterMap(JNIEnv* env)
+int register_android_view_KeyCharacterMap(JNIEnv* env)
{
+ FIND_CLASS(gKeyCharacterMapClassInfo.clazz, "android/view/KeyCharacterMap");
+ gKeyCharacterMapClassInfo.clazz = jclass(env->NewGlobalRef(gKeyCharacterMapClassInfo.clazz));
+
+ GET_METHOD_ID(gKeyCharacterMapClassInfo.ctor, gKeyCharacterMapClassInfo.clazz,
+ "<init>", "(I)V");
+
FIND_CLASS(gKeyEventClassInfo.clazz, "android/view/KeyEvent");
gKeyEventClassInfo.clazz = jclass(env->NewGlobalRef(gKeyEventClassInfo.clazz));
diff --git a/core/jni/android_view_KeyCharacterMap.h b/core/jni/android_view_KeyCharacterMap.h
new file mode 100644
index 0000000..04024f6
--- /dev/null
+++ b/core/jni/android_view_KeyCharacterMap.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#ifndef _ANDROID_VIEW_KEY_CHARACTER_MAP_H
+#define _ANDROID_VIEW_KEY_CHARACTER_MAP_H
+
+#include "jni.h"
+
+#include <androidfw/KeyCharacterMap.h>
+
+namespace android {
+
+/* Creates a KeyCharacterMap object from the given information. */
+extern jobject android_view_KeyCharacterMap_create(JNIEnv* env, int32_t deviceId,
+ const sp<KeyCharacterMap>& map);
+
+} // namespace android
+
+#endif // _ANDROID_VIEW_KEY_CHARACTER_MAP_H
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 3ee2377..f5c0f8f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1256,6 +1256,13 @@
android:description="@string/permdesc_setPointerSpeed"
android:protectionLevel="signature" />
+ <!-- Allows low-level access to setting the keyboard layout.
+ Not for use by normal applications. -->
+ <permission android:name="android.permission.SET_KEYBOARD_LAYOUT"
+ android:label="@string/permlab_setKeyboardLayout"
+ android:description="@string/permdesc_setKeyboardLayout"
+ android:protectionLevel="signature" />
+
<!-- Allows an application to install packages. -->
<permission android:name="android.permission.INSTALL_PACKAGES"
android:label="@string/permlab_installPackages"
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 44f2ade..86cece4 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -768,6 +768,12 @@
the mouse or trackpad pointer speed at any time. Should never be needed for
normal apps.</string>
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=30] -->
+ <string name="permlab_setKeyboardLayout">change keyboard layout</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] -->
+ <string name="permdesc_setKeyboardLayout">Allows the app to change
+ the keyboard layout. Should never be needed for normal apps.</string>
+
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_signalPersistentProcesses">send Linux signals to apps</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
diff --git a/include/androidfw/Input.h b/include/androidfw/Input.h
index f8cbdde..a98e1a2 100644
--- a/include/androidfw/Input.h
+++ b/include/androidfw/Input.h
@@ -811,117 +811,6 @@ private:
VelocityTracker mVelocityTracker;
};
-/*
- * Identifies a device.
- */
-struct InputDeviceIdentifier {
- inline InputDeviceIdentifier() :
- bus(0), vendor(0), product(0), version(0) {
- }
-
- // Information provided by the kernel.
- String8 name;
- String8 location;
- String8 uniqueId;
- uint16_t bus;
- uint16_t vendor;
- uint16_t product;
- uint16_t version;
-
- // A composite input device descriptor string that uniquely identifies the device
- // even across reboots or reconnections. The value of this field is used by
- // upper layers of the input system to associate settings with individual devices.
- // It is hashed from whatever kernel provided information is available.
- // Ideally, the way this value is computed should not change between Android releases
- // because that would invalidate persistent settings that rely on it.
- String8 descriptor;
-};
-
-/*
- * Describes the characteristics and capabilities of an input device.
- */
-class InputDeviceInfo {
-public:
- InputDeviceInfo();
- InputDeviceInfo(const InputDeviceInfo& other);
- ~InputDeviceInfo();
-
- struct MotionRange {
- int32_t axis;
- uint32_t source;
- float min;
- float max;
- float flat;
- float fuzz;
- };
-
- void initialize(int32_t id, const String8& name, const String8& descriptor);
-
- inline int32_t getId() const { return mId; }
- inline const String8 getName() const { return mName; }
- inline const String8 getDescriptor() const { return mDescriptor; }
- inline uint32_t getSources() const { return mSources; }
-
- const MotionRange* getMotionRange(int32_t axis, uint32_t source) const;
-
- void addSource(uint32_t source);
- void addMotionRange(int32_t axis, uint32_t source,
- float min, float max, float flat, float fuzz);
- void addMotionRange(const MotionRange& range);
-
- inline void setKeyboardType(int32_t keyboardType) { mKeyboardType = keyboardType; }
- inline int32_t getKeyboardType() const { return mKeyboardType; }
-
- inline void setKeyCharacterMapFile(const String8& value) { mKeyCharacterMapFile = value; }
- inline const String8& getKeyCharacterMapFile() const { return mKeyCharacterMapFile; }
-
- inline const Vector<MotionRange>& getMotionRanges() const {
- return mMotionRanges;
- }
-
-private:
- int32_t mId;
- String8 mName;
- String8 mDescriptor;
- uint32_t mSources;
- int32_t mKeyboardType;
- String8 mKeyCharacterMapFile;
-
- Vector<MotionRange> mMotionRanges;
-};
-
-/* Types of input device configuration files. */
-enum InputDeviceConfigurationFileType {
- INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION = 0, /* .idc file */
- INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT = 1, /* .kl file */
- INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP = 2, /* .kcm file */
-};
-
-/*
- * Gets the path of an input device configuration file, if one is available.
- * Considers both system provided and user installed configuration files.
- *
- * The device identifier is used to construct several default configuration file
- * names to try based on the device name, vendor, product, and version.
- *
- * Returns an empty string if not found.
- */
-extern String8 getInputDeviceConfigurationFilePathByDeviceIdentifier(
- const InputDeviceIdentifier& deviceIdentifier,
- InputDeviceConfigurationFileType type);
-
-/*
- * Gets the path of an input device configuration file, if one is available.
- * Considers both system provided and user installed configuration files.
- *
- * The name is case-sensitive and is used to construct the filename to resolve.
- * All characters except 'a'-'z', 'A'-'Z', '0'-'9', '-', and '_' are replaced by underscores.
- *
- * Returns an empty string if not found.
- */
-extern String8 getInputDeviceConfigurationFilePathByName(
- const String8& name, InputDeviceConfigurationFileType type);
-
} // namespace android
#endif // _ANDROIDFW_INPUT_H
diff --git a/include/androidfw/InputDevice.h b/include/androidfw/InputDevice.h
new file mode 100644
index 0000000..c9554dc
--- /dev/null
+++ b/include/androidfw/InputDevice.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#ifndef _ANDROIDFW_INPUT_DEVICE_H
+#define _ANDROIDFW_INPUT_DEVICE_H
+
+#include <androidfw/Input.h>
+#include <androidfw/KeyCharacterMap.h>
+
+namespace android {
+
+/*
+ * Identifies a device.
+ */
+struct InputDeviceIdentifier {
+ inline InputDeviceIdentifier() :
+ bus(0), vendor(0), product(0), version(0) {
+ }
+
+ // Information provided by the kernel.
+ String8 name;
+ String8 location;
+ String8 uniqueId;
+ uint16_t bus;
+ uint16_t vendor;
+ uint16_t product;
+ uint16_t version;
+
+ // A composite input device descriptor string that uniquely identifies the device
+ // even across reboots or reconnections. The value of this field is used by
+ // upper layers of the input system to associate settings with individual devices.
+ // It is hashed from whatever kernel provided information is available.
+ // Ideally, the way this value is computed should not change between Android releases
+ // because that would invalidate persistent settings that rely on it.
+ String8 descriptor;
+};
+
+/*
+ * Describes the characteristics and capabilities of an input device.
+ */
+class InputDeviceInfo {
+public:
+ InputDeviceInfo();
+ InputDeviceInfo(const InputDeviceInfo& other);
+ ~InputDeviceInfo();
+
+ struct MotionRange {
+ int32_t axis;
+ uint32_t source;
+ float min;
+ float max;
+ float flat;
+ float fuzz;
+ };
+
+ void initialize(int32_t id, const String8& name, const String8& descriptor);
+
+ inline int32_t getId() const { return mId; }
+ inline const String8 getName() const { return mName; }
+ inline const String8 getDescriptor() const { return mDescriptor; }
+ inline uint32_t getSources() const { return mSources; }
+
+ const MotionRange* getMotionRange(int32_t axis, uint32_t source) const;
+
+ void addSource(uint32_t source);
+ void addMotionRange(int32_t axis, uint32_t source,
+ float min, float max, float flat, float fuzz);
+ void addMotionRange(const MotionRange& range);
+
+ inline void setKeyboardType(int32_t keyboardType) { mKeyboardType = keyboardType; }
+ inline int32_t getKeyboardType() const { return mKeyboardType; }
+
+ inline void setKeyCharacterMap(const sp<KeyCharacterMap>& value) {
+ mKeyCharacterMap = value;
+ }
+
+ inline sp<KeyCharacterMap> getKeyCharacterMap() const {
+ return mKeyCharacterMap;
+ }
+
+ inline const Vector<MotionRange>& getMotionRanges() const {
+ return mMotionRanges;
+ }
+
+private:
+ int32_t mId;
+ String8 mName;
+ String8 mDescriptor;
+ uint32_t mSources;
+ int32_t mKeyboardType;
+ sp<KeyCharacterMap> mKeyCharacterMap;
+
+ Vector<MotionRange> mMotionRanges;
+};
+
+/* Types of input device configuration files. */
+enum InputDeviceConfigurationFileType {
+ INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION = 0, /* .idc file */
+ INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT = 1, /* .kl file */
+ INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP = 2, /* .kcm file */
+};
+
+/*
+ * Gets the path of an input device configuration file, if one is available.
+ * Considers both system provided and user installed configuration files.
+ *
+ * The device identifier is used to construct several default configuration file
+ * names to try based on the device name, vendor, product, and version.
+ *
+ * Returns an empty string if not found.
+ */
+extern String8 getInputDeviceConfigurationFilePathByDeviceIdentifier(
+ const InputDeviceIdentifier& deviceIdentifier,
+ InputDeviceConfigurationFileType type);
+
+/*
+ * Gets the path of an input device configuration file, if one is available.
+ * Considers both system provided and user installed configuration files.
+ *
+ * The name is case-sensitive and is used to construct the filename to resolve.
+ * All characters except 'a'-'z', 'A'-'Z', '0'-'9', '-', and '_' are replaced by underscores.
+ *
+ * Returns an empty string if not found.
+ */
+extern String8 getInputDeviceConfigurationFilePathByName(
+ const String8& name, InputDeviceConfigurationFileType type);
+
+} // namespace android
+
+#endif // _ANDROIDFW_INPUT_DEVICE_H
diff --git a/include/androidfw/KeyCharacterMap.h b/include/androidfw/KeyCharacterMap.h
index 679dd2c..3cc1cb2 100644
--- a/include/androidfw/KeyCharacterMap.h
+++ b/include/androidfw/KeyCharacterMap.h
@@ -19,12 +19,17 @@
#include <stdint.h>
+#if HAVE_ANDROID_OS
+#include <binder/IBinder.h>
+#endif
+
#include <androidfw/Input.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/Tokenizer.h>
#include <utils/String8.h>
#include <utils/Unicode.h>
+#include <utils/RefBase.h>
namespace android {
@@ -32,8 +37,10 @@ namespace android {
* Describes a mapping from Android key codes to characters.
* Also specifies other functions of the keyboard such as the keyboard type
* and key modifier semantics.
+ *
+ * This object is immutable after it has been loaded.
*/
-class KeyCharacterMap {
+class KeyCharacterMap : public RefBase {
public:
enum KeyboardType {
KEYBOARD_TYPE_UNKNOWN = 0,
@@ -50,9 +57,11 @@ public:
int32_t metaState;
};
- ~KeyCharacterMap();
+ /* Loads a key character map from a file. */
+ static status_t load(const String8& filename, sp<KeyCharacterMap>* outMap);
- static status_t load(const String8& filename, KeyCharacterMap** outMap);
+ /* Returns an empty key character map. */
+ static sp<KeyCharacterMap> empty();
/* Gets the keyboard type. */
int32_t getKeyboardType() const;
@@ -92,6 +101,17 @@ public:
bool getEvents(int32_t deviceId, const char16_t* chars, size_t numChars,
Vector<KeyEvent>& outEvents) const;
+#if HAVE_ANDROID_OS
+ /* Reads a key map from a parcel. */
+ static sp<KeyCharacterMap> readFromParcel(Parcel* parcel);
+
+ /* Writes a key map to a parcel. */
+ void writeToParcel(Parcel* parcel) const;
+#endif
+
+protected:
+ virtual ~KeyCharacterMap();
+
private:
struct Behavior {
Behavior();
@@ -162,6 +182,8 @@ private:
status_t parseCharacterLiteral(char16_t* outCharacter);
};
+ static sp<KeyCharacterMap> sEmpty;
+
KeyedVector<int32_t, Key*> mKeys;
int mType;
diff --git a/include/androidfw/KeyLayoutMap.h b/include/androidfw/KeyLayoutMap.h
index 5a6f550..5408680 100644
--- a/include/androidfw/KeyLayoutMap.h
+++ b/include/androidfw/KeyLayoutMap.h
@@ -21,6 +21,7 @@
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/Tokenizer.h>
+#include <utils/RefBase.h>
namespace android {
@@ -56,18 +57,21 @@ struct AxisInfo {
/**
* Describes a mapping from keyboard scan codes and joystick axes to Android key codes and axes.
+ *
+ * This object is immutable after it has been loaded.
*/
-class KeyLayoutMap {
+class KeyLayoutMap : public RefBase {
public:
- ~KeyLayoutMap();
-
- static status_t load(const String8& filename, KeyLayoutMap** outMap);
+ static status_t load(const String8& filename, sp<KeyLayoutMap>* outMap);
status_t mapKey(int32_t scanCode, int32_t* keyCode, uint32_t* flags) const;
status_t findScanCodesForKey(int32_t keyCode, Vector<int32_t>* outScanCodes) const;
status_t mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const;
+protected:
+ virtual ~KeyLayoutMap();
+
private:
struct Key {
int32_t keyCode;
diff --git a/include/androidfw/Keyboard.h b/include/androidfw/Keyboard.h
index ae65198..6537a8f 100644
--- a/include/androidfw/Keyboard.h
+++ b/include/androidfw/Keyboard.h
@@ -18,6 +18,7 @@
#define _ANDROIDFW_KEYBOARD_H
#include <androidfw/Input.h>
+#include <androidfw/InputDevice.h>
#include <utils/Errors.h>
#include <utils/String8.h>
#include <utils/PropertyMap.h>
@@ -42,10 +43,10 @@ class KeyCharacterMap;
class KeyMap {
public:
String8 keyLayoutFile;
- KeyLayoutMap* keyLayoutMap;
+ sp<KeyLayoutMap> keyLayoutMap;
String8 keyCharacterMapFile;
- KeyCharacterMap* keyCharacterMap;
+ sp<KeyCharacterMap> keyCharacterMap;
KeyMap();
~KeyMap();
diff --git a/include/androidfw/VirtualKeyMap.h b/include/androidfw/VirtualKeyMap.h
index 66340e3..dd3ad1e 100644
--- a/include/androidfw/VirtualKeyMap.h
+++ b/include/androidfw/VirtualKeyMap.h
@@ -43,6 +43,8 @@ struct VirtualKeyDefinition {
/**
* Describes a collection of virtual keys on a touch screen in terms of
* virtual scan codes and hit rectangles.
+ *
+ * This object is immutable after it has been loaded.
*/
class VirtualKeyMap {
public:
diff --git a/libs/androidfw/Android.mk b/libs/androidfw/Android.mk
index a3f92cb..95c77d4 100644
--- a/libs/androidfw/Android.mk
+++ b/libs/androidfw/Android.mk
@@ -29,6 +29,7 @@ commonUtilsSources:= \
# formerly in libui
commonUiSources:= \
Input.cpp \
+ InputDevice.cpp \
Keyboard.cpp \
KeyCharacterMap.cpp \
KeyLayoutMap.cpp \
diff --git a/libs/androidfw/Input.cpp b/libs/androidfw/Input.cpp
index 2e4b26f..1617a3f 100644
--- a/libs/androidfw/Input.cpp
+++ b/libs/androidfw/Input.cpp
@@ -1,8 +1,19 @@
-//
-// Copyright 2010 The Android Open Source Project
-//
-// Provides a pipe-based transport for native events in the NDK.
-//
+/*
+ * Copyright (C) 2010 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.
+ */
+
#define LOG_TAG "Input"
//#define LOG_NDEBUG 0
@@ -39,106 +50,6 @@
namespace android {
-static const char* CONFIGURATION_FILE_DIR[] = {
- "idc/",
- "keylayout/",
- "keychars/",
-};
-
-static const char* CONFIGURATION_FILE_EXTENSION[] = {
- ".idc",
- ".kl",
- ".kcm",
-};
-
-static bool isValidNameChar(char ch) {
- return isascii(ch) && (isdigit(ch) || isalpha(ch) || ch == '-' || ch == '_');
-}
-
-static void appendInputDeviceConfigurationFileRelativePath(String8& path,
- const String8& name, InputDeviceConfigurationFileType type) {
- path.append(CONFIGURATION_FILE_DIR[type]);
- for (size_t i = 0; i < name.length(); i++) {
- char ch = name[i];
- if (!isValidNameChar(ch)) {
- ch = '_';
- }
- path.append(&ch, 1);
- }
- path.append(CONFIGURATION_FILE_EXTENSION[type]);
-}
-
-String8 getInputDeviceConfigurationFilePathByDeviceIdentifier(
- const InputDeviceIdentifier& deviceIdentifier,
- InputDeviceConfigurationFileType type) {
- if (deviceIdentifier.vendor !=0 && deviceIdentifier.product != 0) {
- if (deviceIdentifier.version != 0) {
- // Try vendor product version.
- String8 versionPath(getInputDeviceConfigurationFilePathByName(
- String8::format("Vendor_%04x_Product_%04x_Version_%04x",
- deviceIdentifier.vendor, deviceIdentifier.product,
- deviceIdentifier.version),
- type));
- if (!versionPath.isEmpty()) {
- return versionPath;
- }
- }
-
- // Try vendor product.
- String8 productPath(getInputDeviceConfigurationFilePathByName(
- String8::format("Vendor_%04x_Product_%04x",
- deviceIdentifier.vendor, deviceIdentifier.product),
- type));
- if (!productPath.isEmpty()) {
- return productPath;
- }
- }
-
- // Try device name.
- return getInputDeviceConfigurationFilePathByName(deviceIdentifier.name, type);
-}
-
-String8 getInputDeviceConfigurationFilePathByName(
- const String8& name, InputDeviceConfigurationFileType type) {
- // Search system repository.
- String8 path;
- path.setTo(getenv("ANDROID_ROOT"));
- path.append("/usr/");
- appendInputDeviceConfigurationFileRelativePath(path, name, type);
-#if DEBUG_PROBE
- ALOGD("Probing for system provided input device configuration file: path='%s'", path.string());
-#endif
- if (!access(path.string(), R_OK)) {
-#if DEBUG_PROBE
- ALOGD("Found");
-#endif
- return path;
- }
-
- // Search user repository.
- // TODO Should only look here if not in safe mode.
- path.setTo(getenv("ANDROID_DATA"));
- path.append("/system/devices/");
- appendInputDeviceConfigurationFileRelativePath(path, name, type);
-#if DEBUG_PROBE
- ALOGD("Probing for system user input device configuration file: path='%s'", path.string());
-#endif
- if (!access(path.string(), R_OK)) {
-#if DEBUG_PROBE
- ALOGD("Found");
-#endif
- return path;
- }
-
- // Not found.
-#if DEBUG_PROBE
- ALOGD("Probe failed to find input device configuration file: name='%s', type=%d",
- name.string(), type);
-#endif
- return String8();
-}
-
-
// --- InputEvent ---
void InputEvent::initialize(int32_t deviceId, int32_t source) {
@@ -1222,57 +1133,4 @@ void VelocityControl::move(nsecs_t eventTime, float* deltaX, float* deltaY) {
}
}
-
-// --- InputDeviceInfo ---
-
-InputDeviceInfo::InputDeviceInfo() {
- initialize(-1, String8("uninitialized device info"), String8("unknown"));
-}
-
-InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other) :
- mId(other.mId), mName(other.mName), mDescriptor(other.mDescriptor),
- mSources(other.mSources),
- mKeyboardType(other.mKeyboardType),
- mKeyCharacterMapFile(other.mKeyCharacterMapFile),
- mMotionRanges(other.mMotionRanges) {
-}
-
-InputDeviceInfo::~InputDeviceInfo() {
-}
-
-void InputDeviceInfo::initialize(int32_t id, const String8& name, const String8& descriptor) {
- mId = id;
- mName = name;
- mDescriptor = descriptor;
- mSources = 0;
- mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE;
- mMotionRanges.clear();
-}
-
-const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange(
- int32_t axis, uint32_t source) const {
- size_t numRanges = mMotionRanges.size();
- for (size_t i = 0; i < numRanges; i++) {
- const MotionRange& range = mMotionRanges.itemAt(i);
- if (range.axis == axis && range.source == source) {
- return &range;
- }
- }
- return NULL;
-}
-
-void InputDeviceInfo::addSource(uint32_t source) {
- mSources |= source;
-}
-
-void InputDeviceInfo::addMotionRange(int32_t axis, uint32_t source, float min, float max,
- float flat, float fuzz) {
- MotionRange range = { axis, source, min, max, flat, fuzz };
- mMotionRanges.add(range);
-}
-
-void InputDeviceInfo::addMotionRange(const MotionRange& range) {
- mMotionRanges.add(range);
-}
-
} // namespace android
diff --git a/libs/androidfw/InputDevice.cpp b/libs/androidfw/InputDevice.cpp
new file mode 100644
index 0000000..698feb6
--- /dev/null
+++ b/libs/androidfw/InputDevice.cpp
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#define LOG_TAG "InputDevice"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#include <androidfw/InputDevice.h>
+
+namespace android {
+
+static const char* CONFIGURATION_FILE_DIR[] = {
+ "idc/",
+ "keylayout/",
+ "keychars/",
+};
+
+static const char* CONFIGURATION_FILE_EXTENSION[] = {
+ ".idc",
+ ".kl",
+ ".kcm",
+};
+
+static bool isValidNameChar(char ch) {
+ return isascii(ch) && (isdigit(ch) || isalpha(ch) || ch == '-' || ch == '_');
+}
+
+static void appendInputDeviceConfigurationFileRelativePath(String8& path,
+ const String8& name, InputDeviceConfigurationFileType type) {
+ path.append(CONFIGURATION_FILE_DIR[type]);
+ for (size_t i = 0; i < name.length(); i++) {
+ char ch = name[i];
+ if (!isValidNameChar(ch)) {
+ ch = '_';
+ }
+ path.append(&ch, 1);
+ }
+ path.append(CONFIGURATION_FILE_EXTENSION[type]);
+}
+
+String8 getInputDeviceConfigurationFilePathByDeviceIdentifier(
+ const InputDeviceIdentifier& deviceIdentifier,
+ InputDeviceConfigurationFileType type) {
+ if (deviceIdentifier.vendor !=0 && deviceIdentifier.product != 0) {
+ if (deviceIdentifier.version != 0) {
+ // Try vendor product version.
+ String8 versionPath(getInputDeviceConfigurationFilePathByName(
+ String8::format("Vendor_%04x_Product_%04x_Version_%04x",
+ deviceIdentifier.vendor, deviceIdentifier.product,
+ deviceIdentifier.version),
+ type));
+ if (!versionPath.isEmpty()) {
+ return versionPath;
+ }
+ }
+
+ // Try vendor product.
+ String8 productPath(getInputDeviceConfigurationFilePathByName(
+ String8::format("Vendor_%04x_Product_%04x",
+ deviceIdentifier.vendor, deviceIdentifier.product),
+ type));
+ if (!productPath.isEmpty()) {
+ return productPath;
+ }
+ }
+
+ // Try device name.
+ return getInputDeviceConfigurationFilePathByName(deviceIdentifier.name, type);
+}
+
+String8 getInputDeviceConfigurationFilePathByName(
+ const String8& name, InputDeviceConfigurationFileType type) {
+ // Search system repository.
+ String8 path;
+ path.setTo(getenv("ANDROID_ROOT"));
+ path.append("/usr/");
+ appendInputDeviceConfigurationFileRelativePath(path, name, type);
+#if DEBUG_PROBE
+ ALOGD("Probing for system provided input device configuration file: path='%s'", path.string());
+#endif
+ if (!access(path.string(), R_OK)) {
+#if DEBUG_PROBE
+ ALOGD("Found");
+#endif
+ return path;
+ }
+
+ // Search user repository.
+ // TODO Should only look here if not in safe mode.
+ path.setTo(getenv("ANDROID_DATA"));
+ path.append("/system/devices/");
+ appendInputDeviceConfigurationFileRelativePath(path, name, type);
+#if DEBUG_PROBE
+ ALOGD("Probing for system user input device configuration file: path='%s'", path.string());
+#endif
+ if (!access(path.string(), R_OK)) {
+#if DEBUG_PROBE
+ ALOGD("Found");
+#endif
+ return path;
+ }
+
+ // Not found.
+#if DEBUG_PROBE
+ ALOGD("Probe failed to find input device configuration file: name='%s', type=%d",
+ name.string(), type);
+#endif
+ return String8();
+}
+
+
+// --- InputDeviceInfo ---
+
+InputDeviceInfo::InputDeviceInfo() {
+ initialize(-1, String8("uninitialized device info"), String8("unknown"));
+}
+
+InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other) :
+ mId(other.mId), mName(other.mName), mDescriptor(other.mDescriptor),
+ mSources(other.mSources),
+ mKeyboardType(other.mKeyboardType),
+ mKeyCharacterMap(other.mKeyCharacterMap),
+ mMotionRanges(other.mMotionRanges) {
+}
+
+InputDeviceInfo::~InputDeviceInfo() {
+}
+
+void InputDeviceInfo::initialize(int32_t id, const String8& name, const String8& descriptor) {
+ mId = id;
+ mName = name;
+ mDescriptor = descriptor;
+ mSources = 0;
+ mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE;
+ mMotionRanges.clear();
+}
+
+const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange(
+ int32_t axis, uint32_t source) const {
+ size_t numRanges = mMotionRanges.size();
+ for (size_t i = 0; i < numRanges; i++) {
+ const MotionRange& range = mMotionRanges.itemAt(i);
+ if (range.axis == axis && range.source == source) {
+ return &range;
+ }
+ }
+ return NULL;
+}
+
+void InputDeviceInfo::addSource(uint32_t source) {
+ mSources |= source;
+}
+
+void InputDeviceInfo::addMotionRange(int32_t axis, uint32_t source, float min, float max,
+ float flat, float fuzz) {
+ MotionRange range = { axis, source, min, max, flat, fuzz };
+ mMotionRanges.add(range);
+}
+
+void InputDeviceInfo::addMotionRange(const MotionRange& range) {
+ mMotionRanges.add(range);
+}
+
+} // namespace android
diff --git a/libs/androidfw/KeyCharacterMap.cpp b/libs/androidfw/KeyCharacterMap.cpp
index 6984084..9abbf38 100644
--- a/libs/androidfw/KeyCharacterMap.cpp
+++ b/libs/androidfw/KeyCharacterMap.cpp
@@ -21,6 +21,11 @@
#include <android/keycodes.h>
#include <androidfw/Keyboard.h>
#include <androidfw/KeyCharacterMap.h>
+
+#if HAVE_ANDROID_OS
+#include <binder/Parcel.h>
+#endif
+
#include <utils/Log.h>
#include <utils/Errors.h>
#include <utils/Tokenizer.h>
@@ -78,6 +83,8 @@ static String8 toString(const char16_t* chars, size_t numChars) {
// --- KeyCharacterMap ---
+sp<KeyCharacterMap> KeyCharacterMap::sEmpty = new KeyCharacterMap();
+
KeyCharacterMap::KeyCharacterMap() :
mType(KEYBOARD_TYPE_UNKNOWN) {
}
@@ -89,23 +96,23 @@ KeyCharacterMap::~KeyCharacterMap() {
}
}
-status_t KeyCharacterMap::load(const String8& filename, KeyCharacterMap** outMap) {
- *outMap = NULL;
+status_t KeyCharacterMap::load(const String8& filename, sp<KeyCharacterMap>* outMap) {
+ outMap->clear();
Tokenizer* tokenizer;
status_t status = Tokenizer::open(filename, &tokenizer);
if (status) {
ALOGE("Error %d opening key character map file %s.", status, filename.string());
} else {
- KeyCharacterMap* map = new KeyCharacterMap();
- if (!map) {
+ sp<KeyCharacterMap> map = new KeyCharacterMap();
+ if (!map.get()) {
ALOGE("Error allocating key character map.");
status = NO_MEMORY;
} else {
#if DEBUG_PARSER_PERFORMANCE
nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
#endif
- Parser parser(map, tokenizer);
+ Parser parser(map.get(), tokenizer);
status = parser.parse();
#if DEBUG_PARSER_PERFORMANCE
nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
@@ -113,9 +120,7 @@ status_t KeyCharacterMap::load(const String8& filename, KeyCharacterMap** outMap
tokenizer->getFilename().string(), tokenizer->getLineNumber(),
elapsedTime / 1000000.0);
#endif
- if (status) {
- delete map;
- } else {
+ if (!status) {
*outMap = map;
}
}
@@ -124,6 +129,10 @@ status_t KeyCharacterMap::load(const String8& filename, KeyCharacterMap** outMap
return status;
}
+sp<KeyCharacterMap> KeyCharacterMap::empty() {
+ return sEmpty;
+}
+
int32_t KeyCharacterMap::getKeyboardType() const {
return mType;
}
@@ -419,6 +428,79 @@ void KeyCharacterMap::addLockedMetaKey(Vector<KeyEvent>& outEvents,
}
}
+#if HAVE_ANDROID_OS
+sp<KeyCharacterMap> KeyCharacterMap::readFromParcel(Parcel* parcel) {
+ sp<KeyCharacterMap> map = new KeyCharacterMap();
+ map->mType = parcel->readInt32();
+ size_t numKeys = parcel->readInt32();
+ if (parcel->errorCheck()) {
+ return NULL;
+ }
+
+ for (size_t i = 0; i < numKeys; i++) {
+ int32_t keyCode = parcel->readInt32();
+ char16_t label = parcel->readInt32();
+ char16_t number = parcel->readInt32();
+ if (parcel->errorCheck()) {
+ return NULL;
+ }
+
+ Key* key = new Key();
+ key->label = label;
+ key->number = number;
+ map->mKeys.add(keyCode, key);
+
+ Behavior* lastBehavior = NULL;
+ while (parcel->readInt32()) {
+ int32_t metaState = parcel->readInt32();
+ char16_t character = parcel->readInt32();
+ int32_t fallbackKeyCode = parcel->readInt32();
+ if (parcel->errorCheck()) {
+ return NULL;
+ }
+
+ Behavior* behavior = new Behavior();
+ behavior->metaState = metaState;
+ behavior->character = character;
+ behavior->fallbackKeyCode = fallbackKeyCode;
+ if (lastBehavior) {
+ lastBehavior->next = behavior;
+ } else {
+ key->firstBehavior = behavior;
+ }
+ lastBehavior = behavior;
+ }
+
+ if (parcel->errorCheck()) {
+ return NULL;
+ }
+ }
+ return map;
+}
+
+void KeyCharacterMap::writeToParcel(Parcel* parcel) const {
+ parcel->writeInt32(mType);
+
+ size_t numKeys = mKeys.size();
+ parcel->writeInt32(numKeys);
+ for (size_t i = 0; i < numKeys; i++) {
+ int32_t keyCode = mKeys.keyAt(i);
+ const Key* key = mKeys.valueAt(i);
+ parcel->writeInt32(keyCode);
+ parcel->writeInt32(key->label);
+ parcel->writeInt32(key->number);
+ for (const Behavior* behavior = key->firstBehavior; behavior != NULL;
+ behavior = behavior->next) {
+ parcel->writeInt32(1);
+ parcel->writeInt32(behavior->metaState);
+ parcel->writeInt32(behavior->character);
+ parcel->writeInt32(behavior->fallbackKeyCode);
+ }
+ parcel->writeInt32(0);
+ }
+}
+#endif
+
// --- KeyCharacterMap::Key ---
diff --git a/libs/androidfw/KeyLayoutMap.cpp b/libs/androidfw/KeyLayoutMap.cpp
index 15d81ee..1809412 100644
--- a/libs/androidfw/KeyLayoutMap.cpp
+++ b/libs/androidfw/KeyLayoutMap.cpp
@@ -47,23 +47,23 @@ KeyLayoutMap::KeyLayoutMap() {
KeyLayoutMap::~KeyLayoutMap() {
}
-status_t KeyLayoutMap::load(const String8& filename, KeyLayoutMap** outMap) {
- *outMap = NULL;
+status_t KeyLayoutMap::load(const String8& filename, sp<KeyLayoutMap>* outMap) {
+ outMap->clear();
Tokenizer* tokenizer;
status_t status = Tokenizer::open(filename, &tokenizer);
if (status) {
ALOGE("Error %d opening key layout map file %s.", status, filename.string());
} else {
- KeyLayoutMap* map = new KeyLayoutMap();
- if (!map) {
+ sp<KeyLayoutMap> map = new KeyLayoutMap();
+ if (!map.get()) {
ALOGE("Error allocating key layout map.");
status = NO_MEMORY;
} else {
#if DEBUG_PARSER_PERFORMANCE
nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
#endif
- Parser parser(map, tokenizer);
+ Parser parser(map.get(), tokenizer);
status = parser.parse();
#if DEBUG_PARSER_PERFORMANCE
nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
@@ -71,9 +71,7 @@ status_t KeyLayoutMap::load(const String8& filename, KeyLayoutMap** outMap) {
tokenizer->getFilename().string(), tokenizer->getLineNumber(),
elapsedTime / 1000000.0);
#endif
- if (status) {
- delete map;
- } else {
+ if (!status) {
*outMap = map;
}
}
diff --git a/libs/androidfw/Keyboard.cpp b/libs/androidfw/Keyboard.cpp
index e97a5eb..a84a8c7 100644
--- a/libs/androidfw/Keyboard.cpp
+++ b/libs/androidfw/Keyboard.cpp
@@ -24,6 +24,7 @@
#include <androidfw/KeycodeLabels.h>
#include <androidfw/KeyLayoutMap.h>
#include <androidfw/KeyCharacterMap.h>
+#include <androidfw/InputDevice.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <cutils/properties.h>
@@ -32,13 +33,10 @@ namespace android {
// --- KeyMap ---
-KeyMap::KeyMap() :
- keyLayoutMap(NULL), keyCharacterMap(NULL) {
+KeyMap::KeyMap() {
}
KeyMap::~KeyMap() {
- delete keyLayoutMap;
- delete keyCharacterMap;
}
status_t KeyMap::load(const InputDeviceIdentifier& deviceIdenfifier,
@@ -114,14 +112,12 @@ status_t KeyMap::loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier,
return NAME_NOT_FOUND;
}
- KeyLayoutMap* map;
- status_t status = KeyLayoutMap::load(path, &map);
+ status_t status = KeyLayoutMap::load(path, &keyLayoutMap);
if (status) {
return status;
}
keyLayoutFile.setTo(path);
- keyLayoutMap = map;
return OK;
}
@@ -133,14 +129,12 @@ status_t KeyMap::loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifi
return NAME_NOT_FOUND;
}
- KeyCharacterMap* map;
- status_t status = KeyCharacterMap::load(path, &map);
+ status_t status = KeyCharacterMap::load(path, &keyCharacterMap);
if (status) {
return status;
}
keyCharacterMapFile.setTo(path);
- keyCharacterMap = map;
return OK;
}
diff --git a/native/android/input.cpp b/native/android/input.cpp
index 6eb2990..accec64 100644
--- a/native/android/input.cpp
+++ b/native/android/input.cpp
@@ -32,7 +32,6 @@
using android::InputEvent;
using android::KeyEvent;
using android::MotionEvent;
-using android::InputDeviceInfo;
using android::sp;
using android::Vector;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 0c8208f..a00fab3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -273,7 +273,8 @@ public class KeyButtonView extends ImageView {
0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
flags | KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
InputDevice.SOURCE_KEYBOARD);
- InputManager.injectInputEvent(ev, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
+ InputManager.getInstance().injectInputEvent(ev,
+ InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
}
}
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index 7060ae2..744f2ad 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -93,6 +93,32 @@ static String8 sha1(const String8& in) {
return out;
}
+static void setDescriptor(InputDeviceIdentifier& identifier) {
+ // Compute a device descriptor that uniquely identifies the device.
+ // The descriptor is assumed to be a stable identifier. Its value should not
+ // change between reboots, reconnections, firmware updates or new releases of Android.
+ // Ideally, we also want the descriptor to be short and relatively opaque.
+ String8 rawDescriptor;
+ rawDescriptor.appendFormat(":%04x:%04x:", identifier.vendor, identifier.product);
+ if (!identifier.uniqueId.isEmpty()) {
+ rawDescriptor.append("uniqueId:");
+ rawDescriptor.append(identifier.uniqueId);
+ } if (identifier.vendor == 0 && identifier.product == 0) {
+ // If we don't know the vendor and product id, then the device is probably
+ // built-in so we need to rely on other information to uniquely identify
+ // the input device. Usually we try to avoid relying on the device name or
+ // location but for built-in input device, they are unlikely to ever change.
+ if (!identifier.name.isEmpty()) {
+ rawDescriptor.append("name:");
+ rawDescriptor.append(identifier.name);
+ } else if (!identifier.location.isEmpty()) {
+ rawDescriptor.append("location:");
+ rawDescriptor.append(identifier.location);
+ }
+ }
+ identifier.descriptor = sha1(rawDescriptor);
+}
+
// --- Global Functions ---
uint32_t getAbsAxisUsage(int32_t axis, uint32_t deviceClasses) {
@@ -164,7 +190,7 @@ const int EventHub::EPOLL_SIZE_HINT;
const int EventHub::EPOLL_MAX_EVENTS;
EventHub::EventHub(void) :
- mBuiltInKeyboardId(-1), mNextDeviceId(1),
+ mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1),
mOpeningDevices(0), mClosingDevices(0),
mNeedToSendFinishedDeviceScan(false),
mNeedToReopenDevices(false), mNeedToScanDevices(true),
@@ -256,7 +282,7 @@ status_t EventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis,
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device && test_bit(axis, device->absBitmask)) {
+ if (device && !device->isVirtual() && test_bit(axis, device->absBitmask)) {
struct input_absinfo info;
if(ioctl(device->fd, EVIOCGABS(axis), &info)) {
ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d",
@@ -307,7 +333,7 @@ int32_t EventHub::getScanCodeState(int32_t deviceId, int32_t scanCode) const {
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device && test_bit(scanCode, device->keyBitmask)) {
+ if (device && !device->isVirtual() && test_bit(scanCode, device->keyBitmask)) {
uint8_t keyState[sizeof_bit_array(KEY_MAX + 1)];
memset(keyState, 0, sizeof(keyState));
if (ioctl(device->fd, EVIOCGKEY(sizeof(keyState)), keyState) >= 0) {
@@ -322,7 +348,7 @@ int32_t EventHub::getKeyCodeState(int32_t deviceId, int32_t keyCode) const {
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device && device->keyMap.haveKeyLayout()) {
+ if (device && !device->isVirtual() && device->keyMap.haveKeyLayout()) {
Vector<int32_t> scanCodes;
device->keyMap.keyLayoutMap->findScanCodesForKey(keyCode, &scanCodes);
if (scanCodes.size() != 0) {
@@ -347,7 +373,7 @@ int32_t EventHub::getSwitchState(int32_t deviceId, int32_t sw) const {
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device && test_bit(sw, device->swBitmask)) {
+ if (device && !device->isVirtual() && test_bit(sw, device->swBitmask)) {
uint8_t swState[sizeof_bit_array(SW_MAX + 1)];
memset(swState, 0, sizeof(swState));
if (ioctl(device->fd, EVIOCGSW(sizeof(swState)), swState) >= 0) {
@@ -365,7 +391,7 @@ status_t EventHub::getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t*
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device && test_bit(axis, device->absBitmask)) {
+ if (device && !device->isVirtual() && test_bit(axis, device->absBitmask)) {
struct input_absinfo info;
if(ioctl(device->fd, EVIOCGABS(axis), &info)) {
ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d",
@@ -421,7 +447,7 @@ status_t EventHub::mapKey(int32_t deviceId, int scancode,
}
}
- if (mBuiltInKeyboardId != -1) {
+ if (mBuiltInKeyboardId != NO_BUILT_IN_KEYBOARD) {
device = getDeviceLocked(mBuiltInKeyboardId);
if (device && device->keyMap.haveKeyLayout()) {
@@ -449,7 +475,7 @@ status_t EventHub::mapAxis(int32_t deviceId, int scancode, AxisInfo* outAxisInfo
}
}
- if (mBuiltInKeyboardId != -1) {
+ if (mBuiltInKeyboardId != NO_BUILT_IN_KEYBOARD) {
device = getDeviceLocked(mBuiltInKeyboardId);
if (device && device->keyMap.haveKeyLayout()) {
@@ -494,7 +520,7 @@ bool EventHub::hasLed(int32_t deviceId, int32_t led) const {
void EventHub::setLedState(int32_t deviceId, int32_t led, bool on) {
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device && led >= 0 && led <= LED_MAX) {
+ if (device && !device->isVirtual() && led >= 0 && led <= LED_MAX) {
struct input_event ev;
ev.time.tv_sec = 0;
ev.time.tv_usec = 0;
@@ -520,17 +546,17 @@ void EventHub::getVirtualKeyDefinitions(int32_t deviceId,
}
}
-String8 EventHub::getKeyCharacterMapFile(int32_t deviceId) const {
+sp<KeyCharacterMap> EventHub::getKeyCharacterMap(int32_t deviceId) const {
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
if (device) {
- return device->keyMap.keyCharacterMapFile;
+ return device->keyMap.keyCharacterMap;
}
- return String8();
+ return NULL;
}
EventHub::Device* EventHub::getDeviceLocked(int32_t deviceId) const {
- if (deviceId == 0) {
+ if (deviceId == BUILT_IN_KEYBOARD_ID) {
deviceId = mBuiltInKeyboardId;
}
ssize_t index = mDevices.indexOfKey(deviceId);
@@ -578,7 +604,7 @@ size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSiz
device->id, device->path.string());
mClosingDevices = device->next;
event->when = now;
- event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
+ event->deviceId = device->id == mBuiltInKeyboardId ? BUILT_IN_KEYBOARD_ID : device->id;
event->type = DEVICE_REMOVED;
event += 1;
delete device;
@@ -813,6 +839,9 @@ void EventHub::scanDevicesLocked() {
if(res < 0) {
ALOGE("scan dir failed for %s\n", DEVICE_PATH);
}
+ if (mDevices.indexOfKey(VIRTUAL_KEYBOARD_ID) < 0) {
+ createVirtualKeyboardLocked();
+ }
}
// ----------------------------------------------------------------------------
@@ -908,29 +937,8 @@ status_t EventHub::openDeviceLocked(const char *devicePath) {
identifier.uniqueId.setTo(buffer);
}
- // Compute a device descriptor that uniquely identifies the device.
- // The descriptor is assumed to be a stable identifier. Its value should not
- // change between reboots, reconnections, firmware updates or new releases of Android.
- // Ideally, we also want the descriptor to be short and relatively opaque.
- String8 rawDescriptor;
- rawDescriptor.appendFormat(":%04x:%04x:", identifier.vendor, identifier.product);
- if (!identifier.uniqueId.isEmpty()) {
- rawDescriptor.append("uniqueId:");
- rawDescriptor.append(identifier.uniqueId);
- } if (identifier.vendor == 0 && identifier.product == 0) {
- // If we don't know the vendor and product id, then the device is probably
- // built-in so we need to rely on other information to uniquely identify
- // the input device. Usually we try to avoid relying on the device name or
- // location but for built-in input device, they are unlikely to ever change.
- if (!identifier.name.isEmpty()) {
- rawDescriptor.append("name:");
- rawDescriptor.append(identifier.name);
- } else if (!identifier.location.isEmpty()) {
- rawDescriptor.append("location:");
- rawDescriptor.append(identifier.location);
- }
- }
- identifier.descriptor = sha1(rawDescriptor);
+ // Fill in the descriptor.
+ setDescriptor(identifier);
// Make file descriptor non-blocking for use with poll().
if (fcntl(fd, F_SETFL, O_NONBLOCK)) {
@@ -1048,7 +1056,7 @@ status_t EventHub::openDeviceLocked(const char *devicePath) {
if (device->classes & INPUT_DEVICE_CLASS_KEYBOARD) {
// Register the keyboard as a built-in keyboard if it is eligible.
if (!keyMapStatus
- && mBuiltInKeyboardId == -1
+ && mBuiltInKeyboardId == NO_BUILT_IN_KEYBOARD
&& isEligibleBuiltInKeyboard(device->identifier,
device->configuration, &device->keyMap)) {
mBuiltInKeyboardId = device->id;
@@ -1133,11 +1141,29 @@ status_t EventHub::openDeviceLocked(const char *devicePath) {
toString(mBuiltInKeyboardId == deviceId),
toString(usingSuspendBlockIoctl), toString(usingClockIoctl));
- mDevices.add(deviceId, device);
+ addDeviceLocked(device);
+ return 0;
+}
+void EventHub::createVirtualKeyboardLocked() {
+ InputDeviceIdentifier identifier;
+ identifier.name = "Virtual";
+ identifier.uniqueId = "<virtual>";
+ setDescriptor(identifier);
+
+ Device* device = new Device(-1, VIRTUAL_KEYBOARD_ID, String8("<virtual>"), identifier);
+ device->classes = INPUT_DEVICE_CLASS_KEYBOARD
+ | INPUT_DEVICE_CLASS_ALPHAKEY
+ | INPUT_DEVICE_CLASS_DPAD
+ | INPUT_DEVICE_CLASS_VIRTUAL;
+ loadKeyMapLocked(device);
+ addDeviceLocked(device);
+}
+
+void EventHub::addDeviceLocked(Device* device) {
+ mDevices.add(device->id, device);
device->next = mOpeningDevices;
mOpeningDevices = device;
- return 0;
}
void EventHub::loadConfigurationLocked(Device* device) {
@@ -1224,11 +1250,13 @@ void EventHub::closeDeviceLocked(Device* device) {
if (device->id == mBuiltInKeyboardId) {
ALOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this",
device->path.string(), mBuiltInKeyboardId);
- mBuiltInKeyboardId = -1;
+ mBuiltInKeyboardId = NO_BUILT_IN_KEYBOARD;
}
- if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, device->fd, NULL)) {
- ALOGW("Could not remove device fd from epoll instance. errno=%d", errno);
+ if (!device->isVirtual()) {
+ if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, device->fd, NULL)) {
+ ALOGW("Could not remove device fd from epoll instance. errno=%d", errno);
+ }
}
mDevices.removeItem(device->id);
diff --git a/services/input/EventHub.h b/services/input/EventHub.h
index bd21a3d..c35df109 100644
--- a/services/input/EventHub.h
+++ b/services/input/EventHub.h
@@ -19,6 +19,7 @@
#define _RUNTIME_EVENT_HUB_H
#include <androidfw/Input.h>
+#include <androidfw/InputDevice.h>
#include <androidfw/Keyboard.h>
#include <androidfw/KeyLayoutMap.h>
#include <androidfw/KeyCharacterMap.h>
@@ -43,6 +44,13 @@
namespace android {
+enum {
+ // Device id of a special "virtual" keyboard that is always present.
+ VIRTUAL_KEYBOARD_ID = -1,
+ // Device id of the "built-in" keyboard if there is one.
+ BUILT_IN_KEYBOARD_ID = 0,
+};
+
/*
* A raw event as retrieved from the EventHub.
*/
@@ -107,6 +115,9 @@ enum {
/* The input device is a joystick (implies gamepad, has joystick absolute axes). */
INPUT_DEVICE_CLASS_JOYSTICK = 0x00000100,
+ /* The input device is virtual (not a real device, not part of UI configuration). */
+ INPUT_DEVICE_CLASS_VIRTUAL = 0x40000000,
+
/* The input device is external (not built-in). */
INPUT_DEVICE_CLASS_EXTERNAL = 0x80000000,
};
@@ -208,7 +219,7 @@ public:
virtual void getVirtualKeyDefinitions(int32_t deviceId,
Vector<VirtualKeyDefinition>& outVirtualKeys) const = 0;
- virtual String8 getKeyCharacterMapFile(int32_t deviceId) const = 0;
+ virtual sp<KeyCharacterMap> getKeyCharacterMap(int32_t deviceId) const = 0;
/* Requests the EventHub to reopen all input devices on the next call to getEvents(). */
virtual void requestReopenDevices() = 0;
@@ -266,7 +277,7 @@ public:
virtual void getVirtualKeyDefinitions(int32_t deviceId,
Vector<VirtualKeyDefinition>& outVirtualKeys) const;
- virtual String8 getKeyCharacterMapFile(int32_t deviceId) const;
+ virtual sp<KeyCharacterMap> getKeyCharacterMap(int32_t deviceId) const;
virtual void requestReopenDevices();
@@ -282,7 +293,7 @@ private:
struct Device {
Device* next;
- int fd;
+ int fd; // may be -1 if device is virtual
const int32_t id;
const String8 path;
const InputDeviceIdentifier identifier;
@@ -305,11 +316,15 @@ private:
~Device();
void close();
+
+ inline bool isVirtual() const { return fd < 0; }
};
status_t openDeviceLocked(const char *devicePath);
- status_t closeDeviceByPathLocked(const char *devicePath);
+ void createVirtualKeyboardLocked();
+ void addDeviceLocked(Device* device);
+ status_t closeDeviceByPathLocked(const char *devicePath);
void closeDeviceLocked(Device* device);
void closeAllDevicesLocked();
@@ -331,8 +346,13 @@ private:
// Protect all internal state.
mutable Mutex mLock;
- // The actual id of the built-in keyboard, or -1 if none.
+ // The actual id of the built-in keyboard, or NO_BUILT_IN_KEYBOARD if none.
// EventHub remaps the built-in keyboard to id 0 externally as required by the API.
+ enum {
+ // Must not conflict with any other assigned device ids, including
+ // the virtual keyboard id (-1).
+ NO_BUILT_IN_KEYBOARD = -2,
+ };
int32_t mBuiltInKeyboardId;
int32_t mNextDeviceId;
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index ddd870d..42512d8 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -523,19 +523,21 @@ void InputReader::updateInputConfigurationLocked() {
InputDeviceInfo deviceInfo;
for (size_t i = 0; i < mDevices.size(); i++) {
InputDevice* device = mDevices.valueAt(i);
- device->getDeviceInfo(& deviceInfo);
- uint32_t sources = deviceInfo.getSources();
+ if (!(device->getClasses() & INPUT_DEVICE_CLASS_VIRTUAL)) {
+ device->getDeviceInfo(& deviceInfo);
+ uint32_t sources = deviceInfo.getSources();
- if ((sources & AINPUT_SOURCE_TOUCHSCREEN) == AINPUT_SOURCE_TOUCHSCREEN) {
- touchScreenConfig = InputConfiguration::TOUCHSCREEN_FINGER;
- }
- if ((sources & AINPUT_SOURCE_TRACKBALL) == AINPUT_SOURCE_TRACKBALL) {
- navigationConfig = InputConfiguration::NAVIGATION_TRACKBALL;
- } else if ((sources & AINPUT_SOURCE_DPAD) == AINPUT_SOURCE_DPAD) {
- navigationConfig = InputConfiguration::NAVIGATION_DPAD;
- }
- if (deviceInfo.getKeyboardType() == AINPUT_KEYBOARD_TYPE_ALPHABETIC) {
- keyboardConfig = InputConfiguration::KEYBOARD_QWERTY;
+ if ((sources & AINPUT_SOURCE_TOUCHSCREEN) == AINPUT_SOURCE_TOUCHSCREEN) {
+ touchScreenConfig = InputConfiguration::TOUCHSCREEN_FINGER;
+ }
+ if ((sources & AINPUT_SOURCE_TRACKBALL) == AINPUT_SOURCE_TRACKBALL) {
+ navigationConfig = InputConfiguration::NAVIGATION_TRACKBALL;
+ } else if ((sources & AINPUT_SOURCE_DPAD) == AINPUT_SOURCE_DPAD) {
+ navigationConfig = InputConfiguration::NAVIGATION_DPAD;
+ }
+ if (deviceInfo.getKeyboardType() == AINPUT_KEYBOARD_TYPE_ALPHABETIC) {
+ keyboardConfig = InputConfiguration::KEYBOARD_QWERTY;
+ }
}
}
@@ -1789,7 +1791,7 @@ void KeyboardInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
InputMapper::populateDeviceInfo(info);
info->setKeyboardType(mKeyboardType);
- info->setKeyCharacterMapFile(getEventHub()->getKeyCharacterMapFile(getDeviceId()));
+ info->setKeyCharacterMap(getEventHub()->getKeyCharacterMap(getDeviceId()));
}
void KeyboardInputMapper::dump(String8& dump) {
diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index 2cccf9f..057ad18 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -610,8 +610,8 @@ private:
}
}
- virtual String8 getKeyCharacterMapFile(int32_t deviceId) const {
- return String8();
+ virtual sp<KeyCharacterMap> getKeyCharacterMap(int32_t deviceId) const {
+ return NULL;
}
virtual bool isExternal(int32_t deviceId) const {
diff --git a/services/java/com/android/server/input/InputManagerService.java b/services/java/com/android/server/input/InputManagerService.java
index b8cc65e..2f25df1 100644
--- a/services/java/com/android/server/input/InputManagerService.java
+++ b/services/java/com/android/server/input/InputManagerService.java
@@ -18,37 +18,45 @@ package com.android.server.input;
import com.android.internal.util.XmlUtils;
import com.android.server.Watchdog;
-import com.android.server.input.InputFilter.Host;
-import com.android.server.wm.WindowManagerService;
import org.xmlpull.v1.XmlPullParser;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
import android.database.ContentObserver;
import android.hardware.input.IInputManager;
import android.hardware.input.InputManager;
+import android.hardware.input.KeyboardLayout;
import android.os.Binder;
+import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
-import android.os.Looper;
import android.os.MessageQueue;
import android.os.Process;
-import android.os.SystemProperties;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
+import android.util.Log;
import android.util.Slog;
import android.util.Xml;
import android.view.InputChannel;
import android.view.InputDevice;
import android.view.InputEvent;
+import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.PointerIcon;
import android.view.Surface;
import android.view.ViewConfiguration;
-import android.view.WindowManager;
import android.view.WindowManagerPolicy;
+import android.view.KeyCharacterMap.UnavailableException;
import java.io.File;
import java.io.FileDescriptor;
@@ -57,6 +65,8 @@ import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
/*
* Wraps the C++ InputManager and provides its callbacks.
@@ -135,6 +145,10 @@ public class InputManagerService extends IInputManager.Stub implements Watchdog.
/** The key is down but is a virtual key press that is being emulated by the system. */
public static final int KEY_STATE_VIRTUAL = 2;
+ // Used to simulate a persistent data store for keyboard layouts.
+ // TODO: Replace with the real thing.
+ private final HashMap<String, String> mFakeRegistry = new HashMap<String, String>();
+
// State for the currently installed input filter.
final Object mInputFilterLock = new Object();
InputFilter mInputFilter;
@@ -246,7 +260,7 @@ public class InputManagerService extends IInputManager.Stub implements Watchdog.
* key codes.
* @return True if the lookup was successful, false otherwise.
*/
- @Override
+ @Override // Binder call
public boolean hasKeys(int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists) {
if (keyCodes == null) {
throw new IllegalArgumentException("keyCodes must not be null.");
@@ -337,7 +351,7 @@ public class InputManagerService extends IInputManager.Stub implements Watchdog.
}
}
- @Override
+ @Override // Binder call
public boolean injectInputEvent(InputEvent event, int mode) {
if (event == null) {
throw new IllegalArgumentException("event must not be null");
@@ -380,7 +394,7 @@ public class InputManagerService extends IInputManager.Stub implements Watchdog.
* @param id The device id.
* @return The input device or null if not found.
*/
- @Override
+ @Override // Binder call
public InputDevice getInputDevice(int deviceId) {
return nativeGetInputDevice(mPtr, deviceId);
}
@@ -389,11 +403,187 @@ public class InputManagerService extends IInputManager.Stub implements Watchdog.
* Gets the ids of all input devices in the system.
* @return The input device ids.
*/
- @Override
+ @Override // Binder call
public int[] getInputDeviceIds() {
return nativeGetInputDeviceIds(mPtr);
}
-
+
+ @Override // Binder call
+ public KeyboardLayout[] getKeyboardLayouts() {
+ ArrayList<KeyboardLayout> list = new ArrayList<KeyboardLayout>();
+
+ final PackageManager pm = mContext.getPackageManager();
+ Intent intent = new Intent(InputManager.ACTION_QUERY_KEYBOARD_LAYOUTS);
+ for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent,
+ PackageManager.GET_META_DATA)) {
+ loadKeyboardLayouts(pm, resolveInfo.activityInfo, list, null);
+ }
+ return list.toArray(new KeyboardLayout[list.size()]);
+ }
+
+ @Override // Binder call
+ public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) {
+ if (keyboardLayoutDescriptor == null) {
+ throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
+ }
+
+ KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(keyboardLayoutDescriptor);
+ if (d == null) {
+ return null;
+ }
+
+ final PackageManager pm = mContext.getPackageManager();
+ try {
+ ActivityInfo receiver = pm.getReceiverInfo(
+ new ComponentName(d.packageName, d.receiverName),
+ PackageManager.GET_META_DATA);
+ return loadKeyboardLayouts(pm, receiver, null, d.keyboardLayoutName);
+ } catch (NameNotFoundException ex) {
+ Log.w(TAG, "Could not load keyboard layout '" + d.keyboardLayoutName
+ + "' from receiver " + d.packageName + "/" + d.receiverName, ex);
+ return null;
+ }
+ }
+
+ private KeyboardLayout loadKeyboardLayouts(
+ PackageManager pm, ActivityInfo receiver,
+ List<KeyboardLayout> list, String keyboardName) {
+ Bundle metaData = receiver.metaData;
+ if (metaData == null) {
+ return null;
+ }
+
+ int configResId = metaData.getInt(InputManager.META_DATA_KEYBOARD_LAYOUTS);
+ if (configResId == 0) {
+ Log.w(TAG, "Missing meta-data '" + InputManager.META_DATA_KEYBOARD_LAYOUTS
+ + "' on receiver " + receiver.packageName + "/" + receiver.name);
+ return null;
+ }
+
+ try {
+ Resources resources = pm.getResourcesForApplication(receiver.applicationInfo);
+ XmlResourceParser parser = resources.getXml(configResId);
+ try {
+ XmlUtils.beginDocument(parser, "keyboard-layouts");
+
+ for (;;) {
+ XmlUtils.nextElement(parser);
+ String element = parser.getName();
+ if (element == null) {
+ break;
+ }
+ if (element.equals("keyboard-layout")) {
+ TypedArray a = resources.obtainAttributes(
+ parser, com.android.internal.R.styleable.KeyboardLayout);
+ try {
+ String name = a.getString(
+ com.android.internal.R.styleable.KeyboardLayout_name);
+ String label = a.getString(
+ com.android.internal.R.styleable.KeyboardLayout_label);
+ int kcmResId = a.getResourceId(
+ com.android.internal.R.styleable.KeyboardLayout_kcm, 0);
+ if (name == null || label == null || kcmResId == 0) {
+ Log.w(TAG, "Missing required 'name', 'label' or 'kcm' "
+ + "attributes in keyboard layout "
+ + "resource from receiver "
+ + receiver.packageName + "/" + receiver.name);
+ } else {
+ String descriptor = KeyboardLayoutDescriptor.format(
+ receiver.packageName, receiver.name, name);
+ KeyboardLayout c = new KeyboardLayout(descriptor, label);
+ if (keyboardName != null && name.equals(keyboardName)) {
+ return c;
+ }
+ if (list != null) {
+ list.add(c);
+ }
+ }
+ } finally {
+ a.recycle();
+ }
+ } else {
+ Log.w(TAG, "Skipping unrecognized element '" + element
+ + "' in keyboard layout resource from receiver "
+ + receiver.packageName + "/" + receiver.name);
+ }
+ }
+ } finally {
+ parser.close();
+ }
+ } catch (Exception ex) {
+ Log.w(TAG, "Could not load keyboard layout resource from receiver "
+ + receiver.packageName + "/" + receiver.name, ex);
+ return null;
+ }
+ if (keyboardName != null) {
+ Log.w(TAG, "Could not load keyboard layout '" + keyboardName
+ + "' from receiver " + receiver.packageName + "/" + receiver.name
+ + " because it was not declared in the keyboard layout resource.");
+ }
+ return null;
+ }
+
+ @Override // Binder call
+ public String getKeyboardLayoutForInputDevice(String inputDeviceDescriptor) {
+ if (inputDeviceDescriptor == null) {
+ throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
+ }
+
+ return mFakeRegistry.get(inputDeviceDescriptor);
+ }
+
+ @Override // Binder call
+ public void setKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
+ String keyboardLayoutDescriptor) {
+ if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
+ "setKeyboardLayoutForInputDevice()")) {
+ throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
+ }
+
+ if (inputDeviceDescriptor == null) {
+ throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
+ }
+
+ mFakeRegistry.put(inputDeviceDescriptor, keyboardLayoutDescriptor);
+ }
+
+ /**
+ * Loads the key character map associated with the keyboard layout.
+ *
+ * @param pm The package manager.
+ * @return The key character map, or null if it could not be loaded for any reason.
+ *
+ public KeyCharacterMap loadKeyCharacterMap(PackageManager pm) {
+ if (pm == null) {
+ throw new IllegalArgumentException("pm must not be null");
+ }
+
+ if (mKeyCharacterMap == null) {
+ KeyboardLayoutDescriptor d = InputManager.parseKeyboardLayoutDescriptor(mDescriptor);
+ if (d == null) {
+ Log.e(InputManager.TAG, "Could not load key character map '" + mDescriptor
+ + "' because the descriptor could not be parsed.");
+ return null;
+ }
+
+ CharSequence cs = pm.getText(d.packageName, mKeyCharacterMapResId, null);
+ if (cs == null) {
+ Log.e(InputManager.TAG, "Could not load key character map '" + mDescriptor
+ + "' because its associated resource could not be loaded.");
+ return null;
+ }
+
+ try {
+ mKeyCharacterMap = KeyCharacterMap.load(cs);
+ } catch (UnavailableException ex) {
+ Log.e(InputManager.TAG, "Could not load key character map '" + mDescriptor
+ + "' due to an error while parsing.", ex);
+ return null;
+ }
+ }
+ return mKeyCharacterMap;
+ }*/
+
public void setInputWindows(InputWindowHandle[] windowHandles) {
nativeSetInputWindows(mPtr, windowHandles);
}
@@ -433,18 +623,17 @@ public class InputManagerService extends IInputManager.Stub implements Watchdog.
return nativeTransferTouchFocus(mPtr, fromChannel, toChannel);
}
- /**
- * Set the pointer speed.
- * @param speed The pointer speed as a value between -7 (slowest) and 7 (fastest)
- * where 0 is the default speed.
- */
- @Override
+ @Override // Binder call
public void tryPointerSpeed(int speed) {
if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED,
"tryPointerSpeed()")) {
throw new SecurityException("Requires SET_POINTER_SPEED permission");
}
+ if (speed < InputManager.MIN_POINTER_SPEED || speed > InputManager.MAX_POINTER_SPEED) {
+ throw new IllegalArgumentException("speed out of range");
+ }
+
setPointerSpeedUnchecked(speed);
}
@@ -740,4 +929,32 @@ public class InputManagerService extends IInputManager.Stub implements Watchdog.
}
}
}
+
+ private static final class KeyboardLayoutDescriptor {
+ public String packageName;
+ public String receiverName;
+ public String keyboardLayoutName;
+
+ public static String format(String packageName,
+ String receiverName, String keyboardName) {
+ return packageName + "/" + receiverName + "/" + keyboardName;
+ }
+
+ public static KeyboardLayoutDescriptor parse(String descriptor) {
+ int pos = descriptor.indexOf('/');
+ if (pos < 0 || pos + 1 == descriptor.length()) {
+ return null;
+ }
+ int pos2 = descriptor.indexOf('/', pos + 1);
+ if (pos2 < pos + 2 || pos2 + 1 == descriptor.length()) {
+ return null;
+ }
+
+ KeyboardLayoutDescriptor result = new KeyboardLayoutDescriptor();
+ result.packageName = descriptor.substring(0, pos);
+ result.receiverName = descriptor.substring(pos + 1, pos2);
+ result.keyboardLayoutName = descriptor.substring(pos2 + 1);
+ return result;
+ }
+ }
}
diff --git a/services/jni/com_android_server_input_InputManagerService.cpp b/services/jni/com_android_server_input_InputManagerService.cpp
index c137a78..85d6e11 100644
--- a/services/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/jni/com_android_server_input_InputManagerService.cpp
@@ -39,6 +39,7 @@
#include <input/SpriteController.h>
#include <android_os_MessageQueue.h>
+#include <android_view_InputDevice.h>
#include <android_view_KeyEvent.h>
#include <android_view_MotionEvent.h>
#include <android_view_InputChannel.h>
@@ -88,20 +89,6 @@ static struct {
} gMotionEventClassInfo;
static struct {
- jclass clazz;
-
- jmethodID ctor;
- jmethodID addMotionRange;
-
- jfieldID mId;
- jfieldID mName;
- jfieldID mDescriptor;
- jfieldID mSources;
- jfieldID mKeyboardType;
- jfieldID mKeyCharacterMapFile;
-} gInputDeviceClassInfo;
-
-static struct {
jfieldID touchscreen;
jfieldID keyboard;
jfieldID navigation;
@@ -1171,44 +1158,7 @@ static jobject nativeGetInputDevice(JNIEnv* env,
return NULL;
}
- jobject deviceObj = env->NewObject(gInputDeviceClassInfo.clazz, gInputDeviceClassInfo.ctor);
- if (!deviceObj) {
- return NULL;
- }
-
- jstring deviceNameObj = env->NewStringUTF(deviceInfo.getName().string());
- if (!deviceNameObj) {
- return NULL;
- }
-
- jstring deviceDescriptorObj = env->NewStringUTF(deviceInfo.getDescriptor().string());
- if (!deviceDescriptorObj) {
- return NULL;
- }
-
- jstring fileStr = env->NewStringUTF(deviceInfo.getKeyCharacterMapFile());
- if (!fileStr) {
- return NULL;
- }
-
- env->SetIntField(deviceObj, gInputDeviceClassInfo.mId, deviceInfo.getId());
- env->SetObjectField(deviceObj, gInputDeviceClassInfo.mName, deviceNameObj);
- env->SetObjectField(deviceObj, gInputDeviceClassInfo.mDescriptor, deviceDescriptorObj);
- env->SetIntField(deviceObj, gInputDeviceClassInfo.mSources, deviceInfo.getSources());
- env->SetIntField(deviceObj, gInputDeviceClassInfo.mKeyboardType, deviceInfo.getKeyboardType());
- env->SetObjectField(deviceObj, gInputDeviceClassInfo.mKeyCharacterMapFile, fileStr);
-
- const Vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
- for (size_t i = 0; i < ranges.size(); i++) {
- const InputDeviceInfo::MotionRange& range = ranges.itemAt(i);
- env->CallVoidMethod(deviceObj, gInputDeviceClassInfo.addMotionRange,
- range.axis, range.source, range.min, range.max, range.flat, range.fuzz);
- if (env->ExceptionCheck()) {
- return NULL;
- }
- }
-
- return deviceObj;
+ return android_view_InputDevice_create(env, deviceInfo);
}
static jintArray nativeGetInputDeviceIds(JNIEnv* env,
@@ -1437,35 +1387,6 @@ int register_android_server_InputManager(JNIEnv* env) {
FIND_CLASS(gMotionEventClassInfo.clazz, "android/view/MotionEvent");
gMotionEventClassInfo.clazz = jclass(env->NewGlobalRef(gMotionEventClassInfo.clazz));
- // InputDevice
-
- FIND_CLASS(gInputDeviceClassInfo.clazz, "android/view/InputDevice");
- gInputDeviceClassInfo.clazz = jclass(env->NewGlobalRef(gInputDeviceClassInfo.clazz));
-
- GET_METHOD_ID(gInputDeviceClassInfo.ctor, gInputDeviceClassInfo.clazz,
- "<init>", "()V");
-
- GET_METHOD_ID(gInputDeviceClassInfo.addMotionRange, gInputDeviceClassInfo.clazz,
- "addMotionRange", "(IIFFFF)V");
-
- GET_FIELD_ID(gInputDeviceClassInfo.mId, gInputDeviceClassInfo.clazz,
- "mId", "I");
-
- GET_FIELD_ID(gInputDeviceClassInfo.mName, gInputDeviceClassInfo.clazz,
- "mName", "Ljava/lang/String;");
-
- GET_FIELD_ID(gInputDeviceClassInfo.mDescriptor, gInputDeviceClassInfo.clazz,
- "mDescriptor", "Ljava/lang/String;");
-
- GET_FIELD_ID(gInputDeviceClassInfo.mSources, gInputDeviceClassInfo.clazz,
- "mSources", "I");
-
- GET_FIELD_ID(gInputDeviceClassInfo.mKeyboardType, gInputDeviceClassInfo.clazz,
- "mKeyboardType", "I");
-
- GET_FIELD_ID(gInputDeviceClassInfo.mKeyCharacterMapFile, gInputDeviceClassInfo.clazz,
- "mKeyCharacterMapFile", "Ljava/lang/String;");
-
// Configuration
FIND_CLASS(clazz, "android/content/res/Configuration");
diff --git a/tools/validatekeymaps/Main.cpp b/tools/validatekeymaps/Main.cpp
index 3cc2467..563225e 100644
--- a/tools/validatekeymaps/Main.cpp
+++ b/tools/validatekeymaps/Main.cpp
@@ -78,7 +78,7 @@ static bool validateFile(const char* filename) {
return false;
case FILETYPE_KEYLAYOUT: {
- KeyLayoutMap* map;
+ sp<KeyLayoutMap> map;
status_t status = KeyLayoutMap::load(String8(filename), &map);
if (status) {
fprintf(stderr, "Error %d parsing key layout file.\n\n", status);
@@ -88,7 +88,7 @@ static bool validateFile(const char* filename) {
}
case FILETYPE_KEYCHARACTERMAP: {
- KeyCharacterMap* map;
+ sp<KeyCharacterMap> map;
status_t status = KeyCharacterMap::load(String8(filename), &map);
if (status) {
fprintf(stderr, "Error %d parsing key character map file.\n\n", status);
@@ -104,6 +104,7 @@ static bool validateFile(const char* filename) {
fprintf(stderr, "Error %d parsing input device configuration file.\n\n", status);
return false;
}
+ delete map;
break;
}
@@ -114,6 +115,7 @@ static bool validateFile(const char* filename) {
fprintf(stderr, "Error %d parsing virtual key definition file.\n\n", status);
return false;
}
+ delete map;
break;
}
}