From d279cc74537d038437b3de1172b2633d8b124516 Mon Sep 17 00:00:00 2001 From: muendelezaji Date: Tue, 6 Sep 2016 14:22:27 +0100 Subject: [PATCH] Add Google Slides workload --- wlauto/workloads/googleslides/__init__.py | 143 ++++++ .../com.arm.wlauto.uiauto.googleslides.jar | Bin 0 -> 15164 bytes wlauto/workloads/googleslides/uiauto/build.sh | 39 ++ .../workloads/googleslides/uiauto/build.xml | 92 ++++ .../googleslides/uiauto/project.properties | 14 + .../com/arm/wlauto/uiauto/UiAutomation.java | 417 ++++++++++++++++++ 6 files changed, 705 insertions(+) create mode 100755 wlauto/workloads/googleslides/__init__.py create mode 100644 wlauto/workloads/googleslides/com.arm.wlauto.uiauto.googleslides.jar create mode 100755 wlauto/workloads/googleslides/uiauto/build.sh create mode 100644 wlauto/workloads/googleslides/uiauto/build.xml create mode 100644 wlauto/workloads/googleslides/uiauto/project.properties create mode 100755 wlauto/workloads/googleslides/uiauto/src/com/arm/wlauto/uiauto/UiAutomation.java diff --git a/wlauto/workloads/googleslides/__init__.py b/wlauto/workloads/googleslides/__init__.py new file mode 100755 index 00000000..c70077a7 --- /dev/null +++ b/wlauto/workloads/googleslides/__init__.py @@ -0,0 +1,143 @@ +# 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 re + +from wlauto import AndroidUxPerfWorkload, Parameter, File +from wlauto.exceptions import WorkloadError + + +class GoogleSlides(AndroidUxPerfWorkload): + + name = 'googleslides' + description = ''' + A workload to perform standard productivity tasks with Google Slides. The workload carries + out various tasks, such as creating a new presentation, adding text, images, and shapes, + as well as basic editing and playing a slideshow. + This workload should be able to run without a network connection. + + There are two main scenarios: + 1. create test: a presentation is created in-app and some editing done on it, + 2. load test: a pre-existing PowerPoint file is copied onto the device for testing. + + --- create --- + Create a new file in the application and perform basic editing on it. This test also + requires an image file specified by the param ``test_image`` to be copied onto the device. + + Test description: + 1. Start the app and skip the welcome screen. Dismiss the work offline banner if present. + 2. Go to the app settings page and enables PowerPoint compatibility mode. This allows + PowerPoint files to be created inside Google Slides. + 3. Create a new PowerPoint presentation in the app (PPT compatibility mode) with a title + slide and save it to device storage. + 4. Insert another slide and to it insert the pushed image by picking it from the gallery. + 5. Insert the final slide and add a shape to it. Resize and drag the shape to modify it. + 6. Finally, navigate back to the documents list and delete file from the list to remove + it from the device. + + --- load --- + Copy a PowerPoint presentation onto the device to test slide navigation. The PowerPoint + file to be copied is given by ``test_file``. + + Test description: + 1. From the documents list (following the create test), open the specified PowerPoint + by navigating into device storage and wait for it to be loaded. + 2. A navigation test is performed while the file is in editing mode (i.e. not slideshow). + swiping forward to the next slide until ``slide_count`` swipes are performed. + 3. While still in editing mode, the same action is done in the reverse direction back to + the first slide. + 4. Enter presentation mode by selecting to play the slideshow. + 5. Swipe forward to play the slideshow, for a maximum number of ``slide_count`` swipes. + 6. Finally, repeat the previous step in the reverse direction while still in presentation + mode, navigating back to the first slide. + + NOTE: There are known issues with the reliability of this workload on some targets. + It MAY NOT ALWAYS WORK on your device. If you do run into problems, it might help to + set ``do_text_entry`` parameter to ``False``. + + ''' + + package = 'com.google.android.apps.docs.editors.slides' + min_apk_version = '1.6.312.08' + max_apk_version = None # works with latest (1.6.332.13) at time of publishing this + activity = '' + + # Views for FPS instrumentation + view = [ + package + '/com.google.android.apps.docs.quickoffice.filepicker.FilePickerActivity', + package + '/com.google.android.apps.docs.editors.shared.filepicker.FilePickerActivity', + package + '/com.google.android.apps.docs.quickoffice.filepicker.LocalSaveAsActivity', + package + '/com.qo.android.quickpoint.Quickpoint', + package + '/com.google.android.apps.docs.app.DocsPreferencesActivity', + package + '/com.google.android.apps.docs.app.DocListActivity', + package + '/com.google.android.apps.docs.welcome.warmwelcome.TrackingWelcomeActivity', + package + '/com.google.android.apps.docs.app.NewMainProxyActivity', + ] + + parameters = [ + Parameter('test_image', kind=str, mandatory=True, default='uxperf_1600x1200.jpg', + description=''' + An image to be copied onto the device that will be embedded in the + PowerPoint file as part of the test. + '''), + Parameter('test_file', kind=str, default='uxperf_test_doc.pptx', + description=''' + If specified, the workload will copy the PowerPoint file to be used for + testing onto the device. Otherwise, a file will be created inside the app. + '''), + Parameter('slide_count', kind=int, default=5, + description=''' + Number of slides in aforementioned local file. Determines number of + swipe actions when playing slide show. + '''), + Parameter('do_text_entry', kind=bool, default=True, + description=''' + If set to ``True``, will attempt to enter text in the first slide as part + of the test. Currently seems to be problematic on some devices, most + notably Samsung devices. + ''') + ] + + # Created file will be saved with this name + new_doc_name = "WORKLOAD AUTOMATION" + + def __init__(self, device, **kwargs): + super(GoogleSlides, self).__init__(device, **kwargs) + self.run_timeout = 600 + self.deployable_assets += [self.test_image, self.test_file] + + def validate(self): + super(GoogleSlides, self).validate() + self.uiauto_params['workdir_name'] = self.device.path.basename(self.device.working_directory) + self.uiauto_params['test_file'] = self.test_file.replace(' ', '0space0') + self.uiauto_params['slide_count'] = self.slide_count + self.uiauto_params['do_text_entry'] = self.do_text_entry + self.uiauto_params['new_doc_name'] = self.new_doc_name.replace(' ', '0space0') + + def setup(self, context): + super(GoogleSlides, self).setup(context) + # Force re-index of removable storage to pick up pushed image in gallery + self.device.broadcast_media_mounted(self.device.working_directory) + + def teardown(self, context): + super(GoogleSlides, self).teardown(context) + self.device.delete_file(self.device.path.join(self.device.working_directory, self.new_doc_name)) + self.device.broadcast_media_mounted(self.device.working_directory) + + def finalize(self, context): + super(GoogleSlides, self).finalize(context) + self.delete_assets() + self.device.broadcast_media_mounted(self.device.working_directory) diff --git a/wlauto/workloads/googleslides/com.arm.wlauto.uiauto.googleslides.jar b/wlauto/workloads/googleslides/com.arm.wlauto.uiauto.googleslides.jar new file mode 100644 index 0000000000000000000000000000000000000000..c9fb0d7d3283b858a1c9f09c837808ca610be510 GIT binary patch literal 15164 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/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 (remove previous) +package=com.arm.wlauto.uiauto.googleslides.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/googleslides/uiauto/build.xml b/wlauto/workloads/googleslides/uiauto/build.xml new file mode 100644 index 00000000..259eaa6e --- /dev/null +++ b/wlauto/workloads/googleslides/uiauto/build.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wlauto/workloads/googleslides/uiauto/project.properties b/wlauto/workloads/googleslides/uiauto/project.properties new file mode 100644 index 00000000..ce39f2d0 --- /dev/null +++ b/wlauto/workloads/googleslides/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/googleslides/uiauto/src/com/arm/wlauto/uiauto/UiAutomation.java b/wlauto/workloads/googleslides/uiauto/src/com/arm/wlauto/uiauto/UiAutomation.java new file mode 100755 index 00000000..1b96a68f --- /dev/null +++ b/wlauto/workloads/googleslides/uiauto/src/com/arm/wlauto/uiauto/UiAutomation.java @@ -0,0 +1,417 @@ +/* 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.googleslides; + +import java.io.File; +import java.util.LinkedHashMap; +import java.util.Map; + +import android.graphics.Rect; +import android.os.Bundle; +import android.os.SystemClock; + +// Import the uiautomator libraries +import com.android.uiautomator.core.Configurator; +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.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; + +public class UiAutomation extends UxPerfUiAutomation { + + public static final String ANDROID_WIDGET = "android.widget."; + public static final String CLASS_TEXT_VIEW = ANDROID_WIDGET + "TextView"; + public static final String CLASS_IMAGE_VIEW = ANDROID_WIDGET + "ImageView"; + public static final String CLASS_BUTTON = ANDROID_WIDGET + "Button"; + public static final String CLASS_IMAGE_BUTTON = ANDROID_WIDGET + "ImageButton"; + public static final String CLASS_TABLE_ROW = ANDROID_WIDGET + "TableRow"; + public static final String CLASS_PROGRESS_BAR = ANDROID_WIDGET + "ProgressBar"; + public static final String CLASS_LIST_VIEW = ANDROID_WIDGET + "ListView"; + + public static final int WAIT_TIMEOUT_1SEC = 1000; + public static final int SLIDE_WAIT_TIME_MS = 200; + public static final int DEFAULT_SWIPE_STEPS = 10; + + protected ActionLogger logger; + protected String packageId; + protected Bundle parameters; + protected String newDocumentName; + protected String pushedDocumentName; + protected String workingDirectoryName; + protected int slideCount; + protected boolean doTextEntry; + + public void runUiAutomation() throws Exception { + // Setup + parameters = getParams(); + parseParams(parameters); + setScreenOrientation(ScreenOrientation.NATURAL); + changeAckTimeout(100); + // UI automation begins here + skipWelcomeScreen(); + sleep(1); + dismissWorkOfflineBanner(); + sleep(1); + enablePowerpointCompat(); + sleep(1); + testEditNewSlidesDocument(newDocumentName); + sleep(1); + testSlideshowFromStorage(pushedDocumentName); + // UI automation ends here + unsetScreenOrientation(); + } + + public void parseParams(Bundle parameters) throws Exception { + pushedDocumentName = parameters.getString("test_file").replaceAll("0space0", " "); + newDocumentName = parameters.getString("new_doc_name").replaceAll("0space0", " "); + slideCount = Integer.parseInt(parameters.getString("slide_count")); + packageId = parameters.getString("package") + ":id/"; + workingDirectoryName = parameters.getString("workdir_name"); + doTextEntry = Boolean.parseBoolean(parameters.getString("do_text_entry")); + } + + public void dismissWorkOfflineBanner() throws Exception { + UiObject banner = new UiObject(new UiSelector().textContains("Work offline")); + if (banner.waitForExists(WAIT_TIMEOUT_1SEC)) { + clickUiObject(BY_TEXT, "Got it", CLASS_BUTTON); + } + } + + public void enterTextInSlide(String viewName, String textToEnter) throws Exception { + UiSelector container = new UiSelector().resourceId(packageId + "main_canvas"); + UiObject view = new UiObject(container.childSelector(new UiSelector().descriptionMatches(viewName))); + view.click(); + getUiDevice().pressEnter(); + view.setText(textToEnter); + tapOpenArea(); + // On some devices, keyboard pops up when entering text, and takes a noticeable + // amount of time (few milliseconds) to disappear after clicking Done. + // In these cases, trying to find a view immediately after entering text leads + // to an exception, so a short wait-time is added for stability. + SystemClock.sleep(SLIDE_WAIT_TIME_MS); + } + + public void insertSlide(String slideLayout) throws Exception { + clickUiObject(BY_DESC, "Add slide", true); + clickUiObject(BY_TEXT, slideLayout, true); + } + + public void insertImage() throws Exception { + UiObject insertButton = new UiObject(new UiSelector().descriptionContains("Insert")); + if (insertButton.exists()) { + insertButton.click(); + } else { + clickUiObject(BY_DESC, "More options"); + clickUiObject(BY_TEXT, "Insert"); + } + clickUiObject(BY_TEXT, "Image", true); + clickUiObject(BY_TEXT, "From photos"); + + UiObject imagesFolder = new UiObject(new UiSelector().className(CLASS_TEXT_VIEW).textContains("Images")); + if (!imagesFolder.waitForExists(WAIT_TIMEOUT_1SEC*10)) { + clickUiObject(BY_DESC, "Show roots"); + } + imagesFolder.click(); + + UiObject folderEntry = new UiObject(new UiSelector().textContains(workingDirectoryName)); + UiScrollable list = new UiScrollable(new UiSelector().scrollable(true)); + if (!folderEntry.exists() && list.waitForExists(WAIT_TIMEOUT_1SEC)) { + list.scrollIntoView(folderEntry); + } else { + folderEntry.waitForExists(WAIT_TIMEOUT_1SEC*10); + } + folderEntry.clickAndWaitForNewWindow(); + clickUiObject(BY_ID, "com.android.documentsui:id/date", true); + } + + public void insertShape(String shapeName) throws Exception { + startLogger("shape_insert"); + UiObject insertButton = new UiObject(new UiSelector().descriptionContains("Insert")); + if (insertButton.exists()) { + insertButton.click(); + } else { + clickUiObject(BY_DESC, "More options"); + clickUiObject(BY_TEXT, "Insert"); + } + clickUiObject(BY_TEXT, "Shape"); + clickUiObject(BY_DESC, shapeName); + stopLogger("shape_insert"); + } + + public void modifyShape(String shapeName) throws Exception { + UiObject resizeHandle = new UiObject(new UiSelector().descriptionMatches(".*Bottom[- ]right resize.*")); + Rect bounds = resizeHandle.getVisibleBounds(); + int newX = bounds.left - 40; + int newY = bounds.bottom - 40; + startLogger("shape_resize"); + resizeHandle.dragTo(newX, newY, 40); + stopLogger("shape_resize"); + + UiSelector container = new UiSelector().resourceId(packageId + "main_canvas"); + UiSelector shapeSelector = container.childSelector(new UiSelector().descriptionContains(shapeName)); + startLogger("shape_drag"); + new UiObject(shapeSelector).dragTo(newX, newY, 40); + stopLogger("shape_drag"); + } + + public void openDocument(String docName) throws Exception { + clickUiObject(BY_DESC, "Open presentation"); + clickUiObject(BY_TEXT, "Device storage", true); + clickUiObject(BY_DESC, "Navigate up"); + UiScrollable list = new UiScrollable(new UiSelector().className(CLASS_LIST_VIEW)); + list.scrollIntoView(new UiSelector().textMatches(workingDirectoryName)); + clickUiObject(BY_TEXT, workingDirectoryName); + list.scrollIntoView(new UiSelector().textContains(docName)); + startLogger("document_open"); + clickUiObject(BY_TEXT, docName); + clickUiObject(BY_TEXT, "Open", CLASS_BUTTON, true); + stopLogger("document_open"); + } + + public void newDocument() throws Exception { + startLogger("document_new"); + clickUiObject(BY_DESC, "New presentation"); + clickUiObject(BY_TEXT, "New PowerPoint", true); + stopLogger("document_new"); + waitForProgress(WAIT_TIMEOUT_1SEC * 30); + } + + public void saveDocument(String docName) throws Exception { + UiObject saveActionButton = new UiObject(new UiSelector().resourceId(packageId + "action")); + UiObject unsavedIndicator = new UiObject(new UiSelector().textContains("Not saved")); + startLogger("document_save"); + if (saveActionButton.waitForExists(WAIT_TIMEOUT_1SEC)) { + saveActionButton.click(); + } else if (unsavedIndicator.waitForExists(WAIT_TIMEOUT_1SEC)) { + unsavedIndicator.click(); + } + clickUiObject(BY_TEXT, "Device"); + UiObject save = clickUiObject(BY_TEXT, "Save", CLASS_BUTTON); + if (save.waitForExists(WAIT_TIMEOUT_1SEC)) { + save.click(); + } + stopLogger("document_save"); + + // Overwrite if prompted + // Should not happen under normal circumstances. But ensures test doesn't stop + // if a previous iteration failed prematurely and was unable to delete the file. + // Note that this file isn't removed during workload teardown as deleting it is + // part of the UiAutomator test case. + UiObject overwriteView = new UiObject(new UiSelector().textContains("already exists")); + if (overwriteView.waitForExists(WAIT_TIMEOUT_1SEC)) { + clickUiObject(BY_TEXT, "Overwrite"); + } + } + + public void deleteDocument(String docName) throws Exception { + String filenameRegex = String.format(".*((%s)|([Uu]ntitled presentation)).pptx.*", docName); + UiObject doc = new UiObject(new UiSelector().textMatches(filenameRegex)); + UiObject moreActions = doc.getFromParent(new UiSelector().descriptionContains("More actions")); + startLogger("document_delete"); + moreActions.click(); + + UiObject deleteButton = new UiObject(new UiSelector().textMatches(".*([Dd]elete|[Rr]emove).*")); + if (deleteButton.waitForExists(WAIT_TIMEOUT_1SEC)) { + deleteButton.click(); + } else { + // Delete button not found, try to scroll the view + UiScrollable scrollable = new UiScrollable(new UiSelector().scrollable(true) + .childSelector(new UiSelector().textContains("Rename"))); + if (scrollable.exists()) { + scrollable.scrollIntoView(deleteButton); + } else { + UiObject content = new UiObject(new UiSelector().resourceId(packageId + "content")); + int attemptsLeft = 10; // try a maximum of 10 swipe attempts + while (!deleteButton.exists() && attemptsLeft > 0) { + content.swipeUp(DEFAULT_SWIPE_STEPS); + attemptsLeft--; + } + } + deleteButton.click(); + } + + UiObject okButton = new UiObject(new UiSelector().className(CLASS_BUTTON).textContains("OK")); + if (okButton.waitForExists(WAIT_TIMEOUT_1SEC)) { + okButton.clickAndWaitForNewWindow(); + } else { + clickUiObject(BY_TEXT, "Remove", CLASS_BUTTON, true); + } + stopLogger("document_delete"); + } + + + protected void skipWelcomeScreen() throws Exception { + clickUiObject(BY_TEXT, "Skip", true); + } + + protected void enablePowerpointCompat() throws Exception { + startLogger("enable_pptmode"); + clickUiObject(BY_DESC, "drawer"); + clickUiObject(BY_TEXT, "Settings", true); + clickUiObject(BY_TEXT, "Create PowerPoint"); + getUiDevice().pressBack(); + stopLogger("enable_pptmode"); + } + + protected void testEditNewSlidesDocument(String docName) throws Exception { + // Init + newDocument(); + + // Slide 1 - Text + if (doTextEntry) { + enterTextInSlide(".*[Tt]itle.*", docName); + // Save + saveDocument(docName); + sleep(1); + } + + // Slide 2 - Image + insertSlide("Title only"); + insertImage(); + sleep(1); + + // If text wasn't entered in first slide, save prompt will appear here + if (!doTextEntry) { + // Save + saveDocument(docName); + sleep(1); + } + + // Slide 3 - Shape + insertSlide("Title slide"); + String shapeName = "Rounded rectangle"; + insertShape(shapeName); + modifyShape(shapeName); + getUiDevice().pressBack(); + sleep(1); + + // Tidy up + getUiDevice().pressBack(); + dismissWorkOfflineBanner(); // if it appears on the homescreen + + // Note: Currently disabled because it fails on Samsung devices + // deleteDocument(docName); + } + + protected void testSlideshowFromStorage(String docName) throws Exception { + // Open document + openDocument(docName); + waitForProgress(WAIT_TIMEOUT_1SEC*30); + + // Begin Slide show test + + // Note: Using coordinates slightly offset from the slide edges avoids accidentally + // selecting any shapes or text boxes inside the slides while swiping, which may + // cause the view to switch into edit mode and fail the test + UiObject slideCanvas = new UiObject(new UiSelector().resourceId(packageId + "main_canvas")); + Rect canvasBounds = slideCanvas.getVisibleBounds(); + int leftEdge = canvasBounds.left + 10; + int rightEdge = canvasBounds.right - 10; + int yCoordinate = canvasBounds.top + 5; + int slideIndex = 0; + + // scroll forward in edit mode + startLogger("slideshow_editforward"); + while (++slideIndex < slideCount) { + uiDeviceSwipeHorizontal(rightEdge, leftEdge, yCoordinate, DEFAULT_SWIPE_STEPS); + waitForProgress(WAIT_TIMEOUT_1SEC*5); + } + stopLogger("slideshow_editforward"); + sleep(1); + + // scroll backward in edit mode + startLogger("slideshow_editbackward"); + while (--slideIndex > 0) { + uiDeviceSwipeHorizontal(leftEdge, rightEdge, yCoordinate, DEFAULT_SWIPE_STEPS); + waitForProgress(WAIT_TIMEOUT_1SEC*5); + } + stopLogger("slideshow_editbackward"); + sleep(1); + + // run slideshow + startLogger("slideshow_run"); + clickUiObject(BY_DESC, "Start slideshow", true); + UiObject onDevice = new UiObject(new UiSelector().textContains("this device")); + if (onDevice.waitForExists(WAIT_TIMEOUT_1SEC)) { + onDevice.clickAndWaitForNewWindow(); + waitForProgress(WAIT_TIMEOUT_1SEC*30); + UiObject presentation = new UiObject(new UiSelector().descriptionContains("Presentation Viewer")); + presentation.waitForExists(WAIT_TIMEOUT_1SEC*30); + } + stopLogger("slideshow_run"); + sleep(1); + + // scroll forward in slideshow mode + startLogger("slideshow_playforward"); + while (++slideIndex < slideCount) { + uiDeviceSwipeHorizontal(rightEdge, leftEdge, yCoordinate, DEFAULT_SWIPE_STEPS); + waitForProgress(WAIT_TIMEOUT_1SEC*5); + } + stopLogger("slideshow_playforward"); + sleep(1); + + // scroll backward in slideshow mode + startLogger("slideshow_playbackward"); + while (--slideIndex > 0) { + uiDeviceSwipeHorizontal(leftEdge, rightEdge, yCoordinate, DEFAULT_SWIPE_STEPS); + waitForProgress(WAIT_TIMEOUT_1SEC*5); + } + stopLogger("slideshow_playbackward"); + sleep(1); + + getUiDevice().pressBack(); + getUiDevice().pressBack(); + } + + protected void startLogger(String name) throws Exception { + logger = new ActionLogger(name, parameters); + logger.start(); + } + + protected void stopLogger(String name) throws Exception { + logger.stop(); + } + + protected boolean waitForProgress(int timeout) throws Exception { + UiObject progress = new UiObject(new UiSelector().className(CLASS_PROGRESS_BAR)); + if (progress.waitForExists(WAIT_TIMEOUT_1SEC)) { + return progress.waitUntilGone(timeout); + } else { + return false; + } + } + + private long changeAckTimeout(long newTimeout) { + Configurator config = Configurator.getInstance(); + long oldTimeout = config.getActionAcknowledgmentTimeout(); + config.setActionAcknowledgmentTimeout(newTimeout); + return oldTimeout; + } + + private void tapOpenArea() throws Exception { + UiObject openArea = getUiObjectByResourceId(packageId + "punch_view_pager"); + Rect bounds = openArea.getVisibleBounds(); + // 10px from top of view, 10px from the right edge + tapDisplay(bounds.right - 10, bounds.top + 10); + } + +}