From c2a68074be6d953339d6567e14c93becce0853ff Mon Sep 17 00:00:00 2001 From: John Richardson Date: Tue, 3 May 2016 11:49:05 +0100 Subject: [PATCH] Googlephotos productivity workload A new workload to perform standard productivity tasks within Googlephotos. Each user event/step is timed and reported back as a metric. Dumpsys also captures SurfaceFlinger logs for each event for post analysis. --- wlauto/workloads/googlephotos/__init__.py | 99 ++++++ .../com.arm.wlauto.uiauto.googlephotos.jar | Bin 0 -> 11019 bytes wlauto/workloads/googlephotos/uiauto/build.sh | 12 + .../workloads/googlephotos/uiauto/build.xml | 92 ++++++ .../googlephotos/uiauto/project.properties | 14 + .../com/arm/wlauto/uiauto/UiAutomation.java | 291 ++++++++++++++++++ 6 files changed, 508 insertions(+) create mode 100644 wlauto/workloads/googlephotos/__init__.py create mode 100644 wlauto/workloads/googlephotos/com.arm.wlauto.uiauto.googlephotos.jar create mode 100755 wlauto/workloads/googlephotos/uiauto/build.sh create mode 100644 wlauto/workloads/googlephotos/uiauto/build.xml create mode 100644 wlauto/workloads/googlephotos/uiauto/project.properties create mode 100644 wlauto/workloads/googlephotos/uiauto/src/com/arm/wlauto/uiauto/UiAutomation.java diff --git a/wlauto/workloads/googlephotos/__init__.py b/wlauto/workloads/googlephotos/__init__.py new file mode 100644 index 00000000..db0107b3 --- /dev/null +++ b/wlauto/workloads/googlephotos/__init__.py @@ -0,0 +1,99 @@ +import os +import re + +from wlauto import AndroidUiAutoBenchmark, Parameter + + +class Googlephotos(AndroidUiAutoBenchmark): + + name = 'googlephotos' + package = 'com.google.android.apps.photos' + activity = 'com.google.android.apps.photos.home.HomeActivity' + + description = """ + A workload to perform standard productivity tasks with googlephotos. + + The workload carries out various tasks, such as browsing images, performing zooms, + postprocessing and saving a selected image to file. + + NOTE: This workload requires four jpeg files to be placed in the + dependencies directory to run. + + Although this workload attempts to be network independent it requires a + network connection (ideally, wifi) to run. This is because the welcome + screen UI is dependent on an existing connection. + """ + + parameters = [ + Parameter('dumpsys_enabled', kind=bool, default=True, + description=""" + If ``True``, dumpsys captures will be carried out during the + test run. The output is piped to log files which are then + pulled from the phone. + """), + ] + + instrumentation_log = ''.join([name, '_instrumentation.log']) + file_prefix = 'wa_test_' + + def __init__(self, device, **kwargs): + super(Googlephotos, self).__init__(device, **kwargs) + self.output_file = os.path.join(self.device.working_directory, self.instrumentation_log) + self.camera_dir = self.device.path.join(self.device.external_storage_directory, + 'DCIM/Camera/') + + def validate(self): + super(Googlephotos, self).validate() + self.uiauto_params['package'] = self.package + self.uiauto_params['output_dir'] = self.device.working_directory + self.uiauto_params['output_file'] = self.output_file + self.uiauto_params['dumpsys_enabled'] = self.dumpsys_enabled + + def setup(self, context): + super(Googlephotos, self).setup(context) + + for entry in os.listdir(self.dependencies_directory): + wa_file = ''.join([self.file_prefix, entry]) + if entry.endswith(".jpg"): + self.device.push_file(os.path.join(self.dependencies_directory, entry), + os.path.join(self.camera_dir, wa_file), + timeout=300) + + # Force a re-index of the mediaserver cache to pick up new files + self.device.execute('am broadcast -a android.intent.action.MEDIA_MOUNTED -d file:///sdcard') + + def update_result(self, context): + super(Googlephotos, self).update_result(context) + + if self.dumpsys_enabled: + self.device.pull_file(self.output_file, context.output_directory) + result_file = os.path.join(context.output_directory, self.instrumentation_log) + + with open(result_file, 'r') as wfh: + pattern = r'(?P\w+)\s+(?P\d+)\s+(?P\d+)\s+(?P\d+)' + regex = re.compile(pattern) + for line in wfh: + match = regex.search(line) + if match: + context.result.add_metric((match.group('key') + "_start"), + match.group('value1')) + context.result.add_metric((match.group('key') + "_finish"), + match.group('value2')) + context.result.add_metric((match.group('key') + "_duration"), + match.group('value3')) + + def teardown(self, context): + super(Googlephotos, self).teardown(context) + + for entry in self.device.listdir(self.device.working_directory): + if entry.startswith(self.name) and entry.endswith(".log"): + self.device.pull_file(os.path.join(self.device.working_directory, entry), + context.output_directory) + self.device.delete_file(os.path.join(self.device.working_directory, entry)) + + for entry in self.device.listdir(self.camera_dir): + if entry.startswith(self.file_prefix) and entry.endswith(".jpg"): + self.device.delete_file(os.path.join(self.camera_dir, entry)) + + # Force a re-index of the mediaserver cache to removed cached files + self.device.execute('am broadcast -a android.intent.action.MEDIA_MOUNTED -d file:///sdcard') diff --git a/wlauto/workloads/googlephotos/com.arm.wlauto.uiauto.googlephotos.jar b/wlauto/workloads/googlephotos/com.arm.wlauto.uiauto.googlephotos.jar new file mode 100644 index 0000000000000000000000000000000000000000..2a4fdd3dfe20bdec746f079613637275d236be80 GIT binary patch literal 11019 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 F{udO>SMmS= literal 0 HcmV?d00001 diff --git a/wlauto/workloads/googlephotos/uiauto/build.sh b/wlauto/workloads/googlephotos/uiauto/build.sh new file mode 100755 index 00000000..f60c0b43 --- /dev/null +++ b/wlauto/workloads/googlephotos/uiauto/build.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +class_dir=bin/classes/com/arm/wlauto/uiauto +base_class=`python -c "import os, wlauto; print os.path.join(os.path.dirname(wlauto.__file__), 'common', 'android', '*.class')"` +mkdir -p $class_dir +cp $base_class $class_dir + +ant build + +if [[ -f bin/com.arm.wlauto.uiauto.googlephotos.jar ]]; then + cp bin/com.arm.wlauto.uiauto.googlephotos.jar .. +fi diff --git a/wlauto/workloads/googlephotos/uiauto/build.xml b/wlauto/workloads/googlephotos/uiauto/build.xml new file mode 100644 index 00000000..648161d0 --- /dev/null +++ b/wlauto/workloads/googlephotos/uiauto/build.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wlauto/workloads/googlephotos/uiauto/project.properties b/wlauto/workloads/googlephotos/uiauto/project.properties new file mode 100644 index 00000000..916037e3 --- /dev/null +++ b/wlauto/workloads/googlephotos/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-23 diff --git a/wlauto/workloads/googlephotos/uiauto/src/com/arm/wlauto/uiauto/UiAutomation.java b/wlauto/workloads/googlephotos/uiauto/src/com/arm/wlauto/uiauto/UiAutomation.java new file mode 100644 index 00000000..1c7a8c22 --- /dev/null +++ b/wlauto/workloads/googlephotos/uiauto/src/com/arm/wlauto/uiauto/UiAutomation.java @@ -0,0 +1,291 @@ +package com.arm.wlauto.uiauto.googlephotos; + +import android.os.Bundle; +import android.graphics.Point; +import android.graphics.Rect; + +// Import the uiautomator libraries +import com.android.uiautomator.core.UiObject; +import com.android.uiautomator.core.UiObjectNotFoundException; +import com.android.uiautomator.core.UiSelector; + +import com.arm.wlauto.uiauto.UxPerfUiAutomation; + +import java.io.File; +import java.io.FileWriter; +import java.io.BufferedWriter; +import java.util.concurrent.TimeUnit; +import java.util.LinkedHashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; + +public class UiAutomation extends UxPerfUiAutomation { + + public static String TAG = "uxperf_googlephotos"; + + public Bundle parameters; + private long viewTimeout = TimeUnit.SECONDS.toMillis(20); + private LinkedHashMap timingResults = new LinkedHashMap(); + + public void runUiAutomation() throws Exception { + Timer result = new Timer(); + result.start(); + parameters = getParams(); + + dismissWelcomeView(); + gesturesTest(); + editPhotoTest(); + + result.end(); + timingResults.put("total", result); + + writeResultsToFile(timingResults, parameters.getString("output_file")); + } + + private void dismissWelcomeView() throws Exception { + // Click through the first two pages and make sure that we don't sign + // in to our google account. This ensures the same set of photographs + // are placed in the camera directory for each run. + + sleep(3); // Pause while splash screen loads + + UiObject getStarteddButton = + getUiObjectByResourceId("com.google.android.apps.photos:id/get_started", + "android.widget.Button"); + getStarteddButton.clickAndWaitForNewWindow(); + + UiObject welcomeButton = + getUiObjectByResourceId("com.google.android.apps.photos:id/name", + "android.widget.TextView"); + welcomeButton.clickAndWaitForNewWindow(); + + UiObject useWithoutAccount = + getUiObjectByText("Use without an account", "android.widget.TextView"); + useWithoutAccount.clickAndWaitForNewWindow(); + + // Dismiss welcome views promoting app features + sleep(1); + uiDeviceSwipeLeft(10); + sleep(1); + uiDeviceSwipeLeft(10); + sleep(1); + uiDeviceSwipeLeft(10); + sleep(1); + + UiObject nextButton = + getUiObjectByResourceId("com.google.android.apps.photos:id/next_button", + "android.widget.ImageView"); + nextButton.clickAndWaitForNewWindow(); + } + + private void gesturesTest () throws Exception { + String testTag = "gestures"; + + // Perform a range of swipe tests while browsing photo gallery + LinkedHashMap testParams = new LinkedHashMap(); + testParams.put("swipe_left", new GestureTestParams(GestureType.UIDEVICE_SWIPE, Direction.LEFT, 10)); + testParams.put("pinch_out", new GestureTestParams(GestureType.PINCH, PinchType.OUT, 100, 50)); + testParams.put("pinch_in", new GestureTestParams(GestureType.PINCH, PinchType.IN, 100, 50)); + testParams.put("swipe_right", new GestureTestParams(GestureType.UIDEVICE_SWIPE, Direction.RIGHT, 10)); + testParams.put("swipe_up", new GestureTestParams(GestureType.UIDEVICE_SWIPE, Direction.UP, 10)); + + Iterator> it = testParams.entrySet().iterator(); + + // Select third photograph + selectPhoto(2); + + 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()); + String gfxInfologName = String.format(TAG + "_" + runName + "_gfxInfo.log"); + String surfFlingerlogName = String.format(runName + "_surfFlinger.log"); + String viewName = new String("com.google.android.apps.photos.home.HomeActivity"); + + UiObject view = new UiObject(new UiSelector().enabled(true)); + + if (!view.waitForExists(viewTimeout)) { + throw new UiObjectNotFoundException("Could not find \"photo view\"."); + }; + + startDumpsysGfxInfo(); + startDumpsysSurfaceFlinger(viewName); + + Timer results = new Timer(); + + switch (type) { + case UIDEVICE_SWIPE: + results = uiDeviceSwipeTest(dir, steps); + break; + case UIOBJECT_SWIPE: + results = uiObjectSwipeTest(view, dir, steps); + break; + case PINCH: + results = uiObjectVertPinchTest(view, pinch, steps, percent); + break; + default: + break; + } + + stopDumpsysSurfaceFlinger(viewName, surfFlingerlogName); + stopDumpsysGfxInfo(gfxInfologName); + + timingResults.put(runName, results); + } + } + + private void editPhotoTest() throws Exception { + String testTag = "edit_photo"; + + Timer result = new Timer(); + result.start(); + + // Select first photograph + selectPhoto(0); + UiObject editView = getUiObjectByResourceId("com.google.android.apps.photos:id/edit", + "android.widget.ImageView"); + editView.click(); + + UiObject editColor = getUiObjectByText("Colour", "android.widget.RadioButton"); + editColor.click(); + + UiObject seekBar = getUiObjectByResourceId("com.google.android.apps.photos:id/cpe_strength_seek_bar", + "android.widget.SeekBar"); + seekBar.swipeLeft(10); + + UiObject accept = getUiObjectByDescription("Accept", "android.widget.ImageView"); + accept.click(); + + UiObject save = getUiObjectByText("SAVE", "android.widget.TextView"); + save.click(); + + // Return to application home screen + getUiDevice().pressBack(); + + result.end(); + timingResults.put(testTag, result); + } + + // Helper to click on an individual photographs based on index in Camera gallery. + private void selectPhoto(int index) throws Exception { + UiObject cameraHeading = new UiObject(new UiSelector().text("Camera")); + cameraHeading.clickAndWaitForNewWindow(); + + UiObject photo = + new UiObject(new UiSelector().resourceId("com.google.android.apps.photos:id/recycler_view") + .childSelector(new UiSelector() + .index(index))); + photo.click(); + } + + // Helper for testing zoom facility. NOTE: the built in UiObject methods + // pinchIn() and pinchOut() do not zoom appropriately for this application. + private Timer uiObjectVertPinchTest( + UiObject view, PinchType direction, + int steps, int percent) throws Exception { + + Timer results = new Timer(); + results.start(); + + final int FINGER_TOUCH_HALF_WIDTH = 20; + + // make value between 1 and 100 + percent = (percent < 0) ? 1 : (percent > 100) ? 100 : percent; + float percentage = percent / 100f; + + Rect rect = view.getVisibleBounds(); + if (rect.width() <= FINGER_TOUCH_HALF_WIDTH * 2) + throw new IllegalStateException("Object width is too small for operation"); + + // start from the same point at the center of the control + Point startPoint1 = new Point(rect.centerX(), rect.centerY() + FINGER_TOUCH_HALF_WIDTH); + Point startPoint2 = new Point(rect.centerX(), rect.centerY() - FINGER_TOUCH_HALF_WIDTH); + + // End at the top-center and bottom-center of the control + Point endPoint1 = new Point(rect.centerX(), rect.centerY() + (int) ((rect.height() / 2) * percentage)); + Point endPoint2 = new Point(rect.centerX(), rect.centerY() - (int) ((rect.height() / 2) * percentage)); + + if (direction.equals(PinchType.IN)) { + view.performTwoPointerGesture(endPoint1, endPoint2, startPoint1, startPoint2, steps); + } else if (direction.equals(PinchType.OUT)) { + view.performTwoPointerGesture(startPoint1, startPoint2, endPoint1, endPoint2, steps); + } + + results.end(); + + return results; + } + + private class GestureTestParams { + GestureType gestureType; + Direction gestureDirection; + PinchType pinchType; + private int percent; + private int steps; + + GestureTestParams(GestureType gesture, Direction direction, int steps) { + this.gestureType = gesture; + this.gestureDirection = direction; + this.pinchType = PinchType.NULL; + this.steps = steps; + this.percent = 0; + } + + GestureTestParams(GestureType gesture, PinchType pinchType, int steps, int percent) { + this.gestureType = gesture; + this.gestureDirection = Direction.NULL; + this.pinchType = pinchType; + this.steps = steps; + this.percent = percent; + } + } + + private void writeResultsToFile(LinkedHashMap timingResults, String file) throws Exception { + // Write out the key/value pairs to the instrumentation log file + FileWriter fstream = new FileWriter(file); + BufferedWriter out = new BufferedWriter(fstream); + Iterator> it = timingResults.entrySet().iterator(); + + while (it.hasNext()) { + Map.Entry pairs = it.next(); + Timer results = pairs.getValue(); + long start = results.getStart(); + long finish = results.getFinish(); + long duration = results.getDuration(); + out.write(String.format(pairs .getKey() + " " + start + " " + finish + " " + duration + "\n")); + } + out.close(); + } + + private void startDumpsysSurfaceFlinger(String view) { + if (Boolean.parseBoolean(parameters.getString("dumpsys_enabled"))) { + initDumpsysSurfaceFlinger(parameters.getString("package"), view); + } + } + + private void stopDumpsysSurfaceFlinger(String view, String filename) throws Exception { + if (Boolean.parseBoolean(parameters.getString("dumpsys_enabled"))) { + File out_file = new File(parameters.getString("output_dir"), filename); + exitDumpsysSurfaceFlinger(parameters.getString("package"), view, out_file); + } + } + + private void startDumpsysGfxInfo() { + if (Boolean.parseBoolean(parameters.getString("dumpsys_enabled"))) { + initDumpsysGfxInfo(parameters.getString("package")); + } + } + + private void stopDumpsysGfxInfo(String filename) throws Exception { + if (Boolean.parseBoolean(parameters.getString("dumpsys_enabled"))) { + File out_file = new File(parameters.getString("output_dir"), filename); + exitDumpsysGfxInfo(parameters.getString("package"), out_file); + } + } +}