1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.commands.hid; 18 19import android.os.SystemClock; 20import android.util.JsonReader; 21import android.util.JsonToken; 22import android.util.Log; 23import android.util.SparseArray; 24 25import libcore.io.IoUtils; 26 27import java.io.BufferedInputStream; 28import java.io.File; 29import java.io.FileInputStream; 30import java.io.FileNotFoundException; 31import java.io.InputStream; 32import java.io.InputStreamReader; 33import java.io.IOException; 34import java.io.UnsupportedEncodingException; 35import java.util.ArrayList; 36 37public class Hid { 38 private static final String TAG = "HID"; 39 40 private final Event.Reader mReader; 41 private final SparseArray<Device> mDevices; 42 43 private static void usage() { 44 error("Usage: hid [FILE]"); 45 } 46 47 public static void main(String[] args) { 48 if (args.length != 1) { 49 usage(); 50 System.exit(1); 51 } 52 53 InputStream stream = null; 54 try { 55 if (args[0].equals("-")) { 56 stream = System.in; 57 } else { 58 File f = new File(args[0]); 59 stream = new FileInputStream(f); 60 } 61 (new Hid(stream)).run(); 62 } catch (Exception e) { 63 error("HID injection failed.", e); 64 System.exit(1); 65 } finally { 66 IoUtils.closeQuietly(stream); 67 } 68 } 69 70 private Hid(InputStream in) { 71 mDevices = new SparseArray<Device>(); 72 try { 73 mReader = new Event.Reader(new InputStreamReader(in, "UTF-8")); 74 } catch (UnsupportedEncodingException e) { 75 throw new RuntimeException(e); 76 } 77 } 78 79 private void run() { 80 try { 81 Event e = null; 82 while ((e = mReader.getNextEvent()) != null) { 83 process(e); 84 } 85 } catch (IOException ex) { 86 error("Error reading in events.", ex); 87 } 88 89 for (int i = 0; i < mDevices.size(); i++) { 90 mDevices.valueAt(i).close(); 91 } 92 } 93 94 95 private void process(Event e) { 96 final int index = mDevices.indexOfKey(e.getId()); 97 if (index >= 0) { 98 Device d = mDevices.valueAt(index); 99 if (Event.COMMAND_DELAY.equals(e.getCommand())) { 100 d.addDelay(e.getDuration()); 101 } else if (Event.COMMAND_REPORT.equals(e.getCommand())) { 102 d.sendReport(e.getReport()); 103 } else { 104 error("Unknown command \"" + e.getCommand() + "\". Ignoring event."); 105 } 106 } else { 107 registerDevice(e); 108 } 109 } 110 111 private void registerDevice(Event e) { 112 if (!Event.COMMAND_REGISTER.equals(e.getCommand())) { 113 throw new IllegalStateException( 114 "Tried to send command \"" + e.getCommand() + "\" to an unregistered device!"); 115 } 116 int id = e.getId(); 117 Device d = new Device(id, e.getName(), e.getVendorId(), e.getProductId(), 118 e.getDescriptor(), e.getReport()); 119 mDevices.append(id, d); 120 } 121 122 private static void error(String msg) { 123 error(msg, null); 124 } 125 126 private static void error(String msg, Exception e) { 127 System.out.println(msg); 128 Log.e(TAG, msg); 129 if (e != null) { 130 Log.e(TAG, Log.getStackTraceString(e)); 131 } 132 } 133} 134