src.com.android.commands.hid.Event Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of android-all Show documentation
Show all versions of android-all Show documentation
A library jar that provides APIs for Applications written for the Google Android Platform.
/*
* 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 android.util.SparseArray;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
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";
// These constants come from "include/uapi/linux/input.h" in the kernel
enum Bus {
USB(0x03), BLUETOOTH(0x05);
Bus(int value) {
mValue = value;
}
int getValue() {
return mValue;
}
private int mValue;
}
private int mId;
private String mCommand;
private String mName;
private byte[] mDescriptor;
private int mVid;
private int mPid;
private Bus mBus;
private byte[] mReport;
private SparseArray mFeatureReports;
private Map mOutputs;
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 int getBus() {
return mBus.getValue();
}
public byte[] getReport() {
return mReport;
}
public SparseArray getFeatureReports() {
return mFeatureReports;
}
public Map getOutputs() {
return mOutputs;
}
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
+ ", bus=" + mBus
+ ", report=" + Arrays.toString(mReport)
+ ", feature_reports=" + mFeatureReports.toString()
+ ", outputs=" + mOutputs.toString()
+ ", 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 setFeatureReports(SparseArray reports) {
mEvent.mFeatureReports = reports;
}
public void setOutputs(Map outputs) {
mEvent.mOutputs = outputs;
}
public void setVid(int vid) {
mEvent.mVid = vid;
}
public void setPid(int pid) {
mEvent.mPid = pid;
}
public void setBus(Bus bus) {
mEvent.mBus = bus;
}
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 "bus":
eb.setBus(readBus());
break;
case "report":
eb.setReport(readData());
break;
case "feature_reports":
eb.setFeatureReports(readFeatureReports());
break;
case "outputs":
eb.setOutputs(readOutputs());
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 Bus readBus() throws IOException {
String val = mReader.nextString();
return Bus.valueOf(val.toUpperCase());
}
private SparseArray readFeatureReports()
throws IllegalStateException, IOException {
SparseArray featureReports = new SparseArray<>();
try {
mReader.beginArray();
while (mReader.hasNext()) {
// If "id" is not specified, it defaults to 0, which means
// report does not contain report ID (based on HID specs).
int id = 0;
byte[] data = null;
mReader.beginObject();
while (mReader.hasNext()) {
String name = mReader.nextName();
switch (name) {
case "id":
id = readInt();
break;
case "data":
data = readData();
break;
default:
consumeRemainingElements();
mReader.endObject();
throw new IllegalStateException("Invalid key in feature report: "
+ name);
}
}
mReader.endObject();
if (data != null) {
featureReports.put(id, data);
}
}
mReader.endArray();
} catch (IllegalStateException | NumberFormatException e) {
consumeRemainingElements();
mReader.endArray();
throw new IllegalStateException("Encountered malformed data.", e);
}
return featureReports;
}
private Map readOutputs()
throws IllegalStateException, IOException {
Map outputs = new HashMap<>();
try {
mReader.beginArray();
while (mReader.hasNext()) {
byte[] output = null;
byte[] response = null;
mReader.beginObject();
while (mReader.hasNext()) {
String name = mReader.nextName();
switch (name) {
case "description":
// Description is only used to keep track of the output responses
mReader.nextString();
break;
case "output":
output = readData();
break;
case "response":
response = readData();
break;
default:
consumeRemainingElements();
mReader.endObject();
throw new IllegalStateException("Invalid key in outputs: " + name);
}
}
mReader.endObject();
if (output != null) {
outputs.put(ByteBuffer.wrap(output), response);
}
}
mReader.endArray();
} catch (IllegalStateException | NumberFormatException e) {
consumeRemainingElements();
mReader.endArray();
throw new IllegalStateException("Encountered malformed data.", e);
}
return outputs;
}
private void consumeRemainingElements() throws IOException {
while (mReader.hasNext()) {
mReader.skipValue();
}
}
}
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));
}
}
}