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