diff --git a/wlauto/workloads/adobereader/__init__.py b/wlauto/workloads/adobereader/__init__.py new file mode 100755 index 00000000..98f7c0c1 --- /dev/null +++ b/wlauto/workloads/adobereader/__init__.py @@ -0,0 +1,92 @@ +# 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 +from wlauto.exceptions import ValidationError +from wlauto.utils.types import list_of_strings + + +class AdobeReader(AndroidUxPerfWorkload): + + name = 'adobereader' + package = 'com.adobe.reader' + min_apk_verson = '16.1.1' + activity = 'com.adobe.reader.AdobeReader' + view = [package + '/com.adobe.reader.help.AROnboardingHelpActivity', + package + '/com.adobe.reader.viewer.ARSplitPaneActivity', + package + '/com.adobe.reader.viewer.ARViewerActivity'] + description = ''' + The Adobe Reader workflow carries out the following typical productivity tasks. + + Test description: + 1. Open a local file on the device + 2. Gestures test: + 2.1. Swipe down across the central 50% of the screen in 200 x 5ms steps + 2.2. Swipe up across the central 50% of the screen in 200 x 5ms steps + 2.3. Swipe right from the edge of the screen in 50 x 5ms steps + 2.4. Swipe left from the edge of the screen in 50 x 5ms steps + 2.5. Pinch out 50% in 100 x 5ms steps + 2.6. Pinch In 50% in 100 x 5ms steps + 3. Search test: + Search ``document_name`` for each string in the ``search_string_list`` + 4. Close the document + ''' + + default_search_strings = [ + 'The quick brown fox jumps over the lazy dog', + 'TEST_SEARCH_STRING', + ] + + parameters = [ + Parameter('document_name', kind=str, default="uxperf_test_doc.pdf", + description=''' + The document name to use for the Gesture and Search test. + '''), + Parameter('search_string_list', kind=list_of_strings, default=default_search_strings, + constraint=lambda x: len(x) > 0, + description=''' + For each string in the list, a document search is performed + using the string as the search term. At least one must be + provided. + '''), + ] + + def __init__(self, device, **kwargs): + super(AdobeReader, self).__init__(device, **kwargs) + self.deployable_assets = [self.document_name] + # Adobe only looks for local files in a specific path + self.adobe_path = self.device.path.join(self.device.external_storage_directory, + 'Android', 'data', 'com.adobe.reader', 'files') + + def validate(self): + super(AdobeReader, self).validate() + self.uiauto_params['filename'] = self.document_name.replace(' ', '0space0') + self.uiauto_params['search_string_list'] = '0newline0'.join([x.replace(' ', '0space0') for x in self.search_string_list]) + # Only accept certain file formats + if os.path.splitext(self.document_name.lower())[1] not in ['.pdf']: + raise ValidationError('{} must be a PDF file'.format(self.document_name)) + + def setup(self, context): + super(AdobeReader, self).setup(context) + # Create the adobe path if it doesnt exist yet, and move the asset to this location + self.device.execute('mkdir -p {}'.format(self.adobe_path)) + self.device.execute('mv {0}/{1} {2}/{1}'.format(self.device.working_directory, self.document_name, self.adobe_path)) + + def teardown(self, context): + super(AdobeReader, self).teardown(context) + # Remove the asset from the adobe location + self.device.execute('rm -rf {0}/{1}'.format(self.adobe_path, self.document_name)) diff --git a/wlauto/workloads/adobereader/com.arm.wlauto.uiauto.adobereader.jar b/wlauto/workloads/adobereader/com.arm.wlauto.uiauto.adobereader.jar new file mode 100644 index 00000000..f9f395ec Binary files /dev/null and b/wlauto/workloads/adobereader/com.arm.wlauto.uiauto.adobereader.jar differ diff --git a/wlauto/workloads/adobereader/uiauto/build.sh b/wlauto/workloads/adobereader/uiauto/build.sh new file mode 100755 index 00000000..2c282fd8 --- /dev/null +++ b/wlauto/workloads/adobereader/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.adobereader.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/adobereader/uiauto/build.xml b/wlauto/workloads/adobereader/uiauto/build.xml new file mode 100755 index 00000000..30b09298 --- /dev/null +++ b/wlauto/workloads/adobereader/uiauto/build.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wlauto/workloads/adobereader/uiauto/project.properties b/wlauto/workloads/adobereader/uiauto/project.properties new file mode 100644 index 00000000..ce39f2d0 --- /dev/null +++ b/wlauto/workloads/adobereader/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/adobereader/uiauto/src/com/arm/wlauto/uiauto/UiAutomation.java b/wlauto/workloads/adobereader/uiauto/src/com/arm/wlauto/uiauto/UiAutomation.java new file mode 100755 index 00000000..509c3f19 --- /dev/null +++ b/wlauto/workloads/adobereader/uiauto/src/com/arm/wlauto/uiauto/UiAutomation.java @@ -0,0 +1,246 @@ +/* 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.adobereader; + +import android.os.Bundle; + +// Import the uiautomator libraries +import com.android.uiautomator.core.UiObject; +import com.android.uiautomator.core.UiObjectNotFoundException; +import com.android.uiautomator.core.UiSelector; + +import com.arm.wlauto.uiauto.UxPerfUiAutomation; + +import static com.arm.wlauto.uiauto.BaseUiAutomation.FindByCriteria.BY_ID; +import static com.arm.wlauto.uiauto.BaseUiAutomation.FindByCriteria.BY_TEXT; +import static com.arm.wlauto.uiauto.BaseUiAutomation.FindByCriteria.BY_DESC; + +import java.util.concurrent.TimeUnit; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Map.Entry; + +public class UiAutomation extends UxPerfUiAutomation { + + protected Bundle parameters; + protected String packageName; + protected String packageID; + + private long networkTimeout = TimeUnit.SECONDS.toMillis(20); + private long searchTimeout = TimeUnit.SECONDS.toMillis(20); + + public void runUiAutomation() throws Exception { + parameters = getParams(); + packageName = parameters.getString("package"); + packageID = packageName + ":id/"; + + String filename = parameters.getString("filename").replace("0space0", " "); + String[] searchStrings = + parameters.getString("search_string_list").replace("0space0", " ").split("0newline0"); + + setScreenOrientation(ScreenOrientation.NATURAL); + + dismissWelcomeView(); + openFile(filename); + gesturesTest(); + searchPdfTest(searchStrings); + exitDocument(); + + unsetScreenOrientation(); + } + + private void dismissWelcomeView() throws Exception { + UiObject welcomeView = getUiObjectByResourceId("android:id/content", + "android.widget.FrameLayout"); + welcomeView.swipeLeft(10); + welcomeView.swipeLeft(10); + + clickUiObject(BY_ID, packageID + "onboarding_finish_button", "android.widget.Button"); + + // Deal with popup dialog message promoting Dropbox access + UiObject dropBoxDialog = + new UiObject(new UiSelector().text("Now you can access your Dropbox files.") + .className("android.widget.TextView")); + if (dropBoxDialog.exists()) { + clickUiObject(BY_TEXT, "Remind Me Later", "android.widget.Button"); + } + + // Also deal with the Dropbox CoachMark blue hint popup + UiObject dropBoxcoachMark = + new UiObject(new UiSelector().description("CoachMark") + .className("android.widget.LinearLayout")); + if (dropBoxcoachMark.exists()) { + tapDisplayCentre(); + } + + UiObject actionBarTitle = getUiObjectByDescription("My Documents", + "android.widget.LinearLayout"); + actionBarTitle.waitForExists(uiAutoTimeout); + } + + private void openFile(final String filename) throws Exception { + String testTag = "open_document"; + ActionLogger logger = new ActionLogger(testTag, parameters); + + // Select the local files list from the My Documents view + clickUiObject(BY_TEXT, "LOCAL", "android.widget.TextView"); + UiObject directoryPath = + new UiObject(new UiSelector().resourceId(packageID + "directoryPath")); + if (!directoryPath.waitForExists(TimeUnit.SECONDS.toMillis(60))) { + throw new UiObjectNotFoundException("Could not find any local files"); + } + + // Click the button to search from the present file list view + UiObject searchButton = getUiObjectByResourceId(packageID + "split_pane_search", + "android.widget.TextView", + TimeUnit.SECONDS.toMillis(10)); + searchButton.click(); + + // Enter search text into the file searchBox. This will automatically filter the list. + UiObject searchBox = getUiObjectByResourceId("android:id/search_src_text", + "android.widget.EditText"); + searchBox.setText(filename); + + // Open a file from a file list view by searching for UiObjects containing the doc title. + UiObject fileObject = getUiObjectByText(filename, "android.widget.TextView"); + + logger.start(); + + fileObject.clickAndWaitForNewWindow(uiAutoTimeout); + // Wait for the doc to open by waiting for the viewPager UiObject to exist + UiObject viewPager = + new UiObject(new UiSelector().resourceId(packageID + "viewPager")); + if (!viewPager.waitForExists(uiAutoTimeout)) { + throw new UiObjectNotFoundException("Could not find \"viewPager\"."); + }; + + logger.stop(); + } + + private void gesturesTest() throws Exception { + String testTag = "gesture"; + + // Perform a range of swipe tests at different speeds and on different views + LinkedHashMap testParams = new LinkedHashMap(); + testParams.put("swipe_down", new GestureTestParams(GestureType.UIDEVICE_SWIPE, Direction.DOWN, 100)); + testParams.put("swipe_up", new GestureTestParams(GestureType.UIDEVICE_SWIPE, Direction.UP, 100)); + testParams.put("swipe_right", new GestureTestParams(GestureType.UIOBJECT_SWIPE, Direction.RIGHT, 50)); + testParams.put("swipe_left", new GestureTestParams(GestureType.UIOBJECT_SWIPE, Direction.LEFT, 50)); + testParams.put("pinch_out", new GestureTestParams(GestureType.PINCH, PinchType.OUT, 100, 50)); + testParams.put("pinch_in", new GestureTestParams(GestureType.PINCH, PinchType.IN, 100, 50)); + + Iterator> it = testParams.entrySet().iterator(); + + // On some devices the first device swipe is ignored so perform it here + // to prevent the first test gesture from being incorrectly logged + uiDeviceSwipe(Direction.DOWN, 200); + + UiObject view = + new UiObject(new UiSelector().resourceId(packageID + "pageView")); + if (!view.waitForExists(TimeUnit.SECONDS.toMillis(10))) { + throw new UiObjectNotFoundException("Could not find page view"); + } + + 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; + + 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(); + } + } + + private void searchPdfTest(final String[] searchStrings) throws Exception { + String testTag = "search"; + + // Tap the centre to bring up the menu gui + // Sometimes the first tap wont register, so check if search appears + // and if not, tap again before continuing + tapDisplayCentre(); + UiObject searchIcon = + new UiObject(new UiSelector().resourceId(packageID + "document_view_search_icon") + .className("android.widget.TextView")); + if (!searchIcon.waitForExists(uiAutoTimeout)) { + tapDisplayCentre(); + } + + for (int i = 0; i < searchStrings.length; i++) { + String runName = String.format(testTag + "_string" + i); + ActionLogger logger = new ActionLogger(runName, parameters); + + // Click on the search button icon and enter text in the box. This closes the keyboard + // so click the box again and press Enter to start the search. + searchIcon.clickAndWaitForNewWindow(); + + UiObject searchBox = getUiObjectByResourceId("android:id/search_src_text", + "android.widget.EditText"); + searchBox.setText(searchStrings[i]); + + logger.start(); + + getUiDevice().getInstance().pressSearch(); + pressEnter(); + + // Check the progress bar icon. When this disappears the search is complete. + UiObject progressBar = + new UiObject(new UiSelector().resourceId(packageID + "searchProgress") + .className("android.widget.ProgressBar")); + progressBar.waitForExists(uiAutoTimeout); + progressBar.waitUntilGone(searchTimeout); + + logger.stop(); + + // Get back to the main document view by clicking twice on the close button + UiObject searchCloseButton = clickUiObject(BY_ID, "android:id/search_close_btn", "android.widget.ImageView", true); + searchCloseButton.clickAndWaitForNewWindow(); + } + } + + private void exitDocument() throws Exception { + // Return from the document view to the file list view by pressing home and my documents. + UiObject homeButton = + new UiObject(new UiSelector().resourceId("android:id/home") + .className("android.widget.ImageView")); + if (!homeButton.waitForExists(uiAutoTimeout)) { + tapDisplayCentre(); + } + homeButton.clickAndWaitForNewWindow(); + clickUiObject(BY_DESC, "My Documents", "android.widget.LinearLayout", true); + clickUiObject(BY_ID, "android:id/up", "android.widget.ImageView", true); + } +}