11f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright/* 21f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright * Copyright (C) 2015 The Android Open Source Project 31f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright * 41f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright * Licensed under the Apache License, Version 2.0 (the "License"); 51f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright * you may not use this file except in compliance with the License. 61f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright * You may obtain a copy of the License at 71f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright * 81f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright * http://www.apache.org/licenses/LICENSE-2.0 91f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright * 101f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright * Unless required by applicable law or agreed to in writing, software 111f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright * distributed under the License is distributed on an "AS IS" BASIS, 121f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright * See the License for the specific language governing permissions and 141f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright * limitations under the License. 151f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright */ 161f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 171f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright#define LOG_TAG "HidCommandDevice" 181f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 191f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright#include "com_android_commands_hid_Device.h" 201f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 211f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright#include <linux/uhid.h> 221f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 231f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright#include <fcntl.h> 241f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright#include <cstdio> 251f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright#include <cstring> 261f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright#include <memory> 271f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright#include <unistd.h> 281f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 291f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright#include <jni.h> 30c95dca8ce1bc58a015a938afcfc3e595d1bca16bSteven Moreland#include <nativehelper/JNIHelp.h> 31c95dca8ce1bc58a015a938afcfc3e595d1bca16bSteven Moreland#include <nativehelper/ScopedPrimitiveArray.h> 3265e2ca280897dd9902b8aeba7edd6cbe44e3aef3Steven Moreland#include <nativehelper/ScopedUtfChars.h> 3355656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou#include <android/looper.h> 3455656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou#include <android/log.h> 3555656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou 3655656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) 3755656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__) 3855656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__) 3955656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) 401f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 411f2c7688c1f673790d61645632ae5e1838f021a4Michael Wrightnamespace android { 421f2c7688c1f673790d61645632ae5e1838f021a4Michael Wrightnamespace uhid { 431f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 441f2c7688c1f673790d61645632ae5e1838f021a4Michael Wrightstatic const char* UHID_PATH = "/dev/uhid"; 451f2c7688c1f673790d61645632ae5e1838f021a4Michael Wrightstatic const size_t UHID_MAX_NAME_LENGTH = 128; 461f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 471f2c7688c1f673790d61645632ae5e1838f021a4Michael Wrightstatic struct { 481f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright jmethodID onDeviceOpen; 491f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright jmethodID onDeviceError; 501f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright} gDeviceCallbackClassInfo; 511f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 521c8cbb54407b9c1d56626de80a796a395012a92cAurimas Liutikasstatic int handleLooperEvents(int /* fd */, int events, void* data) { 531f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright Device* d = reinterpret_cast<Device*>(data); 541f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright return d->handleEvents(events); 551f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright} 561f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 571f2c7688c1f673790d61645632ae5e1838f021a4Michael Wrightstatic void checkAndClearException(JNIEnv* env, const char* methodName) { 581f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright if (env->ExceptionCheck()) { 5955656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou LOGE("An exception was thrown by callback '%s'.", methodName); 601f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright env->ExceptionClear(); 611f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright } 621f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright} 631f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 641f2c7688c1f673790d61645632ae5e1838f021a4Michael WrightDeviceCallback::DeviceCallback(JNIEnv* env, jobject callback) : 6555656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou mCallbackObject(env->NewGlobalRef(callback)) { 6655656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou env->GetJavaVM(&mJavaVM); 6755656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou } 681f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 691f2c7688c1f673790d61645632ae5e1838f021a4Michael WrightDeviceCallback::~DeviceCallback() { 7055656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou JNIEnv* env = getJNIEnv(); 711f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright env->DeleteGlobalRef(mCallbackObject); 721f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright} 731f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 741f2c7688c1f673790d61645632ae5e1838f021a4Michael Wrightvoid DeviceCallback::onDeviceError() { 7555656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou JNIEnv* env = getJNIEnv(); 761f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceError); 771f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright checkAndClearException(env, "onDeviceError"); 781f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright} 791f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 801f2c7688c1f673790d61645632ae5e1838f021a4Michael Wrightvoid DeviceCallback::onDeviceOpen() { 8155656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou JNIEnv* env = getJNIEnv(); 821f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceOpen); 831f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright checkAndClearException(env, "onDeviceOpen"); 841f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright} 851f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 8655656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei VishniakouJNIEnv* DeviceCallback::getJNIEnv() { 8755656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou JNIEnv* env; 8855656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou mJavaVM->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6); 8955656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou return env; 9055656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou} 9155656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou 921f2c7688c1f673790d61645632ae5e1838f021a4Michael WrightDevice* Device::open(int32_t id, const char* name, int32_t vid, int32_t pid, 931f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright std::unique_ptr<uint8_t[]> descriptor, size_t descriptorSize, 9455656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou std::unique_ptr<DeviceCallback> callback) { 951f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 961f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright int fd = ::open(UHID_PATH, O_RDWR | O_CLOEXEC); 971f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright if (fd < 0) { 9855656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou LOGE("Failed to open uhid: %s", strerror(errno)); 991f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright return nullptr; 1001f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright } 1011f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 1021f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright struct uhid_event ev; 1031f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright memset(&ev, 0, sizeof(ev)); 10455656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou ev.type = UHID_CREATE2; 10555656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou strncpy((char*)ev.u.create2.name, name, UHID_MAX_NAME_LENGTH); 10655656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou memcpy(&ev.u.create2.rd_data, descriptor.get(), 10755656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou descriptorSize * sizeof(ev.u.create2.rd_data[0])); 10855656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou ev.u.create2.rd_size = descriptorSize; 10955656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou ev.u.create2.bus = BUS_BLUETOOTH; 11055656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou ev.u.create2.vendor = vid; 11155656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou ev.u.create2.product = pid; 11255656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou ev.u.create2.version = 0; 11355656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou ev.u.create2.country = 0; 1141f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 1151f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright errno = 0; 1161f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright ssize_t ret = TEMP_FAILURE_RETRY(::write(fd, &ev, sizeof(ev))); 1171f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright if (ret < 0 || ret != sizeof(ev)) { 1181f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright ::close(fd); 11955656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou LOGE("Failed to create uhid node: %s", strerror(errno)); 1201f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright return nullptr; 1211f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright } 1221f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 1231f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright // Wait for the device to actually be created. 1241f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright ret = TEMP_FAILURE_RETRY(::read(fd, &ev, sizeof(ev))); 1251f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright if (ret < 0 || ev.type != UHID_START) { 1261f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright ::close(fd); 12755656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou LOGE("uhid node failed to start: %s", strerror(errno)); 1281f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright return nullptr; 1291f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright } 13055656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou return new Device(id, fd, std::move(callback)); 1311f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright} 1321f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 13355656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei VishniakouDevice::Device(int32_t id, int fd, std::unique_ptr<DeviceCallback> callback) : 13455656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou mId(id), mFd(fd), mDeviceCallback(std::move(callback)) { 13555656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou ALooper* aLooper = ALooper_forThread(); 13655656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou if (aLooper == NULL) { 13755656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou LOGE("Could not get ALooper, ALooper_forThread returned NULL"); 13855656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou aLooper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS); 13955656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou } 14055656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou ALooper_addFd(aLooper, fd, 0, ALOOPER_EVENT_INPUT, handleLooperEvents, 14155656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou reinterpret_cast<void*>(this)); 1421f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright} 1431f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 1441f2c7688c1f673790d61645632ae5e1838f021a4Michael WrightDevice::~Device() { 14555656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou ALooper* looper = ALooper_forThread(); 14655656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou if (looper != NULL) { 14755656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou ALooper_removeFd(looper, mFd); 14855656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou } else { 14955656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou LOGE("Could not remove fd, ALooper_forThread() returned NULL!"); 15055656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou } 1511f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright struct uhid_event ev; 1521f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright memset(&ev, 0, sizeof(ev)); 1531f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright ev.type = UHID_DESTROY; 1541f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright TEMP_FAILURE_RETRY(::write(mFd, &ev, sizeof(ev))); 1551f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright ::close(mFd); 1561f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright mFd = -1; 1571f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright} 1581f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 1591f2c7688c1f673790d61645632ae5e1838f021a4Michael Wrightvoid Device::sendReport(uint8_t* report, size_t reportSize) { 1601f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright struct uhid_event ev; 1611f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright memset(&ev, 0, sizeof(ev)); 16255656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou ev.type = UHID_INPUT2; 16355656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou ev.u.input2.size = reportSize; 16455656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou memcpy(&ev.u.input2.data, report, reportSize); 1651f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright ssize_t ret = TEMP_FAILURE_RETRY(::write(mFd, &ev, sizeof(ev))); 1661f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright if (ret < 0 || ret != sizeof(ev)) { 16755656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou LOGE("Failed to send hid event: %s", strerror(errno)); 1681f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright } 1691f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright} 1701f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 1711f2c7688c1f673790d61645632ae5e1838f021a4Michael Wrightint Device::handleEvents(int events) { 17255656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) { 17355656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou LOGE("uhid node was closed or an error occurred. events=0x%x", events); 1741f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright mDeviceCallback->onDeviceError(); 1751f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright return 0; 1761f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright } 1771f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright struct uhid_event ev; 1781f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright ssize_t ret = TEMP_FAILURE_RETRY(::read(mFd, &ev, sizeof(ev))); 1791f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright if (ret < 0) { 18055656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou LOGE("Failed to read from uhid node: %s", strerror(errno)); 1811f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright mDeviceCallback->onDeviceError(); 1821f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright return 0; 1831f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright } 1841f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 1851f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright if (ev.type == UHID_OPEN) { 1861f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright mDeviceCallback->onDeviceOpen(); 1871f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright } 1881f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 1891f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright return 1; 1901f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright} 1911f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 1921f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright} // namespace uhid 1931f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 1941f2c7688c1f673790d61645632ae5e1838f021a4Michael Wrightstd::unique_ptr<uint8_t[]> getData(JNIEnv* env, jbyteArray javaArray, size_t& outSize) { 1951f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright ScopedByteArrayRO scopedArray(env, javaArray); 1961f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright outSize = scopedArray.size(); 1971f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright std::unique_ptr<uint8_t[]> data(new uint8_t[outSize]); 1981f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright for (size_t i = 0; i < outSize; i++) { 1991f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright data[i] = static_cast<uint8_t>(scopedArray[i]); 2001f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright } 2011f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright return data; 2021f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright} 2031f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 2041c8cbb54407b9c1d56626de80a796a395012a92cAurimas Liutikasstatic jlong openDevice(JNIEnv* env, jclass /* clazz */, jstring rawName, jint id, jint vid, jint pid, 20555656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou jbyteArray rawDescriptor, jobject callback) { 2061f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright ScopedUtfChars name(env, rawName); 2071f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright if (name.c_str() == nullptr) { 2081f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright return 0; 2091f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright } 2101f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 2111f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright size_t size; 2121f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright std::unique_ptr<uint8_t[]> desc = getData(env, rawDescriptor, size); 2131f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 2141f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright std::unique_ptr<uhid::DeviceCallback> cb(new uhid::DeviceCallback(env, callback)); 2151f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 2161f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright uhid::Device* d = uhid::Device::open( 2171f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright id, reinterpret_cast<const char*>(name.c_str()), vid, pid, 21855656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou std::move(desc), size, std::move(cb)); 2191f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright return reinterpret_cast<jlong>(d); 2201f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright} 2211f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 22255656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakoustatic void sendReport(JNIEnv* env, jclass /* clazz */, jlong ptr, jbyteArray rawReport) { 2231f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright size_t size; 2241f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright std::unique_ptr<uint8_t[]> report = getData(env, rawReport, size); 2251f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright uhid::Device* d = reinterpret_cast<uhid::Device*>(ptr); 2261f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright if (d) { 2271f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright d->sendReport(report.get(), size); 22855656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou } else { 22955656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou LOGE("Could not send report, Device* is null!"); 2301f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright } 2311f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright} 2321f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 2331c8cbb54407b9c1d56626de80a796a395012a92cAurimas Liutikasstatic void closeDevice(JNIEnv* /* env */, jclass /* clazz */, jlong ptr) { 2341f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright uhid::Device* d = reinterpret_cast<uhid::Device*>(ptr); 2351f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright if (d) { 2361f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright delete d; 2371f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright } 2381f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright} 2391f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 2401f2c7688c1f673790d61645632ae5e1838f021a4Michael Wrightstatic JNINativeMethod sMethods[] = { 2411f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright { "nativeOpenDevice", 24255656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou "(Ljava/lang/String;III[B" 2431f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright "Lcom/android/commands/hid/Device$DeviceCallback;)J", 2441f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright reinterpret_cast<void*>(openDevice) }, 2451f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright { "nativeSendReport", "(J[B)V", reinterpret_cast<void*>(sendReport) }, 2461f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright { "nativeCloseDevice", "(J)V", reinterpret_cast<void*>(closeDevice) }, 2471f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright}; 2481f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 2491f2c7688c1f673790d61645632ae5e1838f021a4Michael Wrightint register_com_android_commands_hid_Device(JNIEnv* env) { 25055656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou jclass clazz = env->FindClass("com/android/commands/hid/Device$DeviceCallback"); 25155656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou if (clazz == NULL) { 25255656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou LOGE("Unable to find class 'DeviceCallback'"); 25355656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou return JNI_ERR; 25455656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou } 2551f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright uhid::gDeviceCallbackClassInfo.onDeviceOpen = 25655656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou env->GetMethodID(clazz, "onDeviceOpen", "()V"); 25755656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou uhid::gDeviceCallbackClassInfo.onDeviceError = 25855656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou env->GetMethodID(clazz, "onDeviceError", "()V"); 25955656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou if (uhid::gDeviceCallbackClassInfo.onDeviceOpen == NULL || 26055656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou uhid::gDeviceCallbackClassInfo.onDeviceError == NULL) { 26155656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou LOGE("Unable to obtain onDeviceOpen or onDeviceError methods"); 26255656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou return JNI_ERR; 26355656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou } 26455656e4cb923d1aeef4445b3aaa3a6ce3f35c90aSiarhei Vishniakou 2651f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright return jniRegisterNativeMethods(env, "com/android/commands/hid/Device", 2661f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright sMethods, NELEM(sMethods)); 2671f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright} 2681f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 2691f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright} // namespace android 2701f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 2711f2c7688c1f673790d61645632ae5e1838f021a4Michael Wrightjint JNI_OnLoad(JavaVM* jvm, void*) { 2721f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright JNIEnv *env = NULL; 2731f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright if (jvm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6)) { 2741f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright return JNI_ERR; 2751f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright } 2761f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 2771f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright if (android::register_com_android_commands_hid_Device(env) < 0 ){ 2781f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright return JNI_ERR; 2791f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright } 2801f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright 2811f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright return JNI_VERSION_1_6; 2821f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright} 283