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