1 /* 2 * Copyright (C) 2021 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 android.view; 18 19 import static android.os.IInputConstants.INVALID_INPUT_EVENT_ID; 20 import static android.view.InputDevice.SOURCE_TOUCHSCREEN; 21 22 /** 23 * Process input events and assign input event id to a specific frame. 24 * 25 * The assigned input event id is determined by where the current gesture is relative to the vsync. 26 * In the middle of the gesture (we already processed some input events, and already received at 27 * least 1 vsync), the latest InputEvent is assigned to the next frame. 28 * If a gesture just started, then the ACTION_DOWN event will be assigned to the next frame. 29 * 30 * Consider the following sequence: 31 * DOWN -> VSYNC 1 -> MOVE 1 -> MOVE 2 -> VSYNC 2. 32 * 33 * For VSYNC 1, we will assign the "DOWN" input event. 34 * For VSYNC 2, we will assign the "MOVE 2" input event. 35 * 36 * Consider another sequence: 37 * DOWN -> MOVE 1 -> MOVE 2 -> VSYNC 1 -> MOVE 3 -> VSYNC 2. 38 * 39 * For VSYNC 1, we will still assign the "DOWN" input event. That means that "MOVE 1" and "MOVE 2" 40 * events are not attributed to any frame. 41 * For VSYNC 2, the "MOVE 3" input event will be assigned. 42 * 43 * @hide 44 */ 45 public class InputEventAssigner { 46 private static final String TAG = "InputEventAssigner"; 47 private boolean mHasUnprocessedDown = false; 48 private int mDownEventId = INVALID_INPUT_EVENT_ID; 49 50 /** 51 * Notify InputEventAssigner that a frame has been processed. We no longer need to keep track of 52 * the DOWN event because a frame has already been produced for it. 53 */ notifyFrameProcessed()54 public void notifyFrameProcessed() { 55 // Mark completion of this frame. Use newest input event from now on. 56 mHasUnprocessedDown = false; 57 } 58 59 /** 60 * Process the provided input event to determine which event id to assign to the current frame. 61 * @param event the input event currently being processed 62 * @return the id of the input event to use for the current frame 63 */ processEvent(InputEvent event)64 public int processEvent(InputEvent event) { 65 if (event instanceof MotionEvent) { 66 MotionEvent motionEvent = (MotionEvent) event; 67 if (motionEvent.isFromSource(SOURCE_TOUCHSCREEN)) { 68 final int action = motionEvent.getActionMasked(); 69 if (action == MotionEvent.ACTION_DOWN) { 70 mHasUnprocessedDown = true; 71 mDownEventId = event.getId(); 72 } 73 if (mHasUnprocessedDown && action == MotionEvent.ACTION_MOVE) { 74 return mDownEventId; 75 } 76 if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) { 77 mHasUnprocessedDown = false; 78 } 79 } 80 } 81 return event.getId(); 82 } 83 } 84