/*
* 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<Integer> data = new ArrayList<Integer>();
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));
}
}
}