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.util.JsonReader;
20import android.util.JsonToken;
21import android.util.Log;
22import android.util.SparseArray;
23
24import libcore.io.IoUtils;
25
26import java.io.BufferedInputStream;
27import java.io.File;
28import java.io.FileInputStream;
29import java.io.FileNotFoundException;
30import java.io.InputStream;
31import java.io.InputStreamReader;
32import java.io.IOException;
33import java.io.UnsupportedEncodingException;
34import java.util.ArrayList;
35
36public 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