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