mirror of
https://github.com/ARM-software/workload-automation.git
synced 2025-03-14 06:38:36 +00:00
Merge 1fd8a14ca9e7d4d7cd176b6a6d5aaa1b8a30f2d5 into ee7c04a5688be6ad16105ec62f9d394feffad1d9
This commit is contained in:
commit
627066224a
wlauto
common/android
BaseUiAutomation$1.classBaseUiAutomation$ActionLogger.classBaseUiAutomation$Direction.classBaseUiAutomation$FindByCriteria.classBaseUiAutomation$PinchType.classBaseUiAutomation$ScreenOrientation.classBaseUiAutomation.classUxPerfUiAutomation$1.classUxPerfUiAutomation$ActionLogger.classUxPerfUiAutomation$Direction.classUxPerfUiAutomation$GestureTestParams.classUxPerfUiAutomation$GestureType.classUxPerfUiAutomation$PinchType.classUxPerfUiAutomation$SurfaceLogger.classUxPerfUiAutomation$Timer.classUxPerfUiAutomation$UxPerfLogger.classUxPerfUiAutomation.class
external/uiauto
workloads
andebench/uiauto
androbench/uiauto
benchmarkpi/uiauto
caffeinemark/uiauto
cfbench/uiauto
facebook/uiauto
geekbench/uiauto
glbenchmark/uiauto
googlephotos
linpack/uiauto
peacekeeper/uiauto
quadrant/uiauto
real_linpack/uiauto
smartbench/uiauto
BIN
wlauto/common/android/BaseUiAutomation$1.class
Normal file
BIN
wlauto/common/android/BaseUiAutomation$1.class
Normal file
Binary file not shown.
BIN
wlauto/common/android/BaseUiAutomation$ActionLogger.class
Normal file
BIN
wlauto/common/android/BaseUiAutomation$ActionLogger.class
Normal file
Binary file not shown.
BIN
wlauto/common/android/BaseUiAutomation$Direction.class
Normal file
BIN
wlauto/common/android/BaseUiAutomation$Direction.class
Normal file
Binary file not shown.
BIN
wlauto/common/android/BaseUiAutomation$FindByCriteria.class
Normal file
BIN
wlauto/common/android/BaseUiAutomation$FindByCriteria.class
Normal file
Binary file not shown.
BIN
wlauto/common/android/BaseUiAutomation$PinchType.class
Normal file
BIN
wlauto/common/android/BaseUiAutomation$PinchType.class
Normal file
Binary file not shown.
BIN
wlauto/common/android/BaseUiAutomation$ScreenOrientation.class
Normal file
BIN
wlauto/common/android/BaseUiAutomation$ScreenOrientation.class
Normal file
Binary file not shown.
Binary file not shown.
BIN
wlauto/common/android/UxPerfUiAutomation$1.class
Normal file
BIN
wlauto/common/android/UxPerfUiAutomation$1.class
Normal file
Binary file not shown.
BIN
wlauto/common/android/UxPerfUiAutomation$ActionLogger.class
Normal file
BIN
wlauto/common/android/UxPerfUiAutomation$ActionLogger.class
Normal file
Binary file not shown.
BIN
wlauto/common/android/UxPerfUiAutomation$Direction.class
Normal file
BIN
wlauto/common/android/UxPerfUiAutomation$Direction.class
Normal file
Binary file not shown.
BIN
wlauto/common/android/UxPerfUiAutomation$GestureTestParams.class
Normal file
BIN
wlauto/common/android/UxPerfUiAutomation$GestureTestParams.class
Normal file
Binary file not shown.
BIN
wlauto/common/android/UxPerfUiAutomation$GestureType.class
Normal file
BIN
wlauto/common/android/UxPerfUiAutomation$GestureType.class
Normal file
Binary file not shown.
BIN
wlauto/common/android/UxPerfUiAutomation$PinchType.class
Normal file
BIN
wlauto/common/android/UxPerfUiAutomation$PinchType.class
Normal file
Binary file not shown.
BIN
wlauto/common/android/UxPerfUiAutomation$SurfaceLogger.class
Normal file
BIN
wlauto/common/android/UxPerfUiAutomation$SurfaceLogger.class
Normal file
Binary file not shown.
BIN
wlauto/common/android/UxPerfUiAutomation$Timer.class
Normal file
BIN
wlauto/common/android/UxPerfUiAutomation$Timer.class
Normal file
Binary file not shown.
BIN
wlauto/common/android/UxPerfUiAutomation$UxPerfLogger.class
Normal file
BIN
wlauto/common/android/UxPerfUiAutomation$UxPerfLogger.class
Normal file
Binary file not shown.
BIN
wlauto/common/android/UxPerfUiAutomation.class
Normal file
BIN
wlauto/common/android/UxPerfUiAutomation.class
Normal file
Binary file not shown.
8
wlauto/external/uiauto/build.sh
vendored
8
wlauto/external/uiauto/build.sh
vendored
@ -16,6 +16,12 @@
|
||||
|
||||
|
||||
|
||||
# Build and return appropriate exit code if failed
|
||||
ant build
|
||||
exit_code=$?
|
||||
if [ $exit_code -ne 0 ]; then
|
||||
echo "ERROR: 'ant build' exited with code $exit_code"
|
||||
exit $exit_code
|
||||
fi
|
||||
|
||||
cp bin/classes/com/arm/wlauto/uiauto/BaseUiAutomation.class ../../common/android
|
||||
cp bin/classes/com/arm/wlauto/uiauto/*.class ../../common/android
|
||||
|
2
wlauto/external/uiauto/project.properties
vendored
2
wlauto/external/uiauto/project.properties
vendored
@ -11,4 +11,4 @@
|
||||
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
||||
|
||||
# Project target.
|
||||
target=android-17
|
||||
target=android-18
|
||||
|
@ -20,6 +20,7 @@ import java.io.File;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.regex.Matcher;
|
||||
@ -27,6 +28,9 @@ import java.util.regex.Pattern;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.os.SystemClock;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.util.Log;
|
||||
|
||||
// Import the uiautomator libraries
|
||||
@ -34,9 +38,25 @@ import com.android.uiautomator.core.UiObject;
|
||||
import com.android.uiautomator.core.UiObjectNotFoundException;
|
||||
import com.android.uiautomator.core.UiScrollable;
|
||||
import com.android.uiautomator.core.UiSelector;
|
||||
import com.android.uiautomator.core.UiDevice;
|
||||
import com.android.uiautomator.core.UiWatcher;
|
||||
import com.android.uiautomator.testrunner.UiAutomatorTestCase;
|
||||
|
||||
public class BaseUiAutomation extends UiAutomatorTestCase {
|
||||
public class BaseUiAutomation extends UiAutomatorTestCase {
|
||||
|
||||
public long uiAutoTimeout = TimeUnit.SECONDS.toMillis(4);
|
||||
|
||||
public enum ScreenOrientation { RIGHT, NATURAL, LEFT };
|
||||
public enum Direction { UP, DOWN, LEFT, RIGHT, NULL };
|
||||
public enum PinchType { IN, OUT, NULL };
|
||||
|
||||
public static final int CLICK_REPEAT_INTERVAL_MINIMUM = 5;
|
||||
public static final int CLICK_REPEAT_INTERVAL_DEFAULT = 50;
|
||||
|
||||
/*
|
||||
* Used by clickUiObject() methods in order to provide a consistent API
|
||||
*/
|
||||
public enum FindByCriteria { BY_ID, BY_TEXT, BY_DESC; }
|
||||
|
||||
/**
|
||||
* Basic marker API for workloads to generate start and end markers for
|
||||
@ -86,11 +106,11 @@ public class BaseUiAutomation extends UiAutomatorTestCase {
|
||||
|
||||
public boolean takeScreenshot(String name) {
|
||||
Bundle params = getParams();
|
||||
String png_dir = params.getString("workdir");
|
||||
String pngDir = params.getString("workdir");
|
||||
|
||||
try {
|
||||
return getUiDevice().takeScreenshot(new File(png_dir, name + ".png"));
|
||||
} catch(NoSuchMethodError e) {
|
||||
return getUiDevice().takeScreenshot(new File(pngDir, name + ".png"));
|
||||
} catch (NoSuchMethodError e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -101,9 +121,9 @@ public class BaseUiAutomation extends UiAutomatorTestCase {
|
||||
|
||||
public void waitText(String text, int second) throws UiObjectNotFoundException {
|
||||
UiSelector selector = new UiSelector();
|
||||
UiObject text_obj = new UiObject(selector.text(text)
|
||||
UiObject textObj = new UiObject(selector.text(text)
|
||||
.className("android.widget.TextView"));
|
||||
waitObject(text_obj, second);
|
||||
waitObject(textObj, second);
|
||||
}
|
||||
|
||||
public void waitObject(UiObject obj) throws UiObjectNotFoundException {
|
||||
@ -111,7 +131,7 @@ public class BaseUiAutomation extends UiAutomatorTestCase {
|
||||
}
|
||||
|
||||
public void waitObject(UiObject obj, int second) throws UiObjectNotFoundException {
|
||||
if (! obj.waitForExists(second * 1000)){
|
||||
if (!obj.waitForExists(second * 1000)) {
|
||||
throw new UiObjectNotFoundException("UiObject is not found: "
|
||||
+ obj.getSelector().toString());
|
||||
}
|
||||
@ -133,10 +153,10 @@ public class BaseUiAutomation extends UiAutomatorTestCase {
|
||||
|
||||
long currentTime = System.currentTimeMillis();
|
||||
boolean found = false;
|
||||
while ((currentTime - startTime) < timeout){
|
||||
while ((currentTime - startTime) < timeout) {
|
||||
sleep(2); // poll every two seconds
|
||||
|
||||
while((line=reader.readLine())!=null) {
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (line.contains(searchText)) {
|
||||
found = true;
|
||||
break;
|
||||
@ -152,7 +172,8 @@ public class BaseUiAutomation extends UiAutomatorTestCase {
|
||||
process.destroy();
|
||||
|
||||
if ((currentTime - startTime) >= timeout) {
|
||||
throw new TimeoutException("Timed out waiting for Logcat text \"%s\"".format(searchText));
|
||||
throw new TimeoutException(String.format("Timed out waiting for Logcat text \"%s\"",
|
||||
searchText));
|
||||
}
|
||||
}
|
||||
|
||||
@ -190,5 +211,367 @@ public class BaseUiAutomation extends UiAutomatorTestCase {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void registerWatcher(String name, UiWatcher watcher) {
|
||||
UiDevice.getInstance().registerWatcher(name, watcher);
|
||||
}
|
||||
|
||||
public void runWatchers() {
|
||||
UiDevice.getInstance().runWatchers();
|
||||
}
|
||||
|
||||
public void removeWatcher(String name) {
|
||||
UiDevice.getInstance().removeWatcher(name);
|
||||
}
|
||||
|
||||
public void pressEnter() {
|
||||
UiDevice.getInstance().pressEnter();
|
||||
}
|
||||
|
||||
public void pressBack() {
|
||||
UiDevice.getInstance().pressBack();
|
||||
}
|
||||
|
||||
public void pressDPadUp() {
|
||||
UiDevice.getInstance().pressDPadUp();
|
||||
}
|
||||
|
||||
public void pressDPadDown() {
|
||||
UiDevice.getInstance().pressDPadDown();
|
||||
}
|
||||
|
||||
public void pressDPadLeft() {
|
||||
UiDevice.getInstance().pressDPadLeft();
|
||||
}
|
||||
|
||||
public void pressDPadRight() {
|
||||
UiDevice.getInstance().pressDPadRight();
|
||||
}
|
||||
|
||||
public int getDisplayHeight() {
|
||||
return UiDevice.getInstance().getDisplayHeight();
|
||||
}
|
||||
|
||||
public int getDisplayWidth() {
|
||||
return UiDevice.getInstance().getDisplayWidth();
|
||||
}
|
||||
|
||||
public int getDisplayCentreWidth() {
|
||||
return getDisplayWidth() / 2;
|
||||
}
|
||||
|
||||
public int getDisplayCentreHeight() {
|
||||
return getDisplayHeight() / 2;
|
||||
}
|
||||
|
||||
public void tapDisplayCentre() {
|
||||
tapDisplay(getDisplayCentreWidth(), getDisplayCentreHeight());
|
||||
}
|
||||
|
||||
public void tapDisplay(int x, int y) {
|
||||
UiDevice.getInstance().click(x, y);
|
||||
}
|
||||
|
||||
public void uiDeviceSwipeUp(int steps) {
|
||||
UiDevice.getInstance().swipe(
|
||||
getDisplayCentreWidth(),
|
||||
(getDisplayCentreHeight() / 2),
|
||||
getDisplayCentreWidth(),
|
||||
(getDisplayCentreHeight() + (getDisplayCentreHeight() / 2)),
|
||||
steps);
|
||||
}
|
||||
|
||||
public void uiDeviceSwipeDown(int steps) {
|
||||
UiDevice.getInstance().swipe(
|
||||
getDisplayCentreWidth(),
|
||||
(getDisplayCentreHeight() + (getDisplayCentreHeight() / 2)),
|
||||
getDisplayCentreWidth(),
|
||||
(getDisplayCentreHeight() / 2),
|
||||
steps);
|
||||
}
|
||||
|
||||
public void uiDeviceSwipeLeft(int steps) {
|
||||
UiDevice.getInstance().swipe(
|
||||
(getDisplayCentreWidth() + (getDisplayCentreWidth() / 2)),
|
||||
getDisplayCentreHeight(),
|
||||
(getDisplayCentreWidth() / 2),
|
||||
getDisplayCentreHeight(),
|
||||
steps);
|
||||
}
|
||||
|
||||
public void uiDeviceSwipeRight(int steps) {
|
||||
UiDevice.getInstance().swipe(
|
||||
(getDisplayCentreWidth() / 2),
|
||||
getDisplayCentreHeight(),
|
||||
(getDisplayCentreWidth() + (getDisplayCentreWidth() / 2)),
|
||||
getDisplayCentreHeight(),
|
||||
steps);
|
||||
}
|
||||
|
||||
public void uiDeviceSwipe(Direction direction, int steps) throws Exception {
|
||||
switch (direction) {
|
||||
case UP:
|
||||
uiDeviceSwipeUp(steps);
|
||||
break;
|
||||
case DOWN:
|
||||
uiDeviceSwipeDown(steps);
|
||||
break;
|
||||
case LEFT:
|
||||
uiDeviceSwipeLeft(steps);
|
||||
break;
|
||||
case RIGHT:
|
||||
uiDeviceSwipeRight(steps);
|
||||
break;
|
||||
case NULL:
|
||||
throw new Exception("No direction specified");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void uiObjectSwipe(UiObject view, Direction direction, int steps) throws Exception {
|
||||
switch (direction) {
|
||||
case UP:
|
||||
view.swipeUp(steps);
|
||||
break;
|
||||
case DOWN:
|
||||
view.swipeDown(steps);
|
||||
break;
|
||||
case LEFT:
|
||||
view.swipeLeft(steps);
|
||||
break;
|
||||
case RIGHT:
|
||||
view.swipeRight(steps);
|
||||
break;
|
||||
case NULL:
|
||||
throw new Exception("No direction specified");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void uiObjectVertPinchIn(UiObject view, int steps, int percent) throws Exception {
|
||||
final int FINGER_TOUCH_HALF_WIDTH = 20;
|
||||
|
||||
// Make value between 1 and 100
|
||||
int nPercent = (percent < 0) ? 1 : (percent > 100) ? 100 : percent;
|
||||
float percentage = nPercent / 100f;
|
||||
|
||||
Rect rect = view.getVisibleBounds();
|
||||
|
||||
if (rect.width() <= FINGER_TOUCH_HALF_WIDTH * 2) {
|
||||
throw new IllegalStateException("Object width is too small for operation");
|
||||
}
|
||||
|
||||
// Start at the top-center and bottom-center of the control
|
||||
Point startPoint1 = new Point(rect.centerX(), rect.centerY()
|
||||
+ (int) ((rect.height() / 2) * percentage));
|
||||
Point startPoint2 = new Point(rect.centerX(), rect.centerY()
|
||||
- (int) ((rect.height() / 2) * percentage));
|
||||
|
||||
// End at the same point at the center of the control
|
||||
Point endPoint1 = new Point(rect.centerX(), rect.centerY() + FINGER_TOUCH_HALF_WIDTH);
|
||||
Point endPoint2 = new Point(rect.centerX(), rect.centerY() - FINGER_TOUCH_HALF_WIDTH);
|
||||
|
||||
view.performTwoPointerGesture(startPoint1, startPoint2, endPoint1, endPoint2, steps);
|
||||
}
|
||||
|
||||
public void uiObjectVertPinchOut(UiObject view, int steps, int percent) throws Exception {
|
||||
final int FINGER_TOUCH_HALF_WIDTH = 20;
|
||||
|
||||
// Make value between 1 and 100
|
||||
int nPercent = (percent < 0) ? 1 : (percent > 100) ? 100 : percent;
|
||||
float percentage = nPercent / 100f;
|
||||
|
||||
Rect rect = view.getVisibleBounds();
|
||||
|
||||
if (rect.width() <= FINGER_TOUCH_HALF_WIDTH * 2) {
|
||||
throw new IllegalStateException("Object width is too small for operation");
|
||||
}
|
||||
|
||||
// Start from the same point at the center of the control
|
||||
Point startPoint1 = new Point(rect.centerX(), rect.centerY() + FINGER_TOUCH_HALF_WIDTH);
|
||||
Point startPoint2 = new Point(rect.centerX(), rect.centerY() - FINGER_TOUCH_HALF_WIDTH);
|
||||
|
||||
// End at the top-center and bottom-center of the control
|
||||
Point endPoint1 = new Point(rect.centerX(), rect.centerY()
|
||||
+ (int) ((rect.height() / 2) * percentage));
|
||||
Point endPoint2 = new Point(rect.centerX(), rect.centerY()
|
||||
- (int) ((rect.height() / 2) * percentage));
|
||||
|
||||
view.performTwoPointerGesture(startPoint1, startPoint2, endPoint1, endPoint2, steps);
|
||||
}
|
||||
|
||||
public void setScreenOrientation(ScreenOrientation orientation) throws Exception {
|
||||
switch (orientation) {
|
||||
case RIGHT:
|
||||
getUiDevice().setOrientationRight();
|
||||
break;
|
||||
case NATURAL:
|
||||
getUiDevice().setOrientationNatural();
|
||||
break;
|
||||
case LEFT:
|
||||
getUiDevice().setOrientationLeft();
|
||||
break;
|
||||
default:
|
||||
throw new Exception("No orientation specified");
|
||||
}
|
||||
}
|
||||
|
||||
public void unsetScreenOrientation() throws Exception {
|
||||
getUiDevice().unfreezeRotation();
|
||||
}
|
||||
|
||||
public void uiObjectPerformLongClick(UiObject view, int steps) throws Exception {
|
||||
Rect rect = view.getBounds();
|
||||
UiDevice.getInstance().swipe(rect.centerX(), rect.centerY(),
|
||||
rect.centerX(), rect.centerY(), steps);
|
||||
}
|
||||
|
||||
public void uiDeviceSwipeVertical(int startY, int endY, int xCoordinate, int steps) {
|
||||
getUiDevice().swipe(startY, xCoordinate, endY, xCoordinate, steps);
|
||||
}
|
||||
|
||||
public void uiDeviceSwipeHorizontal(int startX, int endX, int yCoordinate, int steps) {
|
||||
getUiDevice().swipe(startX, yCoordinate, endX, yCoordinate, steps);
|
||||
}
|
||||
|
||||
public void uiObjectPinch(UiObject view, PinchType direction, int steps,
|
||||
int percent) throws Exception {
|
||||
if (direction.equals(PinchType.IN)) {
|
||||
view.pinchIn(percent, steps);
|
||||
} else if (direction.equals(PinchType.OUT)) {
|
||||
view.pinchOut(percent, steps);
|
||||
}
|
||||
}
|
||||
|
||||
public void uiObjectVertPinch(UiObject view, PinchType direction,
|
||||
int steps, int percent) throws Exception {
|
||||
if (direction.equals(PinchType.IN)) {
|
||||
uiObjectVertPinchIn(view, steps, percent);
|
||||
} else if (direction.equals(PinchType.OUT)) {
|
||||
uiObjectVertPinchOut(view, steps, percent);
|
||||
}
|
||||
}
|
||||
|
||||
public void repeatClickUiObject(UiObject view, int repeatCount, int intervalInMillis) throws Exception {
|
||||
int repeatInterval = intervalInMillis > CLICK_REPEAT_INTERVAL_MINIMUM
|
||||
? intervalInMillis : CLICK_REPEAT_INTERVAL_DEFAULT;
|
||||
if (repeatCount < 1 || !view.isClickable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < repeatCount; ++i) {
|
||||
view.click();
|
||||
SystemClock.sleep(repeatInterval); // in order to register as separate click
|
||||
}
|
||||
}
|
||||
|
||||
public UiObject clickUiObject(FindByCriteria criteria, String matching) throws Exception {
|
||||
return clickUiObject(criteria, matching, null, false);
|
||||
}
|
||||
|
||||
public UiObject clickUiObject(FindByCriteria criteria, String matching, boolean wait) throws Exception {
|
||||
return clickUiObject(criteria, matching, null, wait);
|
||||
}
|
||||
|
||||
public UiObject clickUiObject(FindByCriteria criteria, String matching, String clazz) throws Exception {
|
||||
return clickUiObject(criteria, matching, clazz, false);
|
||||
}
|
||||
|
||||
public UiObject clickUiObject(FindByCriteria criteria, String matching, String clazz, boolean wait) throws Exception {
|
||||
UiObject view;
|
||||
|
||||
switch (criteria) {
|
||||
case BY_ID:
|
||||
view = (clazz == null)
|
||||
? getUiObjectByResourceId(matching) : getUiObjectByResourceId(matching, clazz);
|
||||
break;
|
||||
case BY_DESC:
|
||||
view = (clazz == null)
|
||||
? getUiObjectByDescription(matching) : getUiObjectByDescription(matching, clazz);
|
||||
break;
|
||||
case BY_TEXT:
|
||||
default:
|
||||
view = (clazz == null)
|
||||
? getUiObjectByText(matching) : getUiObjectByText(matching, clazz);
|
||||
break;
|
||||
}
|
||||
|
||||
if (wait) {
|
||||
view.clickAndWaitForNewWindow();
|
||||
} else {
|
||||
view.click();
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
public UiObject getUiObjectByResourceId(String resourceId, String className) throws Exception {
|
||||
return getUiObjectByResourceId(resourceId, className, uiAutoTimeout);
|
||||
}
|
||||
|
||||
public UiObject getUiObjectByResourceId(String resourceId, String className, long timeout) throws Exception {
|
||||
UiObject object = new UiObject(new UiSelector().resourceId(resourceId)
|
||||
.className(className));
|
||||
if (!object.waitForExists(timeout)) {
|
||||
throw new UiObjectNotFoundException(String.format("Could not find \"%s\" \"%s\"",
|
||||
resourceId, className));
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
public UiObject getUiObjectByResourceId(String id) throws Exception {
|
||||
UiObject object = new UiObject(new UiSelector().resourceId(id));
|
||||
|
||||
if (!object.waitForExists(uiAutoTimeout)) {
|
||||
throw new UiObjectNotFoundException("Could not find view with resource ID: " + id);
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
public UiObject getUiObjectByDescription(String description, String className) throws Exception {
|
||||
return getUiObjectByDescription(description, className, uiAutoTimeout);
|
||||
}
|
||||
|
||||
public UiObject getUiObjectByDescription(String description, String className, long timeout) throws Exception {
|
||||
UiObject object = new UiObject(new UiSelector().descriptionContains(description)
|
||||
.className(className));
|
||||
if (!object.waitForExists(timeout)) {
|
||||
throw new UiObjectNotFoundException(String.format("Could not find \"%s\" \"%s\"",
|
||||
description, className));
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
public UiObject getUiObjectByDescription(String desc) throws Exception {
|
||||
UiObject object = new UiObject(new UiSelector().descriptionContains(desc));
|
||||
|
||||
if (!object.waitForExists(uiAutoTimeout)) {
|
||||
throw new UiObjectNotFoundException("Could not find view with description: " + desc);
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
public UiObject getUiObjectByText(String text, String className) throws Exception {
|
||||
return getUiObjectByText(text, className, uiAutoTimeout);
|
||||
}
|
||||
|
||||
public UiObject getUiObjectByText(String text, String className, long timeout) throws Exception {
|
||||
UiObject object = new UiObject(new UiSelector().textContains(text)
|
||||
.className(className));
|
||||
if (!object.waitForExists(timeout)) {
|
||||
throw new UiObjectNotFoundException(String.format("Could not find \"%s\" \"%s\"",
|
||||
text, className));
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
public UiObject getUiObjectByText(String text) throws Exception {
|
||||
UiObject object = new UiObject(new UiSelector().textContains(text));
|
||||
|
||||
if (!object.waitForExists(uiAutoTimeout)) {
|
||||
throw new UiObjectNotFoundException("Could not find view with text: " + text);
|
||||
}
|
||||
return object;
|
||||
}
|
||||
}
|
||||
|
49
wlauto/external/uiauto/src/com/arm/wlauto/uiauto/UxPerfUiAutomation.java
vendored
Normal file
49
wlauto/external/uiauto/src/com/arm/wlauto/uiauto/UxPerfUiAutomation.java
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
/* Copyright 2013-2016 ARM Limited
|
||||
*
|
||||
* 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.arm.wlauto.uiauto;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class UxPerfUiAutomation extends BaseUiAutomation {
|
||||
|
||||
private Logger logger = Logger.getLogger(UxPerfUiAutomation.class.getName());
|
||||
|
||||
public enum GestureType { UIDEVICE_SWIPE, UIOBJECT_SWIPE, PINCH };
|
||||
|
||||
public static class GestureTestParams {
|
||||
public GestureType gestureType;
|
||||
public Direction gestureDirection;
|
||||
public PinchType pinchType;
|
||||
public int percent;
|
||||
public int steps;
|
||||
|
||||
public GestureTestParams(GestureType gesture, Direction direction, int steps) {
|
||||
this.gestureType = gesture;
|
||||
this.gestureDirection = direction;
|
||||
this.pinchType = PinchType.NULL;
|
||||
this.steps = steps;
|
||||
this.percent = 0;
|
||||
}
|
||||
|
||||
public GestureTestParams(GestureType gesture, PinchType pinchType, int steps, int percent) {
|
||||
this.gestureType = gesture;
|
||||
this.gestureDirection = Direction.NULL;
|
||||
this.pinchType = pinchType;
|
||||
this.steps = steps;
|
||||
this.percent = percent;
|
||||
}
|
||||
}
|
||||
}
|
@ -11,4 +11,4 @@
|
||||
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
||||
|
||||
# Project target.
|
||||
target=android-17
|
||||
target=android-18
|
||||
|
@ -11,4 +11,4 @@
|
||||
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
||||
|
||||
# Project target.
|
||||
target=android-17
|
||||
target=android-18
|
||||
|
@ -11,4 +11,4 @@
|
||||
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
||||
|
||||
# Project target.
|
||||
target=android-17
|
||||
target=android-18
|
||||
|
@ -11,4 +11,4 @@
|
||||
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
||||
|
||||
# Project target.
|
||||
target=android-17
|
||||
target=android-18
|
||||
|
@ -11,4 +11,4 @@
|
||||
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
||||
|
||||
# Project target.
|
||||
target=android-17
|
||||
target=android-18
|
||||
|
@ -11,4 +11,4 @@
|
||||
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
||||
|
||||
# Project target.
|
||||
target=android-17
|
||||
target=android-18
|
||||
|
@ -11,4 +11,4 @@
|
||||
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
||||
|
||||
# Project target.
|
||||
target=android-17
|
||||
target=android-18
|
||||
|
@ -11,4 +11,4 @@
|
||||
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
||||
|
||||
# Project target.
|
||||
target=android-17
|
||||
target=android-18
|
||||
|
131
wlauto/workloads/googlephotos/__init__.py
Executable file
131
wlauto/workloads/googlephotos/__init__.py
Executable file
@ -0,0 +1,131 @@
|
||||
# Copyright 2014-2016 ARM Limited
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
import os
|
||||
import wlauto.common.resources
|
||||
|
||||
from wlauto import AndroidUiAutoBenchmark, Parameter
|
||||
from wlauto.exceptions import ValidationError
|
||||
from wlauto.utils.types import list_of_strings
|
||||
|
||||
__version__ = '0.1.1'
|
||||
|
||||
|
||||
class Googlephotos(AndroidUiAutoBenchmark):
|
||||
|
||||
name = 'googlephotos'
|
||||
package = 'com.google.android.apps.photos'
|
||||
activity = 'com.google.android.apps.photos.home.HomeActivity'
|
||||
view = [package + '/com.google.android.apps.consumerphotoeditor.fragments.ConsumerPhotoEditorActivity',
|
||||
package + '/com.google.android.apps.photos.home.HomeActivity',
|
||||
package + '/com.google.android.apps.photos.localmedia.ui.LocalPhotosActivity',
|
||||
package + '/com.google.android.apps.photos.onboarding.AccountPickerActivity',
|
||||
package + '/com.google.android.apps.photos.onboarding.IntroActivity']
|
||||
description = """
|
||||
A workload to perform standard productivity tasks with Google Photos. The workload carries out
|
||||
various tasks, such as browsing images, performing zooms, post-processing and saving a selected
|
||||
image to file.
|
||||
|
||||
Test description:
|
||||
1. Four images are copied to the device
|
||||
2. The application is started in offline access mode
|
||||
3. Gestures are performed to swipe between images and pinch zoom in and out of the selected
|
||||
image
|
||||
4. The Colour of a selected image is edited by selecting the colour menu, incrementing the
|
||||
colour, resetting the colour and decrementing the colour using the seek bar.
|
||||
5. A Crop test is performed on a selected image. UiAutomator does not allow the selection of
|
||||
the crop markers so the image is tilted positively, reset and then negatively to get a
|
||||
similar cropping effect.
|
||||
6. A Rotate test is performed on a selected image, rotating anticlockwise 90 degrees, 180
|
||||
degrees and 270 degrees.
|
||||
"""
|
||||
|
||||
default_test_images = [
|
||||
'uxperf_1200x1600.png', 'uxperf_1600x1200.jpg',
|
||||
'uxperf_2448x3264.png', 'uxperf_3264x2448.jpg',
|
||||
]
|
||||
|
||||
parameters = [
|
||||
Parameter('dumpsys_enabled', kind=bool, default=True,
|
||||
description="""
|
||||
If ``True`` turns on the action logger which outputs
|
||||
timestamps to logcat for actions recorded in the workload.
|
||||
"""),
|
||||
Parameter('test_images', kind=list_of_strings, default=default_test_images,
|
||||
description="""
|
||||
A list of four image files to be pushed to the device.
|
||||
Absolute file paths may be used but tilde expansion is not supported.
|
||||
"""),
|
||||
]
|
||||
|
||||
def validate(self):
|
||||
super(Googlephotos, self).validate()
|
||||
self.uiauto_params['package'] = self.package
|
||||
self.uiauto_params['output_dir'] = self.device.working_directory
|
||||
self.uiauto_params['dumpsys_enabled'] = self.dumpsys_enabled
|
||||
|
||||
self._check_image_numbers()
|
||||
self._check_image_extensions()
|
||||
self._check_image_duplicates()
|
||||
self._info_image_used()
|
||||
|
||||
def initialize(self, context):
|
||||
super(Googlephotos, self).initialize(context)
|
||||
for image in self.test_images:
|
||||
if os.path.exists(image):
|
||||
image_path = image
|
||||
else:
|
||||
image_path = context.resolver.get(wlauto.common.resources.File(self, image))
|
||||
self.device.push_file(image_path, self.device.working_directory, timeout=300)
|
||||
|
||||
# Force a re-index of the mediaserver cache to pick up new files
|
||||
self.device.execute('am broadcast -a android.intent.action.MEDIA_MOUNTED -d file:///sdcard')
|
||||
|
||||
def teardown(self, context):
|
||||
super(Googlephotos, self).teardown(context)
|
||||
self.device.execute('am broadcast -a android.intent.action.MEDIA_MOUNTED -d file:///sdcard')
|
||||
|
||||
def finalize(self, context):
|
||||
super(Googlephotos, self).finalize(context)
|
||||
|
||||
for entry in self.device.listdir(self.device.working_directory):
|
||||
if entry in self.test_images:
|
||||
self.device.delete_file(self.device.path.join(self.device.working_directory, entry))
|
||||
|
||||
self.device.execute('am broadcast -a android.intent.action.MEDIA_MOUNTED -d file:///sdcard')
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Internal methods
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
def _check_image_extensions(self):
|
||||
for image in self.test_images:
|
||||
if not image.endswith(('jpg', 'jpeg', 'png')):
|
||||
raise ValidationError('{} must be a jpeg or png file'.format(image))
|
||||
|
||||
def _check_image_numbers(self):
|
||||
if len(self.test_images) != 4:
|
||||
message = "This workload requires four test images - only {} specified"
|
||||
raise ValidationError(message.format(len(self.test_images)))
|
||||
|
||||
def _check_image_duplicates(self):
|
||||
if len(self.test_images) != len(set(self.test_images)):
|
||||
raise ValidationError('Duplicate image names not allowed')
|
||||
|
||||
def _info_image_used(self):
|
||||
if set(self.test_images) & set(self.default_test_images):
|
||||
self.logger.info('Using default test images')
|
||||
else:
|
||||
self.logger.warning('Using custom test images')
|
Binary file not shown.
39
wlauto/workloads/googlephotos/uiauto/build.sh
Executable file
39
wlauto/workloads/googlephotos/uiauto/build.sh
Executable file
@ -0,0 +1,39 @@
|
||||
#!/bin/bash
|
||||
|
||||
# CD into build dir if possible - allows building from any directory
|
||||
script_path='.'
|
||||
if `readlink -f $0 &>/dev/null`; then
|
||||
script_path=`readlink -f $0 2>/dev/null`
|
||||
fi
|
||||
script_dir=`dirname $script_path`
|
||||
cd $script_dir
|
||||
|
||||
# Ensure build.xml exists before starting
|
||||
if [[ ! -f build.xml ]]; then
|
||||
echo 'Ant build.xml file not found! Check that you are in the right directory.'
|
||||
exit 9
|
||||
fi
|
||||
|
||||
# Copy base classes from wlauto dist
|
||||
class_dir=bin/classes/com/arm/wlauto/uiauto
|
||||
base_classes=`python -c "import os, wlauto; print os.path.join(os.path.dirname(wlauto.__file__), 'common', 'android', '*.class')"`
|
||||
mkdir -p $class_dir
|
||||
cp $base_classes $class_dir
|
||||
|
||||
# Build and return appropriate exit code if failed
|
||||
ant build
|
||||
exit_code=$?
|
||||
if [[ $exit_code -ne 0 ]]; then
|
||||
echo "ERROR: 'ant build' exited with code $exit_code"
|
||||
exit $exit_code
|
||||
fi
|
||||
|
||||
# If successful move JAR file to workload folder (overwrite previous)
|
||||
package=com.arm.wlauto.uiauto.googlephotos.jar
|
||||
rm -f ../$package
|
||||
if [[ -f bin/$package ]]; then
|
||||
cp bin/$package ..
|
||||
else
|
||||
echo 'ERROR: UiAutomator JAR could not be found!'
|
||||
exit 9
|
||||
fi
|
92
wlauto/workloads/googlephotos/uiauto/build.xml
Normal file
92
wlauto/workloads/googlephotos/uiauto/build.xml
Normal file
@ -0,0 +1,92 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project name="com.arm.wlauto.uiauto.googlephotos" default="help">
|
||||
|
||||
<!-- The local.properties file is created and updated by the 'android' tool.
|
||||
It contains the path to the SDK. It should *NOT* be checked into
|
||||
Version Control Systems. -->
|
||||
<property file="local.properties" />
|
||||
|
||||
<!-- The ant.properties file can be created by you. It is only edited by the
|
||||
'android' tool to add properties to it.
|
||||
This is the place to change some Ant specific build properties.
|
||||
Here are some properties you may want to change/update:
|
||||
|
||||
source.dir
|
||||
The name of the source directory. Default is 'src'.
|
||||
out.dir
|
||||
The name of the output directory. Default is 'bin'.
|
||||
|
||||
For other overridable properties, look at the beginning of the rules
|
||||
files in the SDK, at tools/ant/build.xml
|
||||
|
||||
Properties related to the SDK location or the project target should
|
||||
be updated using the 'android' tool with the 'update' action.
|
||||
|
||||
This file is an integral part of the build system for your
|
||||
application and should be checked into Version Control Systems.
|
||||
|
||||
-->
|
||||
<property file="ant.properties" />
|
||||
|
||||
<!-- if sdk.dir was not set from one of the property file, then
|
||||
get it from the ANDROID_HOME env var.
|
||||
This must be done before we load project.properties since
|
||||
the proguard config can use sdk.dir -->
|
||||
<property environment="env" />
|
||||
<condition property="sdk.dir" value="${env.ANDROID_HOME}">
|
||||
<isset property="env.ANDROID_HOME" />
|
||||
</condition>
|
||||
|
||||
<!-- The project.properties file is created and updated by the 'android'
|
||||
tool, as well as ADT.
|
||||
|
||||
This contains project specific properties such as project target, and library
|
||||
dependencies. Lower level build properties are stored in ant.properties
|
||||
(or in .classpath for Eclipse projects).
|
||||
|
||||
This file is an integral part of the build system for your
|
||||
application and should be checked into Version Control Systems. -->
|
||||
<loadproperties srcFile="project.properties" />
|
||||
|
||||
<!-- quick check on sdk.dir -->
|
||||
<fail
|
||||
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
|
||||
unless="sdk.dir"
|
||||
/>
|
||||
|
||||
<!--
|
||||
Import per project custom build rules if present at the root of the project.
|
||||
This is the place to put custom intermediary targets such as:
|
||||
-pre-build
|
||||
-pre-compile
|
||||
-post-compile (This is typically used for code obfuscation.
|
||||
Compiled code location: ${out.classes.absolute.dir}
|
||||
If this is not done in place, override ${out.dex.input.absolute.dir})
|
||||
-post-package
|
||||
-post-build
|
||||
-pre-clean
|
||||
-->
|
||||
<import file="custom_rules.xml" optional="true" />
|
||||
|
||||
<!-- Import the actual build file.
|
||||
|
||||
To customize existing targets, there are two options:
|
||||
- Customize only one target:
|
||||
- copy/paste the target into this file, *before* the
|
||||
<import> task.
|
||||
- customize it to your needs.
|
||||
- Customize the whole content of build.xml
|
||||
- copy/paste the content of the rules files (minus the top node)
|
||||
into this file, replacing the <import> task.
|
||||
- customize to your needs.
|
||||
|
||||
***********************
|
||||
****** IMPORTANT ******
|
||||
***********************
|
||||
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
|
||||
in order to avoid having your file be overridden by tools such as "android update project"
|
||||
-->
|
||||
<!-- version-tag: VERSION_TAG -->
|
||||
<import file="${sdk.dir}/tools/ant/uibuild.xml" />
|
||||
|
||||
</project>
|
14
wlauto/workloads/googlephotos/uiauto/project.properties
Normal file
14
wlauto/workloads/googlephotos/uiauto/project.properties
Normal file
@ -0,0 +1,14 @@
|
||||
# This file is automatically generated by Android Tools.
|
||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||
#
|
||||
# This file must be checked in Version Control Systems.
|
||||
#
|
||||
# To customize properties used by the Ant build system edit
|
||||
# "ant.properties", and override values to adapt the script to your
|
||||
# project structure.
|
||||
#
|
||||
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
|
||||
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
||||
|
||||
# Project target.
|
||||
target=android-18
|
440
wlauto/workloads/googlephotos/uiauto/src/com/arm/wlauto/uiauto/UiAutomation.java
Executable file
440
wlauto/workloads/googlephotos/uiauto/src/com/arm/wlauto/uiauto/UiAutomation.java
Executable file
@ -0,0 +1,440 @@
|
||||
/* Copyright 2014-2016 ARM Limited
|
||||
*
|
||||
* 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.arm.wlauto.uiauto.googlephotos;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.graphics.Rect;
|
||||
|
||||
// Import the uiautomator libraries
|
||||
import com.android.uiautomator.core.UiObject;
|
||||
import com.android.uiautomator.core.UiObjectNotFoundException;
|
||||
import com.android.uiautomator.core.UiSelector;
|
||||
import com.android.uiautomator.core.UiScrollable;
|
||||
|
||||
import com.arm.wlauto.uiauto.UxPerfUiAutomation;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
public class UiAutomation extends UxPerfUiAutomation {
|
||||
|
||||
public static String TAG = "uxperf_googlephotos";
|
||||
|
||||
public Bundle parameters;
|
||||
private int viewTimeoutSecs = 10;
|
||||
private long viewTimeout = TimeUnit.SECONDS.toMillis(viewTimeoutSecs);
|
||||
|
||||
public void runUiAutomation() throws Exception {
|
||||
parameters = getParams();
|
||||
|
||||
pauseForSplashScreen();
|
||||
setScreenOrientation(ScreenOrientation.NATURAL);
|
||||
dismissWelcomeView();
|
||||
closePromotionPopUp();
|
||||
selectWorkingGallery();
|
||||
gesturesTest();
|
||||
editPhotoColorTest();
|
||||
cropPhotoTest();
|
||||
rotatePhotoTest();
|
||||
unsetScreenOrientation();
|
||||
}
|
||||
|
||||
public void pauseForSplashScreen() {
|
||||
sleep(5); // Pause while splash screen loads
|
||||
}
|
||||
|
||||
public void dismissWelcomeView() throws Exception {
|
||||
|
||||
// Click through the first two pages and make sure that we don't sign
|
||||
// in to our google account. This ensures the same set of photographs
|
||||
// are placed in the camera directory for each run.
|
||||
|
||||
UiObject getStartedButton =
|
||||
new UiObject(new UiSelector().textContains("Get started")
|
||||
.className("android.widget.Button"));
|
||||
|
||||
waitObject(getStartedButton, viewTimeoutSecs);
|
||||
getStartedButton.click();
|
||||
|
||||
// A network connection is not required for this workload. However,
|
||||
// when the Google Photos app is invoked from the multiapp workload a
|
||||
// connection is required for sharing content. Handle the different UI
|
||||
// pathways when dismissing welcome views here.
|
||||
UiObject doNotSignInButton =
|
||||
new UiObject(new UiSelector().resourceId("com.google.android.apps.photos:id/dont_sign_in_button"));
|
||||
|
||||
if (doNotSignInButton.exists()) {
|
||||
doNotSignInButton.click();
|
||||
} else {
|
||||
UiObject welcomeButton =
|
||||
getUiObjectByResourceId("com.google.android.apps.photos:id/name",
|
||||
"android.widget.TextView");
|
||||
welcomeButton.click();
|
||||
|
||||
UiObject useWithoutAccount =
|
||||
getUiObjectByText("Use without an account", "android.widget.TextView");
|
||||
useWithoutAccount.clickAndWaitForNewWindow();
|
||||
|
||||
// Dismiss welcome views promoting app features
|
||||
sleep(1);
|
||||
uiDeviceSwipeLeft(10);
|
||||
sleep(1);
|
||||
uiDeviceSwipeLeft(10);
|
||||
sleep(1);
|
||||
uiDeviceSwipeLeft(10);
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
UiObject nextButton =
|
||||
new UiObject(new UiSelector().resourceId("com.google.android.apps.photos:id/next_button")
|
||||
.className("android.widget.ImageView"));
|
||||
|
||||
if (nextButton.exists()) {
|
||||
nextButton.clickAndWaitForNewWindow();
|
||||
}
|
||||
|
||||
UiObject workingFolder = new UiObject(new UiSelector().text("wa-working"));
|
||||
waitObject(workingFolder, viewTimeoutSecs);
|
||||
}
|
||||
|
||||
private void gesturesTest() throws Exception {
|
||||
String testTag = "gestures";
|
||||
|
||||
// Perform a range of swipe tests while browsing photo gallery
|
||||
LinkedHashMap<String, GestureTestParams> testParams = new LinkedHashMap<String, GestureTestParams>();
|
||||
testParams.put("swipe_left", new GestureTestParams(GestureType.UIDEVICE_SWIPE, Direction.LEFT, 10));
|
||||
testParams.put("pinch_out", new GestureTestParams(GestureType.PINCH, PinchType.OUT, 100, 50));
|
||||
testParams.put("pinch_in", new GestureTestParams(GestureType.PINCH, PinchType.IN, 100, 50));
|
||||
testParams.put("swipe_right", new GestureTestParams(GestureType.UIDEVICE_SWIPE, Direction.RIGHT, 10));
|
||||
|
||||
Iterator<Entry<String, GestureTestParams>> it = testParams.entrySet().iterator();
|
||||
|
||||
// Select first photograph
|
||||
selectPhoto(1);
|
||||
|
||||
while (it.hasNext()) {
|
||||
Map.Entry<String, GestureTestParams> pair = it.next();
|
||||
GestureType type = pair.getValue().gestureType;
|
||||
Direction dir = pair.getValue().gestureDirection;
|
||||
PinchType pinch = pair.getValue().pinchType;
|
||||
int steps = pair.getValue().steps;
|
||||
int percent = pair.getValue().percent;
|
||||
|
||||
UiObject view = new UiObject(new UiSelector().enabled(true));
|
||||
|
||||
if (!view.waitForExists(viewTimeout)) {
|
||||
throw new UiObjectNotFoundException("Could not find \"photo view\".");
|
||||
}
|
||||
|
||||
String runName = String.format(testTag + "_" + pair.getKey());
|
||||
ActionLogger logger = new ActionLogger(runName, parameters);
|
||||
logger.start();
|
||||
|
||||
switch (type) {
|
||||
case UIDEVICE_SWIPE:
|
||||
uiDeviceSwipe(dir, steps);
|
||||
break;
|
||||
case UIOBJECT_SWIPE:
|
||||
uiObjectSwipe(view, dir, steps);
|
||||
break;
|
||||
case PINCH:
|
||||
uiObjectVertPinch(view, pinch, steps, percent);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
logger.stop();
|
||||
}
|
||||
|
||||
UiObject navigateUpButton =
|
||||
getUiObjectByDescription("Navigate Up", "android.widget.ImageButton");
|
||||
navigateUpButton.click();
|
||||
}
|
||||
|
||||
public enum Position { LEFT, RIGHT, CENTRE };
|
||||
|
||||
private class SeekBarTestParams {
|
||||
|
||||
private Position seekBarPosition;
|
||||
private int percent;
|
||||
private int steps;
|
||||
|
||||
SeekBarTestParams(final Position position, final int steps, final int percent) {
|
||||
this.seekBarPosition = position;
|
||||
this.steps = steps;
|
||||
this.percent = percent;
|
||||
}
|
||||
}
|
||||
|
||||
private void editPhotoColorTest() throws Exception {
|
||||
String testTag = "edit_photo";
|
||||
|
||||
// Perform a range of swipe tests while browsing photo gallery
|
||||
LinkedHashMap<String, SeekBarTestParams> testParams = new LinkedHashMap<String, SeekBarTestParams>();
|
||||
testParams.put("increment_color", new SeekBarTestParams(Position.RIGHT, 10, 20));
|
||||
testParams.put("reset_color", new SeekBarTestParams(Position.CENTRE, 0, 0));
|
||||
testParams.put("decrement_color", new SeekBarTestParams(Position.LEFT, 10, 20));
|
||||
|
||||
Iterator<Entry<String, SeekBarTestParams>> it = testParams.entrySet().iterator();
|
||||
|
||||
// Select second photograph
|
||||
selectPhoto(2);
|
||||
UiObject editView = getUiObjectByResourceId("com.google.android.apps.photos:id/edit",
|
||||
"android.widget.ImageView");
|
||||
editView.click();
|
||||
|
||||
// Manage potential different spelling of UI element
|
||||
UiObject editColor = new UiObject(new UiSelector().text("Color"));
|
||||
UiObject editColour = new UiObject(new UiSelector().text("Colour"));
|
||||
|
||||
if (editColor.exists()) {
|
||||
editColor.click();
|
||||
} else if (editColour.exists()) {
|
||||
editColour.click();
|
||||
} else {
|
||||
throw new UiObjectNotFoundException(String.format("Could not find \"%s\" \"%s\"",
|
||||
"Color/Colour", "android.widget.RadioButton"));
|
||||
}
|
||||
|
||||
UiObject seekBar = getUiObjectByResourceId("com.google.android.apps.photos:id/cpe_strength_seek_bar",
|
||||
"android.widget.SeekBar");
|
||||
|
||||
while (it.hasNext()) {
|
||||
Map.Entry<String, SeekBarTestParams> pair = it.next();
|
||||
Position pos = pair.getValue().seekBarPosition;
|
||||
int steps = pair.getValue().steps;
|
||||
int percent = pair.getValue().percent;
|
||||
|
||||
String runName = String.format(testTag + "_" + pair.getKey());
|
||||
ActionLogger logger = new ActionLogger(runName, parameters);
|
||||
|
||||
logger.start();
|
||||
seekBarTest(seekBar, pos, steps);
|
||||
logger.stop();
|
||||
}
|
||||
|
||||
closeAndReturn(true);
|
||||
}
|
||||
|
||||
private void cropPhotoTest() throws Exception {
|
||||
String testTag = "crop_photo";
|
||||
|
||||
// To improve travel accuracy perform the slide bar operation slowly
|
||||
final int steps = 500;
|
||||
|
||||
// Perform a range of swipe tests while browsing photo gallery
|
||||
LinkedHashMap<String, Position> testParams = new LinkedHashMap<String, Position>();
|
||||
testParams.put("tilt_positive", Position.LEFT);
|
||||
testParams.put("tilt_reset", Position.RIGHT);
|
||||
testParams.put("tilt_negative", Position.RIGHT);
|
||||
|
||||
Iterator<Entry<String, Position>> it = testParams.entrySet().iterator();
|
||||
|
||||
// Select third photograph
|
||||
selectPhoto(3);
|
||||
UiObject editView = getUiObjectByResourceId("com.google.android.apps.photos:id/edit",
|
||||
"android.widget.ImageView");
|
||||
editView.click();
|
||||
|
||||
UiObject cropTool = getUiObjectByResourceId("com.google.android.apps.photos:id/cpe_crop_tool",
|
||||
"android.widget.ImageView");
|
||||
cropTool.click();
|
||||
|
||||
UiObject straightenSlider = getUiObjectByResourceId("com.google.android.apps.photos:id/cpe_straighten_slider",
|
||||
"android.view.View");
|
||||
|
||||
while (it.hasNext()) {
|
||||
Map.Entry<String, Position> pair = it.next();
|
||||
Position pos = pair.getValue();
|
||||
|
||||
String runName = String.format(testTag + "_" + pair.getKey());
|
||||
ActionLogger logger = new ActionLogger(runName, parameters);
|
||||
|
||||
logger.start();
|
||||
slideBarTest(straightenSlider, pos, steps);
|
||||
logger.stop();
|
||||
}
|
||||
|
||||
closeAndReturn(true);
|
||||
}
|
||||
|
||||
private void rotatePhotoTest() throws Exception {
|
||||
String testTag = "rotate_photo";
|
||||
|
||||
String[] subTests = {"anticlockwise_90", "anticlockwise_180", "anticlockwise_270"};
|
||||
|
||||
// Select fourth photograph
|
||||
selectPhoto(4);
|
||||
UiObject editView = getUiObjectByResourceId("com.google.android.apps.photos:id/edit",
|
||||
"android.widget.ImageView");
|
||||
editView.click();
|
||||
|
||||
UiObject cropTool = getUiObjectByResourceId("com.google.android.apps.photos:id/cpe_crop_tool",
|
||||
"android.widget.ImageView");
|
||||
cropTool.click();
|
||||
|
||||
UiObject rotate = getUiObjectByResourceId("com.google.android.apps.photos:id/cpe_rotate_90",
|
||||
"android.widget.ImageView");
|
||||
|
||||
for (String subTest : subTests) {
|
||||
String runName = String.format(testTag + "_" + subTest);
|
||||
ActionLogger logger = new ActionLogger(runName, parameters);
|
||||
|
||||
logger.start();
|
||||
rotate.click();
|
||||
logger.stop();
|
||||
}
|
||||
|
||||
closeAndReturn(true);
|
||||
}
|
||||
|
||||
// Helper to slide the seekbar during photo edit.
|
||||
private void seekBarTest(final UiObject view, final Position pos, final int steps) throws Exception {
|
||||
final int SWIPE_MARGIN_LIMIT = 5;
|
||||
Rect rect = view.getVisibleBounds();
|
||||
|
||||
switch (pos) {
|
||||
case LEFT:
|
||||
getUiDevice().click(rect.left + SWIPE_MARGIN_LIMIT, rect.centerY());
|
||||
break;
|
||||
case RIGHT:
|
||||
getUiDevice().click(rect.right - SWIPE_MARGIN_LIMIT, rect.centerY());
|
||||
break;
|
||||
case CENTRE:
|
||||
view.click();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Helper to slide the slidebar during photo edit.
|
||||
private void slideBarTest(final UiObject view, final Position pos, final int steps) throws Exception {
|
||||
final int SWIPE_MARGIN_LIMIT = 5;
|
||||
Rect rect = view.getBounds();
|
||||
|
||||
switch (pos) {
|
||||
case LEFT:
|
||||
getUiDevice().drag(rect.left + SWIPE_MARGIN_LIMIT, rect.centerY(),
|
||||
rect.left + rect.width() / 4, rect.centerY(),
|
||||
steps);
|
||||
break;
|
||||
case RIGHT:
|
||||
getUiDevice().drag(rect.right - SWIPE_MARGIN_LIMIT, rect.centerY(),
|
||||
rect.right - rect.width() / 4, rect.centerY(),
|
||||
steps);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void closePromotionPopUp() throws Exception {
|
||||
UiObject promoCloseButton =
|
||||
new UiObject(new UiSelector().resourceId("com.google.android.apps.photos:id/promo_close_button"));
|
||||
|
||||
if (promoCloseButton.exists()) {
|
||||
promoCloseButton.click();
|
||||
}
|
||||
}
|
||||
|
||||
// Helper to click on the wa-working gallery.
|
||||
public void selectWorkingGallery() throws Exception {
|
||||
UiObject workdir = new UiObject(new UiSelector().text("wa-working")
|
||||
.className("android.widget.TextView"));
|
||||
|
||||
UiScrollable scrollView = new UiScrollable(new UiSelector().scrollable(true));
|
||||
|
||||
while (!workdir.exists()) {
|
||||
scrollView.scrollForward();
|
||||
}
|
||||
|
||||
workdir.clickAndWaitForNewWindow();
|
||||
}
|
||||
|
||||
// Helper to click on an individual photograph based on index in wa-working gallery.
|
||||
public void selectPhoto(final int index) throws Exception {
|
||||
UiObject photo =
|
||||
new UiObject(new UiSelector().resourceId("com.google.android.apps.photos:id/recycler_view")
|
||||
.childSelector(new UiSelector()
|
||||
.index(index)));
|
||||
|
||||
// On some versions of the app a non-zero index is used for the
|
||||
// photographs position while on other versions a zero index is used.
|
||||
// Try both possiblities before throwing an exception.
|
||||
if (photo.exists()) {
|
||||
photo.click();
|
||||
} else {
|
||||
photo = new UiObject(new UiSelector().resourceId("com.google.android.apps.photos:id/recycler_view")
|
||||
.childSelector(new UiSelector()
|
||||
.index(index - 1)));
|
||||
photo.click();
|
||||
}
|
||||
}
|
||||
|
||||
// Helper that accepts, closes and navigates back to application home screen after an edit operation.
|
||||
// dontsave - True will discard the image. False will save the image
|
||||
public void closeAndReturn(final boolean dontsave) throws Exception {
|
||||
|
||||
UiObject accept = getUiObjectByDescription("Accept", "android.widget.ImageView");
|
||||
accept.click();
|
||||
|
||||
if (dontsave) {
|
||||
UiObject close = getUiObjectByDescription("Close editor", "android.widget.ImageView");
|
||||
close.click();
|
||||
|
||||
UiObject discard = getUiObjectByText("DISCARD", "android.widget.Button");
|
||||
discard.waitForExists(viewTimeout);
|
||||
discard.click();
|
||||
} else {
|
||||
UiObject save = getUiObjectByText("SAVE", "android.widget.TextView");
|
||||
save.waitForExists(viewTimeout);
|
||||
save.click();
|
||||
}
|
||||
|
||||
UiObject navigateUpButton =
|
||||
new UiObject(new UiSelector().descriptionContains("Navigate Up")
|
||||
.className("android.widget.ImageButton"));
|
||||
navigateUpButton.waitForExists(viewTimeout);
|
||||
navigateUpButton.click();
|
||||
}
|
||||
|
||||
// Helper to tag an individual photograph based on the index in wa-working
|
||||
// gallery. After long clicking it tags the photograph with a tick in the
|
||||
// corner of the image to indicate that the photograph has been selected
|
||||
public void tagPhoto(final int index) throws Exception {
|
||||
UiObject photo =
|
||||
new UiObject(new UiSelector().resourceId("com.google.android.apps.photos:id/recycler_view")
|
||||
.childSelector(new UiSelector()
|
||||
.index(index)));
|
||||
|
||||
// On some versions of the app a non-zero index is used for the
|
||||
// photographs position while on other versions a zero index is used.
|
||||
// Try both possiblities before throwing an exception.
|
||||
if (photo.exists()) {
|
||||
uiObjectPerformLongClick(photo, 100);
|
||||
} else {
|
||||
photo = new UiObject(new UiSelector().resourceId("com.google.android.apps.photos:id/recycler_view")
|
||||
.childSelector(new UiSelector()
|
||||
.index(index - 1)));
|
||||
uiObjectPerformLongClick(photo, 100);
|
||||
}
|
||||
}
|
||||
}
|
@ -11,4 +11,4 @@
|
||||
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
||||
|
||||
# Project target.
|
||||
target=android-17
|
||||
target=android-18
|
||||
|
@ -11,4 +11,4 @@
|
||||
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
||||
|
||||
# Project target.
|
||||
target=android-17
|
||||
target=android-18
|
||||
|
@ -11,4 +11,4 @@
|
||||
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
||||
|
||||
# Project target.
|
||||
target=android-17
|
||||
target=android-18
|
||||
|
@ -11,4 +11,4 @@
|
||||
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
||||
|
||||
# Project target.
|
||||
target=android-17
|
||||
target=android-18
|
||||
|
@ -11,4 +11,4 @@
|
||||
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
||||
|
||||
# Project target.
|
||||
target=android-17
|
||||
target=android-18
|
||||
|
Loading…
x
Reference in New Issue
Block a user