Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright 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_TAG "TvRemote-native-uiBridge"
     18 
     19 #include "com_android_server_tv_TvKeys.h"
     20 
     21 #include "jni.h"
     22 #include <android_runtime/AndroidRuntime.h>
     23 #include <nativehelper/ScopedUtfChars.h>
     24 #include <android/keycodes.h>
     25 
     26 #include <utils/BitSet.h>
     27 #include <utils/Errors.h>
     28 #include <utils/misc.h>
     29 #include <utils/Log.h>
     30 #include <utils/String8.h>
     31 
     32 #include <ctype.h>
     33 #include <linux/input.h>
     34 #include <unistd.h>
     35 #include <sys/time.h>
     36 #include <time.h>
     37 #include <stdint.h>
     38 #include <map>
     39 #include <fcntl.h>
     40 #include <linux/uinput.h>
     41 #include <signal.h>
     42 #include <sys/inotify.h>
     43 #include <sys/stat.h>
     44 #include <sys/types.h>
     45 
     46 // Refer to EventHub.h
     47 #define MSC_ANDROID_TIME_SEC 0x6
     48 #define MSC_ANDROID_TIME_USEC 0x7
     49 
     50 #define SLOT_UNKNOWN -1
     51 
     52 namespace android {
     53 
     54 static std::map<int32_t,int> keysMap;
     55 static std::map<int32_t,int32_t> slotsMap;
     56 static BitSet32 mtSlots;
     57 
     58 static void initKeysMap() {
     59     if (keysMap.empty()) {
     60         for (size_t i = 0; i < NELEM(KEYS); i++) {
     61             keysMap[KEYS[i].androidKeyCode] = KEYS[i].linuxKeyCode;
     62         }
     63     }
     64 }
     65 
     66 static int32_t getLinuxKeyCode(int32_t androidKeyCode) {
     67     std::map<int,int>::iterator it = keysMap.find(androidKeyCode);
     68     if (it != keysMap.end()) {
     69         return it->second;
     70     }
     71     return KEY_UNKNOWN;
     72 }
     73 
     74 static int findSlot(int32_t pointerId) {
     75     std::map<int,int>::iterator it = slotsMap.find(pointerId);
     76     if (it != slotsMap.end()) {
     77         return it->second;
     78     }
     79     return SLOT_UNKNOWN;
     80 }
     81 
     82 static int assignSlot(int32_t pointerId) {
     83     if (!mtSlots.isFull()) {
     84         uint32_t slot = mtSlots.markFirstUnmarkedBit();
     85         slotsMap[pointerId] = slot;
     86         return slot;
     87     }
     88     return SLOT_UNKNOWN;
     89 }
     90 
     91 static void unassignSlot(int32_t pointerId) {
     92     int slot = findSlot(pointerId);
     93     if (slot != SLOT_UNKNOWN) {
     94         mtSlots.clearBit(slot);
     95         slotsMap.erase(pointerId);
     96     }
     97 }
     98 
     99 class NativeConnection {
    100 public:
    101     ~NativeConnection();
    102 
    103     static NativeConnection* open(const char* name, const char* uniqueId,
    104             int32_t width, int32_t height, int32_t maxPointerId);
    105 
    106     void sendEvent(int32_t type, int32_t code, int32_t value);
    107 
    108     int32_t getMaxPointers() const { return mMaxPointers; }
    109 
    110 private:
    111     NativeConnection(int fd, int32_t maxPointers);
    112 
    113     const int mFd;
    114     const int32_t mMaxPointers;
    115 };
    116 
    117 NativeConnection::NativeConnection(int fd, int32_t maxPointers) :
    118         mFd(fd), mMaxPointers(maxPointers) {
    119 }
    120 
    121 NativeConnection::~NativeConnection() {
    122     ALOGI("Un-Registering uinput device %d.", mFd);
    123     ioctl(mFd, UI_DEV_DESTROY);
    124     close(mFd);
    125 }
    126 
    127 NativeConnection* NativeConnection::open(const char* name, const char* uniqueId,
    128         int32_t width, int32_t height, int32_t maxPointers) {
    129     ALOGI("Registering uinput device %s: touch pad size %dx%d, "
    130             "max pointers %d.", name, width, height, maxPointers);
    131 
    132     int fd = ::open("/dev/uinput", O_WRONLY | O_NDELAY);
    133     if (fd < 0) {
    134         ALOGE("Cannot open /dev/uinput: %s.", strerror(errno));
    135         return nullptr;
    136     }
    137 
    138     struct uinput_user_dev uinp;
    139     memset(&uinp, 0, sizeof(struct uinput_user_dev));
    140     strlcpy(uinp.name, name, UINPUT_MAX_NAME_SIZE);
    141     uinp.id.version = 1;
    142     uinp.id.bustype = BUS_VIRTUAL;
    143 
    144     // initialize keymap
    145     initKeysMap();
    146 
    147     // write device unique id to the phys property
    148     ioctl(fd, UI_SET_PHYS, uniqueId);
    149 
    150     // set the keys mapped
    151     ioctl(fd, UI_SET_EVBIT, EV_KEY);
    152     for (size_t i = 0; i < NELEM(KEYS); i++) {
    153         ioctl(fd, UI_SET_KEYBIT, KEYS[i].linuxKeyCode);
    154     }
    155 
    156     // set the misc events maps
    157     ioctl(fd, UI_SET_EVBIT, EV_MSC);
    158     ioctl(fd, UI_SET_MSCBIT, MSC_ANDROID_TIME_SEC);
    159     ioctl(fd, UI_SET_MSCBIT, MSC_ANDROID_TIME_USEC);
    160 
    161     // register the input device
    162     if (write(fd, &uinp, sizeof(uinp)) != sizeof(uinp)) {
    163         ALOGE("Cannot write uinput_user_dev to fd %d: %s.", fd, strerror(errno));
    164         close(fd);
    165         return NULL;
    166     }
    167     if (ioctl(fd, UI_DEV_CREATE) != 0) {
    168         ALOGE("Unable to create uinput device: %s.", strerror(errno));
    169         close(fd);
    170         return nullptr;
    171     }
    172 
    173     ALOGV("Created uinput device, fd=%d.", fd);
    174     return new NativeConnection(fd, maxPointers);
    175 }
    176 
    177 void NativeConnection::sendEvent(int32_t type, int32_t code, int32_t value) {
    178     struct input_event iev;
    179     memset(&iev, 0, sizeof(iev));
    180     iev.type = type;
    181     iev.code = code;
    182     iev.value = value;
    183     write(mFd, &iev, sizeof(iev));
    184 }
    185 
    186 
    187 static jlong nativeOpen(JNIEnv* env, jclass clazz,
    188         jstring nameStr, jstring uniqueIdStr,
    189         jint width, jint height, jint maxPointers) {
    190     ScopedUtfChars name(env, nameStr);
    191     ScopedUtfChars uniqueId(env, uniqueIdStr);
    192 
    193     NativeConnection* connection = NativeConnection::open(name.c_str(), uniqueId.c_str(),
    194             width, height, maxPointers);
    195     return reinterpret_cast<jlong>(connection);
    196 }
    197 
    198 static void nativeClose(JNIEnv* env, jclass clazz, jlong ptr) {
    199     NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr);
    200     delete connection;
    201 }
    202 
    203 static void nativeSendTimestamp(JNIEnv* env, jclass clazz, jlong ptr, jlong timestamp) {
    204     NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr);
    205 
    206     connection->sendEvent(EV_MSC, MSC_ANDROID_TIME_SEC, timestamp / 1000L);
    207     connection->sendEvent(EV_MSC, MSC_ANDROID_TIME_USEC, (timestamp % 1000L) * 1000L);
    208 }
    209 
    210 static void nativeSendKey(JNIEnv* env, jclass clazz, jlong ptr, jint keyCode, jboolean down) {
    211     int32_t code = getLinuxKeyCode(keyCode);
    212     NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr);
    213     if (code != KEY_UNKNOWN) {
    214         connection->sendEvent(EV_KEY, code, down ? 1 : 0);
    215     } else {
    216         ALOGE("Received an unknown keycode of %d.", keyCode);
    217     }
    218 }
    219 
    220 static void nativeSendPointerDown(JNIEnv* env, jclass clazz, jlong ptr,
    221         jint pointerId, jint x, jint y) {
    222     NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr);
    223 
    224     int32_t slot = findSlot(pointerId);
    225     if (slot == SLOT_UNKNOWN) {
    226         slot = assignSlot(pointerId);
    227     }
    228     if (slot != SLOT_UNKNOWN) {
    229         connection->sendEvent(EV_ABS, ABS_MT_SLOT, slot);
    230         connection->sendEvent(EV_ABS, ABS_MT_TRACKING_ID, pointerId);
    231         connection->sendEvent(EV_ABS, ABS_MT_POSITION_X, x);
    232         connection->sendEvent(EV_ABS, ABS_MT_POSITION_Y, y);
    233     }
    234 }
    235 
    236 static void nativeSendPointerUp(JNIEnv* env, jclass clazz, jlong ptr,
    237         jint pointerId) {
    238     NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr);
    239 
    240     int32_t slot = findSlot(pointerId);
    241     if (slot != SLOT_UNKNOWN) {
    242         connection->sendEvent(EV_ABS, ABS_MT_SLOT, slot);
    243         connection->sendEvent(EV_ABS, ABS_MT_TRACKING_ID, -1);
    244         unassignSlot(pointerId);
    245     }
    246 }
    247 
    248 static void nativeSendPointerSync(JNIEnv* env, jclass clazz, jlong ptr) {
    249     NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr);
    250     connection->sendEvent(EV_SYN, SYN_REPORT, 0);
    251 }
    252 
    253 static void nativeClear(JNIEnv* env, jclass clazz, jlong ptr) {
    254     NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr);
    255 
    256     // Clear keys.
    257     for (size_t i = 0; i < NELEM(KEYS); i++) {
    258         connection->sendEvent(EV_KEY, KEYS[i].linuxKeyCode, 0);
    259     }
    260 
    261     // Clear pointers.
    262     int32_t slot = SLOT_UNKNOWN;
    263     for (int32_t i = 0; i < connection->getMaxPointers(); i++) {
    264         slot = findSlot(i);
    265         if (slot != SLOT_UNKNOWN) {
    266             connection->sendEvent(EV_ABS, ABS_MT_SLOT, slot);
    267             connection->sendEvent(EV_ABS, ABS_MT_TRACKING_ID, -1);
    268         }
    269     }
    270 
    271     // Sync pointer events
    272     connection->sendEvent(EV_SYN, SYN_REPORT, 0);
    273 }
    274 
    275 /*
    276  * JNI registration
    277  */
    278 
    279 static JNINativeMethod gUinputBridgeMethods[] = {
    280     { "nativeOpen", "(Ljava/lang/String;Ljava/lang/String;III)J",
    281         (void*)nativeOpen },
    282     { "nativeClose", "(J)V",
    283         (void*)nativeClose },
    284     { "nativeSendTimestamp", "(JJ)V",
    285         (void*)nativeSendTimestamp },
    286     { "nativeSendKey", "(JIZ)V",
    287         (void*)nativeSendKey },
    288     { "nativeSendPointerDown", "(JIII)V",
    289         (void*)nativeSendPointerDown },
    290     { "nativeSendPointerUp", "(JI)V",
    291         (void*)nativeSendPointerUp },
    292     { "nativeClear", "(J)V",
    293         (void*)nativeClear },
    294     { "nativeSendPointerSync", "(J)V",
    295         (void*)nativeSendPointerSync },
    296 };
    297 
    298 int register_android_server_tv_TvUinputBridge(JNIEnv* env) {
    299     int res = jniRegisterNativeMethods(env, "com/android/server/tv/UinputBridge",
    300               gUinputBridgeMethods, NELEM(gUinputBridgeMethods));
    301 
    302     LOG_FATAL_IF(res < 0, "Unable to register native methods.");
    303     (void)res; // Don't complain about unused variable in the LOG_NDEBUG case
    304 
    305     return 0;
    306 }
    307 
    308 } // namespace android
    309