1 /* 2 * Copyright 2006, The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <android_runtime/AndroidRuntime.h> 18 19 #include <androidfw/KeyCharacterMap.h> 20 #include <androidfw/Input.h> 21 #include <binder/Parcel.h> 22 23 #include <nativehelper/jni.h> 24 #include <nativehelper/JNIHelp.h> 25 26 #include "android_os_Parcel.h" 27 #include "android_view_KeyEvent.h" 28 29 namespace android { 30 31 static struct { 32 jclass clazz; 33 jmethodID ctor; 34 } gKeyCharacterMapClassInfo; 35 36 static struct { 37 jclass clazz; 38 } gKeyEventClassInfo; 39 40 static struct { 41 jfieldID keyCode; 42 jfieldID metaState; 43 } gFallbackActionClassInfo; 44 45 46 class NativeKeyCharacterMap { 47 public: 48 NativeKeyCharacterMap(int32_t deviceId, const sp<KeyCharacterMap>& map) : 49 mDeviceId(deviceId), mMap(map) { 50 } 51 52 ~NativeKeyCharacterMap() { 53 } 54 55 inline int32_t getDeviceId() const { 56 return mDeviceId; 57 } 58 59 inline const sp<KeyCharacterMap>& getMap() const { 60 return mMap; 61 } 62 63 private: 64 int32_t mDeviceId; 65 sp<KeyCharacterMap> mMap; 66 }; 67 68 69 jobject android_view_KeyCharacterMap_create(JNIEnv* env, int32_t deviceId, 70 const sp<KeyCharacterMap>& kcm) { 71 NativeKeyCharacterMap* map = new NativeKeyCharacterMap(deviceId, 72 kcm.get() ? kcm : KeyCharacterMap::empty()); 73 if (!map) { 74 return NULL; 75 } 76 77 return env->NewObject(gKeyCharacterMapClassInfo.clazz, gKeyCharacterMapClassInfo.ctor, 78 reinterpret_cast<jint>(map)); 79 } 80 81 static jint nativeReadFromParcel(JNIEnv *env, jobject clazz, jobject parcelObj) { 82 Parcel* parcel = parcelForJavaObject(env, parcelObj); 83 if (!parcel) { 84 return 0; 85 } 86 87 int32_t deviceId = parcel->readInt32(); 88 if (parcel->errorCheck()) { 89 return 0; 90 } 91 92 sp<KeyCharacterMap> kcm = KeyCharacterMap::readFromParcel(parcel); 93 if (!kcm.get()) { 94 return 0; 95 } 96 97 NativeKeyCharacterMap* map = new NativeKeyCharacterMap(deviceId, kcm); 98 return reinterpret_cast<jint>(map); 99 } 100 101 static void nativeWriteToParcel(JNIEnv* env, jobject clazz, jint ptr, jobject parcelObj) { 102 NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr); 103 Parcel* parcel = parcelForJavaObject(env, parcelObj); 104 if (parcel) { 105 parcel->writeInt32(map->getDeviceId()); 106 map->getMap()->writeToParcel(parcel); 107 } 108 } 109 110 static void nativeDispose(JNIEnv *env, jobject clazz, jint ptr) { 111 NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr); 112 delete map; 113 } 114 115 static jchar nativeGetCharacter(JNIEnv *env, jobject clazz, jint ptr, 116 jint keyCode, jint metaState) { 117 NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr); 118 return map->getMap()->getCharacter(keyCode, metaState); 119 } 120 121 static jboolean nativeGetFallbackAction(JNIEnv *env, jobject clazz, jint ptr, jint keyCode, 122 jint metaState, jobject fallbackActionObj) { 123 NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr); 124 KeyCharacterMap::FallbackAction fallbackAction; 125 126 bool result = map->getMap()->getFallbackAction(keyCode, metaState, &fallbackAction); 127 if (result) { 128 env->SetIntField(fallbackActionObj, gFallbackActionClassInfo.keyCode, 129 fallbackAction.keyCode); 130 env->SetIntField(fallbackActionObj, gFallbackActionClassInfo.metaState, 131 fallbackAction.metaState); 132 } 133 return result; 134 } 135 136 static jchar nativeGetNumber(JNIEnv *env, jobject clazz, jint ptr, jint keyCode) { 137 NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr); 138 return map->getMap()->getNumber(keyCode); 139 } 140 141 static jchar nativeGetMatch(JNIEnv *env, jobject clazz, jint ptr, jint keyCode, 142 jcharArray charsArray, jint metaState) { 143 NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr); 144 145 jsize numChars = env->GetArrayLength(charsArray); 146 jchar* chars = static_cast<jchar*>(env->GetPrimitiveArrayCritical(charsArray, NULL)); 147 if (!chars) { 148 return 0; 149 } 150 151 char16_t result = map->getMap()->getMatch(keyCode, chars, size_t(numChars), metaState); 152 153 env->ReleasePrimitiveArrayCritical(charsArray, chars, JNI_ABORT); 154 return result; 155 } 156 157 static jchar nativeGetDisplayLabel(JNIEnv *env, jobject clazz, jint ptr, jint keyCode) { 158 NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr); 159 return map->getMap()->getDisplayLabel(keyCode); 160 } 161 162 static jint nativeGetKeyboardType(JNIEnv *env, jobject clazz, jint ptr) { 163 NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr); 164 return map->getMap()->getKeyboardType(); 165 } 166 167 static jobjectArray nativeGetEvents(JNIEnv *env, jobject clazz, jint ptr, 168 jcharArray charsArray) { 169 NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr); 170 171 jchar* chars = env->GetCharArrayElements(charsArray, NULL); 172 if (!chars) { 173 return NULL; 174 } 175 jsize numChars = env->GetArrayLength(charsArray); 176 177 Vector<KeyEvent> events; 178 jobjectArray result = NULL; 179 if (map->getMap()->getEvents(map->getDeviceId(), chars, size_t(numChars), events)) { 180 result = env->NewObjectArray(jsize(events.size()), gKeyEventClassInfo.clazz, NULL); 181 if (result) { 182 for (size_t i = 0; i < events.size(); i++) { 183 jobject keyEventObj = android_view_KeyEvent_fromNative(env, &events.itemAt(i)); 184 if (!keyEventObj) break; // threw OOM exception 185 env->SetObjectArrayElement(result, jsize(i), keyEventObj); 186 env->DeleteLocalRef(keyEventObj); 187 } 188 } 189 } 190 191 env->ReleaseCharArrayElements(charsArray, chars, JNI_ABORT); 192 return result; 193 } 194 195 196 /* 197 * JNI registration. 198 */ 199 200 static JNINativeMethod g_methods[] = { 201 /* name, signature, funcPtr */ 202 { "nativeReadFromParcel", "(Landroid/os/Parcel;)I", 203 (void*)nativeReadFromParcel }, 204 { "nativeWriteToParcel", "(ILandroid/os/Parcel;)V", 205 (void*)nativeWriteToParcel }, 206 { "nativeDispose", "(I)V", 207 (void*)nativeDispose }, 208 { "nativeGetCharacter", "(III)C", 209 (void*)nativeGetCharacter }, 210 { "nativeGetFallbackAction", "(IIILandroid/view/KeyCharacterMap$FallbackAction;)Z", 211 (void*)nativeGetFallbackAction }, 212 { "nativeGetNumber", "(II)C", 213 (void*)nativeGetNumber }, 214 { "nativeGetMatch", "(II[CI)C", 215 (void*)nativeGetMatch }, 216 { "nativeGetDisplayLabel", "(II)C", 217 (void*)nativeGetDisplayLabel }, 218 { "nativeGetKeyboardType", "(I)I", 219 (void*)nativeGetKeyboardType }, 220 { "nativeGetEvents", "(I[C)[Landroid/view/KeyEvent;", 221 (void*)nativeGetEvents }, 222 }; 223 224 #define FIND_CLASS(var, className) \ 225 var = env->FindClass(className); \ 226 LOG_FATAL_IF(! var, "Unable to find class " className); 227 228 #define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \ 229 var = env->GetMethodID(clazz, methodName, methodDescriptor); \ 230 LOG_FATAL_IF(! var, "Unable to find method " methodName); 231 232 #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ 233 var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ 234 LOG_FATAL_IF(! var, "Unable to find field " fieldName); 235 236 int register_android_view_KeyCharacterMap(JNIEnv* env) 237 { 238 FIND_CLASS(gKeyCharacterMapClassInfo.clazz, "android/view/KeyCharacterMap"); 239 gKeyCharacterMapClassInfo.clazz = jclass(env->NewGlobalRef(gKeyCharacterMapClassInfo.clazz)); 240 241 GET_METHOD_ID(gKeyCharacterMapClassInfo.ctor, gKeyCharacterMapClassInfo.clazz, 242 "<init>", "(I)V"); 243 244 FIND_CLASS(gKeyEventClassInfo.clazz, "android/view/KeyEvent"); 245 gKeyEventClassInfo.clazz = jclass(env->NewGlobalRef(gKeyEventClassInfo.clazz)); 246 247 jclass clazz; 248 FIND_CLASS(clazz, "android/view/KeyCharacterMap$FallbackAction"); 249 250 GET_FIELD_ID(gFallbackActionClassInfo.keyCode, clazz, 251 "keyCode", "I"); 252 253 GET_FIELD_ID(gFallbackActionClassInfo.metaState, clazz, 254 "metaState", "I"); 255 256 return AndroidRuntime::registerNativeMethods(env, 257 "android/view/KeyCharacterMap", g_methods, NELEM(g_methods)); 258 } 259 260 }; // namespace android 261