diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/java/android/app/ContextImpl.java | 6 | ||||
-rw-r--r-- | core/java/android/app/Instrumentation.java | 8 | ||||
-rw-r--r-- | core/java/android/hardware/input/IInputManager.aidl | 8 | ||||
-rwxr-xr-x | core/java/android/hardware/input/InputManager.java | 363 | ||||
-rw-r--r-- | core/java/android/hardware/input/KeyboardLayout.aidl | 19 | ||||
-rw-r--r-- | core/java/android/hardware/input/KeyboardLayout.java | 91 | ||||
-rwxr-xr-x | core/java/android/view/InputDevice.java | 112 | ||||
-rw-r--r-- | core/java/android/view/KeyCharacterMap.java | 87 | ||||
-rw-r--r-- | core/jni/Android.mk | 1 | ||||
-rw-r--r-- | core/jni/AndroidRuntime.cpp | 6 | ||||
-rw-r--r-- | core/jni/android_view_InputDevice.cpp | 97 | ||||
-rw-r--r-- | core/jni/android_view_InputDevice.h | 31 | ||||
-rw-r--r-- | core/jni/android_view_KeyCharacterMap.cpp | 139 | ||||
-rw-r--r-- | core/jni/android_view_KeyCharacterMap.h | 32 | ||||
-rw-r--r-- | core/res/AndroidManifest.xml | 7 | ||||
-rwxr-xr-x | core/res/res/values/strings.xml | 6 |
16 files changed, 592 insertions, 421 deletions
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. --> |