From 6ec6f79e1ac1714e3b837796e99f07ff88f66601 Mon Sep 17 00:00:00 2001 From: Jeff Brown Date: Tue, 17 Apr 2012 16:52:41 -0700 Subject: Support loading keyboard layout overlays from resources. Added the concept of a keyboard layout overlay, which is a key character map file that has "type OVERLAY". Added support for loading keyboard layout overlays from resources dynamically. The layouts are reloaded whenever they are changed in the Settings application or an application is installed. This is somewhat more aggressive than necessary so we might want to optimize it later. Before system-ready, the input system uses just the generic keyboard layouts that are included on the device system image. After system-ready, it considers the user's selected keyboard layout overlay and attempts to load it as necessary. We need to wait until system-ready before doing this because we need to be in a state where it is safe to start applications or access their resources. Bug: 6110399 Change-Id: Iae0886d3356649b0d2440aa00910a888cedd8323 --- services/input/EventHub.cpp | 18 ++ services/input/EventHub.h | 5 + services/input/InputReader.cpp | 8 + services/input/InputReader.h | 6 + services/input/tests/InputReader_test.cpp | 8 + .../android/server/InputMethodManagerService.java | 2 +- services/java/com/android/server/SystemServer.java | 11 +- .../android/server/input/InputManagerService.java | 211 +++++++++++++-------- services/jni/Android.mk | 3 +- ...om_android_server_input_InputManagerService.cpp | 46 +++++ 10 files changed, 235 insertions(+), 83 deletions(-) (limited to 'services') diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp index c0eb1b9..b788e16 100644 --- a/services/input/EventHub.cpp +++ b/services/input/EventHub.cpp @@ -531,11 +531,29 @@ sp EventHub::getKeyCharacterMap(int32_t deviceId) const { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device) { + if (device->combinedKeyMap != NULL) { + return device->combinedKeyMap; + } return device->keyMap.keyCharacterMap; } return NULL; } +bool EventHub::setKeyboardLayoutOverlay(int32_t deviceId, + const sp& map) { + AutoMutex _l(mLock); + Device* device = getDeviceLocked(deviceId); + if (device) { + if (map != device->overlayKeyMap) { + device->overlayKeyMap = map; + device->combinedKeyMap = KeyCharacterMap::combine( + device->keyMap.keyCharacterMap, map); + return true; + } + } + return false; +} + void EventHub::vibrate(int32_t deviceId, nsecs_t duration) { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); diff --git a/services/input/EventHub.h b/services/input/EventHub.h index 51d2bac..f885f4d 100644 --- a/services/input/EventHub.h +++ b/services/input/EventHub.h @@ -221,6 +221,7 @@ public: Vector& outVirtualKeys) const = 0; virtual sp getKeyCharacterMap(int32_t deviceId) const = 0; + virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp& map) = 0; /* Control the vibrator. */ virtual void vibrate(int32_t deviceId, nsecs_t duration) = 0; @@ -283,6 +284,7 @@ public: Vector& outVirtualKeys) const; virtual sp getKeyCharacterMap(int32_t deviceId) const; + virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp& map); virtual void vibrate(int32_t deviceId, nsecs_t duration); virtual void cancelVibrate(int32_t deviceId); @@ -321,6 +323,9 @@ private: VirtualKeyMap* virtualKeyMap; KeyMap keyMap; + sp overlayKeyMap; + sp combinedKeyMap; + bool ffEffectPlaying; int16_t ffEffectId; // initially -1 diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp index 8c37fbb..95e56bf 100644 --- a/services/input/InputReader.cpp +++ b/services/input/InputReader.cpp @@ -962,6 +962,14 @@ void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config mContext->getEventHub()->getConfiguration(mId, &mConfiguration); } + if (!changes || (changes & InputReaderConfiguration::CHANGE_KEYBOARD_LAYOUTS)) { + sp keyboardLayout = + mContext->getPolicy()->getKeyboardLayoutOverlay(mIdentifier.descriptor); + if (mContext->getEventHub()->setKeyboardLayoutOverlay(mId, keyboardLayout)) { + bumpGeneration(); + } + } + size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; diff --git a/services/input/InputReader.h b/services/input/InputReader.h index ed57596..e5897e7 100644 --- a/services/input/InputReader.h +++ b/services/input/InputReader.h @@ -67,6 +67,9 @@ struct InputReaderConfiguration { // The visible touches option changed. CHANGE_SHOW_TOUCHES = 1 << 3, + // The keyboard layouts must be reloaded. + CHANGE_KEYBOARD_LAYOUTS = 1 << 4, + // All devices must be reopened. CHANGE_MUST_REOPEN = 1 << 31, }; @@ -222,6 +225,9 @@ public: * and provides information about all current input devices. */ virtual void notifyInputDevicesChanged(const Vector& inputDevices) = 0; + + /* Gets the keyboard layout for a particular input device. */ + virtual sp getKeyboardLayoutOverlay(const String8& inputDeviceDescriptor) = 0; }; diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp index 94d4189..602eb34 100644 --- a/services/input/tests/InputReader_test.cpp +++ b/services/input/tests/InputReader_test.cpp @@ -170,6 +170,10 @@ private: virtual void notifyInputDevicesChanged(const Vector& inputDevices) { mInputDevices = inputDevices; } + + virtual sp getKeyboardLayout(const String8& inputDeviceDescriptor) { + return NULL; + } }; @@ -646,6 +650,10 @@ private: return NULL; } + virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp& map) { + return false; + } + virtual void vibrate(int32_t deviceId, nsecs_t duration) { } diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java index ca7241c..a474cec 100644 --- a/services/java/com/android/server/InputMethodManagerService.java +++ b/services/java/com/android/server/InputMethodManagerService.java @@ -118,7 +118,7 @@ import java.util.TreeMap; public class InputMethodManagerService extends IInputMethodManager.Stub implements ServiceConnection, Handler.Callback { static final boolean DEBUG = false; - static final String TAG = "InputManagerService"; + static final String TAG = "InputMethodManagerService"; static final int MSG_SHOW_IM_PICKER = 1; static final int MSG_SHOW_IM_SUBTYPE_PICKER = 2; diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 75dcf8c..02c4d5a 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -51,6 +51,7 @@ import com.android.internal.os.SamplingProfilerIntegration; import com.android.internal.widget.LockSettingsService; import com.android.server.accessibility.AccessibilityManagerService; import com.android.server.am.ActivityManagerService; +import com.android.server.input.InputManagerService; import com.android.server.net.NetworkPolicyManagerService; import com.android.server.net.NetworkStatsService; import com.android.server.pm.PackageManagerService; @@ -137,6 +138,7 @@ class ServerThread extends Thread { ThrottleService throttle = null; NetworkTimeUpdateService networkTimeUpdater = null; CommonTimeManagementService commonTimeMgmtService = null; + InputManagerService inputManager = null; // Critical services... try { @@ -224,7 +226,8 @@ class ServerThread extends Thread { factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL, !firstBoot); ServiceManager.addService(Context.WINDOW_SERVICE, wm); - ServiceManager.addService(Context.INPUT_SERVICE, wm.getInputManagerService()); + inputManager = wm.getInputManagerService(); + ServiceManager.addService(Context.INPUT_SERVICE, inputManager); ActivityManagerService.self().setWindowManager(wm); @@ -722,6 +725,7 @@ class ServerThread extends Thread { final TextServicesManagerService textServiceManagerServiceF = tsms; final StatusBarManagerService statusBarF = statusBar; final DreamManagerService dreamyF = dreamy; + final InputManagerService inputManagerF = inputManager; // We now tell the activity manager it is okay to run third party // code. It will call back into us once it has gotten to the state @@ -833,6 +837,11 @@ class ServerThread extends Thread { } catch (Throwable e) { reportWtf("making DreamManagerService ready", e); } + try { + if (inputManagerF != null) inputManagerF.systemReady(); + } catch (Throwable e) { + reportWtf("making InputManagerService ready", e); + } } }); diff --git a/services/java/com/android/server/input/InputManagerService.java b/services/java/com/android/server/input/InputManagerService.java index 7640eff..a4ed31c 100644 --- a/services/java/com/android/server/input/InputManagerService.java +++ b/services/java/com/android/server/input/InputManagerService.java @@ -26,15 +26,18 @@ import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; import android.Manifest; +import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; 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.Resources.NotFoundException; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.database.ContentObserver; @@ -60,13 +63,11 @@ 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.WindowManagerPolicy; -import android.view.KeyCharacterMap.UnavailableException; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; @@ -77,13 +78,14 @@ import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; import libcore.io.IoUtils; +import libcore.io.Streams; import libcore.util.Objects; /* @@ -91,7 +93,7 @@ import libcore.util.Objects; */ public class InputManagerService extends IInputManager.Stub implements Watchdog.Monitor { static final String TAG = "InputManager"; - static final boolean DEBUG = false; + static final boolean DEBUG = true; private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml"; @@ -103,6 +105,7 @@ public class InputManagerService extends IInputManager.Stub implements Watchdog. private final Context mContext; private final Callbacks mCallbacks; private final InputManagerHandler mHandler; + private boolean mSystemReady; // Persistent data store. Must be locked each time during use. private final PersistentDataStore mDataStore = new PersistentDataStore(); @@ -163,6 +166,7 @@ public class InputManagerService extends IInputManager.Stub implements Watchdog. private static native void nativeVibrate(int ptr, int deviceId, long[] pattern, int repeat, int token); private static native void nativeCancelVibrate(int ptr, int deviceId, int token); + private static native void nativeReloadKeyboardLayouts(int ptr); private static native String nativeDump(int ptr); private static native void nativeMonitor(int ptr); @@ -212,7 +216,33 @@ public class InputManagerService extends IInputManager.Stub implements Watchdog. updatePointerSpeedFromSettings(); updateShowTouchesFromSettings(); } - + + public void systemReady() { + if (DEBUG) { + Slog.d(TAG, "System ready."); + } + mSystemReady = true; + reloadKeyboardLayouts(); + + IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED); + filter.addAction(Intent.ACTION_PACKAGE_REMOVED); + filter.addAction(Intent.ACTION_PACKAGE_CHANGED); + filter.addDataScheme("package"); + mContext.registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (DEBUG) { + Slog.d(TAG, "Packages changed, reloading keyboard layouts."); + } + reloadKeyboardLayouts(); + } + }, filter, null, mHandler); + } + + private void reloadKeyboardLayouts() { + nativeReloadKeyboardLayouts(mPtr); + } + public void setDisplaySize(int displayId, int width, int height, int externalWidth, int externalHeight) { if (width <= 0 || height <= 0 || externalWidth <= 0 || externalHeight <= 0) { @@ -528,14 +558,14 @@ public class InputManagerService extends IInputManager.Stub implements Watchdog. @Override // Binder call public KeyboardLayout[] getKeyboardLayouts() { - ArrayList list = new ArrayList(); - - 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); - } + final ArrayList list = new ArrayList(); + visitAllKeyboardLayouts(new KeyboardLayoutVisitor() { + @Override + public void visitKeyboardLayout(Resources resources, + String descriptor, String label, int kcmResId) { + list.add(new KeyboardLayout(descriptor, label)); + } + }); return list.toArray(new KeyboardLayout[list.size()]); } @@ -545,37 +575,57 @@ public class InputManagerService extends IInputManager.Stub implements Watchdog. throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null"); } - KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(keyboardLayoutDescriptor); - if (d == null) { - return null; + final KeyboardLayout[] result = new KeyboardLayout[1]; + visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() { + @Override + public void visitKeyboardLayout(Resources resources, + String descriptor, String label, int kcmResId) { + result[0] = new KeyboardLayout(descriptor, label); + } + }); + if (result[0] == null) { + Log.w(TAG, "Could not get keyboard layout with descriptor '" + + keyboardLayoutDescriptor + "'."); } + return result[0]; + } + private void visitAllKeyboardLayouts(KeyboardLayoutVisitor visitor) { 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; + Intent intent = new Intent(InputManager.ACTION_QUERY_KEYBOARD_LAYOUTS); + for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent, + PackageManager.GET_META_DATA)) { + visitKeyboardLayoutsInPackage(pm, resolveInfo.activityInfo, null, visitor); + } + } + + private void visitKeyboardLayout(String keyboardLayoutDescriptor, + KeyboardLayoutVisitor visitor) { + KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(keyboardLayoutDescriptor); + if (d != null) { + final PackageManager pm = mContext.getPackageManager(); + try { + ActivityInfo receiver = pm.getReceiverInfo( + new ComponentName(d.packageName, d.receiverName), + PackageManager.GET_META_DATA); + visitKeyboardLayoutsInPackage(pm, receiver, d.keyboardLayoutName, visitor); + } catch (NameNotFoundException ex) { + } } } - private KeyboardLayout loadKeyboardLayouts( - PackageManager pm, ActivityInfo receiver, - List list, String keyboardName) { + private void visitKeyboardLayoutsInPackage(PackageManager pm, ActivityInfo receiver, + String keyboardName, KeyboardLayoutVisitor visitor) { Bundle metaData = receiver.metaData; if (metaData == null) { - return null; + return; } 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; + return; } try { @@ -608,12 +658,9 @@ public class InputManagerService extends IInputManager.Stub implements Watchdog. } 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); + if (keyboardName == null || name.equals(keyboardName)) { + visitor.visitKeyboardLayout(resources, descriptor, + label, kcmResId); } } } finally { @@ -629,16 +676,9 @@ public class InputManagerService extends IInputManager.Stub implements Watchdog. parser.close(); } } catch (Exception ex) { - Log.w(TAG, "Could not load keyboard layout resource from receiver " + Log.w(TAG, "Could not parse 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 @@ -664,51 +704,23 @@ public class InputManagerService extends IInputManager.Stub implements Watchdog. throw new IllegalArgumentException("inputDeviceDescriptor must not be null"); } + final boolean changed; synchronized (mDataStore) { try { - mDataStore.setKeyboardLayout(inputDeviceDescriptor, keyboardLayoutDescriptor); + changed = mDataStore.setKeyboardLayout( + inputDeviceDescriptor, keyboardLayoutDescriptor); } finally { mDataStore.saveIfNeeded(); } } - } - - /** - * 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; + if (changed) { + if (DEBUG) { + Slog.d(TAG, "Keyboard layout changed, reloading keyboard layouts."); } + reloadKeyboardLayouts(); } - return mKeyCharacterMap; - }*/ + } public void setInputWindows(InputWindowHandle[] windowHandles) { nativeSetInputWindows(mPtr, windowHandles); @@ -1076,6 +1088,40 @@ public class InputManagerService extends IInputManager.Stub implements Watchdog. return PointerIcon.getDefaultIcon(mContext); } + // Native callback. + private String[] getKeyboardLayoutOverlay(String inputDeviceDescriptor) { + if (!mSystemReady) { + return null; + } + + String keyboardLayoutDescriptor = getKeyboardLayoutForInputDevice(inputDeviceDescriptor); + if (keyboardLayoutDescriptor == null) { + return null; + } + + final String[] result = new String[2]; + visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() { + @Override + public void visitKeyboardLayout(Resources resources, + String descriptor, String label, int kcmResId) { + try { + result[0] = descriptor; + result[1] = Streams.readFully(new InputStreamReader( + resources.openRawResource(kcmResId))); + } catch (IOException ex) { + } catch (NotFoundException ex) { + } + } + }); + if (result[0] == null) { + Log.w(TAG, "Could not get keyboard layout with descriptor '" + + keyboardLayoutDescriptor + "'."); + return null; + } + return result; + } + + /** * Callback interface implemented by the Window Manager. */ @@ -1169,6 +1215,11 @@ public class InputManagerService extends IInputManager.Stub implements Watchdog. } } + private interface KeyboardLayoutVisitor { + void visitKeyboardLayout(Resources resources, + String descriptor, String label, int kcmResId); + } + private final class InputDevicesChangedListenerRecord implements DeathRecipient { private final int mPid; private final IInputDevicesChangedListener mListener; diff --git a/services/jni/Android.mk b/services/jni/Android.mk index ac4fd15..e2bd622 100644 --- a/services/jni/Android.mk +++ b/services/jni/Android.mk @@ -22,7 +22,8 @@ LOCAL_C_INCLUDES += \ $(JNI_H_INCLUDE) \ frameworks/base/services \ frameworks/base/core/jni \ - external/skia/include/core + external/skia/include/core \ + libcore/include LOCAL_SHARED_LIBRARIES := \ libandroid_runtime \ diff --git a/services/jni/com_android_server_input_InputManagerService.cpp b/services/jni/com_android_server_input_InputManagerService.cpp index 3795074..b361a26 100644 --- a/services/jni/com_android_server_input_InputManagerService.cpp +++ b/services/jni/com_android_server_input_InputManagerService.cpp @@ -46,6 +46,9 @@ #include #include +#include +#include + #include "com_android_server_PowerManagerService.h" #include "com_android_server_input_InputApplicationHandle.h" #include "com_android_server_input_InputWindowHandle.h" @@ -79,6 +82,7 @@ static struct { jmethodID getLongPressTimeout; jmethodID getPointerLayer; jmethodID getPointerIcon; + jmethodID getKeyboardLayoutOverlay; } gServiceClassInfo; static struct { @@ -179,12 +183,14 @@ public: void setSystemUiVisibility(int32_t visibility); void setPointerSpeed(int32_t speed); void setShowTouches(bool enabled); + void reloadKeyboardLayouts(); /* --- InputReaderPolicyInterface implementation --- */ virtual void getReaderConfiguration(InputReaderConfiguration* outConfig); virtual sp obtainPointerController(int32_t deviceId); virtual void notifyInputDevicesChanged(const Vector& inputDevices); + virtual sp getKeyboardLayoutOverlay(const String8& inputDeviceDescriptor); /* --- InputDispatcherPolicyInterface implementation --- */ @@ -522,6 +528,29 @@ void NativeInputManager::notifyInputDevicesChanged(const Vector checkAndClearExceptionFromCallback(env, "notifyInputDevicesChanged"); } +sp NativeInputManager::getKeyboardLayoutOverlay( + const String8& inputDeviceDescriptor) { + JNIEnv* env = jniEnv(); + + sp result; + ScopedLocalRef descriptorObj(env, env->NewStringUTF(inputDeviceDescriptor.string())); + ScopedLocalRef arrayObj(env, jobjectArray(env->CallObjectMethod(mServiceObj, + gServiceClassInfo.getKeyboardLayoutOverlay, descriptorObj.get()))); + if (arrayObj.get()) { + ScopedLocalRef filenameObj(env, + jstring(env->GetObjectArrayElement(arrayObj.get(), 0))); + ScopedLocalRef contentsObj(env, + jstring(env->GetObjectArrayElement(arrayObj.get(), 1))); + ScopedUtfChars filenameChars(env, filenameObj.get()); + ScopedUtfChars contentsChars(env, contentsObj.get()); + + KeyCharacterMap::loadContents(String8(filenameChars.c_str()), + String8(contentsChars.c_str()), KeyCharacterMap::FORMAT_OVERLAY, &result); + } + checkAndClearExceptionFromCallback(env, "getKeyboardLayoutOverlay"); + return result; +} + void NativeInputManager::notifySwitch(nsecs_t when, int32_t switchCode, int32_t switchValue, uint32_t policyFlags) { #if DEBUG_INPUT_DISPATCHER_POLICY @@ -728,6 +757,11 @@ void NativeInputManager::setShowTouches(bool enabled) { InputReaderConfiguration::CHANGE_SHOW_TOUCHES); } +void NativeInputManager::reloadKeyboardLayouts() { + mInputManager->getReader()->requestRefreshConfiguration( + InputReaderConfiguration::CHANGE_KEYBOARD_LAYOUTS); +} + bool NativeInputManager::isScreenOn() { return android_server_PowerManagerService_isScreenOn(); } @@ -1258,6 +1292,13 @@ static void nativeCancelVibrate(JNIEnv* env, im->getInputManager()->getReader()->cancelVibrate(deviceId, token); } +static void nativeReloadKeyboardLayouts(JNIEnv* env, + jclass clazz, jint ptr) { + NativeInputManager* im = reinterpret_cast(ptr); + + im->reloadKeyboardLayouts(); +} + static jstring nativeDump(JNIEnv* env, jclass clazz, jint ptr) { NativeInputManager* im = reinterpret_cast(ptr); @@ -1323,6 +1364,8 @@ static JNINativeMethod gInputManagerMethods[] = { (void*) nativeVibrate }, { "nativeCancelVibrate", "(III)V", (void*) nativeCancelVibrate }, + { "nativeReloadKeyboardLayouts", "(I)V", + (void*) nativeReloadKeyboardLayouts }, { "nativeDump", "(I)Ljava/lang/String;", (void*) nativeDump }, { "nativeMonitor", "(I)V", @@ -1418,6 +1461,9 @@ int register_android_server_InputManager(JNIEnv* env) { GET_METHOD_ID(gServiceClassInfo.getPointerIcon, clazz, "getPointerIcon", "()Landroid/view/PointerIcon;"); + GET_METHOD_ID(gServiceClassInfo.getKeyboardLayoutOverlay, clazz, + "getKeyboardLayoutOverlay", "(Ljava/lang/String;)[Ljava/lang/String;"); + // InputDevice FIND_CLASS(gInputDeviceClassInfo.clazz, "android/view/InputDevice"); -- cgit v1.1