/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.commands.hid; import android.util.JsonReader; import android.util.JsonToken; import android.util.Log; import java.io.InputStreamReader; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; public class Event { private static final String TAG = "HidEvent"; public static final String COMMAND_REGISTER = "register"; public static final String COMMAND_DELAY = "delay"; public static final String COMMAND_REPORT = "report"; private int mId; private String mCommand; private String mName; private byte[] mDescriptor; private int mVid; private int mPid; private byte[] mReport; private int mDuration; public int getId() { return mId; } public String getCommand() { return mCommand; } public String getName() { return mName; } public byte[] getDescriptor() { return mDescriptor; } public int getVendorId() { return mVid; } public int getProductId() { return mPid; } public byte[] getReport() { return mReport; } public int getDuration() { return mDuration; } public String toString() { return "Event{id=" + mId + ", command=" + String.valueOf(mCommand) + ", name=" + String.valueOf(mName) + ", descriptor=" + Arrays.toString(mDescriptor) + ", vid=" + mVid + ", pid=" + mPid + ", report=" + Arrays.toString(mReport) + ", duration=" + mDuration + "}"; } private static class Builder { private Event mEvent; public Builder() { mEvent = new Event(); } public void setId(int id) { mEvent.mId = id; } private void setCommand(String command) { mEvent.mCommand = command; } public void setName(String name) { mEvent.mName = name; } public void setDescriptor(byte[] descriptor) { mEvent.mDescriptor = descriptor; } public void setReport(byte[] report) { mEvent.mReport = report; } public void setVid(int vid) { mEvent.mVid = vid; } public void setPid(int pid) { mEvent.mPid = pid; } public void setDuration(int duration) { mEvent.mDuration = duration; } public Event build() { if (mEvent.mId == -1) { throw new IllegalStateException("No event id"); } else if (mEvent.mCommand == null) { throw new IllegalStateException("Event does not contain a command"); } if (COMMAND_REGISTER.equals(mEvent.mCommand)) { if (mEvent.mDescriptor == null) { throw new IllegalStateException("Device registration is missing descriptor"); } } else if (COMMAND_DELAY.equals(mEvent.mCommand)) { if (mEvent.mDuration <= 0) { throw new IllegalStateException("Delay has missing or invalid duration"); } } else if (COMMAND_REPORT.equals(mEvent.mCommand)) { if (mEvent.mReport == null) { throw new IllegalStateException("Report command is missing report data"); } } return mEvent; } } public static class Reader { private JsonReader mReader; public Reader(InputStreamReader in) { mReader = new JsonReader(in); mReader.setLenient(true); } public Event getNextEvent() throws IOException { Event e = null; while (e == null && mReader.peek() != JsonToken.END_DOCUMENT) { Event.Builder eb = new Event.Builder(); try { mReader.beginObject(); while (mReader.hasNext()) { String name = mReader.nextName(); switch (name) { case "id": eb.setId(readInt()); break; case "command": eb.setCommand(mReader.nextString()); break; case "descriptor": eb.setDescriptor(readData()); break; case "name": eb.setName(mReader.nextString()); break; case "vid": eb.setVid(readInt()); break; case "pid": eb.setPid(readInt()); break; case "report": eb.setReport(readData()); break; case "duration": eb.setDuration(readInt()); break; default: mReader.skipValue(); } } mReader.endObject(); } catch (IllegalStateException ex) { error("Error reading in object, ignoring.", ex); consumeRemainingElements(); mReader.endObject(); continue; } e = eb.build(); } return e; } private byte[] readData() throws IOException { ArrayList data = new ArrayList(); try { mReader.beginArray(); while (mReader.hasNext()) { data.add(Integer.decode(mReader.nextString())); } mReader.endArray(); } catch (IllegalStateException|NumberFormatException e) { consumeRemainingElements(); mReader.endArray(); throw new IllegalStateException("Encountered malformed data.", e); } byte[] rawData = new byte[data.size()]; for (int i = 0; i < data.size(); i++) { int d = data.get(i); if ((d & 0xFF) != d) { throw new IllegalStateException("Invalid data, all values must be byte-sized"); } rawData[i] = (byte)d; } return rawData; } private int readInt() throws IOException { String val = mReader.nextString(); return Integer.decode(val); } private void consumeRemainingElements() throws IOException { while (mReader.hasNext()) { mReader.skipValue(); } } } private static void error(String msg) { error(msg, null); } private static void error(String msg, Exception e) { System.out.println(msg); Log.e(TAG, msg); if (e != null) { Log.e(TAG, Log.getStackTraceString(e)); } } }