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 17 package com.android.commands.hid; 18 19 import android.util.JsonReader; 20 import android.util.JsonToken; 21 import android.util.Log; 22 import android.util.SparseArray; 23 24 import libcore.io.IoUtils; 25 26 import java.io.BufferedInputStream; 27 import java.io.File; 28 import java.io.FileInputStream; 29 import java.io.FileNotFoundException; 30 import java.io.InputStream; 31 import java.io.InputStreamReader; 32 import java.io.IOException; 33 import java.io.UnsupportedEncodingException; 34 import java.util.ArrayList; 35 36 public class Hid { 37 private static final String TAG = "HID"; 38 39 private final Event.Reader mReader; 40 private final SparseArray<Device> mDevices; 41 42 private static void usage() { 43 error("Usage: hid [FILE]"); 44 } 45 46 public static void main(String[] args) { 47 if (args.length != 1) { 48 usage(); 49 System.exit(1); 50 } 51 52 InputStream stream = null; 53 try { 54 if (args[0].equals("-")) { 55 stream = System.in; 56 } else { 57 File f = new File(args[0]); 58 stream = new FileInputStream(f); 59 } 60 (new Hid(stream)).run(); 61 } catch (Exception e) { 62 error("HID injection failed.", e); 63 System.exit(1); 64 } finally { 65 IoUtils.closeQuietly(stream); 66 } 67 } 68 69 private Hid(InputStream in) { 70 mDevices = new SparseArray<Device>(); 71 try { 72 mReader = new Event.Reader(new InputStreamReader(in, "UTF-8")); 73 } catch (UnsupportedEncodingException e) { 74 throw new RuntimeException(e); 75 } 76 } 77 78 private void run() { 79 try { 80 Event e = null; 81 while ((e = mReader.getNextEvent()) != null) { 82 process(e); 83 } 84 } catch (IOException ex) { 85 error("Error reading in events.", ex); 86 } 87 88 for (int i = 0; i < mDevices.size(); i++) { 89 mDevices.valueAt(i).close(); 90 } 91 } 92 93 private void process(Event e) { 94 final int index = mDevices.indexOfKey(e.getId()); 95 if (index >= 0) { 96 Device d = mDevices.valueAt(index); 97 if (Event.COMMAND_DELAY.equals(e.getCommand())) { 98 d.addDelay(e.getDuration()); 99 } else if (Event.COMMAND_REPORT.equals(e.getCommand())) { 100 d.sendReport(e.getReport()); 101 } else { 102 if (Event.COMMAND_REGISTER.equals(e.getCommand())) { 103 error("Device id=" + e.getId() + " is already registered. Ignoring event."); 104 } else { 105 error("Unknown command \"" + e.getCommand() + "\". Ignoring event."); 106 } 107 } 108 } else if (Event.COMMAND_REGISTER.equals(e.getCommand())) { 109 registerDevice(e); 110 } else { 111 Log.e(TAG, "Unknown device id specified. Ignoring event."); 112 } 113 } 114 115 private void registerDevice(Event e) { 116 if (!Event.COMMAND_REGISTER.equals(e.getCommand())) { 117 throw new IllegalStateException( 118 "Tried to send command \"" + e.getCommand() + "\" to an unregistered device!"); 119 } 120 int id = e.getId(); 121 Device d = new Device(id, e.getName(), e.getVendorId(), e.getProductId(), 122 e.getDescriptor(), e.getReport()); 123 mDevices.append(id, d); 124 } 125 126 private static void error(String msg) { 127 error(msg, null); 128 } 129 130 private static void error(String msg, Exception e) { 131 Log.e(TAG, msg); 132 if (e != null) { 133 Log.e(TAG, Log.getStackTraceString(e)); 134 } 135 } 136 } 137