aboutsummaryrefslogtreecommitdiff
path: root/android/WALT/app/src/main/java/org/chromium/latency/walt/UsMotionEvent.java
blob: f68e4616a2fcf13ce2b4564b7404b53b4e89fc17 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.chromium.latency.walt;

import android.util.Log;
import android.view.MotionEvent;

import java.lang.reflect.Method;
import java.util.Locale;

/**
 * A convenient representation of MotionEvent events
 * - microsecond accuracy
 * - no bundling of ACTION_MOVE events
 */

public class UsMotionEvent {

    public long physicalTime, kernelTime, createTime;
    public float x, y;
    public int slot;
    public int action;
    public int num;
    public String metadata;
    public long baseTime;

    public boolean isOk = false;

    /**
     *
     * @param event - MotionEvent as received by the handler.
     * @param baseTime - base time of the last clock sync.
     */
    public UsMotionEvent(MotionEvent event, long baseTime) {
        createTime = RemoteClockInfo.microTime() - baseTime;
        this.baseTime = baseTime;
        slot = -1;
        kernelTime = getEventTimeMicro(event) - baseTime;
        x = event.getX();
        y = event.getY();
        action = event.getAction();
    }

    public UsMotionEvent(MotionEvent event, long baseTime, int pos) {
        createTime = RemoteClockInfo.microTime() - baseTime;
        this.baseTime = baseTime;
        slot = pos;
        action = MotionEvent.ACTION_MOVE; // Only MOVE events get bundled with history

        kernelTime = getHistoricalEventTimeMicro(event, pos) - baseTime;
        x = event.getHistoricalX(pos);
        y = event.getHistoricalY(pos);
    }

    public String getActionString() {
        return actionToString(action);
    }


    public String toString() {
        return String.format(Locale.US, "%d %f %f",
                kernelTime, x, y);

    }

    public String toStringLong() {
        return String.format(Locale.US, "Event: t=%d x=%.1f y=%.1f slot=%d num=%d %s",
                kernelTime, x, y, slot, num, actionToString(action));

    }

    // The MotionEvent.actionToString is not present before API 19
    public static String actionToString(int action) {
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                return "ACTION_DOWN";
            case MotionEvent.ACTION_UP:
                return "ACTION_UP";
            case MotionEvent.ACTION_CANCEL:
                return "ACTION_CANCEL";
            case MotionEvent.ACTION_OUTSIDE:
                return "ACTION_OUTSIDE";
            case MotionEvent.ACTION_MOVE:
                return "ACTION_MOVE";
            case MotionEvent.ACTION_HOVER_MOVE:
                return "ACTION_HOVER_MOVE";
            case MotionEvent.ACTION_SCROLL:
                return "ACTION_SCROLL";
            case MotionEvent.ACTION_HOVER_ENTER:
                return "ACTION_HOVER_ENTER";
            case MotionEvent.ACTION_HOVER_EXIT:
                return "ACTION_HOVER_EXIT";
        }
        return "UNKNOWN_ACTION";
    }

    /**
     MotionEvent.getEventTime() function only provides millisecond resolution.
     There is a MotionEvent.getEventTimeNano() function but for some reason it
     is hidden by @hide which means it can't be called directly.
     Calling is via reflection.

     See:
     http://stackoverflow.com/questions/17035271/what-does-hide-mean-in-the-android-source-code
     */
    private long getEventTimeMicro(MotionEvent event) {
        long t_nanos = -1;
        try {
            Class<?> cls = Class.forName("android.view.MotionEvent");
            Method myTimeGetter = cls.getMethod("getEventTimeNano");
            t_nanos = (long) myTimeGetter.invoke(event);
        } catch (Exception e) {
            Log.i("WALT.MsMotionEvent", e.getMessage());
        }

        return t_nanos / 1000;
    }

    private long getHistoricalEventTimeMicro(MotionEvent event, int pos) {
        long t_nanos = -1;
        try {
            Class<?> cls = Class.forName("android.view.MotionEvent");
            Method myTimeGetter = cls.getMethod("getHistoricalEventTimeNano", new Class[] {int.class});
            t_nanos = (long) myTimeGetter.invoke(event, new Object[]{pos});
        } catch (Exception e) {
            Log.i("WALT.MsMotionEvent", e.getMessage());
        }

        return t_nanos / 1000;
    }

}