com_android_commands_hid_Device.cpp revision 1f2c7688c1f673790d61645632ae5e1838f021a4
13885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam/*
23885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * Copyright (C) 2015 The Android Open Source Project
33885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam *
43885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * Licensed under the Apache License, Version 2.0 (the "License");
53885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * you may not use this file except in compliance with the License.
63885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * You may obtain a copy of the License at
73885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam *
83885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam *      http://www.apache.org/licenses/LICENSE-2.0
93885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam *
103885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * Unless required by applicable law or agreed to in writing, software
113885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * distributed under the License is distributed on an "AS IS" BASIS,
123885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * See the License for the specific language governing permissions and
143885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam * limitations under the License.
153885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam */
163885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam
173885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam#define LOG_TAG "HidCommandDevice"
183885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam
193885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam#include "com_android_commands_hid_Device.h"
203885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam
213885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam#include <linux/uhid.h>
223885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam
233885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam#include <fcntl.h>
243885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam#include <cstdio>
253885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam#include <cstring>
263885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam#include <memory>
273885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam#include <unistd.h>
283885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam
293885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam#include <android_runtime/AndroidRuntime.h>
303885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam#include <android_runtime/Log.h>
313885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam#include <android_os_MessageQueue.h>
323885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam#include <core_jni_helpers.h>
333885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam#include <jni.h>
343885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam#include <JNIHelp.h>
353885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam#include <ScopedPrimitiveArray.h>
363885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam#include <ScopedUtfChars.h>
373885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam#include <utils/Log.h>
383885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam#include <utils/Looper.h>
393885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam#include <utils/StrongPointer.h>
403885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam
413885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamnamespace android {
423885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamnamespace uhid {
433885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam
443885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamstatic const char* UHID_PATH = "/dev/uhid";
453885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamstatic const size_t UHID_MAX_NAME_LENGTH = 128;
463885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam
473885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamstatic struct {
483885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    jmethodID onDeviceOpen;
493885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    jmethodID onDeviceError;
503885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam} gDeviceCallbackClassInfo;
513885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam
523885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamstatic int handleLooperEvents(int fd, int events, void* data) {
53ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam    Device* d = reinterpret_cast<Device*>(data);
543885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    return d->handleEvents(events);
553885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam}
563885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam
573885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamstatic void checkAndClearException(JNIEnv* env, const char* methodName) {
583885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    if (env->ExceptionCheck()) {
593885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam        ALOGE("An exception was thrown by callback '%s'.", methodName);
603885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam        LOGE_EX(env);
613885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam        env->ExceptionClear();
623885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    }
633885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam}
643885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam
653885d8491a008281d18ddbbabc5b8e26848fadccMaurice LamDeviceCallback::DeviceCallback(JNIEnv* env, jobject callback) :
663885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    mCallbackObject(env->NewGlobalRef(callback)) { }
673885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam
683885d8491a008281d18ddbbabc5b8e26848fadccMaurice LamDeviceCallback::~DeviceCallback() {
693885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    JNIEnv* env = AndroidRuntime::getJNIEnv();
703885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    env->DeleteGlobalRef(mCallbackObject);
713885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam}
723885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam
733885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamvoid DeviceCallback::onDeviceError() {
743885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    JNIEnv* env = AndroidRuntime::getJNIEnv();
753885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceError);
763885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    checkAndClearException(env, "onDeviceError");
773885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam}
783885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam
793885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamvoid DeviceCallback::onDeviceOpen() {
803885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    JNIEnv* env = AndroidRuntime::getJNIEnv();
813885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceOpen);
823885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    checkAndClearException(env, "onDeviceOpen");
833885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam}
843885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam
853885d8491a008281d18ddbbabc5b8e26848fadccMaurice LamDevice* Device::open(int32_t id, const char* name, int32_t vid, int32_t pid,
863885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam        std::unique_ptr<uint8_t[]> descriptor, size_t descriptorSize,
873885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam        std::unique_ptr<DeviceCallback> callback, sp<Looper> looper) {
883885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam
893885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    int fd = ::open(UHID_PATH, O_RDWR | O_CLOEXEC);
903885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    if (fd < 0) {
913885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam        ALOGE("Failed to open uhid: %s", strerror(errno));
923885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam        return nullptr;
933885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    }
943885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam
953885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    struct uhid_event ev;
963885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    memset(&ev, 0, sizeof(ev));
973885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    ev.type = UHID_CREATE;
983885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    strncpy((char*)ev.u.create.name, name, UHID_MAX_NAME_LENGTH);
993885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    ev.u.create.rd_data = descriptor.get();
1003885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    ev.u.create.rd_size = descriptorSize;
1013885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    ev.u.create.bus = BUS_BLUETOOTH;
1023885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    ev.u.create.vendor = vid;
1033885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    ev.u.create.product = pid;
1043885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    ev.u.create.version = 0;
1053885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    ev.u.create.country = 0;
1063885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam
1073885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    errno = 0;
1083885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    ssize_t ret = TEMP_FAILURE_RETRY(::write(fd, &ev, sizeof(ev)));
1093885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    if (ret < 0 || ret != sizeof(ev)) {
1103885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam        ::close(fd);
1113885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam        ALOGE("Failed to create uhid node: %s", strerror(errno));
1123885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam        return nullptr;
1133885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    }
1143885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam
1153885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    // Wait for the device to actually be created.
1163885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    ret = TEMP_FAILURE_RETRY(::read(fd, &ev, sizeof(ev)));
1173885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    if (ret < 0 || ev.type != UHID_START) {
1183885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam        ::close(fd);
1193885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam        ALOGE("uhid node failed to start: %s", strerror(errno));
1203885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam        return nullptr;
1213885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    }
1223885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam
1233885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    return new Device(id, fd, std::move(callback), looper);
1243885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam}
1253885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam
1263885d8491a008281d18ddbbabc5b8e26848fadccMaurice LamDevice::Device(int32_t id, int fd, std::unique_ptr<DeviceCallback> callback, sp<Looper> looper) :
1273885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam            mId(id), mFd(fd), mDeviceCallback(std::move(callback)), mLooper(looper) {
1283885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    looper->addFd(fd, 0, Looper::EVENT_INPUT, handleLooperEvents, reinterpret_cast<void*>(this));
1293885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam}
1303885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam
1313885d8491a008281d18ddbbabc5b8e26848fadccMaurice LamDevice::~Device() {
1323885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    mLooper->removeFd(mFd);
1333885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    struct uhid_event ev;
1343885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    memset(&ev, 0, sizeof(ev));
1353885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    ev.type = UHID_DESTROY;
1363885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    TEMP_FAILURE_RETRY(::write(mFd, &ev, sizeof(ev)));
1373885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    ::close(mFd);
1383885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    mFd = -1;
1393885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam}
140ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam
1413885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamvoid Device::sendReport(uint8_t* report, size_t reportSize) {
1423885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    struct uhid_event ev;
1433885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    memset(&ev, 0, sizeof(ev));
1443885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    ev.type = UHID_INPUT;
1453885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    ev.u.input.size = reportSize;
1463885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    memcpy(&ev.u.input.data, report, reportSize);
1473885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    ssize_t ret = TEMP_FAILURE_RETRY(::write(mFd, &ev, sizeof(ev)));
1483885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    if (ret < 0 || ret != sizeof(ev)) {
1493885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam        ALOGE("Failed to send hid event: %s", strerror(errno));
1503885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    }
1513885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam}
1523885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam
1533885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamint Device::handleEvents(int events) {
1543885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
155ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam        ALOGE("uhid node was closed or an error occurred. events=0x%x", events);
156ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam        mDeviceCallback->onDeviceError();
157ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam        return 0;
158ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam    }
159ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam    struct uhid_event ev;
160ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam    ssize_t ret = TEMP_FAILURE_RETRY(::read(mFd, &ev, sizeof(ev)));
1613885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    if (ret < 0) {
162ec9d8c8aa8fdeb6640fb0037b062bf10ca1c016bMaurice Lam        ALOGE("Failed to read from uhid node: %s", strerror(errno));
1633885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam        mDeviceCallback->onDeviceError();
1643885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam        return 0;
1653885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    }
1663885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam
1673885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    if (ev.type == UHID_OPEN) {
1683885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam        mDeviceCallback->onDeviceOpen();
1693885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    }
1703885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam
1713885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    return 1;
1723885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam}
1733885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam
1743885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam} // namespace uhid
1753885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam
1763885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamstd::unique_ptr<uint8_t[]> getData(JNIEnv* env, jbyteArray javaArray, size_t& outSize) {
1773885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    ScopedByteArrayRO scopedArray(env, javaArray);
1783885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    outSize = scopedArray.size();
1793885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    std::unique_ptr<uint8_t[]> data(new uint8_t[outSize]);
1803885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    for (size_t i = 0; i < outSize; i++) {
1813885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam        data[i] = static_cast<uint8_t>(scopedArray[i]);
1823885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    }
1833885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    return data;
1843885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam}
1853885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam
1863885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamstatic jlong openDevice(JNIEnv* env, jclass clazz, jstring rawName, jint id, jint vid, jint pid,
1873885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam        jbyteArray rawDescriptor, jobject queue, jobject callback) {
1883885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    ScopedUtfChars name(env, rawName);
1893885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    if (name.c_str() == nullptr) {
1903885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam        return 0;
1913885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    }
1923885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam
1933885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    size_t size;
1943885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    std::unique_ptr<uint8_t[]> desc = getData(env, rawDescriptor, size);
1953885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam
1963885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    std::unique_ptr<uhid::DeviceCallback> cb(new uhid::DeviceCallback(env, callback));
1973885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    sp<Looper> looper = android_os_MessageQueue_getMessageQueue(env, queue)->getLooper();
1983885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam
1993885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    uhid::Device* d = uhid::Device::open(
2003885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam            id, reinterpret_cast<const char*>(name.c_str()), vid, pid,
2013885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam            std::move(desc), size, std::move(cb), std::move(looper));
2023885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    return reinterpret_cast<jlong>(d);
2033885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam}
2043885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam
2053885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lamstatic void sendReport(JNIEnv* env, jclass clazz, jlong ptr,jbyteArray rawReport) {
2063885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    size_t size;
2073885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    std::unique_ptr<uint8_t[]> report = getData(env, rawReport, size);
2083885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    uhid::Device* d = reinterpret_cast<uhid::Device*>(ptr);
2093885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    if (d) {
2103885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam        d->sendReport(report.get(), size);
2113885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam    }
2123885d8491a008281d18ddbbabc5b8e26848fadccMaurice Lam}
213
214static void closeDevice(JNIEnv* env, jclass clazz, jlong ptr) {
215    uhid::Device* d = reinterpret_cast<uhid::Device*>(ptr);
216    if (d) {
217        delete d;
218    }
219}
220
221static JNINativeMethod sMethods[] = {
222    { "nativeOpenDevice",
223            "(Ljava/lang/String;III[BLandroid/os/MessageQueue;"
224            "Lcom/android/commands/hid/Device$DeviceCallback;)J",
225            reinterpret_cast<void*>(openDevice) },
226    { "nativeSendReport", "(J[B)V", reinterpret_cast<void*>(sendReport) },
227    { "nativeCloseDevice", "(J)V", reinterpret_cast<void*>(closeDevice) },
228};
229
230int register_com_android_commands_hid_Device(JNIEnv* env) {
231    jclass clazz = FindClassOrDie(env, "com/android/commands/hid/Device$DeviceCallback");
232    uhid::gDeviceCallbackClassInfo.onDeviceOpen =
233            GetMethodIDOrDie(env, clazz, "onDeviceOpen", "()V");
234    uhid::gDeviceCallbackClassInfo.onDeviceError=
235            GetMethodIDOrDie(env, clazz, "onDeviceError", "()V");
236    return jniRegisterNativeMethods(env, "com/android/commands/hid/Device",
237            sMethods, NELEM(sMethods));
238}
239
240} // namespace android
241
242jint JNI_OnLoad(JavaVM* jvm, void*) {
243    JNIEnv *env = NULL;
244    if (jvm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6)) {
245        return JNI_ERR;
246    }
247
248    if (android::register_com_android_commands_hid_Device(env) < 0 ){
249        return JNI_ERR;
250    }
251
252    return JNI_VERSION_1_6;
253}
254