diff options
author | Kolin Lu <kolinlu@google.com> | 2024-02-22 15:06:28 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-02-22 15:06:28 -0800 |
commit | ecea668846f7306ed27003856a28856c69f5bbb6 (patch) | |
tree | b8fa1e2b63a131fabf052ee2744aaa21ec70db31 | |
parent | 08b72cb1ecc65b8ebb23c433dbe4fd45c8ac95d9 (diff) | |
download | mobly-snippet-lib-ecea668846f7306ed27003856a28856c69f5bbb6.tar.gz |
Update UiAutomator example to use Snippet UiAutomator (#132)
4 files changed, 26 insertions, 197 deletions
diff --git a/examples/ex4_uiautomator/README.md b/examples/ex4_uiautomator/README.md index 10fb144..5210333 100644 --- a/examples/ex4_uiautomator/README.md +++ b/examples/ex4_uiautomator/README.md @@ -1,45 +1,36 @@ # UIAutomator Snippet Example -This example shows you how to create snippets that control the UI of a device -across system and multiple app views using UIAutomator. Unlike Espresso-based -UI automation, it does not require access to app source code. +The UiAutomator API, which allows developers to automate UI interactions on an +Android device, is now available in Python on +[google/snippet-uiautomator](https://github.com/google/snippet-uiautomator). +This makes it possible for developers to use UiAutomator in Mobly tests without +having to write Java. -This snippet is written as a [standalone snippet](../ex1_standalone_app/README.md) -and does not target another app. In particular, it doesn't need to target the -app under test, so it doesn't need its classpath or to be signed with the same -key. +The `snippet-uiautomator` package is a wrapper around the AndroidX UiAutomator +APIs. It provides a Pythonic interface for interacting with Android UI elements, +such as finding and clicking on buttons, entering text into fields, and +scrolling through lists. -See the [Espresso snippet tutorial](../ex2_espresso/README.md) for more -information about the app this example automates. +To use the `snippet-uiautomator` package, developers simply need to install it +from PyPI and import it into their Python code. Once imported, they can use the +package's API to automate any UI interaction. -## Running the example code +Here is an example of how to use the `snippet-uiautomator` package to automate a +simple UI interaction: -This folder contains a fully working example of a snippet apk that uses -UIAutomator to automate a simple app. +```Python +from mobly.controllers import android_device +from snippet_uiautomator import uiautomator -1. Compile the main app and automation. The main app of ex2 (espresso) is used - as the app to automate. Unlike espresso, the uiautomator test does not - depend on this apk and does not use its source or classpath, so you must - compile and install the app separately. +# Connect to an Android device. +ad = android_device.AndroidDevice(serial) - ./gradlew examples:ex2_espresso:assembleDebug examples:ex4_uiautomator:assembleDebug +# Load UiAutomator service. +uiautomator.load_uiautomator_service(ad) -1. Install the apks on your phone +# Find the "Login" button. +button = ad.ui(res='com.example.app:id/login_button') - adb install -r ./examples/ex2_espresso/build/outputs/apk/debug/ex2_espresso-main-debug.apk - adb install -r ./examples/ex4_uiautomator/build/outputs/apk/debug/ex4_uiautomator-debug.apk - -1. Use `snippet_shell` from mobly to trigger `pushMainButton()`: - - snippet_shell.py com.google.android.mobly.snippet.example4 - - >>> print(s.help()) - Known methods: - pushMainButton(boolean) returns void // Pushes the main app button, and checks the label if this is the first time. - startMainActivity() returns void // Opens the main activity of the app - uiautomatorDump() returns String // Perform a UIAutomator dump - - >>> s.startMainActivity() - >>> s.pushMainButton(True) - -1. Press ctrl+d to exit the shell and terminate the app. +# Click on the button. +button.click() +``` diff --git a/examples/ex4_uiautomator/build.gradle b/examples/ex4_uiautomator/build.gradle deleted file mode 100644 index 24188d9..0000000 --- a/examples/ex4_uiautomator/build.gradle +++ /dev/null @@ -1,32 +0,0 @@ -apply plugin: 'com.android.application' - -android { - // This has to match what the appcompat dep expects. - compileSdkVersion 31 - - defaultConfig { - applicationId "com.google.android.mobly.snippet.example4" - minSdkVersion 26 - targetSdkVersion 31 - versionCode 1 - versionName "0.0.2" - } - lintOptions { - abortOnError false - checkAllWarnings true - warningsAsErrors true - disable 'HardwareIds','MissingApplicationIcon','GoogleAppIndexingWarning','InvalidPackage','OldTargetApi' - } -} - -dependencies { - // The 'compile project' dep is to compile against the snippet lib source in - // this repo. For your own snippets, you'll want to use the regular - // 'compile' dep instead: - //compile 'com.google.android.mobly:mobly-snippet-lib:1.4.0' - implementation project(':mobly-snippet-lib') - implementation 'junit:junit:4.13.2' - implementation 'androidx.test:runner:1.4.0' - implementation 'androidx.appcompat:appcompat:1.4.0-beta01' - implementation 'androidx.test.uiautomator:uiautomator:2.2.0' -} diff --git a/examples/ex4_uiautomator/src/main/AndroidManifest.xml b/examples/ex4_uiautomator/src/main/AndroidManifest.xml deleted file mode 100644 index 89d5276..0000000 --- a/examples/ex4_uiautomator/src/main/AndroidManifest.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<manifest - xmlns:android="http://schemas.android.com/apk/res/android" - package="com.google.android.mobly.snippet.example4"> - - <application android:allowBackup="false"> - <meta-data - android:name="mobly-snippets" - android:value="com.google.android.mobly.snippet.example4.UiAutomatorSnippet" /> - </application> - - <!-- This snippet does NOT target ex2 (which is the main app the code - automates). The instrumentation target is itself which creates a - standalone snippet. --> - <instrumentation - android:name="com.google.android.mobly.snippet.SnippetRunner" - android:targetPackage="com.google.android.mobly.snippet.example4" /> - -</manifest> diff --git a/examples/ex4_uiautomator/src/main/java/com/google/android/mobly/snippet/example4/UiAutomatorSnippet.java b/examples/ex4_uiautomator/src/main/java/com/google/android/mobly/snippet/example4/UiAutomatorSnippet.java deleted file mode 100644 index 9fc01b2..0000000 --- a/examples/ex4_uiautomator/src/main/java/com/google/android/mobly/snippet/example4/UiAutomatorSnippet.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * 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.google.android.mobly.snippet.example4; - -import static org.junit.Assert.assertEquals; - -import android.content.Context; -import android.content.Intent; - -import androidx.test.platform.app.InstrumentationRegistry; -import androidx.test.uiautomator.By; -import androidx.test.uiautomator.UiDevice; -import androidx.test.uiautomator.UiObject2; -import androidx.test.uiautomator.Until; -import com.google.android.mobly.snippet.Snippet; -import com.google.android.mobly.snippet.rpc.Rpc; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.nio.charset.Charset; - -/** - * Demonstrates how to drive an app using UIAutomator without access to the app's source code or - * classpath. - * - * <p>Drives the Espresso example app from ex2 without instrumenting it. - */ -public class UiAutomatorSnippet implements Snippet { - private static final class UiAutomatorSnippetException extends Exception { - private static final long serialVersionUID = 1; - - public UiAutomatorSnippetException(String message) { - super(message); - } - } - - private static final String MAIN_PACKAGE = "com.google.android.mobly.snippet.example2"; - private static final int LAUNCH_TIMEOUT = 5000; - - private final Context mContext; - private final UiDevice mDevice; - - public UiAutomatorSnippet() { - mContext = InstrumentationRegistry.getInstrumentation().getContext(); - mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); - } - - @Rpc(description="Opens the main activity of the app") - public void startMainActivity() throws UiAutomatorSnippetException { - // Send the launch intent - Intent intent = mContext.getPackageManager().getLaunchIntentForPackage(MAIN_PACKAGE); - if (intent == null) { - throw new UiAutomatorSnippetException( - "Unable to create launch intent for " + MAIN_PACKAGE + "; is the app installed?"); - } - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); - mContext.startActivity(intent); - - // Wait for the app to appear - mDevice.wait(Until.hasObject(By.pkg(MAIN_PACKAGE).depth(0)), LAUNCH_TIMEOUT); - } - - @Rpc(description="Pushes the main app button, and checks the label if this is the first time.") - public void pushMainButton(boolean checkFirstRun) { - if (checkFirstRun) { - assertEquals( - "Hello World!", - // Example of finding object by id. - mDevice.findObject(By.res(MAIN_PACKAGE, "main_text_view")).getText()); - } - // Example of finding a button by text. Finding by ID is also possible, as above. - UiObject2 button = mDevice.findObject(By.text("PUSH THE BUTTON!")); - button.click(); - if (checkFirstRun) { - assertEquals( - "Button pressed 1 times", - mDevice.findObject(By.res(MAIN_PACKAGE, "main_text_view")).getText()); - } - } - - @Rpc(description="Perform a UIAutomator dump") - public String uiautomatorDump() throws IOException { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try { - mDevice.dumpWindowHierarchy(baos); - byte[] dumpBytes = baos.toByteArray(); - String dumpStr = new String(dumpBytes, Charset.forName("UTF-8")); - return dumpStr; - } finally { - baos.close(); - } - } - - @Override - public void shutdown() throws IOException { - mDevice.executeShellCommand("am force-stop " + MAIN_PACKAGE); - } -} |