Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 51f4fb2b authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Support for SensorHeadTrackerTest on Hid command"

parents 0d6c423c f532c911
Loading
Loading
Loading
Loading
+32 −17
Original line number Diff line number Diff line
@@ -18,24 +18,22 @@

#include "com_android_commands_hid_Device.h"

#include <linux/uhid.h>

#include <android-base/stringprintf.h>
#include <android/looper.h>
#include <fcntl.h>
#include <inttypes.h>
#include <unistd.h>
#include <cstdio>
#include <cstring>
#include <memory>

#include <android/looper.h>
#include <jni.h>
#include <linux/uhid.h>
#include <log/log.h>
#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedLocalRef.h>
#include <nativehelper/ScopedPrimitiveArray.h>
#include <nativehelper/ScopedUtfChars.h>
#include <unistd.h>

#include <android-base/stringprintf.h>
#include <cstdio>
#include <cstring>
#include <memory>

// Log debug messages about the output.
static constexpr bool DEBUG_OUTPUT = false;
@@ -109,15 +107,15 @@ void DeviceCallback::onDeviceOpen() {

void DeviceCallback::onDeviceGetReport(uint32_t requestId, uint8_t reportId) {
    JNIEnv* env = getJNIEnv();
    env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceGetReport,
            requestId, reportId);
    env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceGetReport, requestId,
                        reportId);
    checkAndClearException(env, "onDeviceGetReport");
}

void DeviceCallback::onDeviceSetReport(uint8_t rType,
void DeviceCallback::onDeviceSetReport(uint32_t id, uint8_t rType,
                                       const std::vector<uint8_t>& data) {
    JNIEnv* env = getJNIEnv();
    env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceSetReport, rType,
    env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceSetReport, id, rType,
                        toJbyteArray(env, data).get());
    checkAndClearException(env, "onDeviceSetReport");
}
@@ -236,6 +234,14 @@ void Device::sendGetFeatureReportReply(uint32_t id, const std::vector<uint8_t>&
    writeEvent(mFd, ev, "UHID_GET_REPORT_REPLY");
}

void Device::sendSetReportReply(uint32_t id, bool success) const {
    struct uhid_event ev = {};
    ev.type = UHID_SET_REPORT_REPLY;
    ev.u.set_report_reply.id = id;
    ev.u.set_report_reply.err = success ? 0 : EIO;
    writeEvent(mFd, ev, "UHID_SET_REPORT_REPLY");
}

int Device::handleEvents(int events) {
    if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
        ALOGE("uhid node was closed or an error occurred. events=0x%x", events);
@@ -249,7 +255,6 @@ int Device::handleEvents(int events) {
        mDeviceCallback->onDeviceError();
        return 0;
    }

    switch (ev.type) {
        case UHID_OPEN: {
            mDeviceCallback->onDeviceOpen();
@@ -271,7 +276,7 @@ int Device::handleEvents(int events) {
                ALOGD("Received SET_REPORT: id=%" PRIu32 " rnum=%" PRIu8 " data=%s", set_report.id,
                      set_report.rnum, toString(data).c_str());
            }
            mDeviceCallback->onDeviceSetReport(set_report.rtype, data);
            mDeviceCallback->onDeviceSetReport(set_report.id, set_report.rtype, data);
            break;
        }
        case UHID_OUTPUT: {
@@ -347,6 +352,15 @@ static void sendGetFeatureReportReply(JNIEnv* env, jclass /* clazz */, jlong ptr
    }
}

static void sendSetReportReply(JNIEnv*, jclass /* clazz */, jlong ptr, jint id, jboolean success) {
    uhid::Device* d = reinterpret_cast<uhid::Device*>(ptr);
    if (d) {
        d->sendSetReportReply(id, success);
    } else {
        ALOGE("Could not send set report reply, Device* is null!");
    }
}

static void closeDevice(JNIEnv* /* env */, jclass /* clazz */, jlong ptr) {
    uhid::Device* d = reinterpret_cast<uhid::Device*>(ptr);
    if (d) {
@@ -362,6 +376,7 @@ static JNINativeMethod sMethods[] = {
        {"nativeSendReport", "(J[B)V", reinterpret_cast<void*>(sendReport)},
        {"nativeSendGetFeatureReportReply", "(JI[B)V",
         reinterpret_cast<void*>(sendGetFeatureReportReply)},
        {"nativeSendSetReportReply", "(JIZ)V", reinterpret_cast<void*>(sendSetReportReply)},
        {"nativeCloseDevice", "(J)V", reinterpret_cast<void*>(closeDevice)},
};

@@ -376,7 +391,7 @@ int register_com_android_commands_hid_Device(JNIEnv* env) {
    uhid::gDeviceCallbackClassInfo.onDeviceGetReport =
            env->GetMethodID(clazz, "onDeviceGetReport", "(II)V");
    uhid::gDeviceCallbackClassInfo.onDeviceSetReport =
            env->GetMethodID(clazz, "onDeviceSetReport", "(B[B)V");
            env->GetMethodID(clazz, "onDeviceSetReport", "(IB[B)V");
    uhid::gDeviceCallbackClassInfo.onDeviceOutput =
            env->GetMethodID(clazz, "onDeviceOutput", "(B[B)V");
    uhid::gDeviceCallbackClassInfo.onDeviceError =
+5 −6
Original line number Diff line number Diff line
@@ -14,12 +14,11 @@
 * limitations under the License.
 */

#include <memory>
#include <vector>

#include <android-base/unique_fd.h>
#include <jni.h>

#include <android-base/unique_fd.h>
#include <memory>
#include <vector>

namespace android {
namespace uhid {
@@ -31,7 +30,7 @@ public:

    void onDeviceOpen();
    void onDeviceGetReport(uint32_t requestId, uint8_t reportId);
    void onDeviceSetReport(uint8_t rType, const std::vector<uint8_t>& data);
    void onDeviceSetReport(uint32_t id, uint8_t rType, const std::vector<uint8_t>& data);
    void onDeviceOutput(uint8_t rType, const std::vector<uint8_t>& data);
    void onDeviceError();

@@ -50,9 +49,9 @@ public:
    ~Device();

    void sendReport(const std::vector<uint8_t>& report) const;
    void sendSetReportReply(uint32_t id, bool success) const;
    void sendGetFeatureReportReply(uint32_t id, const std::vector<uint8_t>& report) const;
    void close();

    int handleEvents(int events);

private:
+73 −15
Original line number Diff line number Diff line
@@ -42,7 +42,8 @@ public class Device {
    private static final int MSG_OPEN_DEVICE = 1;
    private static final int MSG_SEND_REPORT = 2;
    private static final int MSG_SEND_GET_FEATURE_REPORT_REPLY = 3;
    private static final int MSG_CLOSE_DEVICE = 4;
    private static final int MSG_SEND_SET_REPORT_REPLY = 4;
    private static final int MSG_CLOSE_DEVICE = 5;

    // Sync with linux uhid_event_type::UHID_OUTPUT
    private static final byte UHID_EVENT_TYPE_UHID_OUTPUT = 6;
@@ -56,21 +57,45 @@ public class Device {
    private final Map<ByteBuffer, byte[]> mOutputs;
    private final OutputStream mOutputStream;
    private long mTimeToSend;

    private final Object mCond = new Object();
    /**
     * The report id of the report received in UHID_EVENT_TYPE_SET_REPORT.
     * Used for SET_REPORT_REPLY.
     * This field gets overridden each time SET_REPORT is received.
     */
    private int mResponseId;

    static {
        System.loadLibrary("hidcommand_jni");
    }

    private static native long nativeOpenDevice(String name, int id, int vid, int pid, int bus,
            byte[] descriptor, DeviceCallback callback);
    private static native long nativeOpenDevice(
            String name,
            int id,
            int vid,
            int pid,
            int bus,
            byte[] descriptor,
            DeviceCallback callback);

    private static native void nativeSendReport(long ptr, byte[] data);

    private static native void nativeSendGetFeatureReportReply(long ptr, int id, byte[] data);

    private static native void nativeSendSetReportReply(long ptr, int id, boolean success);

    private static native void nativeCloseDevice(long ptr);

    public Device(int id, String name, int vid, int pid, int bus, byte[] descriptor,
            byte[] report, SparseArray<byte[]> featureReports, Map<ByteBuffer, byte[]> outputs) {
    public Device(
            int id,
            String name,
            int vid,
            int pid,
            int bus,
            byte[] descriptor,
            byte[] report,
            SparseArray<byte[]> featureReports,
            Map<ByteBuffer, byte[]> outputs) {
        mId = id;
        mThread = new HandlerThread("HidDeviceHandler");
        mThread.start();
@@ -100,6 +125,17 @@ public class Device {
        mHandler.sendMessageAtTime(msg, mTimeToSend);
    }

    public void setGetReportResponse(byte[] report) {
        mFeatureReports.put(report[0], report);
    }

    public void sendSetReportReply(boolean success) {
        Message msg =
                mHandler.obtainMessage(MSG_SEND_SET_REPORT_REPLY, mResponseId, success ? 1 : 0);

        mHandler.sendMessageAtTime(msg, mTimeToSend);
    }

    public void addDelay(int delay) {
        mTimeToSend = Math.max(SystemClock.uptimeMillis(), mTimeToSend) + delay;
    }
@@ -111,7 +147,8 @@ public class Device {
            synchronized (mCond) {
                mCond.wait();
            }
        } catch (InterruptedException ignore) {}
        } catch (InterruptedException ignore) {
        }
    }

    private class DeviceHandler extends Handler {
@@ -127,8 +164,15 @@ public class Device {
            switch (msg.what) {
                case MSG_OPEN_DEVICE:
                    SomeArgs args = (SomeArgs) msg.obj;
                    mPtr = nativeOpenDevice((String) args.arg1, args.argi1, args.argi2, args.argi3,
                            args.argi4, (byte[]) args.arg2, new DeviceCallback());
                    mPtr =
                            nativeOpenDevice(
                                    (String) args.arg1,
                                    args.argi1,
                                    args.argi2,
                                    args.argi3,
                                    args.argi4,
                                    (byte[]) args.arg2,
                                    new DeviceCallback());
                    pauseEvents();
                    break;
                case MSG_SEND_REPORT:
@@ -145,6 +189,14 @@ public class Device {
                        Log.e(TAG, "Tried to send feature report reply to closed device.");
                    }
                    break;
                case MSG_SEND_SET_REPORT_REPLY:
                    if (mPtr != 0) {
                        final boolean success = msg.arg2 == 1;
                        nativeSendSetReportReply(mPtr, msg.arg1, success);
                    } else {
                        Log.e(TAG, "Tried to send set report reply to closed device.");
                    }
                    break;
                case MSG_CLOSE_DEVICE:
                    if (mPtr != 0) {
                        nativeCloseDevice(mPtr);
@@ -173,13 +225,17 @@ public class Device {
    }

    private class DeviceCallback {

        public void onDeviceOpen() {
            mHandler.resumeEvents();
        }

        public void onDeviceGetReport(int requestId, int reportId) {
            if (mFeatureReports == null) {
                Log.e(TAG, "Received GET_REPORT request for reportId=" + reportId
                Log.e(
                        TAG,
                        "Received GET_REPORT request for reportId="
                                + reportId
                                + ", but 'feature_reports' section is not found");
                return;
            }
@@ -220,14 +276,15 @@ public class Device {
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

        }

        // native callback
        public void onDeviceSetReport(byte rtype, byte[] data) {
        public void onDeviceSetReport(int id, byte rType, byte[] data) {
            // Used by sendSetReportReply()
            mResponseId = id;
            // We don't need to reply for the SET_REPORT but just send it to HID output for test
            // verification.
            sendReportOutput(UHID_EVENT_TYPE_SET_REPORT, rtype, data);
            sendReportOutput(UHID_EVENT_TYPE_SET_REPORT, rType, data);
        }

        // native callback
@@ -239,7 +296,8 @@ public class Device {
            }
            byte[] response = mOutputs.get(ByteBuffer.wrap(data));
            if (response == null) {
                Log.i(TAG,
                Log.i(
                        TAG,
                        "Requested response for output " + Arrays.toString(data) + " is not found");
                return;
            }
+30 −0
Original line number Diff line number Diff line
@@ -35,6 +35,8 @@ public class Event {
    public static final String COMMAND_REGISTER = "register";
    public static final String COMMAND_DELAY = "delay";
    public static final String COMMAND_REPORT = "report";
    public static final String COMMAND_SET_GET_REPORT_RESPONSE = "set_get_report_response";
    public static final String COMMAND_SEND_SET_REPORT_REPLY = "send_set_report_reply";

    // These constants come from "include/uapi/linux/input.h" in the kernel
    enum Bus {
@@ -62,6 +64,7 @@ public class Event {
    private SparseArray<byte[]> mFeatureReports;
    private Map<ByteBuffer, byte[]> mOutputs;
    private int mDuration;
    private Boolean mReply;

    public int getId() {
        return mId;
@@ -107,6 +110,10 @@ public class Event {
        return mDuration;
    }

    public Boolean getReply() {
        return mReply;
    }

    public String toString() {
        return "Event{id=" + mId
            + ", command=" + String.valueOf(mCommand)
@@ -119,6 +126,7 @@ public class Event {
            + ", feature_reports=" + mFeatureReports.toString()
            + ", outputs=" + mOutputs.toString()
            + ", duration=" + mDuration
            + ", success=" + mReply.toString()
            + "}";
    }

@@ -173,6 +181,10 @@ public class Event {
            mEvent.mDuration = duration;
        }

        public void setReply(boolean success) {
            mEvent.mReply = success;
        }

        public Event build() {
            if (mEvent.mId == -1) {
                throw new IllegalStateException("No event id");
@@ -183,6 +195,16 @@ public class Event {
                if (mEvent.mDescriptor == null) {
                    throw new IllegalStateException("Device registration is missing descriptor");
                }
            }
            if (COMMAND_SET_GET_REPORT_RESPONSE.equals(mEvent.mCommand)) {
                if (mEvent.mReport == null) {
                    throw new IllegalStateException("Report command is missing response data");
                }
            }
            if (COMMAND_SEND_SET_REPORT_REPLY.equals(mEvent.mCommand)) {
                if (mEvent.mReply == null) {
                    throw new IllegalStateException("Reply command is missing reply");
                }
            } else if (COMMAND_DELAY.equals(mEvent.mCommand)) {
                if (mEvent.mDuration <= 0) {
                    throw new IllegalStateException("Delay has missing or invalid duration");
@@ -246,6 +268,9 @@ public class Event {
                            case "duration":
                                eb.setDuration(readInt());
                                break;
                            case "success":
                                eb.setReply(readBool());
                                break;
                            default:
                                mReader.skipValue();
                        }
@@ -292,6 +317,11 @@ public class Event {
            return Integer.decode(val);
        }

        private boolean readBool() throws IOException {
            String val = mReader.nextString();
            return Boolean.parseBoolean(val);
        }

        private Bus readBus() throws IOException {
            String val = mReader.nextString();
            return Bus.valueOf(val.toUpperCase());
+4 −0
Original line number Diff line number Diff line
@@ -93,6 +93,10 @@ public class Hid {
                d.addDelay(e.getDuration());
            } else if (Event.COMMAND_REPORT.equals(e.getCommand())) {
                d.sendReport(e.getReport());
            } else if (Event.COMMAND_SET_GET_REPORT_RESPONSE.equals(e.getCommand())) {
                d.setGetReportResponse(e.getReport());
            } else if (Event.COMMAND_SEND_SET_REPORT_REPLY.equals(e.getCommand())) {
                d.sendSetReportReply(e.getReply());
            } else {
                if (Event.COMMAND_REGISTER.equals(e.getCommand())) {
                    error("Device id=" + e.getId() + " is already registered. Ignoring event.");