I am trying to parse InputEvent
s of an Android device.
Background:
- For an android device we have a utility
getevent
which gives all the touch events that are sent to a device.getevent -l
gives all the input events to the device.- Every event has 3 fields -
EVENT_TYPE
,EVENT_CODE
andVALUE
.EVENT_TYPE
can be of following types -EV_KEY
,EV_ABS
andEV_SYN
.- In turn, each
EVENT_TYPE
can have differentEVENT_CODES
.
For e.g.
EV_KEY
-->BTN_TOUCH
EV_ABS
-->ABS_MT_TOUCH_MAJOR, ABS_MT_TRACKING_ID, ABS_MT_POSITION_X, ABS_MT_POSITION_Y
and
EV_SYN
-->SYN_MT_REPORT, SYN_REPORT
- And every
EVENT_CODE
can have aVALUE
.- Every event is separated by a
SYN_REPORT
.- Each event can itself be a multi touch event be separated by a
SYN_MT_REPORT
.- Every touch starts with a
EV_KEY - BTN_TOUCH - DOWN
and ends with aEV_KEY - BTN_TOUCH - UP
combination. (There are event separators afterEV_KEY - BTN_TOUCH - UP
viz.SYN_MT_REPORT
andSYN_REPORT
, but they are not important.
More description: Event Types and Multi Touch events
EV_KEY BTN_TOUCH DOWN <-------------- EV_ABS ABS_MT_TOUCH_MAJOR 00000011 | EV_ABS ABS_MT_TRACKING_ID 00000000 | EV_ABS ABS_MT_POSITION_X 0000011c |---First event, EV_ABS ABS_MT_POSITION_Y 000001f4 | with DOWN and only EV_SYN SYN_MT_REPORT 00000000 | 1 finger touched. EV_SYN SYN_REPORT 00000000 <-------------- EV_ABS ABS_MT_TOUCH_MAJOR 00000011 <-------------- EV_ABS ABS_MT_TRACKING_ID 00000000 <------- | EV_ABS ABS_MT_POSITION_X 0000011c | | EV_ABS ABS_MT_POSITION_Y 000001f4 Finger 1 | EV_SYN SYN_MT_REPORT 00000000 <------- | EV_ABS ABS_MT_TOUCH_MAJOR 00000013 |---Second event EV_ABS ABS_MT_TRACKING_ID 00000001 <------- | with 2 mutitouch events EV_ABS ABS_MT_POSITION_X 00000076 | | EV_ABS ABS_MT_POSITION_Y 0000026e Finger 2 | EV_SYN SYN_MT_REPORT 00000000 <------- | EV_SYN SYN_REPORT 00000000 <-------------- EV_ABS ABS_MT_TOUCH_MAJOR 00000011 <-------------- EV_ABS ABS_MT_TRACKING_ID 00000000 <------- | EV_ABS ABS_MT_POSITION_X 00000190 | | EV_ABS ABS_MT_POSITION_Y 0000035d Finger 1 | EV_SYN SYN_MT_REPORT 00000000 <------- | EV_ABS ABS_MT_TOUCH_MAJOR 00000013 | EV_ABS ABS_MT_TRACKING_ID 00000001 <------- | EV_ABS ABS_MT_POSITION_X 000000f8 | | EV_ABS ABS_MT_POSITION_Y 000003cf Finger 2 |---Third event EV_SYN SYN_MT_REPORT 00000000 <------- | with 3 mulittouch events EV_ABS ABS_MT_TOUCH_MAJOR 00000015 | EV_ABS ABS_MT_TRACKING_ID 00000002 <------- | EV_ABS ABS_MT_POSITION_X 00000251 | | EV_ABS ABS_MT_POSITION_Y 00000310 Finger 3 | EV_SYN SYN_MT_REPORT 00000000 <------- | EV_SYN SYN_REPORT 00000000 <-------------- EV_KEY BTN_TOUCH UP <-------------- EV_SYN SYN_MT_REPORT 00000000 |---Final Event, EV_SYN SYN_REPORT 00000000 <-------------- only 1 finger
An example of actual input is:
EV_KEY BTN_TOUCH DOWN EV_ABS ABS_MT_TOUCH_MAJOR 00000011 EV_ABS ABS_MT_TRACKING_ID 00000000 EV_ABS ABS_MT_POSITION_X 0000011c EV_ABS ABS_MT_POSITION_Y 000001f4 EV_SYN SYN_MT_REPORT 00000000 EV_SYN SYN_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000011 EV_ABS ABS_MT_TRACKING_ID 00000000 EV_ABS ABS_MT_POSITION_X 0000011c EV_ABS ABS_MT_POSITION_Y 000001f4 EV_SYN SYN_MT_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000013 EV_ABS ABS_MT_TRACKING_ID 00000001 EV_ABS ABS_MT_POSITION_X 00000076 EV_ABS ABS_MT_POSITION_Y 0000026e EV_SYN SYN_MT_REPORT 00000000 EV_SYN SYN_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000011 EV_ABS ABS_MT_TRACKING_ID 00000000 EV_ABS ABS_MT_POSITION_X 0000011c EV_ABS ABS_MT_POSITION_Y 000001f4 EV_SYN SYN_MT_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000013 EV_ABS ABS_MT_TRACKING_ID 00000001 EV_ABS ABS_MT_POSITION_X 00000076 EV_ABS ABS_MT_POSITION_Y 0000026e EV_SYN SYN_MT_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000015 EV_ABS ABS_MT_TRACKING_ID 00000002 EV_ABS ABS_MT_POSITION_X 000001cd EV_ABS ABS_MT_POSITION_Y 000001a3 EV_SYN SYN_MT_REPORT 00000000 EV_SYN SYN_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000011 EV_ABS ABS_MT_TRACKING_ID 00000000 EV_ABS ABS_MT_POSITION_X 0000011c EV_ABS ABS_MT_POSITION_Y 000001f4 EV_SYN SYN_MT_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000013 EV_ABS ABS_MT_TRACKING_ID 00000001 EV_ABS ABS_MT_POSITION_X 00000076 EV_ABS ABS_MT_POSITION_Y 0000026e EV_SYN SYN_MT_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000015 EV_ABS ABS_MT_TRACKING_ID 00000002 EV_ABS ABS_MT_POSITION_X 000001cd EV_ABS ABS_MT_POSITION_Y 000001a3 EV_SYN SYN_MT_REPORT 00000000 EV_SYN SYN_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000011 EV_ABS ABS_MT_TRACKING_ID 00000000 EV_ABS ABS_MT_POSITION_X 0000011c EV_ABS ABS_MT_POSITION_Y 000001f4 EV_SYN SYN_MT_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000013 EV_ABS ABS_MT_TRACKING_ID 00000001 EV_ABS ABS_MT_POSITION_X 00000076 EV_ABS ABS_MT_POSITION_Y 0000026e EV_SYN SYN_MT_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000015 EV_ABS ABS_MT_TRACKING_ID 00000002 EV_ABS ABS_MT_POSITION_X 000001cd EV_ABS ABS_MT_POSITION_Y 000001a3 EV_SYN SYN_MT_REPORT 00000000 EV_SYN SYN_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000011 EV_ABS ABS_MT_TRACKING_ID 00000000 EV_ABS ABS_MT_POSITION_X 0000011c EV_ABS ABS_MT_POSITION_Y 000001f4 EV_SYN SYN_MT_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000013 EV_ABS ABS_MT_TRACKING_ID 00000001 EV_ABS ABS_MT_POSITION_X 00000076 EV_ABS ABS_MT_POSITION_Y 0000026e EV_SYN SYN_MT_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000015 EV_ABS ABS_MT_TRACKING_ID 00000002 EV_ABS ABS_MT_POSITION_X 000001cd EV_ABS ABS_MT_POSITION_Y 000001a3 EV_SYN SYN_MT_REPORT 00000000 EV_SYN SYN_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000011 EV_ABS ABS_MT_TRACKING_ID 00000000 EV_ABS ABS_MT_POSITION_X 0000011c EV_ABS ABS_MT_POSITION_Y 000001f4 EV_SYN SYN_MT_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000013 EV_ABS ABS_MT_TRACKING_ID 00000001 EV_ABS ABS_MT_POSITION_X 00000076 EV_ABS ABS_MT_POSITION_Y 0000026e EV_SYN SYN_MT_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000015 EV_ABS ABS_MT_TRACKING_ID 00000002 EV_ABS ABS_MT_POSITION_X 000001cd EV_ABS ABS_MT_POSITION_Y 000001a3 EV_SYN SYN_MT_REPORT 00000000 EV_SYN SYN_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000011 EV_ABS ABS_MT_TRACKING_ID 00000000 EV_ABS ABS_MT_POSITION_X 0000011c EV_ABS ABS_MT_POSITION_Y 000001f4 EV_SYN SYN_MT_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000013 EV_ABS ABS_MT_TRACKING_ID 00000001 EV_ABS ABS_MT_POSITION_X 00000076 EV_ABS ABS_MT_POSITION_Y 0000026e EV_SYN SYN_MT_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000015 EV_ABS ABS_MT_TRACKING_ID 00000002 EV_ABS ABS_MT_POSITION_X 000001cd EV_ABS ABS_MT_POSITION_Y 000001a3 EV_SYN SYN_MT_REPORT 00000000 EV_SYN SYN_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000011 EV_ABS ABS_MT_TRACKING_ID 00000000 EV_ABS ABS_MT_POSITION_X 0000011c EV_ABS ABS_MT_POSITION_Y 000001f4 EV_SYN SYN_MT_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000013 EV_ABS ABS_MT_TRACKING_ID 00000001 EV_ABS ABS_MT_POSITION_X 00000076 EV_ABS ABS_MT_POSITION_Y 0000026e EV_SYN SYN_MT_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000015 EV_ABS ABS_MT_TRACKING_ID 00000002 EV_ABS ABS_MT_POSITION_X 000001cd EV_ABS ABS_MT_POSITION_Y 000001a3 EV_SYN SYN_MT_REPORT 00000000 EV_SYN SYN_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000011 EV_ABS ABS_MT_TRACKING_ID 00000000 EV_ABS ABS_MT_POSITION_X 0000011c EV_ABS ABS_MT_POSITION_Y 000001f4 EV_SYN SYN_MT_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000013 EV_ABS ABS_MT_TRACKING_ID 00000001 EV_ABS ABS_MT_POSITION_X 00000076 EV_ABS ABS_MT_POSITION_Y 0000026e EV_SYN SYN_MT_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000015 EV_ABS ABS_MT_TRACKING_ID 00000002 EV_ABS ABS_MT_POSITION_X 000001cd EV_ABS ABS_MT_POSITION_Y 000001a3 EV_SYN SYN_MT_REPORT 00000000 EV_SYN SYN_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000011 EV_ABS ABS_MT_TRACKING_ID 00000000 EV_ABS ABS_MT_POSITION_X 0000014b EV_ABS ABS_MT_POSITION_Y 0000026e EV_SYN SYN_MT_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000013 EV_ABS ABS_MT_TRACKING_ID 00000001 EV_ABS ABS_MT_POSITION_X 000000b7 EV_ABS ABS_MT_POSITION_Y 000002ef EV_SYN SYN_MT_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000015 EV_ABS ABS_MT_TRACKING_ID 00000002 EV_ABS ABS_MT_POSITION_X 00000209 EV_ABS ABS_MT_POSITION_Y 00000225 EV_SYN SYN_MT_REPORT 00000000 EV_SYN SYN_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000011 EV_ABS ABS_MT_TRACKING_ID 00000000 EV_ABS ABS_MT_POSITION_X 0000015f EV_ABS ABS_MT_POSITION_Y 000002a1 EV_SYN SYN_MT_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000013 EV_ABS ABS_MT_TRACKING_ID 00000001 EV_ABS ABS_MT_POSITION_X 000000c7 EV_ABS ABS_MT_POSITION_Y 00000319 EV_SYN SYN_MT_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000015 EV_ABS ABS_MT_TRACKING_ID 00000002 EV_ABS ABS_MT_POSITION_X 0000021e EV_ABS ABS_MT_POSITION_Y 00000258 EV_SYN SYN_MT_REPORT 00000000 EV_SYN SYN_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000011 EV_ABS ABS_MT_TRACKING_ID 00000000 EV_ABS ABS_MT_POSITION_X 00000167 EV_ABS ABS_MT_POSITION_Y 000002cc EV_SYN SYN_MT_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000013 EV_ABS ABS_MT_TRACKING_ID 00000001 EV_ABS ABS_MT_POSITION_X 000000d4 EV_ABS ABS_MT_POSITION_Y 00000339 EV_SYN SYN_MT_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000015 EV_ABS ABS_MT_TRACKING_ID 00000002 EV_ABS ABS_MT_POSITION_X 00000228 EV_ABS ABS_MT_POSITION_Y 0000027d EV_SYN SYN_MT_REPORT 00000000 EV_SYN SYN_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000011 EV_ABS ABS_MT_TRACKING_ID 00000000 EV_ABS ABS_MT_POSITION_X 0000016f EV_ABS ABS_MT_POSITION_Y 000002ed EV_SYN SYN_MT_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000013 EV_ABS ABS_MT_TRACKING_ID 00000001 EV_ABS ABS_MT_POSITION_X 000000dd EV_ABS ABS_MT_POSITION_Y 0000035e EV_SYN SYN_MT_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000015 EV_ABS ABS_MT_TRACKING_ID 00000002 EV_ABS ABS_MT_POSITION_X 00000231 EV_ABS ABS_MT_POSITION_Y 000002a1 EV_SYN SYN_MT_REPORT 00000000 EV_SYN SYN_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000011 EV_ABS ABS_MT_TRACKING_ID 00000000 EV_ABS ABS_MT_POSITION_X 00000178 EV_ABS ABS_MT_POSITION_Y 0000030f EV_SYN SYN_MT_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000013 EV_ABS ABS_MT_TRACKING_ID 00000001 EV_ABS ABS_MT_POSITION_X 000000e4 EV_ABS ABS_MT_POSITION_Y 0000037d EV_SYN SYN_MT_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000015 EV_ABS ABS_MT_TRACKING_ID 00000002 EV_ABS ABS_MT_POSITION_X 0000023a EV_ABS ABS_MT_POSITION_Y 000002c2 EV_SYN SYN_MT_REPORT 00000000 EV_SYN SYN_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000011 EV_ABS ABS_MT_TRACKING_ID 00000000 EV_ABS ABS_MT_POSITION_X 00000182 EV_ABS ABS_MT_POSITION_Y 00000329 EV_SYN SYN_MT_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000013 EV_ABS ABS_MT_TRACKING_ID 00000001 EV_ABS ABS_MT_POSITION_X 000000eb EV_ABS ABS_MT_POSITION_Y 0000039b EV_SYN SYN_MT_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000015 EV_ABS ABS_MT_TRACKING_ID 00000002 EV_ABS ABS_MT_POSITION_X 00000242 EV_ABS ABS_MT_POSITION_Y 000002de EV_SYN SYN_MT_REPORT 00000000 EV_SYN SYN_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000011 EV_ABS ABS_MT_TRACKING_ID 00000000 EV_ABS ABS_MT_POSITION_X 0000018a EV_ABS ABS_MT_POSITION_Y 00000343 EV_SYN SYN_MT_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000013 EV_ABS ABS_MT_TRACKING_ID 00000001 EV_ABS ABS_MT_POSITION_X 000000ef EV_ABS ABS_MT_POSITION_Y 000003b3 EV_SYN SYN_MT_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000015 EV_ABS ABS_MT_TRACKING_ID 00000002 EV_ABS ABS_MT_POSITION_X 00000247 EV_ABS ABS_MT_POSITION_Y 000002f6 EV_SYN SYN_MT_REPORT 00000000 EV_SYN SYN_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000011 EV_ABS ABS_MT_TRACKING_ID 00000000 EV_ABS ABS_MT_POSITION_X 0000018e EV_ABS ABS_MT_POSITION_Y 00000354 EV_SYN SYN_MT_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000013 EV_ABS ABS_MT_TRACKING_ID 00000001 EV_ABS ABS_MT_POSITION_X 000000f3 EV_ABS ABS_MT_POSITION_Y 000003c2 EV_SYN SYN_MT_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000015 EV_ABS ABS_MT_TRACKING_ID 00000002 EV_ABS ABS_MT_POSITION_X 0000024d EV_ABS ABS_MT_POSITION_Y 00000306 EV_SYN SYN_MT_REPORT 00000000 EV_SYN SYN_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000011 EV_ABS ABS_MT_TRACKING_ID 00000000 EV_ABS ABS_MT_POSITION_X 0000018f EV_ABS ABS_MT_POSITION_Y 0000035c EV_SYN SYN_MT_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000013 EV_ABS ABS_MT_TRACKING_ID 00000001 EV_ABS ABS_MT_POSITION_X 000000f5 EV_ABS ABS_MT_POSITION_Y 000003cb EV_SYN SYN_MT_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000015 EV_ABS ABS_MT_TRACKING_ID 00000002 EV_ABS ABS_MT_POSITION_X 0000024f EV_ABS ABS_MT_POSITION_Y 0000030e EV_SYN SYN_MT_REPORT 00000000 EV_SYN SYN_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000011 EV_ABS ABS_MT_TRACKING_ID 00000000 EV_ABS ABS_MT_POSITION_X 00000190 EV_ABS ABS_MT_POSITION_Y 0000035d EV_SYN SYN_MT_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000013 EV_ABS ABS_MT_TRACKING_ID 00000001 EV_ABS ABS_MT_POSITION_X 000000f8 EV_ABS ABS_MT_POSITION_Y 000003cf EV_SYN SYN_MT_REPORT 00000000 EV_ABS ABS_MT_TOUCH_MAJOR 00000015 EV_ABS ABS_MT_TRACKING_ID 00000002 EV_ABS ABS_MT_POSITION_X 00000251 EV_ABS ABS_MT_POSITION_Y 00000310 EV_SYN SYN_MT_REPORT 00000000 EV_SYN SYN_REPORT 00000000 EV_KEY BTN_TOUCH UP EV_SYN SYN_MT_REPORT 00000000 EV_SYN SYN_REPORT 00000000
This is how I am trying to parse it:
package com.xolo;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
public class Main {
public Main() {
}
public void readFile() {
File file = new File("....../output2.txt");
List<Event> listOfEvents = null;
try {
BufferedReader is = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
listOfEvents = createEvents(is);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
if (listOfEvents == null) {
return;
}
for (Event event : listOfEvents) {
System.out.println(event.toString());
}
}
private List<Event> createEvents(BufferedReader is) {
List<Event> listOfEvents = new ArrayList<>();
Event event = null;
String[] tokens;
try {
while (true) {
tokens = is.readLine().split("\\s+");
if (tokens[1].equalsIgnoreCase("BTN_TOUCH")) {
if (tokens[2].equalsIgnoreCase("DOWN")) {
event = new Event();
continue;
} else if (tokens[2].equalsIgnoreCase("UP")) {
tokens = is.readLine().split("\\s+");
if (tokens[1].equalsIgnoreCase("SYN_MT_REPORT")) {
tokens = is.readLine().split("\\s+");
if (tokens[1].equalsIgnoreCase("SYN_REPORT")) {
return listOfEvents;
} else {
throw new IllegalArgumentException();
}
} else {
throw new IllegalArgumentException();
}
}
} else if (tokens[1].equalsIgnoreCase("ABS_MT_TOUCH_MAJOR")) {
event.mtEvents.add(createMTEvent(is));
} else if (tokens[1].equalsIgnoreCase("SYN_REPORT")) {
if (event == null) {
throw new IllegalArgumentException();
}
listOfEvents.add(event);
event = new Event();
}
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private MTEvent createMTEvent(BufferedReader is) {
String[] tokens;
try {
tokens = is.readLine().split("\\s+");
if (!tokens[1].equalsIgnoreCase("ABS_MT_TRACKING_ID")) {
throw new IllegalArgumentException();
}
int id = Integer.valueOf(tokens[2]);
tokens = is.readLine().split("\\s+");
if (!tokens[1].equalsIgnoreCase("ABS_MT_POSITION_X")) {
throw new IllegalArgumentException();
}
int x = Integer.parseInt(tokens[2], 16);
tokens = is.readLine().split("\\s+");
if (!tokens[1].equalsIgnoreCase("ABS_MT_POSITION_Y")) {
throw new IllegalArgumentException();
}
int y = Integer.parseInt(tokens[2], 16);
tokens = is.readLine().split("\\s+");
if (!tokens[1].equalsIgnoreCase("SYN_MT_REPORT")) {
throw new IllegalArgumentException();
}
return new MTEvent(id, x, y);
} catch (IOException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
}
return null;
}
public static void main(String[] args) {
Main mn = new Main();
mn.readFile();
}
private class MTEvent {
int trackingID;
int x;
int y;
public MTEvent(int id, int x, int y) {
this.trackingID = id;
this.x = x;
this.y = y;
}
@Override
public String toString() {
return "ID: " + trackingID + ", x: " + x + ", y: " + y;
}
}
private class Event {
List<MTEvent> mtEvents;
Event() {
mtEvents = new ArrayList<>();
}
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("Event: \n");
for (MTEvent mtEvent : mtEvents) {
stringBuilder.append(mtEvent.toString()).append("\n");
}
return stringBuilder.toString();
}
}
}
I tried to separate the individual event and MultiTouch event into separate methods but I don't think I have done it right.
There are a number of things that I want to correct:
- The parsing logic itself.
- The Exceptions thrown (any different way to do it?)
- The splitting of
input
onspace
characters (any better way to do it?).
1 Answer 1
Naming
The first point i'd like to raise is the naming of your class i.e. Main
. This isn't very descriptive of what your intention is. I'd expect a class like AndroidTouchInputEventsReader
that contains a method such as List<Event> parseAndroidTouchEvents(BufferedReader);
. Try to think in terms of another programmer using the code, and attempt to make it clear how to use your methods.
class Main -> lets rename this AndroidTouchInputEventsReader
readFile() -> lets change this to List<Event> parseAndroidTouchEvents(BufferedReader)
Then, external to this class we can handle creation of a BufferedReader
which could come from a file or in fact any InputStream
.
Data
The classes Event
being private to the Main
class will hide the implementation to the Users. Currently that's OK as you're only printing the Events to the console, but if you think of your class as a way of getting InputEvents
in a different part of your program this won't work. In order for the next step to work, I would enable an MTEvent to be updated using setter methods, so I would add set
Parsing
Firstly, I agree with you splitting your lines on spaces. This certainly fits the file format. I would like to have seen you decouple the reading of the file to the parsing of the lines.
A standard way of dealing with parsing a sequence of things in a certain order is a Finite State Machine. A state machine stores a current state, and has a nextState method, that will verify the input and move to the next state. An easy way of doing this in Java is using an enum.
We have the states
current state | action | next state
INITIAL | t[1] = BTN_TOUCH & t[2] =DOWN | BT_TOUCH-down
BTN_TOUCH-down | t[1] = ABS_MT_TOUCH_MAJOR | ABS_MT_TOUCH_MAJOR
ABS_MT_TOUCH_MAJOR | read t[1] trackingid, update MTEvent | ABS_MT_TRACKING_ID
ABS_MT_TRACKING_ID | read t[1] =x, update MTEvent | ABS_MT_POSITION_X
ABS_MT_POSITION_X |read t[1] =y, update MTEvent | ABS_MT_POSITION_Y
ABS_MT_POSITION_Y | t[1] = (mt_report) | SYN_MT_REPORT
SYN_MT_REPORT | save MTEvent to event
| if t[1] =(touchMajor) | ABS_MT_TOUCH_MAJOR
| if t[1] = (synReport) | SYN_REPORT
SYN_REPORT | add the event to list.
| t[1]=(touchMajor) | ABS_MT_TOUCH_MAJOR
| if t[1]=(BTN_TOUCH-up) | BTN_TOUCH-up
| if (EOF) | END
BTN_TOUCH-UP | token[1]= SYN_MT_REPORT | SYN_MT_REPORT
At each state, you check whether the input line is valid, and update the Event with data. You know at SYN_MT_REPORT
you add the MTEvent to the Event's List and at SYN_REPORT
you have read the whole event, so you can add the event to the event list. If the line isn't valid, have it throw a parseException that your main read loop can catch.
Based on the input, you also choose the next state, So, when you're in the SYN_MT_REPORT
state, when you next call parseLine, the next command could be a ABS_MT_TOUCH_MAJOR
or a SYN_REPORT
, so in the nextAction method, the line read will decide between each.
- If you read the
SYN_REPORT
state, you know that you have a complete event, and to add the list ofMTEvent
in to the currentEvent
- If you read the
ABS_MT_TOUCH_MAJOR
you know the next state will beABS_MT_TRACKING_ID
for another multi-touch event.
This is how I would create the enum
private static enum TouchEventState {
INITIAL{
@Override
public TouchEventState processLine(String line, int currentLine, Event currentEvent, List<Event> ret) throws ParseException {
String[] tokens = tokenize(line);
if (validateLine(tokens)){
return BTN_TOUCH_DOWN;
} else {
throw new ParseException(line, currentLine);
}
}
boolean validateLine(String[] tokens){
return tokens.length == COLS
&& tokens[1].equalsIgnoreCase("BTN_TOUCH")
&& tokens[2].equalsIgnoreCase("DOWN");
}
},
BTN_TOUCH_DOWN{
@Override
public TouchEventState processLine(String line,int currentLine, Event currentEvent, List<Event> ret) {
String[] tokens = tokenize(line);
if (validateLine(tokens){
return ABS_MT_TOUCH_MAJOR;
} else {
throw new ParseException(line, currentLine);
}
}
boolean validateLine(String[] tokens){
return tokens.length == COLS
&& tokens[1].equalsIgnoreCase("ABS_MT_TOUCH_MAJOR");
}
},
ABS_MT_TOUCH_MAJOR
{
TouchEventState processLine(String line, int currentLine,
Event currentEvent,MTEvent currentMtEvent, List<Event> ret) throws ParseException {
//if valid input (you've read ,EV_ABS ABS_MT_TRACKING_ID 00000000) do
//currentMtEvent.setTrackingId(000000);
}
},
ABS_MT_TRACKING_ID {
TouchEventState processLine(String line, int currentLine,
Event currentEvent,MTEvent currentMtEvent, List<Event> ret) throws ParseException {
//if valid input, currentMtEvent.setPosX(tokens[1]);
}
},
ABS_MT_POSITION_X {
TouchEventState processLine(String line, int currentLine,
Event currentEvent,MTEvent currentMtEvent, List<Event> ret) throws ParseException {
//if valid input, currentMtEvent.setPosY(tokens[1]);
//return ABS_MT_POSITION_Y
}
},
ABS_MT_POSITION_Y
{
// Read this-> EV_SYN SYN_MT_REPORT 00000000,
// currentEvent.addMtEvent(currentMtEvent);
// return SYN_MT_REPORT
},
SYN_MT_REPORT {
TouchEventState processLine(String line, int currentLine,
Event currentEvent,MTEvent currentMtEvent, List<Event> ret) throws ParseException {
//if valid input = SYN_REPORT ,
//ret.addEvent(currentEvent);
}
},
SYN_REPORT {
TouchEventState processLine(String line, int currentLine,
Event currentEvent,MTEvent currentMtEvent, List<Event> ret) throws ParseException {
//if input = ABS_MT_TOUCH_MAJOR -> currentEvent = new Event, currentMtEvent = new currentMtEvent(), return ABS_MT_TOUCH_MAJOR
//if EOF return FINISH
}
};
String[] tokenize(String line) {
return line.split("\\+s");
}
so your processing loop becomes
while((currentLine = reader.readLine()) != null){
try{
state = state.processLine(currentLine, lineNumber, currentEvent, ret);
++lineNumber;
} catch (ParseException pse) {
// error with the input - out of sync.
throw pse;
}
}
return ret;
Conclusion
When creating a new class I would encourage you to think about how it will be used in the rest of the System, or by another User. This leads to better naming and easier to understand code.
When parsing, a sequence, I would always use a loop to read each line of the file, then a state machine to decide what to do with that line.
-
\$\begingroup\$ The states clean the code. However, I want the events to be available in a
List
. The way you have suggested, I do not know who(where) theMTEvent
s would be created. \$\endgroup\$yadav_vi– yadav_vi2015年05月20日 15:03:41 +00:00Commented May 20, 2015 at 15:03 -
\$\begingroup\$ Yes - change processLine method to add a currentMtEvent object. In the
ABS_MT_TRACKING_ID
state, you set thecurrentMtEvent
to a new Event. In theABS_MT_TRACKING_ID
ABS_MT_POSITION_X
andABS_MT_POSITION_Y
states you update thecurrentMtEvent
. In theSYN_MT_REPORT
state you add thecurrentMtEvent
to thecurrentEvent
. In theSYN_REPORT
state you add the currentEvent to theret
list. \$\endgroup\$rocka147– rocka1472015年05月20日 15:10:35 +00:00Commented May 20, 2015 at 15:10 -
\$\begingroup\$ I can update the example if you wish \$\endgroup\$rocka147– rocka1472015年05月20日 15:11:44 +00:00Commented May 20, 2015 at 15:11
-
\$\begingroup\$ That would be great, and would clarify a lot. \$\endgroup\$yadav_vi– yadav_vi2015年05月20日 15:55:01 +00:00Commented May 20, 2015 at 15:55
-
\$\begingroup\$ I have added another parameter to the
processLine
method (i.e.currentMtEvent
, i have added psuedo code to the state transitions to show how to handle them \$\endgroup\$rocka147– rocka1472015年05月20日 16:25:04 +00:00Commented May 20, 2015 at 16:25