1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.accessibility.utils; 18 19 import android.view.MotionEvent; 20 21 import java.util.regex.Matcher; 22 import java.util.regex.Pattern; 23 24 /** 25 * This class helps parse a gesture event log into its individual MotionEvents 26 */ 27 public class GestureLogParser { 28 /** Gets a MotionEvent from a log line */ getMotionEventFromLogLine(String line)29 public static MotionEvent getMotionEventFromLogLine(String line) { 30 final int downTime; 31 final int eventTime; 32 int action; 33 final int pointerCount; 34 35 final MotionEvent.PointerProperties[] properties; 36 final MotionEvent.PointerCoords[] pointerCoords; 37 final int metaState; 38 final int buttonState = 0; 39 final int xPrecision = 1; 40 final int yPrecision = 1; 41 final int deviceId; 42 final int edgeFlags; 43 final int source; 44 final int flags; 45 final int actionIndex; 46 47 downTime = findInt(line, "downTime=(\\d+)"); 48 eventTime = findInt(line, "eventTime=(\\d+)"); 49 action = stringToAction(findString(line, "action=(\\w+)")); 50 51 // For pointer indices 52 Pattern p = Pattern.compile("action=(\\w+)\\((\\d)"); 53 Matcher matcher = p.matcher(line); 54 if (matcher.find()) { 55 actionIndex = Integer.decode(matcher.group(2)); 56 action = action | (actionIndex << MotionEvent.ACTION_POINTER_INDEX_SHIFT); 57 } 58 59 pointerCount = findInt(line, "pointerCount=(\\d+)"); 60 metaState = findInt(line, "metaState=(\\d+)"); 61 deviceId = findInt(line, "deviceId=(\\d+)"); 62 edgeFlags = Integer.decode(findString(line, "edgeFlags=(\\w+)")); 63 source = Integer.decode(findString(line, "source=(\\w+)")); 64 flags = Integer.decode(findString(line, "flags=(\\w+)")); 65 properties = findProperties(line, pointerCount); 66 pointerCoords = findCoordinates(line, pointerCount); 67 68 return MotionEvent.obtain(downTime, eventTime, action, 69 pointerCount, properties, pointerCoords, metaState, buttonState, 70 xPrecision, yPrecision, deviceId, edgeFlags, source, flags); 71 } 72 findInt(String eventText, String pattern)73 private static int findInt(String eventText, String pattern) { 74 final Pattern p = Pattern.compile(pattern); 75 final Matcher matcher = p.matcher(eventText); 76 matcher.find(); 77 return Integer.decode(matcher.group(1)); 78 } 79 findFloat(String eventText, String pattern)80 private static float findFloat(String eventText, String pattern) { 81 final Pattern p = Pattern.compile(pattern); 82 final Matcher matcher = p.matcher(eventText); 83 matcher.find(); 84 return Float.parseFloat(matcher.group(1)); 85 } 86 findString(String eventText, String pattern)87 private static String findString(String eventText, String pattern) { 88 final Pattern p = Pattern.compile(pattern); 89 final Matcher matcher = p.matcher(eventText); 90 matcher.find(); 91 return matcher.group(1); 92 } 93 findCoordinates(String eventText, int pointerCount)94 private static MotionEvent.PointerCoords[] findCoordinates(String eventText, int pointerCount) { 95 if (pointerCount == 0) { 96 return null; 97 } 98 99 final MotionEvent.PointerCoords[] coords = new MotionEvent.PointerCoords[pointerCount]; 100 float x; 101 float y; 102 for (int i = 0; i < pointerCount; i++) { 103 104 x = findFloat(eventText, "x\\[" + i + "\\]=([\\d.]+)"); 105 y = findFloat(eventText, "y\\[" + i + "\\]=([\\d.]+)"); 106 107 MotionEvent.PointerCoords pointerCoords = new MotionEvent.PointerCoords(); 108 pointerCoords.x = x; 109 pointerCoords.y = y; 110 pointerCoords.pressure = 1; 111 pointerCoords.size = 1; 112 113 coords[i] = pointerCoords; 114 } 115 return coords; 116 } 117 findProperties( String eventText, int pointerCount)118 private static MotionEvent.PointerProperties[] findProperties( 119 String eventText, int pointerCount) { 120 if (pointerCount == 0) { 121 return null; 122 } 123 124 final MotionEvent.PointerProperties[] props = 125 new MotionEvent.PointerProperties[pointerCount]; 126 int id; 127 for (int i = 0; i < pointerCount; i++) { 128 id = findInt(eventText, "id\\[" + i + "\\]=([\\d])"); 129 MotionEvent.PointerProperties pointerProps = new MotionEvent.PointerProperties(); 130 pointerProps.id = id; 131 pointerProps.toolType = MotionEvent.TOOL_TYPE_FINGER; 132 props[i] = pointerProps; 133 } 134 return props; 135 } 136 stringToAction(String action)137 private static int stringToAction(String action) { 138 switch (action) { 139 case "ACTION_DOWN": 140 return MotionEvent.ACTION_DOWN; 141 case "ACTION_UP": 142 return MotionEvent.ACTION_UP; 143 case "ACTION_CANCEL": 144 return MotionEvent.ACTION_CANCEL; 145 case "ACTION_OUTSIDE": 146 return MotionEvent.ACTION_OUTSIDE; 147 case "ACTION_MOVE": 148 return MotionEvent.ACTION_MOVE; 149 case "ACTION_HOVER_MOVE": 150 return MotionEvent.ACTION_HOVER_MOVE; 151 case "ACTION_SCROLL": 152 return MotionEvent.ACTION_SCROLL; 153 case "ACTION_HOVER_ENTER": 154 return MotionEvent.ACTION_HOVER_ENTER; 155 case "ACTION_HOVER_EXIT": 156 return MotionEvent.ACTION_HOVER_EXIT; 157 case "ACTION_BUTTON_PRESS": 158 return MotionEvent.ACTION_BUTTON_PRESS; 159 case "ACTION_BUTTON_RELEASE": 160 return MotionEvent.ACTION_BUTTON_RELEASE; 161 case "ACTION_POINTER_DOWN": 162 return MotionEvent.ACTION_POINTER_DOWN; 163 case "ACTION_POINTER_UP": 164 return MotionEvent.ACTION_POINTER_UP; 165 default: 166 return -1; 167 } 168 } 169 } 170