• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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