diff options
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 ⦥ - } - } - 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 ⦥ + } + } + 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; } } |