Request key maps from input manager service.

Instead of each application loading the KeyCharacterMap from
the file system, get them from the input manager service as
part of the InputDevice object.

Refactored InputManager to be a proper singleton instead of
having a bunch of static methods.

InputManager now maintains a cache of all InputDevice objects
that it has loaded.  Currently we never invalidate the cache
which can cause InputDevice to return stale motion ranges if
the device is reconfigured.  This will be fixed in a future change.

Added a fake InputDevice with ID -1 to represent the virtual keyboard.

Change-Id: If7a695839ad0972317a5aab89e9d1e42ace28eb7
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 @@
 } 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 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 @@
         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 @@
 
     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 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 @@
             (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 @@
         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));