mirror of
https://github.com/ARM-software/workload-automation.git
synced 2025-01-18 20:11:20 +00:00
Add Google Slides workload
This commit is contained in:
parent
f6b8fd3f4b
commit
d279cc7453
143
wlauto/workloads/googleslides/__init__.py
Executable file
143
wlauto/workloads/googleslides/__init__.py
Executable 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)
|
Binary file not shown.
39
wlauto/workloads/googleslides/uiauto/build.sh
Executable file
39
wlauto/workloads/googleslides/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 (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
|
92
wlauto/workloads/googleslides/uiauto/build.xml
Normal file
92
wlauto/workloads/googleslides/uiauto/build.xml
Normal 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>
|
14
wlauto/workloads/googleslides/uiauto/project.properties
Normal file
14
wlauto/workloads/googleslides/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
|
417
wlauto/workloads/googleslides/uiauto/src/com/arm/wlauto/uiauto/UiAutomation.java
Executable file
417
wlauto/workloads/googleslides/uiauto/src/com/arm/wlauto/uiauto/UiAutomation.java
Executable 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);
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user