package com.jakewharton.rxbinding;
import android.app.Instrumentation;
import android.os.SystemClock;
import android.support.test.InstrumentationRegistry;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
public final class TouchUtilsBackport {
/**
* Simulate touching a view and dragging it to a specified location.
*
* @param v The view that should be dragged
* @param gravity Which part of the view to use for the initial down event. A combination of
* (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
* @param toX Final location of the view after dragging
* @param toY Final location of the view after dragging
* @return distance in pixels covered by the drag
*/
public static int dragViewTo(View v, int gravity, int toX, int toY) {
int[] xy = new int[2];
getStartLocation(v, gravity, xy);
int fromX = xy[0];
int fromY = xy[1];
int deltaX = fromX - toX;
int deltaY = fromY - toY;
int distance = (int) Math.sqrt(deltaX * deltaX + deltaY * deltaY);
drag(fromX, toX, fromY, toY, distance);
return distance;
}
/**
* Simulate touching a specific location and dragging to a new location.
*
* @param fromX X coordinate of the initial touch, in screen coordinates
* @param toX Xcoordinate of the drag destination, in screen coordinates
* @param fromY X coordinate of the initial touch, in screen coordinates
* @param toY Y coordinate of the drag destination, in screen coordinates
* @param stepCount How many move steps to include in the drag
*/
public static void drag(float fromX, float toX, float fromY, float toY, int stepCount) {
Instrumentation inst = InstrumentationRegistry.getInstrumentation();
long downTime = SystemClock.uptimeMillis();
long eventTime = SystemClock.uptimeMillis();
float y = fromY;
float x = fromX;
float yStep = (toY - fromY) / stepCount;
float xStep = (toX - fromX) / stepCount;
MotionEvent event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, x, y, 0);
inst.sendPointerSync(event);
for (int i = 0; i < stepCount; ++i) {
y += yStep;
x += xStep;
eventTime = SystemClock.uptimeMillis();
event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, x, y, 0);
inst.sendPointerSync(event);
}
eventTime = SystemClock.uptimeMillis();
event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
inst.sendPointerSync(event);
inst.waitForIdleSync();
}
/**
* Get the location of a view. Use the gravity param to specify which part of the view to
* return.
*
* @param v View to find
* @param gravity A combination of (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL,
* RIGHT)
* @param xy Result
*/
private static void getStartLocation(View v, int gravity, int[] xy) {
v.getLocationOnScreen(xy);
int viewWidth = v.getWidth();
int viewHeight = v.getHeight();
switch (gravity & Gravity.VERTICAL_GRAVITY_MASK) {
case Gravity.TOP:
break;
case Gravity.CENTER_VERTICAL:
xy[1] += viewHeight / 2;
break;
case Gravity.BOTTOM:
xy[1] += viewHeight - 1;
break;
default:
// Same as top -- do nothing
}
switch (gravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
case Gravity.LEFT:
break;
case Gravity.CENTER_HORIZONTAL:
xy[0] += viewWidth / 2;
break;
case Gravity.RIGHT:
xy[0] += viewWidth - 1;
break;
default:
// Same as left -- do nothing
}
}
private TouchUtilsBackport() {
throw new AssertionError("No instances");
}
}