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