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 <binder/Parcel.h>
20 #include <input/Input.h>
21 #include <input/InputDevice.h>
22 #include <input/KeyCharacterMap.h>
23
24 #include <jni.h>
25 #include <nativehelper/JNIHelp.h>
26
27 #include "android_os_Parcel.h"
28 #include "android_view_KeyEvent.h"
29
30 #include "core_jni_helpers.h"
31
32 namespace android {
33
34 static struct {
35 jclass clazz;
36 jmethodID ctor;
37 } gKeyCharacterMapClassInfo;
38
39 static struct {
40 jclass clazz;
41 } gKeyEventClassInfo;
42
43 static struct {
44 jfieldID keyCode;
45 jfieldID metaState;
46 } gFallbackActionClassInfo;
47
48
49 class NativeKeyCharacterMap {
50 public:
NativeKeyCharacterMap(int32_t deviceId,std::shared_ptr<KeyCharacterMap> map)51 NativeKeyCharacterMap(int32_t deviceId, std::shared_ptr<KeyCharacterMap> map)
52 : mDeviceId(deviceId), mMap(std::move(map)) {}
53
~NativeKeyCharacterMap()54 ~NativeKeyCharacterMap() {
55 }
56
getDeviceId() const57 inline int32_t getDeviceId() const {
58 return mDeviceId;
59 }
60
getMap() const61 inline const std::shared_ptr<KeyCharacterMap> getMap() const { return mMap; }
62
63 private:
64 int32_t mDeviceId;
65 std::shared_ptr<KeyCharacterMap> mMap;
66 };
67
android_view_KeyCharacterMap_create(JNIEnv * env,int32_t deviceId,const std::shared_ptr<KeyCharacterMap> kcm)68 jobject android_view_KeyCharacterMap_create(JNIEnv* env, int32_t deviceId,
69 const std::shared_ptr<KeyCharacterMap> kcm) {
70 NativeKeyCharacterMap* nativeMap = new NativeKeyCharacterMap(deviceId, kcm);
71 if (!nativeMap) {
72 return nullptr;
73 }
74
75 return env->NewObject(gKeyCharacterMapClassInfo.clazz, gKeyCharacterMapClassInfo.ctor,
76 reinterpret_cast<jlong>(nativeMap));
77 }
78
nativeObtainEmptyKeyCharacterMap(JNIEnv * env,jobject,jint deviceId)79 static jobject nativeObtainEmptyKeyCharacterMap(JNIEnv* env, jobject /* clazz */, jint deviceId) {
80 return android_view_KeyCharacterMap_create(env, deviceId, nullptr);
81 }
82
nativeReadFromParcel(JNIEnv * env,jobject clazz,jobject parcelObj)83 static 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 std::shared_ptr<KeyCharacterMap> kcm = nullptr;
95 // Check if map is a null character map
96 if (parcel->readBool()) {
97 kcm = KeyCharacterMap::readFromParcel(parcel);
98 if (!kcm.get()) {
99 return 0;
100 }
101 }
102 NativeKeyCharacterMap* map = new NativeKeyCharacterMap(deviceId, kcm);
103 return reinterpret_cast<jlong>(map);
104 }
105
nativeWriteToParcel(JNIEnv * env,jobject clazz,jlong ptr,jobject parcelObj)106 static void nativeWriteToParcel(JNIEnv* env, jobject clazz, jlong ptr, jobject parcelObj) {
107 NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr);
108 Parcel* parcel = parcelForJavaObject(env, parcelObj);
109 if (!parcel || !map) {
110 return;
111 }
112 parcel->writeInt32(map->getDeviceId());
113 if (!map->getMap()) {
114 parcel->writeBool(false);
115 return;
116 }
117 parcel->writeBool(true);
118 map->getMap()->writeToParcel(parcel);
119 }
120
nativeDispose(JNIEnv * env,jobject clazz,jlong ptr)121 static void nativeDispose(JNIEnv *env, jobject clazz, jlong ptr) {
122 NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr);
123 delete map;
124 }
125
126 // Return the associated character or combining accent, or 0 if none.
nativeGetCharacter(JNIEnv * env,jobject clazz,jlong ptr,jint keyCode,jint metaState)127 static jchar nativeGetCharacter(JNIEnv *env, jobject clazz, jlong ptr,
128 jint keyCode, jint metaState) {
129 NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr);
130 if (!map || !map->getMap()) {
131 return static_cast<jchar>(0);
132 }
133 return map->getMap()->getCharacter(keyCode, metaState);
134 }
135
nativeGetFallbackAction(JNIEnv * env,jobject clazz,jlong ptr,jint keyCode,jint metaState,jobject fallbackActionObj)136 static jboolean nativeGetFallbackAction(JNIEnv *env, jobject clazz, jlong ptr, jint keyCode,
137 jint metaState, jobject fallbackActionObj) {
138 NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr);
139 if (!map || !map->getMap()) {
140 return static_cast<jboolean>(false);
141 }
142 KeyCharacterMap::FallbackAction fallbackAction;
143
144 bool result = map->getMap()->getFallbackAction(keyCode, metaState, &fallbackAction);
145 if (result) {
146 env->SetIntField(fallbackActionObj, gFallbackActionClassInfo.keyCode,
147 fallbackAction.keyCode);
148 env->SetIntField(fallbackActionObj, gFallbackActionClassInfo.metaState,
149 fallbackAction.metaState);
150 }
151 return result;
152 }
153
154 // Return the number of a key code, or 0 if none.
nativeGetNumber(JNIEnv * env,jobject clazz,jlong ptr,jint keyCode)155 static jchar nativeGetNumber(JNIEnv *env, jobject clazz, jlong ptr, jint keyCode) {
156 NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr);
157 if (!map || !map->getMap()) {
158 return static_cast<jchar>(0);
159 }
160 return map->getMap()->getNumber(keyCode);
161 }
162
163 // Return the matched key code and meta state, or 0 if none.
nativeGetMatch(JNIEnv * env,jobject clazz,jlong ptr,jint keyCode,jcharArray charsArray,jint metaState)164 static jchar nativeGetMatch(JNIEnv *env, jobject clazz, jlong ptr, jint keyCode,
165 jcharArray charsArray, jint metaState) {
166 NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr);
167 if (!map || !map->getMap()) {
168 return static_cast<jchar>(0);
169 }
170 jsize numChars = env->GetArrayLength(charsArray);
171 jchar* chars = static_cast<jchar*>(env->GetPrimitiveArrayCritical(charsArray, NULL));
172 if (!chars) {
173 return 0;
174 }
175
176 char16_t result = map->getMap()->getMatch(keyCode, reinterpret_cast<char16_t*>(chars),
177 size_t(numChars), metaState);
178
179 env->ReleasePrimitiveArrayCritical(charsArray, chars, JNI_ABORT);
180 return result;
181 }
182
183 // Return the associated display label, or 0 if none.
nativeGetDisplayLabel(JNIEnv * env,jobject clazz,jlong ptr,jint keyCode)184 static jchar nativeGetDisplayLabel(JNIEnv *env, jobject clazz, jlong ptr, jint keyCode) {
185 NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr);
186 if (!map || !map->getMap()) {
187 return static_cast<jchar>(0);
188 }
189 return map->getMap()->getDisplayLabel(keyCode);
190 }
191
192 // Return the associated keyboard type, or 0 if none.
nativeGetKeyboardType(JNIEnv * env,jobject clazz,jlong ptr)193 static jint nativeGetKeyboardType(JNIEnv *env, jobject clazz, jlong ptr) {
194 NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr);
195 if (!map || !map->getMap()) {
196 return static_cast<jint>(0);
197 }
198 return static_cast<jint>(map->getMap()->getKeyboardType());
199 }
200
nativeGetEvents(JNIEnv * env,jobject clazz,jlong ptr,jcharArray charsArray)201 static jobjectArray nativeGetEvents(JNIEnv *env, jobject clazz, jlong ptr,
202 jcharArray charsArray) {
203 NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr);
204 if (!map || !map->getMap()) {
205 return env->NewObjectArray(0 /* size */, gKeyEventClassInfo.clazz, NULL);
206 }
207 jchar* chars = env->GetCharArrayElements(charsArray, NULL);
208 if (!chars) {
209 return NULL;
210 }
211 jsize numChars = env->GetArrayLength(charsArray);
212
213 Vector<KeyEvent> events;
214 jobjectArray result = NULL;
215 if (map->getMap()->getEvents(map->getDeviceId(), reinterpret_cast<char16_t*>(chars),
216 size_t(numChars), events)) {
217 result = env->NewObjectArray(jsize(events.size()), gKeyEventClassInfo.clazz, NULL);
218 if (result) {
219 for (size_t i = 0; i < events.size(); i++) {
220 jobject keyEventObj = android_view_KeyEvent_fromNative(env, &events.itemAt(i));
221 if (!keyEventObj) break; // threw OOM exception
222 env->SetObjectArrayElement(result, jsize(i), keyEventObj);
223 env->DeleteLocalRef(keyEventObj);
224 }
225 }
226 }
227
228 env->ReleaseCharArrayElements(charsArray, chars, JNI_ABORT);
229 return result;
230 }
231
nativeEquals(JNIEnv * env,jobject clazz,jlong ptr1,jlong ptr2)232 static jboolean nativeEquals(JNIEnv* env, jobject clazz, jlong ptr1, jlong ptr2) {
233 const std::shared_ptr<KeyCharacterMap>& map1 =
234 (reinterpret_cast<NativeKeyCharacterMap*>(ptr1))->getMap();
235 const std::shared_ptr<KeyCharacterMap>& map2 =
236 (reinterpret_cast<NativeKeyCharacterMap*>(ptr2))->getMap();
237 if (map1 == nullptr || map2 == nullptr) {
238 return map1 == map2;
239 }
240 return static_cast<jboolean>(*map1 == *map2);
241 }
242
243 /*
244 * JNI registration.
245 */
246
247 static const JNINativeMethod g_methods[] = {
248 /* name, signature, funcPtr */
249 {"nativeReadFromParcel", "(Landroid/os/Parcel;)J", (void*)nativeReadFromParcel},
250 {"nativeWriteToParcel", "(JLandroid/os/Parcel;)V", (void*)nativeWriteToParcel},
251 {"nativeDispose", "(J)V", (void*)nativeDispose},
252 {"nativeGetCharacter", "(JII)C", (void*)nativeGetCharacter},
253 {"nativeGetFallbackAction", "(JIILandroid/view/KeyCharacterMap$FallbackAction;)Z",
254 (void*)nativeGetFallbackAction},
255 {"nativeGetNumber", "(JI)C", (void*)nativeGetNumber},
256 {"nativeGetMatch", "(JI[CI)C", (void*)nativeGetMatch},
257 {"nativeGetDisplayLabel", "(JI)C", (void*)nativeGetDisplayLabel},
258 {"nativeGetKeyboardType", "(J)I", (void*)nativeGetKeyboardType},
259 {"nativeGetEvents", "(J[C)[Landroid/view/KeyEvent;", (void*)nativeGetEvents},
260 {"nativeObtainEmptyKeyCharacterMap", "(I)Landroid/view/KeyCharacterMap;",
261 (void*)nativeObtainEmptyKeyCharacterMap},
262 {"nativeEquals", "(JJ)Z", (void*)nativeEquals},
263 };
264
register_android_view_KeyCharacterMap(JNIEnv * env)265 int register_android_view_KeyCharacterMap(JNIEnv* env)
266 {
267 gKeyCharacterMapClassInfo.clazz = FindClassOrDie(env, "android/view/KeyCharacterMap");
268 gKeyCharacterMapClassInfo.clazz = MakeGlobalRefOrDie(env, gKeyCharacterMapClassInfo.clazz);
269
270 gKeyCharacterMapClassInfo.ctor = GetMethodIDOrDie(env, gKeyCharacterMapClassInfo.clazz,
271 "<init>", "(J)V");
272
273 gKeyEventClassInfo.clazz = FindClassOrDie(env, "android/view/KeyEvent");
274 gKeyEventClassInfo.clazz = MakeGlobalRefOrDie(env, gKeyEventClassInfo.clazz);
275
276 jclass clazz = FindClassOrDie(env, "android/view/KeyCharacterMap$FallbackAction");
277
278 gFallbackActionClassInfo.keyCode = GetFieldIDOrDie(env, clazz, "keyCode", "I");
279 gFallbackActionClassInfo.metaState = GetFieldIDOrDie(env, clazz, "metaState", "I");
280
281 return RegisterMethodsOrDie(env, "android/view/KeyCharacterMap", g_methods, NELEM(g_methods));
282 }
283
284 }; // namespace android
285