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