Files
Lawnchair/tests/src/com/android/launcher3/testcomponent/TouchEventGenerator.java
T
Hyunyoung Song f40e94955c Add tests to SwipeDetector (formerly VerticalPullDetector).
Change-Id: I09ab4f22d7204ad806825ab0d6374c2b9616bf39
2017-07-06 14:32:35 -07:00

276 lines
7.9 KiB
Java

/*
* Copyright (C) 2017 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 com.android.launcher3.testcomponent;
import android.graphics.Point;
import android.util.Pair;
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.MotionEvent.PointerCoords;
import android.view.MotionEvent.PointerProperties;
import java.util.HashMap;
import java.util.Map;
/**
* Utility class to generate MotionEvent event sequences for testing touch gesture detectors.
*/
public class TouchEventGenerator {
/**
* Amount of time between two generated events.
*/
private static final long TIME_INCREMENT_MS = 20L;
/**
* Id of the fake device generating the events.
*/
private static final int DEVICE_ID = 2104;
/**
* The fingers currently present on the emulated touch screen.
*/
private Map<Integer, Point> mFingers;
/**
* Initial event time for the current sequence.
*/
private long mInitialTime;
/**
* Time of the last generated event.
*/
private long mLastEventTime;
/**
* Time of the next event.
*/
private long mTime;
/**
* Receives the generated events.
*/
public interface Listener {
/**
* Called when an event was generated.
*/
void onTouchEvent(MotionEvent event);
}
private final Listener mListener;
public TouchEventGenerator(Listener listener) {
mListener = listener;
mFingers = new HashMap<Integer, Point>();
}
/**
* Adds a finger on the touchscreen.
*/
public TouchEventGenerator put(int id, int x, int y, long ms) {
checkFingerExistence(id, false);
boolean isInitialDown = mFingers.isEmpty();
mFingers.put(id, new Point(x, y));
int action;
if (isInitialDown) {
action = MotionEvent.ACTION_DOWN;
} else {
action = MotionEvent.ACTION_POINTER_DOWN;
// Set the id of the changed pointer.
action |= id << MotionEvent.ACTION_POINTER_INDEX_SHIFT;
}
generateEvent(action, ms);
return this;
}
/**
* Adds a finger on the touchscreen after advancing default time interval.
*/
public TouchEventGenerator put(int id, int x, int y) {
return put(id, x, y, TIME_INCREMENT_MS);
}
/**
* Adjusts the position of a finger for an upcoming move event.
*
* @see #move(long ms)
*/
public TouchEventGenerator position(int id, int x, int y) {
checkFingerExistence(id, true);
mFingers.get(id).set(x, y);
return this;
}
/**
* Commits the finger position changes of {@link #position(int, int, int)} by generating a move
* event.
*
* @see #position(int, int, int)
*/
public TouchEventGenerator move(long ms) {
generateEvent(MotionEvent.ACTION_MOVE, ms);
return this;
}
/**
* Commits the finger position changes of {@link #position(int, int, int)} by generating a move
* event after advancing the default time interval.
*
* @see #position(int, int, int)
*/
public TouchEventGenerator move() {
return move(TIME_INCREMENT_MS);
}
/**
* Moves a single finger on the touchscreen.
*/
public TouchEventGenerator move(int id, int x, int y, long ms) {
return position(id, x, y).move(ms);
}
/**
* Moves a single finger on the touchscreen after advancing default time interval.
*/
public TouchEventGenerator move(int id, int x, int y) {
return move(id, x, y, TIME_INCREMENT_MS);
}
/**
* Removes an existing finger from the touchscreen.
*/
public TouchEventGenerator lift(int id, long ms) {
checkFingerExistence(id, true);
boolean isFinalUp = mFingers.size() == 1;
int action;
if (isFinalUp) {
action = MotionEvent.ACTION_UP;
} else {
action = MotionEvent.ACTION_POINTER_UP;
// Set the id of the changed pointer.
action |= id << MotionEvent.ACTION_POINTER_INDEX_SHIFT;
}
generateEvent(action, ms);
mFingers.remove(id);
return this;
}
/**
* Removes a finger from the touchscreen.
*/
public TouchEventGenerator lift(int id, int x, int y, long ms) {
checkFingerExistence(id, true);
mFingers.get(id).set(x, y);
return lift(id, ms);
}
/**
* Removes an existing finger from the touchscreen after advancing default time interval.
*/
public TouchEventGenerator lift(int id) {
return lift(id, TIME_INCREMENT_MS);
}
/**
* Cancels an ongoing sequence.
*/
public TouchEventGenerator cancel(long ms) {
generateEvent(MotionEvent.ACTION_CANCEL, ms);
mFingers.clear();
return this;
}
/**
* Cancels an ongoing sequence.
*/
public TouchEventGenerator cancel() {
return cancel(TIME_INCREMENT_MS);
}
private void checkFingerExistence(int id, boolean shouldExist) {
if (shouldExist != mFingers.containsKey(id)) {
throw new IllegalArgumentException(
shouldExist ? "Finger does not exist" : "Finger already exists");
}
}
private void generateEvent(int action, long ms) {
mTime = mLastEventTime + ms;
Pair<PointerProperties[], PointerCoords[]> state = getFingerState();
MotionEvent event = MotionEvent.obtain(
mInitialTime,
mTime,
action,
state.first.length,
state.first,
state.second,
0 /* metaState */,
0 /* buttonState */,
1.0f /* xPrecision */,
1.0f /* yPrecision */,
DEVICE_ID,
0 /* edgeFlags */,
InputDevice.SOURCE_TOUCHSCREEN,
0 /* flags */);
mListener.onTouchEvent(event);
if (action == MotionEvent.ACTION_UP) {
resetTime();
}
event.recycle();
mLastEventTime = mTime;
}
/**
* Returns the description of the fingers' state expected by MotionEvent.
*/
private Pair<PointerProperties[], PointerCoords[]> getFingerState() {
int nFingers = mFingers.size();
PointerProperties[] properties = new PointerProperties[nFingers];
PointerCoords[] coordinates = new PointerCoords[nFingers];
int index = 0;
for (Map.Entry<Integer, Point> entry : mFingers.entrySet()) {
int id = entry.getKey();
Point location = entry.getValue();
PointerProperties property = new PointerProperties();
property.id = id;
property.toolType = MotionEvent.TOOL_TYPE_FINGER;
properties[index] = property;
PointerCoords coordinate = new PointerCoords();
coordinate.x = location.x;
coordinate.y = location.y;
coordinate.pressure = 1.0f;
coordinates[index] = coordinate;
index++;
}
return new Pair<MotionEvent.PointerProperties[], MotionEvent.PointerCoords[]>(
properties, coordinates);
}
/**
* Resets the time references for a new sequence.
*/
private void resetTime() {
mInitialTime = 0L;
mLastEventTime = -1L;
mTime = 0L;
}
}