diff --git a/wlauto/common/android/BaseUiAutomation$1.class b/wlauto/common/android/BaseUiAutomation$1.class new file mode 100644 index 00000000..fea7e68c Binary files /dev/null and b/wlauto/common/android/BaseUiAutomation$1.class differ diff --git a/wlauto/common/android/BaseUiAutomation$ActionLogger.class b/wlauto/common/android/BaseUiAutomation$ActionLogger.class new file mode 100644 index 00000000..53c38828 Binary files /dev/null and b/wlauto/common/android/BaseUiAutomation$ActionLogger.class differ diff --git a/wlauto/common/android/BaseUiAutomation$Direction.class b/wlauto/common/android/BaseUiAutomation$Direction.class new file mode 100644 index 00000000..779a5393 Binary files /dev/null and b/wlauto/common/android/BaseUiAutomation$Direction.class differ diff --git a/wlauto/common/android/BaseUiAutomation$FindByCriteria.class b/wlauto/common/android/BaseUiAutomation$FindByCriteria.class new file mode 100644 index 00000000..97c94868 Binary files /dev/null and b/wlauto/common/android/BaseUiAutomation$FindByCriteria.class differ diff --git a/wlauto/common/android/BaseUiAutomation$PinchType.class b/wlauto/common/android/BaseUiAutomation$PinchType.class new file mode 100644 index 00000000..19a2ab46 Binary files /dev/null and b/wlauto/common/android/BaseUiAutomation$PinchType.class differ diff --git a/wlauto/common/android/BaseUiAutomation$ScreenOrientation.class b/wlauto/common/android/BaseUiAutomation$ScreenOrientation.class new file mode 100644 index 00000000..812f1a4e Binary files /dev/null and b/wlauto/common/android/BaseUiAutomation$ScreenOrientation.class differ diff --git a/wlauto/common/android/BaseUiAutomation.class b/wlauto/common/android/BaseUiAutomation.class index e2bf1737..1f6f8cdd 100644 Binary files a/wlauto/common/android/BaseUiAutomation.class and b/wlauto/common/android/BaseUiAutomation.class differ diff --git a/wlauto/common/android/UxPerfUiAutomation$1.class b/wlauto/common/android/UxPerfUiAutomation$1.class new file mode 100644 index 00000000..bf2abb92 Binary files /dev/null and b/wlauto/common/android/UxPerfUiAutomation$1.class differ diff --git a/wlauto/common/android/UxPerfUiAutomation$ActionLogger.class b/wlauto/common/android/UxPerfUiAutomation$ActionLogger.class new file mode 100644 index 00000000..a8ea0822 Binary files /dev/null and b/wlauto/common/android/UxPerfUiAutomation$ActionLogger.class differ diff --git a/wlauto/common/android/UxPerfUiAutomation$Direction.class b/wlauto/common/android/UxPerfUiAutomation$Direction.class new file mode 100644 index 00000000..5f9bf7ed Binary files /dev/null and b/wlauto/common/android/UxPerfUiAutomation$Direction.class differ diff --git a/wlauto/common/android/UxPerfUiAutomation$GestureTestParams.class b/wlauto/common/android/UxPerfUiAutomation$GestureTestParams.class new file mode 100644 index 00000000..d793d013 Binary files /dev/null and b/wlauto/common/android/UxPerfUiAutomation$GestureTestParams.class differ diff --git a/wlauto/common/android/UxPerfUiAutomation$GestureType.class b/wlauto/common/android/UxPerfUiAutomation$GestureType.class new file mode 100644 index 00000000..8cc30f68 Binary files /dev/null and b/wlauto/common/android/UxPerfUiAutomation$GestureType.class differ diff --git a/wlauto/common/android/UxPerfUiAutomation$PinchType.class b/wlauto/common/android/UxPerfUiAutomation$PinchType.class new file mode 100644 index 00000000..b4b09cda Binary files /dev/null and b/wlauto/common/android/UxPerfUiAutomation$PinchType.class differ diff --git a/wlauto/common/android/UxPerfUiAutomation$SurfaceLogger.class b/wlauto/common/android/UxPerfUiAutomation$SurfaceLogger.class new file mode 100644 index 00000000..eadfd270 Binary files /dev/null and b/wlauto/common/android/UxPerfUiAutomation$SurfaceLogger.class differ diff --git a/wlauto/common/android/UxPerfUiAutomation$Timer.class b/wlauto/common/android/UxPerfUiAutomation$Timer.class new file mode 100644 index 00000000..da53c682 Binary files /dev/null and b/wlauto/common/android/UxPerfUiAutomation$Timer.class differ diff --git a/wlauto/common/android/UxPerfUiAutomation$UxPerfLogger.class b/wlauto/common/android/UxPerfUiAutomation$UxPerfLogger.class new file mode 100644 index 00000000..67fa402b Binary files /dev/null and b/wlauto/common/android/UxPerfUiAutomation$UxPerfLogger.class differ diff --git a/wlauto/common/android/UxPerfUiAutomation.class b/wlauto/common/android/UxPerfUiAutomation.class new file mode 100644 index 00000000..1be53c1f Binary files /dev/null and b/wlauto/common/android/UxPerfUiAutomation.class differ diff --git a/wlauto/external/uiauto/build.sh b/wlauto/external/uiauto/build.sh index 074f245a..95f9872f 100755 --- a/wlauto/external/uiauto/build.sh +++ b/wlauto/external/uiauto/build.sh @@ -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 diff --git a/wlauto/external/uiauto/project.properties b/wlauto/external/uiauto/project.properties index a3ee5ab6..ce39f2d0 100644 --- a/wlauto/external/uiauto/project.properties +++ b/wlauto/external/uiauto/project.properties @@ -11,4 +11,4 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-17 +target=android-18 diff --git a/wlauto/external/uiauto/src/com/arm/wlauto/uiauto/BaseUiAutomation.java b/wlauto/external/uiauto/src/com/arm/wlauto/uiauto/BaseUiAutomation.java index 144fdac5..dbf0bfe5 100644 --- a/wlauto/external/uiauto/src/com/arm/wlauto/uiauto/BaseUiAutomation.java +++ b/wlauto/external/uiauto/src/com/arm/wlauto/uiauto/BaseUiAutomation.java @@ -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; + } +} diff --git a/wlauto/external/uiauto/src/com/arm/wlauto/uiauto/UxPerfUiAutomation.java b/wlauto/external/uiauto/src/com/arm/wlauto/uiauto/UxPerfUiAutomation.java new file mode 100644 index 00000000..10367015 --- /dev/null +++ b/wlauto/external/uiauto/src/com/arm/wlauto/uiauto/UxPerfUiAutomation.java @@ -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; + } + } +} diff --git a/wlauto/workloads/andebench/uiauto/project.properties b/wlauto/workloads/andebench/uiauto/project.properties index a3ee5ab6..ce39f2d0 100644 --- a/wlauto/workloads/andebench/uiauto/project.properties +++ b/wlauto/workloads/andebench/uiauto/project.properties @@ -11,4 +11,4 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-17 +target=android-18 diff --git a/wlauto/workloads/androbench/uiauto/project.properties b/wlauto/workloads/androbench/uiauto/project.properties index a3ee5ab6..ce39f2d0 100644 --- a/wlauto/workloads/androbench/uiauto/project.properties +++ b/wlauto/workloads/androbench/uiauto/project.properties @@ -11,4 +11,4 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-17 +target=android-18 diff --git a/wlauto/workloads/benchmarkpi/uiauto/project.properties b/wlauto/workloads/benchmarkpi/uiauto/project.properties index a3ee5ab6..ce39f2d0 100644 --- a/wlauto/workloads/benchmarkpi/uiauto/project.properties +++ b/wlauto/workloads/benchmarkpi/uiauto/project.properties @@ -11,4 +11,4 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-17 +target=android-18 diff --git a/wlauto/workloads/caffeinemark/uiauto/project.properties b/wlauto/workloads/caffeinemark/uiauto/project.properties index a3ee5ab6..ce39f2d0 100644 --- a/wlauto/workloads/caffeinemark/uiauto/project.properties +++ b/wlauto/workloads/caffeinemark/uiauto/project.properties @@ -11,4 +11,4 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-17 +target=android-18 diff --git a/wlauto/workloads/cfbench/uiauto/project.properties b/wlauto/workloads/cfbench/uiauto/project.properties index a3ee5ab6..ce39f2d0 100644 --- a/wlauto/workloads/cfbench/uiauto/project.properties +++ b/wlauto/workloads/cfbench/uiauto/project.properties @@ -11,4 +11,4 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-17 +target=android-18 diff --git a/wlauto/workloads/facebook/uiauto/project.properties b/wlauto/workloads/facebook/uiauto/project.properties index a3ee5ab6..ce39f2d0 100644 --- a/wlauto/workloads/facebook/uiauto/project.properties +++ b/wlauto/workloads/facebook/uiauto/project.properties @@ -11,4 +11,4 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-17 +target=android-18 diff --git a/wlauto/workloads/geekbench/uiauto/project.properties b/wlauto/workloads/geekbench/uiauto/project.properties index a3ee5ab6..ce39f2d0 100644 --- a/wlauto/workloads/geekbench/uiauto/project.properties +++ b/wlauto/workloads/geekbench/uiauto/project.properties @@ -11,4 +11,4 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-17 +target=android-18 diff --git a/wlauto/workloads/glbenchmark/uiauto/project.properties b/wlauto/workloads/glbenchmark/uiauto/project.properties index a3ee5ab6..ce39f2d0 100644 --- a/wlauto/workloads/glbenchmark/uiauto/project.properties +++ b/wlauto/workloads/glbenchmark/uiauto/project.properties @@ -11,4 +11,4 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-17 +target=android-18 diff --git a/wlauto/workloads/googlephotos/__init__.py b/wlauto/workloads/googlephotos/__init__.py new file mode 100755 index 00000000..ce733478 --- /dev/null +++ b/wlauto/workloads/googlephotos/__init__.py @@ -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') diff --git a/wlauto/workloads/googlephotos/com.arm.wlauto.uiauto.googlephotos.jar b/wlauto/workloads/googlephotos/com.arm.wlauto.uiauto.googlephotos.jar new file mode 100644 index 00000000..acb01ece Binary files /dev/null and b/wlauto/workloads/googlephotos/com.arm.wlauto.uiauto.googlephotos.jar differ diff --git a/wlauto/workloads/googlephotos/uiauto/build.sh b/wlauto/workloads/googlephotos/uiauto/build.sh new file mode 100755 index 00000000..fefef54e --- /dev/null +++ b/wlauto/workloads/googlephotos/uiauto/build.sh @@ -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 diff --git a/wlauto/workloads/googlephotos/uiauto/build.xml b/wlauto/workloads/googlephotos/uiauto/build.xml new file mode 100644 index 00000000..648161d0 --- /dev/null +++ b/wlauto/workloads/googlephotos/uiauto/build.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wlauto/workloads/googlephotos/uiauto/project.properties b/wlauto/workloads/googlephotos/uiauto/project.properties new file mode 100644 index 00000000..ce39f2d0 --- /dev/null +++ b/wlauto/workloads/googlephotos/uiauto/project.properties @@ -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 diff --git a/wlauto/workloads/googlephotos/uiauto/src/com/arm/wlauto/uiauto/UiAutomation.java b/wlauto/workloads/googlephotos/uiauto/src/com/arm/wlauto/uiauto/UiAutomation.java new file mode 100755 index 00000000..3189e8a1 --- /dev/null +++ b/wlauto/workloads/googlephotos/uiauto/src/com/arm/wlauto/uiauto/UiAutomation.java @@ -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 testParams = new LinkedHashMap(); + 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> it = testParams.entrySet().iterator(); + + // Select first photograph + selectPhoto(1); + + while (it.hasNext()) { + Map.Entry 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 testParams = new LinkedHashMap(); + 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> 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 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 testParams = new LinkedHashMap(); + testParams.put("tilt_positive", Position.LEFT); + testParams.put("tilt_reset", Position.RIGHT); + testParams.put("tilt_negative", Position.RIGHT); + + Iterator> 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 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); + } + } +} diff --git a/wlauto/workloads/linpack/uiauto/project.properties b/wlauto/workloads/linpack/uiauto/project.properties index a3ee5ab6..ce39f2d0 100644 --- a/wlauto/workloads/linpack/uiauto/project.properties +++ b/wlauto/workloads/linpack/uiauto/project.properties @@ -11,4 +11,4 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-17 +target=android-18 diff --git a/wlauto/workloads/peacekeeper/uiauto/project.properties b/wlauto/workloads/peacekeeper/uiauto/project.properties index a3ee5ab6..ce39f2d0 100644 --- a/wlauto/workloads/peacekeeper/uiauto/project.properties +++ b/wlauto/workloads/peacekeeper/uiauto/project.properties @@ -11,4 +11,4 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-17 +target=android-18 diff --git a/wlauto/workloads/quadrant/uiauto/project.properties b/wlauto/workloads/quadrant/uiauto/project.properties index a3ee5ab6..ce39f2d0 100644 --- a/wlauto/workloads/quadrant/uiauto/project.properties +++ b/wlauto/workloads/quadrant/uiauto/project.properties @@ -11,4 +11,4 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-17 +target=android-18 diff --git a/wlauto/workloads/real_linpack/uiauto/project.properties b/wlauto/workloads/real_linpack/uiauto/project.properties index a3ee5ab6..ce39f2d0 100644 --- a/wlauto/workloads/real_linpack/uiauto/project.properties +++ b/wlauto/workloads/real_linpack/uiauto/project.properties @@ -11,4 +11,4 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-17 +target=android-18 diff --git a/wlauto/workloads/smartbench/uiauto/project.properties b/wlauto/workloads/smartbench/uiauto/project.properties index a3ee5ab6..ce39f2d0 100644 --- a/wlauto/workloads/smartbench/uiauto/project.properties +++ b/wlauto/workloads/smartbench/uiauto/project.properties @@ -11,4 +11,4 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-17 +target=android-18