summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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;
}
}