mirror of
https://github.com/ARM-software/workload-automation.git
synced 2025-02-22 04:49:00 +00:00
Merge pull request #225 from jimboatarm/googlephotos_uxperf
Add googlephotos workload
This commit is contained in:
commit
ff2f88fbd7
89
wlauto/workloads/googlephotos/__init__.py
Executable file
89
wlauto/workloads/googlephotos/__init__.py
Executable file
@ -0,0 +1,89 @@
|
|||||||
|
# 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
|
||||||
|
|
||||||
|
from wlauto import AndroidUxPerfWorkload, Parameter, File
|
||||||
|
from wlauto.exceptions import ValidationError
|
||||||
|
from wlauto.utils.types import list_of_strings
|
||||||
|
from wlauto.utils.misc import unique
|
||||||
|
|
||||||
|
|
||||||
|
class Googlephotos(AndroidUxPerfWorkload):
|
||||||
|
|
||||||
|
name = 'googlephotos'
|
||||||
|
package = 'com.google.android.apps.photos'
|
||||||
|
min_apk_version = '1.21.0.123444480'
|
||||||
|
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, and post-processing the image.
|
||||||
|
|
||||||
|
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 tilted 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('test_images', kind=list_of_strings, default=default_test_images,
|
||||||
|
constraint=lambda x: len(unique(x)) == 4,
|
||||||
|
description="""
|
||||||
|
A list of four JPEG and/or PNG files to be pushed to the device.
|
||||||
|
Absolute file paths may be used but tilde expansion must be escaped.
|
||||||
|
"""),
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self, device, **kwargs):
|
||||||
|
super(Googlephotos, self).__init__(device, **kwargs)
|
||||||
|
self.deployable_assets = self.test_images
|
||||||
|
|
||||||
|
def validate(self):
|
||||||
|
super(Googlephotos, self).validate()
|
||||||
|
|
||||||
|
for image in self.test_images:
|
||||||
|
if os.path.splitext(image.lower())[1] not in ['.jpg', '.jpeg', '.png']:
|
||||||
|
raise ValidationError('{} must be a JPEG or PNG file'.format(image))
|
||||||
|
|
||||||
|
def setup(self, context):
|
||||||
|
super(Googlephotos, self).setup(context)
|
||||||
|
self.device.broadcast_media_mounted(self.device.working_directory)
|
||||||
|
|
||||||
|
def teardown(self, context):
|
||||||
|
super(Googlephotos, self).teardown(context)
|
||||||
|
self.device.broadcast_media_mounted(self.device.working_directory)
|
||||||
|
|
||||||
|
def finalize(self, context):
|
||||||
|
super(Googlephotos, self).finalize(context)
|
||||||
|
self.delete_assets()
|
||||||
|
self.device.broadcast_media_mounted(self.device.working_directory)
|
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
|
486
wlauto/workloads/googlephotos/uiauto/src/com/arm/wlauto/uiauto/UiAutomation.java
Executable file
486
wlauto/workloads/googlephotos/uiauto/src/com/arm/wlauto/uiauto/UiAutomation.java
Executable file
@ -0,0 +1,486 @@
|
|||||||
|
/* 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;
|
||||||
|
public String packageName;
|
||||||
|
public String packageID;
|
||||||
|
|
||||||
|
private int viewTimeoutSecs = 10;
|
||||||
|
private long viewTimeout = TimeUnit.SECONDS.toMillis(viewTimeoutSecs);
|
||||||
|
|
||||||
|
public void runUiAutomation() throws Exception {
|
||||||
|
parameters = getParams();
|
||||||
|
packageName = parameters.getString("package");
|
||||||
|
packageID = packageName + ":id/";
|
||||||
|
|
||||||
|
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"));
|
||||||
|
|
||||||
|
if (getStartedButton.waitForExists(viewTimeout)) {
|
||||||
|
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(packageID + "dont_sign_in_button"));
|
||||||
|
|
||||||
|
// Folder containing test images (early check required)
|
||||||
|
UiObject workingFolder = new UiObject(new UiSelector().text("wa-working"));
|
||||||
|
|
||||||
|
if (doNotSignInButton.exists()) {
|
||||||
|
doNotSignInButton.click();
|
||||||
|
} else {
|
||||||
|
UiObject welcomeButton =
|
||||||
|
getUiObjectByResourceId(packageID + "name",
|
||||||
|
"android.widget.TextView");
|
||||||
|
welcomeButton.click();
|
||||||
|
|
||||||
|
UiObject useWithoutAccount =
|
||||||
|
getUiObjectByText("Use without an account", "android.widget.TextView");
|
||||||
|
useWithoutAccount.clickAndWaitForNewWindow();
|
||||||
|
|
||||||
|
// On some devices the welcome views don't always appear so check
|
||||||
|
// for the existence of the wa-working directory before attempting
|
||||||
|
// to dismiss welcome views promoting app features
|
||||||
|
if (!workingFolder.exists()) {
|
||||||
|
sleep(1);
|
||||||
|
uiDeviceSwipeLeft(10);
|
||||||
|
sleep(1);
|
||||||
|
uiDeviceSwipeLeft(10);
|
||||||
|
sleep(1);
|
||||||
|
uiDeviceSwipeLeft(10);
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UiObject nextButton =
|
||||||
|
new UiObject(new UiSelector().resourceId(packageID + "next_button")
|
||||||
|
.className("android.widget.ImageView"));
|
||||||
|
|
||||||
|
if (nextButton.exists()) {
|
||||||
|
nextButton.clickAndWaitForNewWindow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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(packageID + "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"));
|
||||||
|
|
||||||
|
long timeout = TimeUnit.SECONDS.toMillis(3);
|
||||||
|
|
||||||
|
if (editColor.waitForExists(timeout)) {
|
||||||
|
editColor.click();
|
||||||
|
} else if (editColour.waitForExists(timeout)) {
|
||||||
|
editColour.click();
|
||||||
|
} else {
|
||||||
|
throw new UiObjectNotFoundException(String.format("Could not find \"%s\" \"%s\"",
|
||||||
|
"Color/Colour", "android.widget.RadioButton"));
|
||||||
|
}
|
||||||
|
|
||||||
|
UiObject seekBar = getUiObjectByResourceId(packageID + "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);
|
||||||
|
|
||||||
|
sleep(1); // pause for stability before editing the colour
|
||||||
|
|
||||||
|
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(packageID + "edit",
|
||||||
|
"android.widget.ImageView");
|
||||||
|
editView.click();
|
||||||
|
|
||||||
|
UiObject cropTool = getUiObjectByResourceId(packageID + "cpe_crop_tool",
|
||||||
|
"android.widget.ImageView");
|
||||||
|
cropTool.click();
|
||||||
|
|
||||||
|
UiObject straightenSlider = getUiObjectByResourceId(packageID + "cpe_straighten_slider");
|
||||||
|
|
||||||
|
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(packageID + "edit",
|
||||||
|
"android.widget.ImageView");
|
||||||
|
editView.click();
|
||||||
|
|
||||||
|
UiObject cropTool = getUiObjectByResourceId(packageID + "cpe_crop_tool");
|
||||||
|
cropTool.click();
|
||||||
|
|
||||||
|
UiObject rotate = getUiObjectByResourceId(packageID + "cpe_rotate_90");
|
||||||
|
|
||||||
|
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(packageID + "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"));
|
||||||
|
|
||||||
|
// If the wa-working gallery is not present wait for a short time for
|
||||||
|
// the media server to refresh its index.
|
||||||
|
boolean discovered = workdir.waitForExists(viewTimeout);
|
||||||
|
UiScrollable scrollView = new UiScrollable(new UiSelector().scrollable(true));
|
||||||
|
|
||||||
|
if (!discovered && scrollView.exists()) {
|
||||||
|
// First check if the wa-working directory is visible on the first
|
||||||
|
// screen and if not scroll to the bottom of the screen to look for it.
|
||||||
|
discovered = scrollView.scrollIntoView(workdir);
|
||||||
|
|
||||||
|
// If still not discovered scroll back to the top of the screen and
|
||||||
|
// wait for a longer amount of time for the media server to refresh
|
||||||
|
// its index.
|
||||||
|
if (!discovered) {
|
||||||
|
// scrollView.scrollToBeggining() doesn't work for this
|
||||||
|
// particular scrollable view so use device method instead
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
uiDeviceSwipeUp(20);
|
||||||
|
}
|
||||||
|
discovered = workdir.waitForExists(TimeUnit.SECONDS.toMillis(60));
|
||||||
|
|
||||||
|
// Scroll to the bottom of the screen one last time
|
||||||
|
if (!discovered) {
|
||||||
|
discovered = scrollView.scrollIntoView(workdir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (discovered) {
|
||||||
|
workdir.clickAndWaitForNewWindow();
|
||||||
|
} else {
|
||||||
|
throw new UiObjectNotFoundException("Could not find \"wa-working\" folder");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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(packageID + "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(packageID + "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 = new UiObject(new UiSelector().description("Accept"));
|
||||||
|
UiObject done = new UiObject(new UiSelector().resourceId(packageID + "cpe_save_button"));
|
||||||
|
|
||||||
|
long timeout = TimeUnit.SECONDS.toMillis(3);
|
||||||
|
|
||||||
|
// On some edit operations we can either confirm an edit with "Accept" or "DONE"
|
||||||
|
if (accept.waitForExists(timeout)) {
|
||||||
|
accept.click();
|
||||||
|
} else if (done.waitForExists(timeout)) {
|
||||||
|
done.click();
|
||||||
|
} else {
|
||||||
|
throw new UiObjectNotFoundException("Could not find \"Accept\" or \"DONE\" button.");
|
||||||
|
}
|
||||||
|
|
||||||
|
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(packageID + "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(packageID + "recycler_view")
|
||||||
|
.childSelector(new UiSelector()
|
||||||
|
.index(index - 1)));
|
||||||
|
uiObjectPerformLongClick(photo, 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user