1e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer/*
2e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer * Copyright (C) 2015 The Android Open Source Project
3e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer *
4e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer * Licensed under the Apache License, Version 2.0 (the "License");
5e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer * you may not use this file except in compliance with the License.
6e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer * You may obtain a copy of the License at
7e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer *
8e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer *      http://www.apache.org/licenses/LICENSE-2.0
9e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer *
10e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer * Unless required by applicable law or agreed to in writing, software
11e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer * distributed under the License is distributed on an "AS IS" BASIS,
12e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer * See the License for the specific language governing permissions and
14e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer * limitations under the License.
15e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer */
16e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
17e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerpackage org.chromium.latency.walt;
18e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
19e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerimport android.util.Log;
20e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerimport android.view.MotionEvent;
21e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
22e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerimport java.lang.reflect.Method;
23e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
24e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer/**
25e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer * A convenient representation of MotionEvent events
26e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer * - microsecond accuracy
27e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer * - no bundling of ACTION_MOVE events
28e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer */
29e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
30e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerpublic class UsMotionEvent {
31e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
32e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    public long physicalTime, kernelTime, createTime;
33e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    public float x, y;
34e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    public int slot;
35e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    public int action;
36e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    public int num;
37e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    public String metadata;
38e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    public long baseTime;
39e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
40e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    public boolean isOk = false;
41e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
42e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    /**
43e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer     *
44e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer     * @param event - MotionEvent as received by the handler.
45e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer     * @param baseTime - base time of the last clock sync.
46e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer     */
47e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    public UsMotionEvent(MotionEvent event, long baseTime) {
48e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        createTime = RemoteClockInfo.microTime() - baseTime;
49e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        this.baseTime = baseTime;
50e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        slot = -1;
51e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        kernelTime = getEventTimeMicro(event) - baseTime;
52e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        x = event.getX();
53e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        y = event.getY();
54e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        action = event.getAction();
55e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    }
56e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
57e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    public UsMotionEvent(MotionEvent event, long baseTime, int pos) {
58e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        createTime = RemoteClockInfo.microTime() - baseTime;
59e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        this.baseTime = baseTime;
60e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        slot = pos;
61e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        action = MotionEvent.ACTION_MOVE; // Only MOVE events get bundled with history
62e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
63e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        kernelTime = getHistoricalEventTimeMicro(event, pos) - baseTime;
64e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        x = event.getHistoricalX(pos);
65e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        y = event.getHistoricalY(pos);
66e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    }
67e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
68e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    public String getActionString() {
69e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        return actionToString(action);
70e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    }
71e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
72e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
73e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    public String toString() {
74e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        return String.format("%d %f %f",
75e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                kernelTime, x, y);
76e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
77e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    }
78e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
79e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    public String toStringLong() {
80e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        return String.format("Event: t=%d x=%.1f y=%.1f slot=%d num=%d %s",
81e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                kernelTime, x, y, slot, num, actionToString(action));
82e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
83e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    }
84e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
85e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // The MotionEvent.actionToString is not present before API 19
86e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    public static String actionToString(int action) {
87e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        switch (action) {
88e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer            case MotionEvent.ACTION_DOWN:
89e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                return "ACTION_DOWN";
90e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer            case MotionEvent.ACTION_UP:
91e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                return "ACTION_UP";
92e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer            case MotionEvent.ACTION_CANCEL:
93e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                return "ACTION_CANCEL";
94e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer            case MotionEvent.ACTION_OUTSIDE:
95e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                return "ACTION_OUTSIDE";
96e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer            case MotionEvent.ACTION_MOVE:
97e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                return "ACTION_MOVE";
98e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer            case MotionEvent.ACTION_HOVER_MOVE:
99e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                return "ACTION_HOVER_MOVE";
100e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer            case MotionEvent.ACTION_SCROLL:
101e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                return "ACTION_SCROLL";
102e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer            case MotionEvent.ACTION_HOVER_ENTER:
103e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                return "ACTION_HOVER_ENTER";
104e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer            case MotionEvent.ACTION_HOVER_EXIT:
105e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                return "ACTION_HOVER_EXIT";
106e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        }
107e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        return "UNKNOWN_ACTION";
108e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    }
109e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
110e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    /**
111e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer     MotionEvent.getEventTime() function only provides millisecond resolution.
112e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer     There is a MotionEvent.getEventTimeNano() function but for some reason it
113e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer     is hidden by @hide which means it can't be called directly.
114e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer     Calling is via reflection.
115e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
116e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer     See:
117e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer     http://stackoverflow.com/questions/17035271/what-does-hide-mean-in-the-android-source-code
118e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer     */
119e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    private long getEventTimeMicro(MotionEvent event) {
120e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        long t_nanos = -1;
121e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        try {
122e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer            Class cls = Class.forName("android.view.MotionEvent");
123e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer            Method myTimeGetter = cls.getMethod("getEventTimeNano");
124e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer            t_nanos = (long) myTimeGetter.invoke(event);
125e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        } catch (Exception e) {
126e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer            Log.i("WALT.MsMotionEvent", e.getMessage());
127e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        }
128e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
129e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        return t_nanos / 1000;
130e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    }
131e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
132e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    private long getHistoricalEventTimeMicro(MotionEvent event, int pos) {
133e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        long t_nanos = -1;
134e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        try {
135e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer            Class cls = Class.forName("android.view.MotionEvent");
136e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer            Method myTimeGetter = cls.getMethod("getHistoricalEventTimeNano", new Class[] {int.class});
137e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer            t_nanos = (long) myTimeGetter.invoke(event, new Object[]{pos});
138e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        } catch (Exception e) {
139e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer            Log.i("WALT.MsMotionEvent", e.getMessage());
140e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        }
141e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
142e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        return t_nanos / 1000;
143e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    }
144e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
145e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer}
146e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
147