1 /*
2 * Copyright (C) 2016 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 #define LOG_NDEBUG 0
18 #define LOG_TAG "CAR.INPUT"
19
20 #include <string.h>
21 #include <sys/time.h>
22 #include <linux/input.h>
23 #include <jni.h>
24 #include <JNIHelp.h>
25 #include <android/keycodes.h>
26 #include <cutils/log.h>
27 #include <utils/Errors.h>
28
29
30 namespace android {
31
androidKeyCodeToLinuxKeyCode(int androidKeyCode)32 static int androidKeyCodeToLinuxKeyCode(int androidKeyCode) {
33 switch (androidKeyCode) {
34 case AKEYCODE_VOLUME_UP:
35 return KEY_VOLUMEUP;
36 case AKEYCODE_VOLUME_DOWN:
37 return KEY_VOLUMEDOWN;
38 case AKEYCODE_CALL:
39 return KEY_SEND;
40 case AKEYCODE_ENDCALL:
41 return KEY_END;
42 /* TODO add more keys like these:
43 case AKEYCODE_MEDIA_PLAY_PAUSE:
44 case AKEYCODE_MEDIA_STOP:
45 case AKEYCODE_MEDIA_NEXT:
46 case AKEYCODE_MEDIA_PREVIOUS:*/
47 case AKEYCODE_VOICE_ASSIST:
48 return KEY_MICMUTE;
49 default:
50 ALOGW("Unmapped android key code %d dropped", androidKeyCode);
51 return 0;
52 }
53 }
54
55 /*
56 * Class: com_android_car_CarInputService
57 * Method: nativeInjectKeyEvent
58 * Signature: (IIZ)I
59 */
com_android_car_CarInputService_nativeInjectKeyEvent(JNIEnv * env,jobject,jint fd,jint keyCode,jboolean down)60 static jint com_android_car_CarInputService_nativeInjectKeyEvent
61 (JNIEnv *env, jobject /*object*/, jint fd, jint keyCode, jboolean down) {
62 int linuxKeyCode = androidKeyCodeToLinuxKeyCode(keyCode);
63 if (linuxKeyCode == 0) {
64 return BAD_VALUE;
65 }
66 struct input_event ev[2];
67 memset(reinterpret_cast<void*>(&ev), 0, sizeof(ev));
68 struct timeval now;
69 gettimeofday(&now, NULL);
70 // kernel driver is not using time now, but set it to be safe.
71 ev[0].time = now;
72 ev[0].type = EV_KEY;
73 ev[0].code = linuxKeyCode;
74 ev[0].value = (down ? 1 : 0);
75 // force delivery and flushing
76 ev[1].time = now;
77 ev[1].type = EV_SYN;
78 ev[1].code = SYN_REPORT;
79 ev[1].value = 0;
80 ALOGI("injectKeyEvent down %d keyCode %d, value %d", down, ev[0].code, ev[0].value);
81 int r = write(fd, reinterpret_cast<void*>(&ev), sizeof(ev));
82 if (r != sizeof(ev)) {
83 return -EIO;
84 }
85 return 0;
86 }
87
88 static JNINativeMethod gMethods[] = {
89 { "nativeInjectKeyEvent", "(IIZ)I",
90 (void*)com_android_car_CarInputService_nativeInjectKeyEvent },
91 };
92
register_com_android_car_CarInputService(JNIEnv * env)93 int register_com_android_car_CarInputService(JNIEnv *env) {
94 return jniRegisterNativeMethods(env, "com/android/car/CarInputService",
95 gMethods, NELEM(gMethods));
96 }
97
98 } // namespace android
99