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 Wrightpackage com.android.commands.hid;
181f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright
191f2c7688c1f673790d61645632ae5e1838f021a4Michael Wrightimport android.os.Handler;
201f2c7688c1f673790d61645632ae5e1838f021a4Michael Wrightimport android.os.HandlerThread;
211f2c7688c1f673790d61645632ae5e1838f021a4Michael Wrightimport android.os.Looper;
221f2c7688c1f673790d61645632ae5e1838f021a4Michael Wrightimport android.os.Message;
231f2c7688c1f673790d61645632ae5e1838f021a4Michael Wrightimport android.os.MessageQueue;
241f2c7688c1f673790d61645632ae5e1838f021a4Michael Wrightimport android.os.SystemClock;
251f2c7688c1f673790d61645632ae5e1838f021a4Michael Wrightimport android.util.Log;
261f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright
271f2c7688c1f673790d61645632ae5e1838f021a4Michael Wrightimport com.android.internal.os.SomeArgs;
281f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright
291f2c7688c1f673790d61645632ae5e1838f021a4Michael Wrightpublic class Device {
301f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright    private static final String TAG = "HidDevice";
311f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright
321f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright    // Minimum amount of time to wait before sending input events to a device. Even though we're
331f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright    // guaranteed that the device has been created and opened by the input system, there's still a
341f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright    // window in which the system hasn't started reading events out of it. If a stream of events
351f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright    // begins in during this window (like a button down event) and *then* we start reading, we're
361f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright    // liable to ignore the whole stream.
371f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright    private static final int MIN_WAIT_FOR_FIRST_EVENT = 150;
381f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright
391f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright    private static final int MSG_OPEN_DEVICE = 1;
401f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright    private static final int MSG_SEND_REPORT = 2;
411f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright    private static final int MSG_CLOSE_DEVICE = 3;
421f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright
431f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright
441f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright    private final int mId;
451f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright    private final HandlerThread mThread;
461f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright    private final DeviceHandler mHandler;
471f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright    private long mEventTime;
481f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright
491f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright    private final Object mCond = new Object();
501f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright
511f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright    static {
521f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        System.loadLibrary("hidcommand_jni");
531f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright    }
541f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright
551f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright    private static native long nativeOpenDevice(String name, int id, int vid, int pid,
561f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright            byte[] descriptor, MessageQueue queue, DeviceCallback callback);
571f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright    private static native void nativeSendReport(long ptr, byte[] data);
581f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright    private static native void nativeCloseDevice(long ptr);
591f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright
601f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright    public Device(int id, String name, int vid, int pid, byte[] descriptor, byte[] report) {
611f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        mId = id;
621f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        mThread = new HandlerThread("HidDeviceHandler");
631f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        mThread.start();
641f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        mHandler = new DeviceHandler(mThread.getLooper());
651f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        SomeArgs args = SomeArgs.obtain();
661f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        args.argi1 = id;
671f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        args.argi2 = vid;
681f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        args.argi3 = pid;
691f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        if (name != null) {
701f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright            args.arg1 = name;
711f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        } else {
721f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright            args.arg1 = id + ":" + vid + ":" + pid;
731f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        }
741f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        args.arg2 = descriptor;
751f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        args.arg3 = report;
761f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        mHandler.obtainMessage(MSG_OPEN_DEVICE, args).sendToTarget();
771f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        mEventTime = SystemClock.uptimeMillis() + MIN_WAIT_FOR_FIRST_EVENT;
781f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright    }
791f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright
801f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright    public void sendReport(byte[] report) {
811f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        Message msg = mHandler.obtainMessage(MSG_SEND_REPORT, report);
821f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        mHandler.sendMessageAtTime(msg, mEventTime);
831f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright    }
841f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright
851f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright    public void addDelay(int delay) {
861f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        mEventTime += delay;
871f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright    }
881f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright
891f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright    public void close() {
901f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        Message msg = mHandler.obtainMessage(MSG_CLOSE_DEVICE);
911f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        msg.setAsynchronous(true);
921f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        mHandler.sendMessageAtTime(msg, mEventTime + 1);
931f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        try {
941f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright            synchronized (mCond) {
951f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright                mCond.wait();
961f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright            }
971f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        } catch (InterruptedException ignore) {}
981f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright    }
991f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright
1001f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright    private class DeviceHandler extends Handler {
1011f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        private long mPtr;
1021f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        private int mBarrierToken;
1031f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright
1041f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        public DeviceHandler(Looper looper) {
1051f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright            super(looper);
1061f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        }
1071f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright
1081f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        @Override
1091f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        public void handleMessage(Message msg) {
1101f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright            switch (msg.what) {
1111f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright                case MSG_OPEN_DEVICE:
1121f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright                    SomeArgs args = (SomeArgs) msg.obj;
1131f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright                    mPtr = nativeOpenDevice((String) args.arg1, args.argi1, args.argi2, args.argi3,
1141f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright                            (byte[]) args.arg2, getLooper().myQueue(), new DeviceCallback());
1151f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright                    nativeSendReport(mPtr, (byte[]) args.arg3);
1161f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright                    pauseEvents();
1171f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright                    break;
1181f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright                case MSG_SEND_REPORT:
1191f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright                    if (mPtr != 0) {
1201f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright                        nativeSendReport(mPtr, (byte[]) msg.obj);
1211f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright                    } else {
1221f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright                        Log.e(TAG, "Tried to send report to closed device.");
1231f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright                    }
1241f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright                    break;
1251f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright                case MSG_CLOSE_DEVICE:
1261f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright                    if (mPtr != 0) {
1271f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright                        nativeCloseDevice(mPtr);
1281f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright                        getLooper().quitSafely();
1291f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright                        mPtr = 0;
1301f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright                    } else {
1311f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright                        Log.e(TAG, "Tried to close already closed device.");
1321f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright                    }
1331f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright                    synchronized (mCond) {
1341f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright                        mCond.notify();
1351f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright                    }
1361f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright                    break;
1371f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright                default:
1381f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright                    throw new IllegalArgumentException("Unknown device message");
1391f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright            }
1401f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        }
1411f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright
1421f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        public void pauseEvents() {
1431f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright            mBarrierToken = getLooper().myQueue().postSyncBarrier();
1441f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        }
1451f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright
1461f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        public void resumeEvents() {
1471f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright            getLooper().myQueue().removeSyncBarrier(mBarrierToken);
1481f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright            mBarrierToken = 0;
1491f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        }
1501f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright    }
1511f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright
1521f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright    private class DeviceCallback {
1531f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        public void onDeviceOpen() {
1541f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright            mHandler.resumeEvents();
1551f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        }
1561f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright
1571f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        public void onDeviceError() {
1581f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright            Message msg = mHandler.obtainMessage(MSG_CLOSE_DEVICE);
1591f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright            msg.setAsynchronous(true);
1601f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright            msg.sendToTarget();
1611f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright        }
1621f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright    }
1631f2c7688c1f673790d61645632ae5e1838f021a4Michael Wright}
164