1
0
mirror of https://github.com/ARM-software/workload-automation.git synced 2024-10-06 10:51:13 +01:00

Merge pull request #242 from jimboatarm/upstream-slides

Add Google slides workload
This commit is contained in:
Sebastian Goscik 2016-09-13 10:24:19 +01:00 committed by GitHub
commit 83ab1ac441
7 changed files with 706 additions and 1 deletions

View File

@ -341,7 +341,7 @@ class ApkWorkload(Workload):
try:
self.device.execute("pm grant {} {}".format(self.package, permission))
except DeviceError as e:
if "not a changeable permission" in e.message:
if "changeable permission" in e.message or "Unknown permission" in e.message:
self.logger.debug(e)
else:
raise e

View File

@ -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)

View 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 (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

View File

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="com.arm.wlauto.uiauto.googleslides" 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>

View 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

View File

@ -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);
}
}