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 <input/KeyCharacterMap.h> 20#include <input/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#include "core_jni_helpers.h" 30 31namespace android { 32 33static struct { 34 jclass clazz; 35 jmethodID ctor; 36} gKeyCharacterMapClassInfo; 37 38static struct { 39 jclass clazz; 40} gKeyEventClassInfo; 41 42static struct { 43 jfieldID keyCode; 44 jfieldID metaState; 45} gFallbackActionClassInfo; 46 47 48class NativeKeyCharacterMap { 49public: 50 NativeKeyCharacterMap(int32_t deviceId, const sp<KeyCharacterMap>& map) : 51 mDeviceId(deviceId), mMap(map) { 52 } 53 54 ~NativeKeyCharacterMap() { 55 } 56 57 inline int32_t getDeviceId() const { 58 return mDeviceId; 59 } 60 61 inline const sp<KeyCharacterMap>& getMap() const { 62 return mMap; 63 } 64 65private: 66 int32_t mDeviceId; 67 sp<KeyCharacterMap> mMap; 68}; 69 70 71jobject android_view_KeyCharacterMap_create(JNIEnv* env, int32_t deviceId, 72 const sp<KeyCharacterMap>& kcm) { 73 NativeKeyCharacterMap* map = new NativeKeyCharacterMap(deviceId, 74 kcm.get() ? kcm : KeyCharacterMap::empty()); 75 if (!map) { 76 return NULL; 77 } 78 79 return env->NewObject(gKeyCharacterMapClassInfo.clazz, gKeyCharacterMapClassInfo.ctor, 80 reinterpret_cast<jlong>(map)); 81} 82 83static jlong nativeReadFromParcel(JNIEnv *env, jobject clazz, jobject parcelObj) { 84 Parcel* parcel = parcelForJavaObject(env, parcelObj); 85 if (!parcel) { 86 return 0; 87 } 88 89 int32_t deviceId = parcel->readInt32(); 90 if (parcel->errorCheck()) { 91 return 0; 92 } 93 94 sp<KeyCharacterMap> kcm = KeyCharacterMap::readFromParcel(parcel); 95 if (!kcm.get()) { 96 return 0; 97 } 98 99 NativeKeyCharacterMap* map = new NativeKeyCharacterMap(deviceId, kcm); 100 return reinterpret_cast<jlong>(map); 101} 102 103static void nativeWriteToParcel(JNIEnv* env, jobject clazz, jlong ptr, jobject parcelObj) { 104 NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr); 105 Parcel* parcel = parcelForJavaObject(env, parcelObj); 106 if (parcel) { 107 parcel->writeInt32(map->getDeviceId()); 108 map->getMap()->writeToParcel(parcel); 109 } 110} 111 112static void nativeDispose(JNIEnv *env, jobject clazz, jlong ptr) { 113 NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr); 114 delete map; 115} 116 117static jchar nativeGetCharacter(JNIEnv *env, jobject clazz, jlong ptr, 118 jint keyCode, jint metaState) { 119 NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr); 120 return map->getMap()->getCharacter(keyCode, metaState); 121} 122 123static jboolean nativeGetFallbackAction(JNIEnv *env, jobject clazz, jlong ptr, jint keyCode, 124 jint metaState, jobject fallbackActionObj) { 125 NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr); 126 KeyCharacterMap::FallbackAction fallbackAction; 127 128 bool result = map->getMap()->getFallbackAction(keyCode, metaState, &fallbackAction); 129 if (result) { 130 env->SetIntField(fallbackActionObj, gFallbackActionClassInfo.keyCode, 131 fallbackAction.keyCode); 132 env->SetIntField(fallbackActionObj, gFallbackActionClassInfo.metaState, 133 fallbackAction.metaState); 134 } 135 return result; 136} 137 138static jchar nativeGetNumber(JNIEnv *env, jobject clazz, jlong ptr, jint keyCode) { 139 NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr); 140 return map->getMap()->getNumber(keyCode); 141} 142 143static jchar nativeGetMatch(JNIEnv *env, jobject clazz, jlong ptr, jint keyCode, 144 jcharArray charsArray, jint metaState) { 145 NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr); 146 147 jsize numChars = env->GetArrayLength(charsArray); 148 jchar* chars = static_cast<jchar*>(env->GetPrimitiveArrayCritical(charsArray, NULL)); 149 if (!chars) { 150 return 0; 151 } 152 153 char16_t result = map->getMap()->getMatch( 154 keyCode, reinterpret_cast<char16_t*>(chars), size_t(numChars), 155 metaState); 156 157 env->ReleasePrimitiveArrayCritical(charsArray, chars, JNI_ABORT); 158 return result; 159} 160 161static jchar nativeGetDisplayLabel(JNIEnv *env, jobject clazz, jlong ptr, jint keyCode) { 162 NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr); 163 return map->getMap()->getDisplayLabel(keyCode); 164} 165 166static jint nativeGetKeyboardType(JNIEnv *env, jobject clazz, jlong ptr) { 167 NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr); 168 return map->getMap()->getKeyboardType(); 169} 170 171static jobjectArray nativeGetEvents(JNIEnv *env, jobject clazz, jlong ptr, 172 jcharArray charsArray) { 173 NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr); 174 175 jchar* chars = env->GetCharArrayElements(charsArray, NULL); 176 if (!chars) { 177 return NULL; 178 } 179 jsize numChars = env->GetArrayLength(charsArray); 180 181 Vector<KeyEvent> events; 182 jobjectArray result = NULL; 183 if (map->getMap()->getEvents(map->getDeviceId(), 184 reinterpret_cast<char16_t*>(chars), 185 size_t(numChars), events)) { 186 result = env->NewObjectArray(jsize(events.size()), gKeyEventClassInfo.clazz, NULL); 187 if (result) { 188 for (size_t i = 0; i < events.size(); i++) { 189 jobject keyEventObj = android_view_KeyEvent_fromNative(env, &events.itemAt(i)); 190 if (!keyEventObj) break; // threw OOM exception 191 env->SetObjectArrayElement(result, jsize(i), keyEventObj); 192 env->DeleteLocalRef(keyEventObj); 193 } 194 } 195 } 196 197 env->ReleaseCharArrayElements(charsArray, chars, JNI_ABORT); 198 return result; 199} 200 201 202/* 203 * JNI registration. 204 */ 205 206static JNINativeMethod g_methods[] = { 207 /* name, signature, funcPtr */ 208 { "nativeReadFromParcel", "(Landroid/os/Parcel;)J", 209 (void*)nativeReadFromParcel }, 210 { "nativeWriteToParcel", "(JLandroid/os/Parcel;)V", 211 (void*)nativeWriteToParcel }, 212 { "nativeDispose", "(J)V", 213 (void*)nativeDispose }, 214 { "nativeGetCharacter", "(JII)C", 215 (void*)nativeGetCharacter }, 216 { "nativeGetFallbackAction", "(JIILandroid/view/KeyCharacterMap$FallbackAction;)Z", 217 (void*)nativeGetFallbackAction }, 218 { "nativeGetNumber", "(JI)C", 219 (void*)nativeGetNumber }, 220 { "nativeGetMatch", "(JI[CI)C", 221 (void*)nativeGetMatch }, 222 { "nativeGetDisplayLabel", "(JI)C", 223 (void*)nativeGetDisplayLabel }, 224 { "nativeGetKeyboardType", "(J)I", 225 (void*)nativeGetKeyboardType }, 226 { "nativeGetEvents", "(J[C)[Landroid/view/KeyEvent;", 227 (void*)nativeGetEvents }, 228}; 229 230int register_android_view_KeyCharacterMap(JNIEnv* env) 231{ 232 gKeyCharacterMapClassInfo.clazz = FindClassOrDie(env, "android/view/KeyCharacterMap"); 233 gKeyCharacterMapClassInfo.clazz = MakeGlobalRefOrDie(env, gKeyCharacterMapClassInfo.clazz); 234 235 gKeyCharacterMapClassInfo.ctor = GetMethodIDOrDie(env, gKeyCharacterMapClassInfo.clazz, 236 "<init>", "(J)V"); 237 238 gKeyEventClassInfo.clazz = FindClassOrDie(env, "android/view/KeyEvent"); 239 gKeyEventClassInfo.clazz = MakeGlobalRefOrDie(env, gKeyEventClassInfo.clazz); 240 241 jclass clazz = FindClassOrDie(env, "android/view/KeyCharacterMap$FallbackAction"); 242 243 gFallbackActionClassInfo.keyCode = GetFieldIDOrDie(env, clazz, "keyCode", "I"); 244 gFallbackActionClassInfo.metaState = GetFieldIDOrDie(env, clazz, "metaState", "I"); 245 246 return RegisterMethodsOrDie(env, "android/view/KeyCharacterMap", g_methods, NELEM(g_methods)); 247} 248 249}; // namespace android 250