xref: /aosp_15_r20/external/walt/android/WALT/app/src/main/java/org/chromium/latency/walt/UsMotionEvent.java (revision bf47c6829f95be9dd55f4c5bbc44a71c90aad403)
1 /*
2  * Copyright (C) 2015 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 org.chromium.latency.walt;
18 
19 import android.util.Log;
20 import android.view.MotionEvent;
21 
22 import java.lang.reflect.Method;
23 import java.util.Locale;
24 
25 /**
26  * A convenient representation of MotionEvent events
27  * - microsecond accuracy
28  * - no bundling of ACTION_MOVE events
29  */
30 
31 public class UsMotionEvent {
32 
33     public long physicalTime, kernelTime, createTime;
34     public float x, y;
35     public int slot;
36     public int action;
37     public int num;
38     public String metadata;
39     public long baseTime;
40 
41     public boolean isOk = false;
42 
43     /**
44      *
45      * @param event - MotionEvent as received by the handler.
46      * @param baseTime - base time of the last clock sync.
47      */
UsMotionEvent(MotionEvent event, long baseTime)48     public UsMotionEvent(MotionEvent event, long baseTime) {
49         createTime = RemoteClockInfo.microTime() - baseTime;
50         this.baseTime = baseTime;
51         slot = -1;
52         kernelTime = getEventTimeMicro(event) - baseTime;
53         x = event.getX();
54         y = event.getY();
55         action = event.getAction();
56     }
57 
UsMotionEvent(MotionEvent event, long baseTime, int pos)58     public UsMotionEvent(MotionEvent event, long baseTime, int pos) {
59         createTime = RemoteClockInfo.microTime() - baseTime;
60         this.baseTime = baseTime;
61         slot = pos;
62         action = MotionEvent.ACTION_MOVE; // Only MOVE events get bundled with history
63 
64         kernelTime = getHistoricalEventTimeMicro(event, pos) - baseTime;
65         x = event.getHistoricalX(pos);
66         y = event.getHistoricalY(pos);
67     }
68 
getActionString()69     public String getActionString() {
70         return actionToString(action);
71     }
72 
73 
toString()74     public String toString() {
75         return String.format(Locale.US, "%d %f %f",
76                 kernelTime, x, y);
77 
78     }
79 
toStringLong()80     public String toStringLong() {
81         return String.format(Locale.US, "Event: t=%d x=%.1f y=%.1f slot=%d num=%d %s",
82                 kernelTime, x, y, slot, num, actionToString(action));
83 
84     }
85 
86     // The MotionEvent.actionToString is not present before API 19
actionToString(int action)87     public static String actionToString(int action) {
88         switch (action) {
89             case MotionEvent.ACTION_DOWN:
90                 return "ACTION_DOWN";
91             case MotionEvent.ACTION_UP:
92                 return "ACTION_UP";
93             case MotionEvent.ACTION_CANCEL:
94                 return "ACTION_CANCEL";
95             case MotionEvent.ACTION_OUTSIDE:
96                 return "ACTION_OUTSIDE";
97             case MotionEvent.ACTION_MOVE:
98                 return "ACTION_MOVE";
99             case MotionEvent.ACTION_HOVER_MOVE:
100                 return "ACTION_HOVER_MOVE";
101             case MotionEvent.ACTION_SCROLL:
102                 return "ACTION_SCROLL";
103             case MotionEvent.ACTION_HOVER_ENTER:
104                 return "ACTION_HOVER_ENTER";
105             case MotionEvent.ACTION_HOVER_EXIT:
106                 return "ACTION_HOVER_EXIT";
107         }
108         return "UNKNOWN_ACTION";
109     }
110 
getEventTimeNanos(MotionEvent event, boolean preAndroidU)111     private long getEventTimeNanos(MotionEvent event, boolean preAndroidU) {
112         long t_nanos = -1;
113         final String methodName = preAndroidU ? "getEventTimeNano" : "getEventTimeNanos";
114         try {
115             Class<?> cls = Class.forName("android.view.MotionEvent");
116             Method myTimeGetter = cls.getMethod(methodName);
117             t_nanos = (long) myTimeGetter.invoke(event);
118         } catch (Exception e) {
119         }
120         return t_nanos;
121     }
122 
getHistoricalEventTimeNanos(MotionEvent event, int pos, boolean preAndroidU)123     private long getHistoricalEventTimeNanos(MotionEvent event, int pos, boolean preAndroidU) {
124         long t_nanos = -1;
125         final String methodName =
126                 preAndroidU ? "getHistoricalEventTimeNano" : "getHistoricalEventTimeNanos";
127         try {
128             Class<?> cls = Class.forName("android.view.MotionEvent");
129             Method myTimeGetter = cls.getMethod(methodName, new Class[]{int.class});
130             t_nanos = (long) myTimeGetter.invoke(event, new Object[]{pos});
131         } catch (Exception e) {
132         }
133         return t_nanos;
134     }
135 
136     /**
137      MotionEvent.getEventTime() function only provides millisecond resolution.
138      There is a MotionEvent.getEventTimeNano() function but for some reason it
139      is hidden by @hide which means it can't be called directly.
140      Calling is via reflection.
141 
142      See:
143      http://stackoverflow.com/questions/17035271/what-does-hide-mean-in-the-android-source-code
144      */
getEventTimeMicro(MotionEvent event)145     private long getEventTimeMicro(MotionEvent event) {
146         long t_nanos = -1;
147         t_nanos = getEventTimeNanos(event, false);
148         if (t_nanos == -1) {
149             t_nanos = getEventTimeNanos(event, true);
150             if (t_nanos == -1) {
151                 Log.i("WALT.UsMotionEvent", "getEventTimeNanos failed.");
152             }
153         }
154         return t_nanos / 1000;
155     }
156 
getHistoricalEventTimeMicro(MotionEvent event, int pos)157     private long getHistoricalEventTimeMicro(MotionEvent event, int pos) {
158         long t_nanos = -1;
159         t_nanos = getHistoricalEventTimeNanos(event, pos, false);
160         if (t_nanos == -1) {
161             t_nanos = getHistoricalEventTimeNanos(event, pos, true);
162             if (t_nanos == -1) {
163                 Log.i("WALT.UsMotionEvent", "getHistoricalEventTimeNanos failed.");
164             }
165         }
166         return t_nanos / 1000;
167     }
168 
169 }
170 
171