185 lines
7.7 KiB
Java
185 lines
7.7 KiB
Java
/*
|
|
* Copyright (C) 2016 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.documentsui.bots;
|
|
|
|
import android.app.UiAutomation;
|
|
import android.content.Context;
|
|
import android.graphics.Point;
|
|
import android.graphics.Rect;
|
|
import android.os.SystemClock;
|
|
import android.support.test.uiautomator.Configurator;
|
|
import android.support.test.uiautomator.UiDevice;
|
|
import android.support.test.uiautomator.UiObject;
|
|
import android.support.test.uiautomator.UiObjectNotFoundException;
|
|
import android.support.test.uiautomator.UiSelector;
|
|
import android.view.InputDevice;
|
|
import android.view.MotionEvent;
|
|
import android.view.MotionEvent.PointerCoords;
|
|
import android.view.MotionEvent.PointerProperties;
|
|
|
|
/**
|
|
* A test helper class that provides support for controlling directory list
|
|
* and making assertions against the state of it.
|
|
*/
|
|
public class GestureBot extends Bots.BaseBot {
|
|
private static final int LONGPRESS_STEPS = 60;
|
|
private static final int TRAVELING_STEPS = 20;
|
|
private static final int BAND_SELECTION_DEFAULT_STEPS = 100;
|
|
private static final int STEPS_INBETWEEN_POINTS = 2;
|
|
// Inserted after each motion event injection.
|
|
private static final int MOTION_EVENT_INJECTION_DELAY_MILLIS = 5;
|
|
private static final int LONG_PRESS_EVENT_INJECTION_DELAY_MILIS = 1000;
|
|
private final String mDirContainerId;
|
|
private final String mDirListId;
|
|
private final UiAutomation mAutomation;
|
|
private long mDownTime = 0;
|
|
|
|
public GestureBot(UiDevice device, UiAutomation automation, Context context, int timeout) {
|
|
super(device, context, timeout);
|
|
mDirContainerId = mTargetPackage + ":id/container_directory";
|
|
mDirListId = mTargetPackage + ":id/dir_list";
|
|
mAutomation = automation;
|
|
}
|
|
|
|
public void gestureSelectFiles(String startLabel, String endLabel) throws Exception {
|
|
int toolType = Configurator.getInstance().getToolType();
|
|
Configurator.getInstance().setToolType(MotionEvent.TOOL_TYPE_FINGER);
|
|
Rect startCoord = findDocument(startLabel).getBounds();
|
|
Rect endCoord = findDocument(endLabel).getBounds();
|
|
double diffX = endCoord.centerX() - startCoord.centerX();
|
|
double diffY = endCoord.centerY() - startCoord.centerY();
|
|
Point[] points = new Point[LONGPRESS_STEPS + TRAVELING_STEPS];
|
|
|
|
// First simulate long-press by having a bunch of MOVE events in the same coordinate
|
|
for (int i = 0; i < LONGPRESS_STEPS; i++) {
|
|
points[i] = new Point(startCoord.centerX(), startCoord.centerY());
|
|
}
|
|
|
|
// Next put the actual drag/move events
|
|
for (int i = 0; i < TRAVELING_STEPS; i++) {
|
|
int newX = startCoord.centerX() + (int) (diffX / TRAVELING_STEPS * i);
|
|
int newY = startCoord.centerY() + (int) (diffY / TRAVELING_STEPS * i);
|
|
points[i + LONGPRESS_STEPS] = new Point(newX, newY);
|
|
}
|
|
mDevice.swipe(points, STEPS_INBETWEEN_POINTS);
|
|
Configurator.getInstance().setToolType(toolType);
|
|
}
|
|
|
|
public void bandSelection(Point start, Point end) throws Exception {
|
|
bandSelection(start, end, BAND_SELECTION_DEFAULT_STEPS);
|
|
}
|
|
|
|
public void fingerSelection(Point start, Point end) throws Exception {
|
|
fingerSelection(start, end, BAND_SELECTION_DEFAULT_STEPS);
|
|
}
|
|
|
|
public void bandSelection(Point start, Point end, int steps) throws Exception {
|
|
int toolType = Configurator.getInstance().getToolType();
|
|
Configurator.getInstance().setToolType(MotionEvent.TOOL_TYPE_MOUSE);
|
|
swipe(start.x, start.y, end.x, end.y, steps, MotionEvent.BUTTON_PRIMARY, false);
|
|
Configurator.getInstance().setToolType(toolType);
|
|
}
|
|
|
|
private void fingerSelection(Point start, Point end, int steps) throws Exception {
|
|
int toolType = Configurator.getInstance().getToolType();
|
|
Configurator.getInstance().setToolType(MotionEvent.TOOL_TYPE_FINGER);
|
|
swipe(start.x, start.y, end.x, end.y, steps, MotionEvent.BUTTON_PRIMARY, true);
|
|
Configurator.getInstance().setToolType(toolType);
|
|
}
|
|
|
|
public UiObject findDocument(String label) throws UiObjectNotFoundException {
|
|
final UiSelector docList = new UiSelector().resourceId(
|
|
mDirContainerId).childSelector(
|
|
new UiSelector().resourceId(mDirListId));
|
|
|
|
// Wait for the first list item to appear
|
|
new UiObject(docList.childSelector(new UiSelector())).waitForExists(mTimeout);
|
|
|
|
return mDevice.findObject(docList.childSelector(new UiSelector().text(label)));
|
|
}
|
|
|
|
private void swipe(int downX, int downY, int upX, int upY, int steps, int button,
|
|
boolean fingerSelection) {
|
|
int swipeSteps = steps;
|
|
double xStep = 0;
|
|
double yStep = 0;
|
|
|
|
// avoid a divide by zero
|
|
if (swipeSteps == 0) {
|
|
swipeSteps = 1;
|
|
}
|
|
|
|
xStep = ((double) (upX - downX)) / swipeSteps;
|
|
yStep = ((double) (upY - downY)) / swipeSteps;
|
|
|
|
// first touch starts exactly at the point requested
|
|
touchDown(downX, downY, button);
|
|
if (fingerSelection) {
|
|
SystemClock.sleep(LONG_PRESS_EVENT_INJECTION_DELAY_MILIS);
|
|
}
|
|
for (int i = 1; i < swipeSteps; i++) {
|
|
touchMove(downX + (int) (xStep * i), downY + (int) (yStep * i), button);
|
|
// set some known constant delay between steps as without it this
|
|
// become completely dependent on the speed of the system and results
|
|
// may vary on different devices. This guarantees at minimum we have
|
|
// a preset delay.
|
|
SystemClock.sleep(MOTION_EVENT_INJECTION_DELAY_MILLIS);
|
|
}
|
|
touchUp(upX, upY);
|
|
}
|
|
|
|
private boolean touchDown(int x, int y, int button) {
|
|
long mDownTime = SystemClock.uptimeMillis();
|
|
MotionEvent event = getMotionEvent(mDownTime, mDownTime, MotionEvent.ACTION_DOWN, button, x,
|
|
y);
|
|
return mAutomation.injectInputEvent(event, true);
|
|
}
|
|
|
|
private boolean touchUp(int x, int y) {
|
|
final long eventTime = SystemClock.uptimeMillis();
|
|
MotionEvent event = getMotionEvent(mDownTime, eventTime, MotionEvent.ACTION_UP, 0, x, y);
|
|
mDownTime = 0;
|
|
return mAutomation.injectInputEvent(event, true);
|
|
}
|
|
|
|
private boolean touchMove(int x, int y, int button) {
|
|
final long eventTime = SystemClock.uptimeMillis();
|
|
MotionEvent event = getMotionEvent(mDownTime, eventTime, MotionEvent.ACTION_MOVE, button, x,
|
|
y);
|
|
return mAutomation.injectInputEvent(event, true);
|
|
}
|
|
|
|
/** Helper function to obtain a MotionEvent. */
|
|
private static MotionEvent getMotionEvent(long downTime, long eventTime, int action, int button,
|
|
float x, float y) {
|
|
|
|
PointerProperties properties = new PointerProperties();
|
|
properties.id = 0;
|
|
properties.toolType = Configurator.getInstance().getToolType();
|
|
|
|
PointerCoords coords = new PointerCoords();
|
|
coords.pressure = 1;
|
|
coords.size = 1;
|
|
coords.x = x;
|
|
coords.y = y;
|
|
|
|
return MotionEvent.obtain(downTime, eventTime, action, 1,
|
|
new PointerProperties[]{properties}, new PointerCoords[]{coords},
|
|
0, button, 1.0f, 1.0f, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0);
|
|
}
|
|
}
|