summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorJeff Brown <jeffbrown@google.com>2012-04-17 16:52:41 -0700
committerJeff Brown <jeffbrown@google.com>2012-04-17 17:56:32 -0700
commit6ec6f79e1ac1714e3b837796e99f07ff88f66601 (patch)
tree02aa55617bfa6dd2eb0bec29156e279c8afaaa0d /services
parenta3bc565882dd3984e995363642b1295fe3d24d10 (diff)
downloadframeworks_base-6ec6f79e1ac1714e3b837796e99f07ff88f66601.zip
frameworks_base-6ec6f79e1ac1714e3b837796e99f07ff88f66601.tar.gz
frameworks_base-6ec6f79e1ac1714e3b837796e99f07ff88f66601.tar.bz2
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
Diffstat (limited to 'services')
-rw-r--r--services/input/EventHub.cpp18
-rw-r--r--services/input/EventHub.h5
-rw-r--r--services/input/InputReader.cpp8
-rw-r--r--services/input/InputReader.h6
-rw-r--r--services/input/tests/InputReader_test.cpp8
-rw-r--r--services/java/com/android/server/InputMethodManagerService.java2
-rw-r--r--services/java/com/android/server/SystemServer.java11
-rw-r--r--services/java/com/android/server/input/InputManagerService.java211
-rw-r--r--services/jni/Android.mk3
-rw-r--r--services/jni/com_android_server_input_InputManagerService.cpp46
10 files changed, 235 insertions, 83 deletions
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<KeyCharacterMap> 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<KeyCharacterMap>& 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<VirtualKeyDefinition>& outVirtualKeys) const = 0;
virtual sp<KeyCharacterMap> getKeyCharacterMap(int32_t deviceId) const = 0;
+ virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp<KeyCharacterMap>& map) = 0;
/* Control the vibrator. */
virtual void vibrate(int32_t deviceId, nsecs_t duration) = 0;
@@ -283,6 +284,7 @@ public:
Vector<VirtualKeyDefinition>& outVirtualKeys) const;
virtual sp<KeyCharacterMap> getKeyCharacterMap(int32_t deviceId) const;
+ virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp<KeyCharacterMap>& 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<KeyCharacterMap> overlayKeyMap;
+ sp<KeyCharacterMap> 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<KeyCharacterMap> 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<InputDeviceInfo>& inputDevices) = 0;
+
+ /* Gets the keyboard layout for a particular input device. */
+ virtual sp<KeyCharacterMap> 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<InputDeviceInfo>& inputDevices) {
mInputDevices = inputDevices;
}
+
+ virtual sp<KeyCharacterMap> getKeyboardLayout(const String8& inputDeviceDescriptor) {
+ return NULL;
+ }
};
@@ -646,6 +650,10 @@ private:
return NULL;
}
+ virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp<KeyCharacterMap>& 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<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);
- }
+ final ArrayList<KeyboardLayout> list = new ArrayList<KeyboardLayout>();
+ 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<KeyboardLayout> 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 <android_view_PointerIcon.h>
#include <android/graphics/GraphicsJNI.h>
+#include <ScopedLocalRef.h>
+#include <ScopedUtfChars.h>
+
#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<PointerControllerInterface> obtainPointerController(int32_t deviceId);
virtual void notifyInputDevicesChanged(const Vector<InputDeviceInfo>& inputDevices);
+ virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(const String8& inputDeviceDescriptor);
/* --- InputDispatcherPolicyInterface implementation --- */
@@ -522,6 +528,29 @@ void NativeInputManager::notifyInputDevicesChanged(const Vector<InputDeviceInfo>
checkAndClearExceptionFromCallback(env, "notifyInputDevicesChanged");
}
+sp<KeyCharacterMap> NativeInputManager::getKeyboardLayoutOverlay(
+ const String8& inputDeviceDescriptor) {
+ JNIEnv* env = jniEnv();
+
+ sp<KeyCharacterMap> result;
+ ScopedLocalRef<jstring> descriptorObj(env, env->NewStringUTF(inputDeviceDescriptor.string()));
+ ScopedLocalRef<jobjectArray> arrayObj(env, jobjectArray(env->CallObjectMethod(mServiceObj,
+ gServiceClassInfo.getKeyboardLayoutOverlay, descriptorObj.get())));
+ if (arrayObj.get()) {
+ ScopedLocalRef<jstring> filenameObj(env,
+ jstring(env->GetObjectArrayElement(arrayObj.get(), 0)));
+ ScopedLocalRef<jstring> 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<NativeInputManager*>(ptr);
+
+ im->reloadKeyboardLayouts();
+}
+
static jstring nativeDump(JNIEnv* env, jclass clazz, jint ptr) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(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");