1
\$\begingroup\$

I am trying to parse InputEvents 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 and VALUE.
  • EVENT_TYPE can be of following types - EV_KEY, EV_ABS and EV_SYN.
  • In turn, each EVENT_TYPE can have different EVENT_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 a VALUE.
  • 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 a EV_KEY - BTN_TOUCH - UP combination. (There are event separators after EV_KEY - BTN_TOUCH - UP viz. SYN_MT_REPORT and SYN_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 on space characters (any better way to do it?).
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked May 19, 2015 at 15:13
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

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 of MTEvent in to the current Event
  • If you read the ABS_MT_TOUCH_MAJOR you know the next state will be ABS_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.

answered May 20, 2015 at 7:30
\$\endgroup\$
6
  • \$\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) the MTEvents would be created. \$\endgroup\$ Commented 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 the currentMtEvent to a new Event. In the ABS_MT_TRACKING_ID ABS_MT_POSITION_X and ABS_MT_POSITION_Y states you update the currentMtEvent. In the SYN_MT_REPORT state you add the currentMtEvent to the currentEvent. In the SYN_REPORT state you add the currentEvent to the ret list. \$\endgroup\$ Commented May 20, 2015 at 15:10
  • \$\begingroup\$ I can update the example if you wish \$\endgroup\$ Commented May 20, 2015 at 15:11
  • \$\begingroup\$ That would be great, and would clarify a lot. \$\endgroup\$ Commented 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\$ Commented May 20, 2015 at 16:25

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.