1
0
mirror of https://github.com/ARM-software/workload-automation.git synced 2025-03-25 03:59:11 +00:00

[framework/uiauto] Update uiauto library to move away from android.support and into androidx

Currently the uiauto library is built on top of the deprecated android.support
libraries. Create an updated uiauto library (uiauto-androidx) using androidx
and keep it alongside the old one for compatibility reasons.

As we update workload-automation going forward, we should update the workloads
to use the androidx version of uiauto.

This has been tested with the latest gradle version available at the time
(8.8).
This commit is contained in:
Luis Machado 2024-07-03 16:38:27 +01:00
parent 412a785068
commit 510b344aa5
18 changed files with 1274 additions and 3 deletions

View File

@ -0,0 +1,18 @@
apply plugin: 'com.android.library'
android {
namespace "com.arm.wa.uiauto"
compileSdkVersion 28
defaultConfig {
minSdkVersion 18
targetSdkVersion 28
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'androidx.test:runner:1.6.1'
implementation 'androidx.test:rules:1.6.1'
implementation 'androidx.test.uiautomator:uiautomator-v18:2.2.0-alpha1'
}

View File

@ -0,0 +1,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.READ_LOGS"/>
<application>
<uses-library android:name="android.test.runner"/>
</application>
</manifest>

View File

@ -0,0 +1,60 @@
/* Copyright 2014-2018 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.wa.uiauto;
import android.os.Bundle;
import android.util.Log;
/**
* Basic marker API for workloads to generate start and end markers for
* deliminating and timing actions. Markers are output to logcat with debug
* priority. Actions represent a series of UI interactions to time.
*
* The marker API provides a way for instruments and output processors to hook into
* per-action timings by parsing logcat logs produced per workload iteration.
*
* The marker output consists of a logcat tag 'UX_PERF' and a message. The
* message consists of a name for the action and a timestamp. The timestamp
* is separated by a single space from the name of the action.
*
* Typical usage:
*
* ActionLogger logger = ActionLogger("testTag", parameters);
* logger.start();
* // actions to be recorded
* logger.stop();
*/
public class ActionLogger {
private String testTag;
private boolean enabled;
public ActionLogger(String testTag, Bundle parameters) {
this.testTag = testTag;
this.enabled = parameters.getBoolean("markers_enabled");
}
public void start() {
if (enabled) {
Log.d("UX_PERF", testTag + " start " + System.nanoTime());
}
}
public void stop() throws Exception {
if (enabled) {
Log.d("UX_PERF", testTag + " end " + System.nanoTime());
}
}
}

View File

@ -0,0 +1,54 @@
/* Copyright 2013-2017 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.wa.uiauto;
import android.os.Bundle;
import androidx.test.uiautomator.UiObject;
/**
* ApplaunchInterface.java
* Interface used for enabling uxperfapplaunch workload.
* This interface gets implemented by all workloads that support application launch
* instrumentation.
*/
public interface ApplaunchInterface {
/**
* Sets the launchEndObject of a workload, which is a UiObject that marks
* the end of the application launch.
*/
public UiObject getLaunchEndObject();
/**
* Runs the Uiautomation methods for clearing the initial run
* dialogues on the first time installation of an application package.
*/
public void runApplicationSetup() throws Exception;
/**
* Provides the application launch command of the application which is
* constructed as a string from the workload.
*/
public String getLaunchCommand();
/** Passes the workload parameters. */
public void setWorkloadParameters(Bundle parameters);
/** Initialize the instrumentation for the workload */
public void initialize_instrumentation();
}

View File

@ -0,0 +1,725 @@
/* Copyright 2013-2018 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.wa.uiauto;
import android.os.Bundle;
import android.os.SystemClock;
import android.app.Instrumentation;
import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
import androidx.test.InstrumentationRegistry;
import androidx.test.uiautomator.UiDevice;
import androidx.test.uiautomator.UiObject;
import androidx.test.uiautomator.UiObjectNotFoundException;
import androidx.test.uiautomator.UiSelector;
import androidx.test.uiautomator.UiWatcher;
import androidx.test.uiautomator.UiScrollable;
import org.junit.Before;
import org.junit.Test;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import static androidx.test.InstrumentationRegistry.getArguments;
public class BaseUiAutomation {
public enum FindByCriteria { BY_ID, BY_TEXT, BY_DESC };
public enum Direction { UP, DOWN, LEFT, RIGHT, NULL };
public enum ScreenOrientation { RIGHT, NATURAL, LEFT, PORTRAIT, LANDSCAPE };
public enum PinchType { IN, OUT, NULL };
// Time in milliseconds
public long uiAutoTimeout = 4 * 1000;
public static final int CLICK_REPEAT_INTERVAL_MINIMUM = 5;
public static final int CLICK_REPEAT_INTERVAL_DEFAULT = 50;
public Instrumentation mInstrumentation;
public Context mContext;
public UiDevice mDevice;
@Before
public void initialize_instrumentation() {
mInstrumentation = InstrumentationRegistry.getInstrumentation();
mDevice = UiDevice.getInstance(mInstrumentation);
mContext = mInstrumentation.getTargetContext();
}
@Test
public void setup() throws Exception {
}
@Test
public void runWorkload() throws Exception {
}
@Test
public void extractResults() throws Exception {
}
@Test
public void teardown() throws Exception {
}
public void sleep(int second) {
SystemClock.sleep(second * 1000);
}
// Generate a package ID
public String getPackageID(Bundle parameters) {
String packageName = parameters.getString("package_name");
return packageName + ":id/";
}
public boolean takeScreenshot(String name) {
Bundle params = getArguments();
String png_dir = params.getString("workdir");
try {
return mDevice.takeScreenshot(new File(png_dir, name + ".png"));
} catch (NoSuchMethodError e) {
return true;
}
}
public void waitText(String text) throws UiObjectNotFoundException {
waitText(text, 600);
}
public void waitText(String text, int second) throws UiObjectNotFoundException {
UiSelector selector = new UiSelector();
UiObject text_obj = mDevice.findObject(selector.text(text)
.className("android.widget.TextView"));
waitObject(text_obj, second);
}
public void waitObject(UiObject obj) throws UiObjectNotFoundException {
waitObject(obj, 600);
}
public void waitObject(UiObject obj, int second) throws UiObjectNotFoundException {
if (!obj.waitForExists(second * 1000)) {
throw new UiObjectNotFoundException("UiObject is not found: "
+ obj.getSelector().toString());
}
}
public boolean waitUntilNoObject(UiObject obj, int second) {
return obj.waitUntilGone(second * 1000);
}
public void clearLogcat() throws Exception {
Runtime.getRuntime().exec("logcat -c");
}
public void waitForLogcatText(String searchText, long timeout) throws Exception {
long startTime = System.currentTimeMillis();
Process process = Runtime.getRuntime().exec("logcat");
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
long currentTime = System.currentTimeMillis();
boolean found = false;
while ((currentTime - startTime) < timeout) {
sleep(2); // poll every two seconds
while ((line = reader.readLine()) != null) {
if (line.contains(searchText)) {
found = true;
break;
}
}
if (found) {
break;
}
currentTime = System.currentTimeMillis();
}
process.destroy();
if ((currentTime - startTime) >= timeout) {
throw new TimeoutException("Timed out waiting for Logcat text \"%s\"".format(searchText));
}
}
public void registerWatcher(String name, UiWatcher watcher) {
mDevice.registerWatcher(name, watcher);
}
public void runWatchers() {
mDevice.runWatchers();
}
public void removeWatcher(String name) {
mDevice.removeWatcher(name);
}
public void setScreenOrientation(ScreenOrientation orientation) throws Exception {
int width = mDevice.getDisplayWidth();
int height = mDevice.getDisplayHeight();
switch (orientation) {
case RIGHT:
mDevice.setOrientationRight();
break;
case NATURAL:
mDevice.setOrientationNatural();
break;
case LEFT:
mDevice.setOrientationLeft();
break;
case LANDSCAPE:
if (mDevice.isNaturalOrientation()){
if (height > width){
mDevice.setOrientationRight();
}
}
else {
if (height > width){
mDevice.setOrientationNatural();
}
}
break;
case PORTRAIT:
if (mDevice.isNaturalOrientation()){
if (height < width){
mDevice.setOrientationRight();
}
}
else {
if (height < width){
mDevice.setOrientationNatural();
}
}
break;
default:
throw new Exception("No orientation specified");
}
}
public void unsetScreenOrientation() throws Exception {
mDevice.unfreezeRotation();
}
public void uiObjectPerformLongClick(UiObject view, int steps) throws Exception {
Rect rect = view.getBounds();
mDevice.swipe(rect.centerX(), rect.centerY(),
rect.centerX(), rect.centerY(), steps);
}
public int getDisplayHeight() {
return mDevice.getDisplayHeight();
}
public int getDisplayWidth() {
return mDevice.getDisplayWidth();
}
public int getDisplayCentreWidth() {
return getDisplayWidth() / 2;
}
public int getDisplayCentreHeight() {
return getDisplayHeight() / 2;
}
public void tapDisplayCentre() {
tapDisplay(getDisplayCentreWidth(), getDisplayCentreHeight());
}
public void tapDisplay(int x, int y) {
mDevice.click(x, y);
}
public void pressEnter() {
mDevice.pressEnter();
}
public void pressHome() {
mDevice.pressHome();
}
public void pressBack() {
mDevice.pressBack();
}
public void uiObjectSwipe(UiObject view, Direction direction, int steps) throws Exception {
switch (direction) {
case UP:
view.swipeUp(steps);
break;
case DOWN:
view.swipeDown(steps);
break;
case LEFT:
view.swipeLeft(steps);
break;
case RIGHT:
view.swipeRight(steps);
break;
case NULL:
throw new Exception("No direction specified");
default:
break;
}
}
public void uiDeviceSwipeVertical(int startY, int endY, int xCoordinate, int steps) {
mDevice.swipe(xCoordinate, startY, xCoordinate, endY, steps);
}
public void uiDeviceSwipeHorizontal(int startX, int endX, int yCoordinate, int steps) {
mDevice.swipe(startX, yCoordinate, endX, yCoordinate, steps);
}
public void uiObjectVertPinchIn(UiObject view, int steps, int percent) throws Exception {
final int FINGER_TOUCH_HALF_WIDTH = 20;
// Make value between 1 and 100
int nPercent = (percent < 0) ? 1 : (percent > 100) ? 100 : percent;
float percentage = nPercent / 100f;
Rect rect = view.getVisibleBounds();
if (rect.width() <= FINGER_TOUCH_HALF_WIDTH * 2) {
throw new IllegalStateException("Object width is too small for operation");
}
// Start at the top-center and bottom-center of the control
Point startPoint1 = new Point(rect.centerX(), rect.centerY()
+ (int) ((rect.height() / 2) * percentage));
Point startPoint2 = new Point(rect.centerX(), rect.centerY()
- (int) ((rect.height() / 2) * percentage));
// End at the same point at the center of the control
Point endPoint1 = new Point(rect.centerX(), rect.centerY() + FINGER_TOUCH_HALF_WIDTH);
Point endPoint2 = new Point(rect.centerX(), rect.centerY() - FINGER_TOUCH_HALF_WIDTH);
view.performTwoPointerGesture(startPoint1, startPoint2, endPoint1, endPoint2, steps);
}
public void uiObjectVertPinchOut(UiObject view, int steps, int percent) throws Exception {
final int FINGER_TOUCH_HALF_WIDTH = 20;
// Make value between 1 and 100
int nPercent = (percent < 0) ? 1 : (percent > 100) ? 100 : percent;
float percentage = nPercent / 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));
view.performTwoPointerGesture(startPoint1, startPoint2, endPoint1, endPoint2, steps);
}
public void uiObjectVertPinch(UiObject view, PinchType direction,
int steps, int percent) throws Exception {
if (direction.equals(PinchType.IN)) {
uiObjectVertPinchIn(view, steps, percent);
} else if (direction.equals(PinchType.OUT)) {
uiObjectVertPinchOut(view, steps, percent);
}
}
public void uiDeviceSwipeUp(int steps) {
mDevice.swipe(
getDisplayCentreWidth(),
(getDisplayCentreHeight() + (getDisplayCentreHeight() / 2)),
getDisplayCentreWidth(),
(getDisplayCentreHeight() / 2),
steps);
}
public void uiDeviceSwipeDown(int steps) {
mDevice.swipe(
getDisplayCentreWidth(),
(getDisplayCentreHeight() / 2),
getDisplayCentreWidth(),
(getDisplayCentreHeight() + (getDisplayCentreHeight() / 2)),
steps);
}
public void uiDeviceSwipeLeft(int steps) {
mDevice.swipe(
(getDisplayCentreWidth() + (getDisplayCentreWidth() / 2)),
getDisplayCentreHeight(),
(getDisplayCentreWidth() / 2),
getDisplayCentreHeight(),
steps);
}
public void uiDeviceSwipeRight(int steps) {
mDevice.swipe(
(getDisplayCentreWidth() / 2),
getDisplayCentreHeight(),
(getDisplayCentreWidth() + (getDisplayCentreWidth() / 2)),
getDisplayCentreHeight(),
steps);
}
public void uiDeviceSwipe(Direction direction, int steps) throws Exception {
switch (direction) {
case UP:
uiDeviceSwipeUp(steps);
break;
case DOWN:
uiDeviceSwipeDown(steps);
break;
case LEFT:
uiDeviceSwipeLeft(steps);
break;
case RIGHT:
uiDeviceSwipeRight(steps);
break;
case NULL:
throw new Exception("No direction specified");
default:
break;
}
}
public void repeatClickUiObject(UiObject view, int repeatCount, int intervalInMillis) throws Exception {
int repeatInterval = intervalInMillis > CLICK_REPEAT_INTERVAL_MINIMUM
? intervalInMillis : CLICK_REPEAT_INTERVAL_DEFAULT;
if (repeatCount < 1 || !view.isClickable()) {
return;
}
for (int i = 0; i < repeatCount; ++i) {
view.click();
SystemClock.sleep(repeatInterval); // in order to register as separate click
}
}
public UiObject clickUiObject(FindByCriteria criteria, String matching) throws Exception {
return clickUiObject(criteria, matching, null, false);
}
public UiObject clickUiObject(FindByCriteria criteria, String matching, boolean wait) throws Exception {
return clickUiObject(criteria, matching, null, wait);
}
public UiObject clickUiObject(FindByCriteria criteria, String matching, String clazz) throws Exception {
return clickUiObject(criteria, matching, clazz, false);
}
public UiObject clickUiObject(FindByCriteria criteria, String matching, String clazz, boolean wait) throws Exception {
UiObject view;
switch (criteria) {
case BY_ID:
view = (clazz == null)
? getUiObjectByResourceId(matching) : getUiObjectByResourceId(matching, clazz);
break;
case BY_DESC:
view = (clazz == null)
? getUiObjectByDescription(matching) : getUiObjectByDescription(matching, clazz);
break;
case BY_TEXT:
default:
view = (clazz == null)
? getUiObjectByText(matching) : getUiObjectByText(matching, clazz);
break;
}
if (wait) {
view.clickAndWaitForNewWindow();
} else {
view.click();
}
return view;
}
public UiObject getUiObjectByResourceId(String resourceId, String className) throws Exception {
return getUiObjectByResourceId(resourceId, className, uiAutoTimeout);
}
public UiObject getUiObjectByResourceId(String resourceId, String className, long timeout) throws Exception {
UiObject object = mDevice.findObject(new UiSelector().resourceId(resourceId)
.className(className));
if (!object.waitForExists(timeout)) {
throw new UiObjectNotFoundException(String.format("Could not find \"%s\" \"%s\"",
resourceId, className));
}
return object;
}
public UiObject getUiObjectByResourceId(String id) throws Exception {
UiObject object = mDevice.findObject(new UiSelector().resourceId(id));
if (!object.waitForExists(uiAutoTimeout)) {
throw new UiObjectNotFoundException("Could not find view with resource ID: " + id);
}
return object;
}
public UiObject getUiObjectByDescription(String description, String className) throws Exception {
return getUiObjectByDescription(description, className, uiAutoTimeout);
}
public UiObject getUiObjectByDescription(String description, String className, long timeout) throws Exception {
UiObject object = mDevice.findObject(new UiSelector().descriptionContains(description)
.className(className));
if (!object.waitForExists(timeout)) {
throw new UiObjectNotFoundException(String.format("Could not find \"%s\" \"%s\"",
description, className));
}
return object;
}
public UiObject getUiObjectByDescription(String desc) throws Exception {
UiObject object = mDevice.findObject(new UiSelector().descriptionContains(desc));
if (!object.waitForExists(uiAutoTimeout)) {
throw new UiObjectNotFoundException("Could not find view with description: " + desc);
}
return object;
}
public UiObject getUiObjectByText(String text, String className) throws Exception {
return getUiObjectByText(text, className, uiAutoTimeout);
}
public UiObject getUiObjectByText(String text, String className, long timeout) throws Exception {
UiObject object = mDevice.findObject(new UiSelector().textContains(text)
.className(className));
if (!object.waitForExists(timeout)) {
throw new UiObjectNotFoundException(String.format("Could not find \"%s\" \"%s\"",
text, className));
}
return object;
}
public UiObject getUiObjectByText(String text) throws Exception {
UiObject object = mDevice.findObject(new UiSelector().textContains(text));
if (!object.waitForExists(uiAutoTimeout)) {
throw new UiObjectNotFoundException("Could not find view with text: " + text);
}
return object;
}
// Helper to select a folder in the gallery
public void selectGalleryFolder(String directory) throws Exception {
UiObject workdir =
mDevice.findObject(new UiSelector().text(directory)
.className("android.widget.TextView"));
UiScrollable scrollView =
new UiScrollable(new UiSelector().scrollable(true));
// If the folder is not present wait for a short time for
// the media server to refresh its index.
boolean discovered = workdir.waitForExists(TimeUnit.SECONDS.toMillis(10));
if (!discovered && scrollView.exists()) {
// First check if the directory is visible on the first
// screen and if not scroll to the bottom of the screen to look for it.
discovered = scrollView.scrollIntoView(workdir);
// If still not discovered scroll back to the top of the screen and
// wait for a longer amount of time for the media server to refresh
// its index.
if (!discovered) {
// scrollView.scrollToBeggining() doesn't work for this
// particular scrollable view so use device method instead
for (int i = 0; i < 10; i++) {
uiDeviceSwipeUp(20);
}
discovered = workdir.waitForExists(TimeUnit.SECONDS.toMillis(60));
// Scroll to the bottom of the screen one last time
if (!discovered) {
discovered = scrollView.scrollIntoView(workdir);
}
}
}
if (discovered) {
workdir.clickAndWaitForNewWindow();
} else {
throw new UiObjectNotFoundException("Could not find folder : " + directory);
}
}
// If an an app is not designed for running on the latest version of android
// (currently Q) an additional screen can popup asking to confirm permissions.
public void dismissAndroidPermissionPopup() throws Exception {
UiObject permissionAccess =
mDevice.findObject(new UiSelector().textMatches(
".*Choose what to allow .* to access"));
UiObject continueButton =
mDevice.findObject(new UiSelector().resourceId("com.android.permissioncontroller:id/continue_button")
.textContains("Continue"));
if (permissionAccess.exists() && continueButton.exists()) {
continueButton.click();
}
}
// If an an app is not designed for running on the latest version of android
// (currently Q) dissmiss the warning popup if present.
public void dismissAndroidVersionPopup() throws Exception {
// Ensure we have dissmied any permission screens before looking for the version popup
dismissAndroidPermissionPopup();
UiObject warningText =
mDevice.findObject(new UiSelector().textContains(
"This app was built for an older version of Android"));
UiObject acceptButton =
mDevice.findObject(new UiSelector().resourceId("android:id/button1")
.className("android.widget.Button"));
if (warningText.exists() && acceptButton.exists()) {
acceptButton.click();
}
}
// If Chrome is a fresh install then these popups may be presented
// dismiss them if visible.
public void dismissChromePopup() throws Exception {
UiObject accept =
mDevice.findObject(new UiSelector().resourceId("com.android.chrome:id/terms_accept")
.className("android.widget.Button"));
if (accept.waitForExists(3000)){
accept.click();
UiObject negative =
mDevice.findObject(new UiSelector().resourceId("com.android.chrome:id/negative_button")
.className("android.widget.Button"));
if (negative.waitForExists(10000)) {
negative.click();
}
}
UiObject lite =
mDevice.findObject(new UiSelector().resourceId("com.android.chrome:id/button_secondary")
.className("android.widget.Button"));
if (lite.exists()){
lite.click();
}
}
// Override getParams function to decode a url encoded parameter bundle before
// passing it to workloads.
public Bundle getParams() {
// Get the original parameter bundle
Bundle parameters = getArguments();
// Decode each parameter in the bundle, except null values and "class", as this
// used to control instrumentation and therefore not encoded.
for (String key : parameters.keySet()) {
String param = parameters.getString(key);
if (param != null && !key.equals("class")) {
param = android.net.Uri.decode(param);
parameters = decode(parameters, key, param);
}
}
return parameters;
}
// Helper function to decode a string and insert it as an appropriate type
// into a provided bundle with its key.
// Each bundle parameter will be a urlencoded string with 2 characters prefixed to the value
// used to store the original type information, e.g. 'fl' -> list of floats.
private Bundle decode(Bundle parameters, String key, String value) {
char value_type = value.charAt(0);
char value_dimension = value.charAt(1);
String param = value.substring(2);
if (value_dimension == 's') {
if (value_type == 's') {
parameters.putString(key, param);
} else if (value_type == 'f') {
parameters.putFloat(key, Float.parseFloat(param));
} else if (value_type == 'd') {
parameters.putDouble(key, Double.parseDouble(param));
} else if (value_type == 'b') {
parameters.putBoolean(key, Boolean.parseBoolean(param));
} else if (value_type == 'i') {
parameters.putInt(key, Integer.parseInt(param));
} else if (value_type == 'n') {
parameters.putString(key, "None");
} else {
throw new IllegalArgumentException("Error decoding:" + key + value
+ " - unknown format");
}
} else if (value_dimension == 'l') {
return decodeArray(parameters, key, value_type, param);
} else {
throw new IllegalArgumentException("Error decoding:" + key + value
+ " - unknown format");
}
return parameters;
}
// Helper function to deal with decoding arrays and update the bundle with
// an appropriate array type. The string "0newelement0" is used to distinguish
// each element from each other in the array when encoded.
private Bundle decodeArray(Bundle parameters, String key, char type, String value) {
String[] string_list = value.split("0newelement0");
if (type == 's') {
parameters.putStringArray(key, string_list);
}
else if (type == 'i') {
int[] int_list = new int[string_list.length];
for (int i = 0; i < string_list.length; i++){
int_list[i] = Integer.parseInt(string_list[i]);
}
parameters.putIntArray(key, int_list);
} else if (type == 'f') {
float[] float_list = new float[string_list.length];
for (int i = 0; i < string_list.length; i++){
float_list[i] = Float.parseFloat(string_list[i]);
}
parameters.putFloatArray(key, float_list);
} else if (type == 'd') {
double[] double_list = new double[string_list.length];
for (int i = 0; i < string_list.length; i++){
double_list[i] = Double.parseDouble(string_list[i]);
}
parameters.putDoubleArray(key, double_list);
} else if (type == 'b') {
boolean[] boolean_list = new boolean[string_list.length];
for (int i = 0; i < string_list.length; i++){
boolean_list[i] = Boolean.parseBoolean(string_list[i]);
}
parameters.putBooleanArray(key, boolean_list);
} else {
throw new IllegalArgumentException("Error decoding array: " +
value + " - unknown format");
}
return parameters;
}
}

View File

@ -0,0 +1,35 @@
/* Copyright 2013-2017 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.wa.uiauto;
import android.os.Bundle;
public final class UiAutoUtils {
/** Construct launch command of an application. */
public static String createLaunchCommand(Bundle parameters) {
String launchCommand;
String activityName = parameters.getString("launch_activity");
String packageName = parameters.getString("package_name");
if (activityName.equals("None")) {
launchCommand = String.format("am start --user -3 %s", packageName);
}
else {
launchCommand = String.format("am start --user -3 -n %s/%s", packageName, activityName);
}
return launchCommand;
}
}

View File

@ -0,0 +1,55 @@
/* Copyright 2013-2017 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.wa.uiauto;
import android.os.Bundle;
import java.util.logging.Logger;
import com.arm.wa.uiauto.BaseUiAutomation.Direction;
import com.arm.wa.uiauto.BaseUiAutomation.PinchType;
public class UxPerfUiAutomation {
private Logger logger = Logger.getLogger(UxPerfUiAutomation.class.getName());
public enum GestureType { UIDEVICE_SWIPE, UIOBJECT_SWIPE, PINCH };
public static class GestureTestParams {
public GestureType gestureType;
public Direction gestureDirection;
public PinchType pinchType;
public int percent;
public int steps;
public GestureTestParams(GestureType gesture, Direction direction, int steps) {
this.gestureType = gesture;
this.gestureDirection = direction;
this.pinchType = PinchType.NULL;
this.steps = steps;
this.percent = 0;
}
public 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;
}
}
}

View File

@ -0,0 +1,25 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.5.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}

View File

@ -0,0 +1,32 @@
#!/bin/bash
# Copyright 2013-2017 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.
#
set -e
# Ensure gradelw exists before starting
if [[ ! -f gradlew ]]; then
echo 'gradlew file not found! Check that you are in the right directory.'
exit 9
fi
# Build and return appropriate exit code if failed
./gradlew clean :app:assembleDebug
exit_code=$?
if [ $exit_code -ne 0 ]; then
echo "ERROR: 'gradle build' exited with code $exit_code"
exit $exit_code
fi
cp app/build/outputs/aar/app-debug.aar ./uiauto.aar

View File

@ -0,0 +1 @@
android.useAndroidX=true

Binary file not shown.

View File

@ -0,0 +1,6 @@
#Wed May 03 15:42:44 BST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-all.zip

160
wa/framework/uiauto-androidx/gradlew vendored Executable file
View File

@ -0,0 +1,160 @@
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

View File

@ -0,0 +1,90 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@ -0,0 +1 @@
include ':app'

Binary file not shown.

View File

@ -2,7 +2,8 @@ apply plugin: 'com.android.library'
android {
compileSdkVersion 28
buildToolsVersion '28.0.3'
// buildToolsVersion is no longer used/accepted.
// buildToolsVersion '28.0.3'
defaultConfig {
minSdkVersion 18
targetSdkVersion 28

View File

@ -2,8 +2,8 @@
buildscript {
repositories {
jcenter()
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.2.1'
@ -16,8 +16,8 @@ buildscript {
allprojects {
repositories {
jcenter()
google()
mavenCentral()
}
}