diff options
30 files changed, 654 insertions, 283 deletions
@@ -3,17 +3,14 @@ gen/ # gradle junk .gradle -gradle/ -gradlew -gradlew.bat build # Android Studio junk .idea/ *.iml -# Don't check in properties -*.properties +# Don't check in local.properties +local.properties .DS_Store diff --git a/Android.mk b/Android.mk deleted file mode 100644 index 2a752d6..0000000 --- a/Android.mk +++ /dev/null @@ -1,16 +0,0 @@ -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := $(call all-java-files-under, src) - -LOCAL_MODULE := droiddriver -LOCAL_MODULE_TAGS := optional -LOCAL_SDK_VERSION := 19 - -LOCAL_JAVACFLAGS += -Xlint:deprecation -Xlint:unchecked - -include $(BUILD_STATIC_JAVA_LIBRARY) - -include $(CLEAR_VARS) - -include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/build.gradle b/build.gradle index 3af6346..cbf12f1 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,6 @@ // sdk.dir for the Android SDK path, you can run // $ ANDROID_HOME=/path/to/android-sdk gradle build -// Gradle >= 2.4 required buildscript { ext.bintrayUser = project.hasProperty('bintrayUser') ? project.bintrayUser : System.getenv('BINTRAY_USER') ext.bintrayKey = project.hasProperty('bintrayKey') ? project.bintrayKey : System.getenv('BINTRAY_KEY') @@ -12,7 +11,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:1.0.1' + classpath 'com.android.tools.build:gradle:1.3.0' classpath 'com.github.dcendents:android-maven-gradle-plugin:1.3' classpath 'com.jakewharton.sdkmanager:gradle-plugin:0.12.0' if (bintrayEnabled) { @@ -30,16 +29,16 @@ apply plugin: 'android-sdk-manager' apply plugin: 'com.android.library' tasks.withType(JavaCompile) { - options.compilerArgs << '-Xlint:deprecation' + options.compilerArgs << '-Xlint:deprecation' << '-Xlint:unchecked' } android { - compileSdkVersion 21 + compileSdkVersion 23 buildToolsVersion '21.1.2' defaultConfig { minSdkVersion 8 - targetSdkVersion 21 + targetSdkVersion 23 versionCode 1 versionName version } diff --git a/contributing.md b/contributing.md index f8ae829..645ef1b 100644 --- a/contributing.md +++ b/contributing.md @@ -6,18 +6,13 @@ The [`master` branch](https://github.com/appium/droiddriver/tree/master) on GitH Code changes should be [submitted to AOSP](contributing_aosp.md) and then they'll be synced to GitHub once they've passed code reivew on Gerrit. -#### Requirements +#### Build -Gradle 2.2.1 or better is required to be installed on the system. In Android Studio, you'll need to provide the gradle location. - -On Mac OSX with homebrew, `brew install gradle` will install gradle. To locate the path, use `brew info gradle` The homebrew path follows this format: `/usr/local/Cellar/gradle/2.2.1/libexec` - -If you installed gradle using the zip (`gradle-2.2.1-bin.zip`), then the path will be the `gradle-2.2.1` folder. +`./gradlew build` #### Import into Android Studio - Clone from git - Launch Android Studio and select `Open an existing Android Studio project` - Navigate to `droiddriver/build.gradle` and press Choose -- Select `Use local gradle distribution` and enter the Gradle path - Android Studio will now import the project successfully diff --git a/contributing_aosp.md b/contributing_aosp.md index c57a0d1..58bca60 100644 --- a/contributing_aosp.md +++ b/contributing_aosp.md @@ -16,9 +16,12 @@ $ repo sync ``` The code should be downloaded to the current dir. You may see some lines in the output like: -curl: (22) The requested URL returned error: 401 Unauthorized + +`curl: (22) The requested URL returned error: 401 Unauthorized` + These messages seem non-fatal and you should see these dirs after it is done: -build/ external/ frameworks/ Makefile prebuilts/ + +`build/ external/ frameworks/ Makefile prebuilts/` #### Submitting Patches @@ -51,16 +54,3 @@ When commenting on the code, posts will show up as drafts. Drafts are not visibl - `repo upload` The [`repo prune`](https://source.android.com/source/using-repo.html) command can be used to delete already merged branches. - -#### Building - -This sets up environment and some bash functions, particularly "tapas" -(the counterpart of "lunch" for unbundled projects) and "m". - -```bash -$ . build/envsetup.sh -$ tapas droiddriver ManualDD -$ m -``` - -ManualDD is an APK you can use to manually test DroidDriver. diff --git a/droiddriver-android_support_test/Android.mk b/droiddriver-android_support_test/Android.mk deleted file mode 100644 index 22c6c0a..0000000 --- a/droiddriver-android_support_test/Android.mk +++ /dev/null @@ -1,19 +0,0 @@ -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := $(call all-java-files-under, src) - -LOCAL_MODULE := droiddriver-android_support_test -LOCAL_MODULE_TAGS := optional -LOCAL_SDK_VERSION := 19 - -LOCAL_JAVACFLAGS += -Xlint:deprecation -Xlint:unchecked - -# android-support-test requires /frameworks/testing, /external/junit, /external/hamcrest -LOCAL_JAVA_LIBRARIES := droiddriver android-support-test - -include $(BUILD_STATIC_JAVA_LIBRARY) - -include $(CLEAR_VARS) - -include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/droiddriver-android_support_test/build.gradle b/droiddriver-android_support_test/build.gradle index 3f6120f..9d71de2 100644 --- a/droiddriver-android_support_test/build.gradle +++ b/droiddriver-android_support_test/build.gradle @@ -3,8 +3,7 @@ buildscript { jcenter() } dependencies { - // this requires Gradle 2 - classpath 'com.android.tools.build:gradle:1.0.1' + classpath 'com.android.tools.build:gradle:1.3.0' classpath 'com.jakewharton.sdkmanager:gradle-plugin:0.12.0' } } @@ -27,24 +26,23 @@ dependencies { // For development only. compile 'io.appium:droiddriver:1.0.0-SNAPSHOT' } else { - // This is broken now b/c droiddriver-1.0.0 is not published yet - compile 'io.appium:droiddriver:1.0.0' + compile 'io.appium:droiddriver:1.0.0-BETA1' } - compile 'com.android.support.test:testing-support-lib:0.1' + compile 'com.android.support.test:runner:0.4.1' } tasks.withType(JavaCompile) { - options.compilerArgs << '-Xlint:deprecation' + options.compilerArgs << '-Xlint:deprecation' << '-Xlint:unchecked' } android { - compileSdkVersion 21 + compileSdkVersion 23 buildToolsVersion '21.1.2' defaultConfig { minSdkVersion 8 - targetSdkVersion 21 + targetSdkVersion 23 versionCode 1 } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar Binary files differnew file mode 100644 index 0000000..c97a8bd --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.jar diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..80b332a --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Mon Mar 14 09:50:19 PDT 2016 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip @@ -0,0 +1,164 @@ +#!/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 + +# For Cygwin, ensure paths are in UNIX format before anything is touched. +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` +fi + +# 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\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +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"` + + # 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 "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..aec9973 --- /dev/null +++ b/gradlew.bat @@ -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
diff --git a/manualtest/Android.mk b/manualtest/Android.mk deleted file mode 100644 index 6b52b73..0000000 --- a/manualtest/Android.mk +++ /dev/null @@ -1,17 +0,0 @@ -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) -LOCAL_PACKAGE_NAME := ManualDD - -LOCAL_MODULE_TAGS := optional -LOCAL_PROGUARD_ENABLED := disabled - -LOCAL_SRC_FILES := \ - $(call all-java-files-under, src) - -LOCAL_STATIC_JAVA_LIBRARIES := \ - droiddriver - -LOCAL_SDK_VERSION := 19 - -include $(BUILD_PACKAGE) - diff --git a/manualtest/build.gradle b/manualtest/build.gradle index a732fe3..5be41b8 100644 --- a/manualtest/build.gradle +++ b/manualtest/build.gradle @@ -3,8 +3,7 @@ buildscript { jcenter() } dependencies { - // this requires Gradle 2 - classpath 'com.android.tools.build:gradle:1.0.1' + classpath 'com.android.tools.build:gradle:1.3.0' } } @@ -12,17 +11,13 @@ buildscript { apply plugin: 'com.android.application' android { - compileSdkVersion 21 + compileSdkVersion 23 buildToolsVersion '21.1.2' - defaultConfig { minSdkVersion 8 - targetSdkVersion 21 - // Force remove the suffix '.test' - testApplicationId 'io.appium.droiddriver.manualtest' + targetSdkVersion 23 testInstrumentationRunner 'io.appium.droiddriver.runner.TestRunner' } - sourceSets { main { manifest.srcFile 'AndroidManifest.xml' @@ -31,6 +26,8 @@ android { java.srcDirs = ['src'] } } + productFlavors { + } } // Building with droiddriver source. Common tests should use droiddriver from jcenter by having @@ -39,7 +36,7 @@ android { // jcenter() // } // dependencies { -// androidTestCompile 'io.appium:droiddriver:0.9.1-BETA' // or another version +// androidTestCompile 'io.appium:droiddriver:1.0.0-BETA1' // or another version // } dependencies { androidTestCompile project(':droiddriver') diff --git a/manualtest/src/io/appium/droiddriver/manualtest/ManualTest.java b/manualtest/src/io/appium/droiddriver/manualtest/ManualTest.java index 83966f7..59beac4 100644 --- a/manualtest/src/io/appium/droiddriver/manualtest/ManualTest.java +++ b/manualtest/src/io/appium/droiddriver/manualtest/ManualTest.java @@ -16,10 +16,10 @@ import io.appium.droiddriver.uiautomation.UiAutomationDriver; * {@link #testSetTextForPassword} assumes the password_edit field is displayed * on screen. * <p> - * Run it as (optionally with -e debug true) + * Run it with * * <pre> - * adb shell am instrument -w io.appium.droiddriver.manualtest/io.appium.droiddriver.runner.TestRunner + * ../gradlew :connectedAndroidTest * </pre> */ public class ManualTest extends BaseDroidDriverTest<Activity> { diff --git a/src/io/appium/droiddriver/base/AbstractDroidDriver.java b/src/io/appium/droiddriver/base/AbstractDroidDriver.java new file mode 100644 index 0000000..bf0df4b --- /dev/null +++ b/src/io/appium/droiddriver/base/AbstractDroidDriver.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2016 DroidDriver committers + * + * 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 io.appium.droiddriver.base; + +import io.appium.droiddriver.DroidDriver; +import io.appium.droiddriver.Poller; +import io.appium.droiddriver.UiElement; +import io.appium.droiddriver.actions.InputInjector; +import io.appium.droiddriver.exceptions.ElementNotFoundException; +import io.appium.droiddriver.exceptions.TimeoutException; +import io.appium.droiddriver.finders.Finder; +import io.appium.droiddriver.util.Logs; + +/** + * Base DroidDriver that implements the common operations. + */ +public abstract class AbstractDroidDriver implements DroidDriver { + + private Poller poller = new DefaultPoller(); + + @Override + public boolean has(Finder finder) { + try { + refreshUiElementTree(); + find(finder); + return true; + } catch (ElementNotFoundException enfe) { + return false; + } + } + + @Override + public boolean has(Finder finder, long timeoutMillis) { + try { + getPoller().pollFor(this, finder, Poller.EXISTS, timeoutMillis); + return true; + } catch (TimeoutException e) { + return false; + } + } + + @Override + public UiElement on(Finder finder) { + Logs.call(this, "on", finder); + return getPoller().pollFor(this, finder, Poller.EXISTS); + } + + @Override + public void checkExists(Finder finder) { + Logs.call(this, "checkExists", finder); + getPoller().pollFor(this, finder, Poller.EXISTS); + } + + @Override + public void checkGone(Finder finder) { + Logs.call(this, "checkGone", finder); + getPoller().pollFor(this, finder, Poller.GONE); + } + + @Override + public Poller getPoller() { + return poller; + } + + @Override + public void setPoller(Poller poller) { + this.poller = poller; + } + + public abstract InputInjector getInjector(); + +}
\ No newline at end of file diff --git a/src/io/appium/droiddriver/base/BaseDroidDriver.java b/src/io/appium/droiddriver/base/BaseDroidDriver.java index e985a38..d6114c6 100644 --- a/src/io/appium/droiddriver/base/BaseDroidDriver.java +++ b/src/io/appium/droiddriver/base/BaseDroidDriver.java @@ -18,22 +18,16 @@ package io.appium.droiddriver.base; import android.util.Log; -import io.appium.droiddriver.DroidDriver; -import io.appium.droiddriver.Poller; import io.appium.droiddriver.UiElement; -import io.appium.droiddriver.actions.InputInjector; -import io.appium.droiddriver.exceptions.ElementNotFoundException; -import io.appium.droiddriver.exceptions.TimeoutException; import io.appium.droiddriver.finders.ByXPath; import io.appium.droiddriver.finders.Finder; import io.appium.droiddriver.util.Logs; /** - * Base DroidDriver that implements the common operations. + * Enhances AbstractDroidDriver to include basic element handling and matching operations. */ -public abstract class BaseDroidDriver<R, E extends BaseUiElement<R, E>> implements DroidDriver { +public abstract class BaseDroidDriver<R, E extends BaseUiElement<R, E>> extends AbstractDroidDriver { - private Poller poller = new DefaultPoller(); private E rootElement; @Override @@ -42,57 +36,6 @@ public abstract class BaseDroidDriver<R, E extends BaseUiElement<R, E>> implemen return finder.find(getRootElement()); } - @Override - public boolean has(Finder finder) { - try { - refreshUiElementTree(); - find(finder); - return true; - } catch (ElementNotFoundException enfe) { - return false; - } - } - - @Override - public boolean has(Finder finder, long timeoutMillis) { - try { - getPoller().pollFor(this, finder, Poller.EXISTS, timeoutMillis); - return true; - } catch (TimeoutException e) { - return false; - } - } - - @Override - public UiElement on(Finder finder) { - Logs.call(this, "on", finder); - return getPoller().pollFor(this, finder, Poller.EXISTS); - } - - @Override - public void checkExists(Finder finder) { - Logs.call(this, "checkExists", finder); - getPoller().pollFor(this, finder, Poller.EXISTS); - } - - @Override - public void checkGone(Finder finder) { - Logs.call(this, "checkGone", finder); - getPoller().pollFor(this, finder, Poller.GONE); - } - - @Override - public Poller getPoller() { - return poller; - } - - @Override - public void setPoller(Poller poller) { - this.poller = poller; - } - - public abstract InputInjector getInjector(); - protected abstract E newRootElement(); /** diff --git a/src/io/appium/droiddriver/base/CompositeDroidDriver.java b/src/io/appium/droiddriver/base/CompositeDroidDriver.java new file mode 100644 index 0000000..c92c5c3 --- /dev/null +++ b/src/io/appium/droiddriver/base/CompositeDroidDriver.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2016 DroidDriver committers + * + * 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 io.appium.droiddriver.base; + +import io.appium.droiddriver.UiDevice; +import io.appium.droiddriver.UiElement; +import io.appium.droiddriver.actions.InputInjector; +import io.appium.droiddriver.finders.Finder; + +/** + * Helper class to ease creation of drivers that defer actions to other drivers. + */ +public abstract class CompositeDroidDriver extends AbstractDroidDriver { + /** + * Determines which DroidDriver should handle the current situation. + * + * @return The DroidDriver instance to use + */ + protected abstract AbstractDroidDriver getApplicableDriver(); + + @Override + public InputInjector getInjector() { + return getApplicableDriver().getInjector(); + } + + @Override + public UiDevice getUiDevice() { + return getApplicableDriver().getUiDevice(); + } + + @Override + public UiElement find(Finder finder) { + return getApplicableDriver().find(finder); + } + + @Override + public void refreshUiElementTree() { + getApplicableDriver().refreshUiElementTree(); + } + + @Override + public boolean dumpUiElementTree(String path) { + return getApplicableDriver().dumpUiElementTree(path); + } +} diff --git a/src/io/appium/droiddriver/duo/DuoDriver.java b/src/io/appium/droiddriver/duo/DuoDriver.java new file mode 100644 index 0000000..0ad84bf --- /dev/null +++ b/src/io/appium/droiddriver/duo/DuoDriver.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2016 DroidDriver committers + * + * 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 io.appium.droiddriver.duo; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.app.Instrumentation; + +import io.appium.droiddriver.base.AbstractDroidDriver; +import io.appium.droiddriver.base.CompositeDroidDriver; +import io.appium.droiddriver.instrumentation.InstrumentationDriver; +import io.appium.droiddriver.uiautomation.UiAutomationDriver; +import io.appium.droiddriver.util.ActivityUtils; +import io.appium.droiddriver.util.InstrumentationUtils; + +/** + * Implementation of DroidDriver that attempts to use the best driver for the current activity. + * If the activity is part of the application under instrumentation, the InstrumentationDriver is + * used. Otherwise, the UiAutomationDriver is used. + */ +@TargetApi(18) +public class DuoDriver extends CompositeDroidDriver { + private final String targetApkPackage; + private final UiAutomationDriver uiAutomationDriver; + private final InstrumentationDriver instrumentationDriver; + + public DuoDriver() { + Instrumentation instrumentation = InstrumentationUtils.getInstrumentation(); + targetApkPackage = InstrumentationUtils.getTargetContext().getPackageName(); + uiAutomationDriver = new UiAutomationDriver(instrumentation); + instrumentationDriver = new InstrumentationDriver(instrumentation); + } + + @Override + protected AbstractDroidDriver getApplicableDriver() { + Activity activity = ActivityUtils.getRunningActivity(); + if (activity != null && targetApkPackage.equals( + activity.getApplicationContext().getPackageName())) { + return instrumentationDriver; + } + return uiAutomationDriver; + } +} diff --git a/src/io/appium/droiddriver/finders/Attribute.java b/src/io/appium/droiddriver/finders/Attribute.java index 9dda497..c2aa83a 100644 --- a/src/io/appium/droiddriver/finders/Attribute.java +++ b/src/io/appium/droiddriver/finders/Attribute.java @@ -38,7 +38,7 @@ public enum Attribute { private final String name; - private Attribute(String name) { + Attribute(String name) { this.name = name; } diff --git a/src/io/appium/droiddriver/finders/By.java b/src/io/appium/droiddriver/finders/By.java index f8ac924..9a38622 100644 --- a/src/io/appium/droiddriver/finders/By.java +++ b/src/io/appium/droiddriver/finders/By.java @@ -16,26 +16,34 @@ package io.appium.droiddriver.finders; +import static io.appium.droiddriver.util.Preconditions.checkNotNull; + import android.content.Context; +import java.util.ArrayList; +import java.util.List; + import io.appium.droiddriver.UiElement; import io.appium.droiddriver.exceptions.ElementNotFoundException; import io.appium.droiddriver.util.InstrumentationUtils; -import static io.appium.droiddriver.util.Preconditions.checkNotNull; - /** * Convenience methods to create commonly used finders. */ public class By { + private static final MatchFinder ANY = new MatchFinder(null); - /** Matches any UiElement. */ + /** + * Matches any UiElement. + */ public static MatchFinder any() { return ANY; } - /** Matches a UiElement whose {@code attribute} is {@code true}. */ + /** + * Matches a UiElement whose {@code attribute} is {@code true}. + */ public static MatchFinder is(Attribute attribute) { return new MatchFinder(Predicates.attributeTrue(attribute)); } @@ -47,74 +55,91 @@ public class By { return new MatchFinder(Predicates.attributeFalse(attribute)); } - /** Matches a UiElement by a resource id defined in the AUT. */ + /** + * Matches a UiElement by a resource id defined in the AUT. + */ public static MatchFinder resourceId(int resourceId) { Context targetContext = InstrumentationUtils.getInstrumentation().getTargetContext(); return resourceId(targetContext.getResources().getResourceName(resourceId)); } /** - * Matches a UiElement by the string representation of a resource id. This works for resources - * not belonging to the AUT. + * Matches a UiElement by the string representation of a resource id. This works for resources not + * belonging to the AUT. */ public static MatchFinder resourceId(String resourceId) { return new MatchFinder(Predicates.attributeEquals(Attribute.RESOURCE_ID, resourceId)); } - /** Matches a UiElement by package name. */ + /** + * Matches a UiElement by package name. + */ public static MatchFinder packageName(String name) { return new MatchFinder(Predicates.attributeEquals(Attribute.PACKAGE, name)); } - /** Matches a UiElement by the exact text. */ + /** + * Matches a UiElement by the exact text. + */ public static MatchFinder text(String text) { return new MatchFinder(Predicates.attributeEquals(Attribute.TEXT, text)); } - /** Matches a UiElement whose text matches {@code regex}. */ + /** + * Matches a UiElement whose text matches {@code regex}. + */ public static MatchFinder textRegex(String regex) { return new MatchFinder(Predicates.attributeMatches(Attribute.TEXT, regex)); } - /** Matches a UiElement whose text contains {@code substring}. */ + /** + * Matches a UiElement whose text contains {@code substring}. + */ public static MatchFinder textContains(String substring) { return new MatchFinder(Predicates.attributeContains(Attribute.TEXT, substring)); } - /** Matches a UiElement by content description. */ + /** + * Matches a UiElement by content description. + */ public static MatchFinder contentDescription(String contentDescription) { return new MatchFinder(Predicates.attributeEquals(Attribute.CONTENT_DESC, contentDescription)); } - /** Matches a UiElement whose content description contains {@code substring}. */ + /** + * Matches a UiElement whose content description contains {@code substring}. + */ public static MatchFinder contentDescriptionContains(String substring) { return new MatchFinder(Predicates.attributeContains(Attribute.CONTENT_DESC, substring)); } - /** Matches a UiElement by class name. */ + /** + * Matches a UiElement by class name. + */ public static MatchFinder className(String className) { return new MatchFinder(Predicates.attributeEquals(Attribute.CLASS, className)); } - /** Matches a UiElement by class name. */ + /** + * Matches a UiElement by class name. + */ public static MatchFinder className(Class<?> clazz) { return className(clazz.getName()); } - /** Matches a UiElement that is selected. */ + /** + * Matches a UiElement that is selected. + */ public static MatchFinder selected() { return is(Attribute.SELECTED); } /** - * Matches by XPath. When applied on an non-root element, it will not evaluate - * above the context element. - * <p> - * XPath is the domain-specific-language for navigating a node tree. It is - * ideal if the UiElement to match has a complex relationship with surrounding - * nodes. For simple cases, {@link #withParent} or {@link #withAncestor} are - * preferred, which can combine with other {@link MatchFinder}s in - * {@link #allOf}. For complex cases like below, XPath is superior: + * Matches by XPath. When applied on an non-root element, it will not evaluate above the context + * element. <p> XPath is the domain-specific-language for navigating a node tree. It is ideal if + * the UiElement to match has a complex relationship with surrounding nodes. For simple cases, + * {@link #withParent} or {@link #withAncestor} are preferred, which can combine with other {@link + * MatchFinder}s in {@link #allOf}. For complex cases like below, XPath is superior: * * <pre> * {@code @@ -132,8 +157,8 @@ public class By { * } * </pre> * - * If we need to locate the RelativeLayout containing the album "Forever" - * instead of a song or an artist named "Forever", this XPath works: + * If we need to locate the RelativeLayout containing the album "Forever" instead of a song or an + * artist named "Forever", this XPath works: * * <pre> * {@code //*[LinearLayout/*[@text='Albums']]/RelativeLayout[*[@text='Forever']]} @@ -147,34 +172,28 @@ public class By { } /** - * Returns a finder that uses the UiElement returned by first Finder as - * context for the second Finder. - * <p> - * typically first Finder finds the ancestor, then second Finder finds the - * target UiElement, which is a descendant. - * </p> - * Note that if the first Finder matches multiple UiElements, only the first - * match is tried, which usually is not what callers expect. In this case, - * allOf(second, withAncesor(first)) may work. + * Returns a finder that uses the UiElement returned by first Finder as context for the second + * Finder. <p> typically first Finder finds the ancestor, then second Finder finds the target + * UiElement, which is a descendant. </p> Note that if the first Finder matches multiple + * UiElements, only the first match is tried, which usually is not what callers expect. In this + * case, allOf(second, withAncesor(first)) may work. */ public static ChainFinder chain(Finder first, Finder second) { return new ChainFinder(first, second); } - private static Predicate<? super UiElement>[] getPredicates(MatchFinder... finders) { - @SuppressWarnings("unchecked") - Predicate<? super UiElement>[] predicates = new Predicate[finders.length]; + private static List<Predicate<? super UiElement>> getPredicates(MatchFinder... finders) { + ArrayList<Predicate<? super UiElement>> predicates = new ArrayList<>(finders.length); for (int i = 0; i < finders.length; i++) { - predicates[i] = finders[i].predicate; + predicates.add(finders[i].predicate); } return predicates; } /** - * Evaluates given {@code finders} in short-circuit fashion in the order - * they are passed. Costly finders (for example those returned by with* - * methods that navigate the node tree) should be passed after cheap finders - * (for example the ByAttribute finders). + * Evaluates given {@code finders} in short-circuit fashion in the order they are passed. Costly + * finders (for example those returned by with* methods that navigate the node tree) should be + * passed after cheap finders (for example the ByAttribute finders). * * @return a finder that is the logical conjunction of given finders */ @@ -183,10 +202,9 @@ public class By { } /** - * Evaluates given {@code finders} in short-circuit fashion in the order - * they are passed. Costly finders (for example those returned by with* - * methods that navigate the node tree) should be passed after cheap finders - * (for example the ByAttribute finders). + * Evaluates given {@code finders} in short-circuit fashion in the order they are passed. Costly + * finders (for example those returned by with* methods that navigate the node tree) should be + * passed after cheap finders (for example the ByAttribute finders). * * @return a finder that is the logical disjunction of given finders */ @@ -195,8 +213,8 @@ public class By { } /** - * Matches a UiElement whose parent matches the given parentFinder. For - * complex cases, consider {@link #xpath}. + * Matches a UiElement whose parent matches the given parentFinder. For complex cases, consider + * {@link #xpath}. */ public static MatchFinder withParent(MatchFinder parentFinder) { checkNotNull(parentFinder); @@ -204,8 +222,8 @@ public class By { } /** - * Matches a UiElement whose ancestor matches the given ancestorFinder. For - * complex cases, consider {@link #xpath}. + * Matches a UiElement whose ancestor matches the given ancestorFinder. For complex cases, + * consider {@link #xpath}. */ public static MatchFinder withAncestor(MatchFinder ancestorFinder) { checkNotNull(ancestorFinder); @@ -213,8 +231,8 @@ public class By { } /** - * Matches a UiElement which has a visible sibling matching the given - * siblingFinder. This could be inefficient; consider {@link #xpath}. + * Matches a UiElement which has a visible sibling matching the given siblingFinder. This could be + * inefficient; consider {@link #xpath}. */ public static MatchFinder withSibling(MatchFinder siblingFinder) { checkNotNull(siblingFinder); @@ -222,8 +240,8 @@ public class By { } /** - * Matches a UiElement which has a visible child matching the given - * childFinder. This could be inefficient; consider {@link #xpath}. + * Matches a UiElement which has a visible child matching the given childFinder. This could be + * inefficient; consider {@link #xpath}. */ public static MatchFinder withChild(MatchFinder childFinder) { checkNotNull(childFinder); @@ -231,8 +249,8 @@ public class By { } /** - * Matches a UiElement whose descendant (including self) matches the given - * descendantFinder. This could be VERY inefficient; consider {@link #xpath}. + * Matches a UiElement whose descendant (including self) matches the given descendantFinder. This + * could be VERY inefficient; consider {@link #xpath}. */ public static MatchFinder withDescendant(final MatchFinder descendantFinder) { checkNotNull(descendantFinder); @@ -254,11 +272,14 @@ public class By { }); } - /** Matches a UiElement that does not match the provided {@code finder}. */ + /** + * Matches a UiElement that does not match the provided {@code finder}. + */ public static MatchFinder not(MatchFinder finder) { checkNotNull(finder); return new MatchFinder(Predicates.not(finder.predicate)); } - private By() {} + private By() { + } } diff --git a/src/io/appium/droiddriver/finders/Predicates.java b/src/io/appium/droiddriver/finders/Predicates.java index 1b9ad80..0d2d9df 100644 --- a/src/io/appium/droiddriver/finders/Predicates.java +++ b/src/io/appium/droiddriver/finders/Predicates.java @@ -18,13 +18,17 @@ package io.appium.droiddriver.finders; import android.text.TextUtils; +import java.util.Arrays; + import io.appium.droiddriver.UiElement; /** * Static utility methods pertaining to {@code Predicate} instances. */ public final class Predicates { - private Predicates() {} + + private Predicates() { + } private static final Predicate<Object> ANY = new Predicate<Object>() { @Override @@ -64,9 +68,9 @@ public final class Predicates { } /** - * Returns a predicate that evaluates to {@code true} if both arguments - * evaluate to {@code true}. The arguments are evaluated in order, and - * evaluation will be "short-circuited" as soon as a false predicate is found. + * Returns a predicate that evaluates to {@code true} if both arguments evaluate to {@code true}. + * The arguments are evaluated in order, and evaluation will be "short-circuited" as soon as a + * false predicate is found. */ @SuppressWarnings("unchecked") public static <T> Predicate<T> allOf(final Predicate<? super T> first, @@ -92,13 +96,11 @@ public final class Predicates { } /** - * Returns a predicate that evaluates to {@code true} if each of its - * components evaluates to {@code true}. The components are evaluated in - * order, and evaluation will be "short-circuited" as soon as a false - * predicate is found. + * Returns a predicate that evaluates to {@code true} if each of its components evaluates to + * {@code true}. The components are evaluated in order, and evaluation will be "short-circuited" + * as soon as a false predicate is found. */ - @SuppressWarnings("unchecked") - public static <T> Predicate<T> allOf(final Predicate<? super T>... components) { + public static <T> Predicate<T> allOf(final Iterable<Predicate<? super T>> components) { return new Predicate<T>() { @Override public boolean apply(T input) { @@ -118,13 +120,22 @@ public final class Predicates { } /** - * Returns a predicate that evaluates to {@code true} if any one of its - * components evaluates to {@code true}. The components are evaluated in - * order, and evaluation will be "short-circuited" as soon as a true predicate - * is found. + * Returns a predicate that evaluates to {@code true} if each of its components evaluates to + * {@code true}. The components are evaluated in order, and evaluation will be "short-circuited" + * as soon as a false predicate is found. */ - @SuppressWarnings("unchecked") - public static <T> Predicate<T> anyOf(final Predicate<? super T>... components) { + @SuppressWarnings("RedundantTypeArguments") // Some compilers cannot infer <T> + @SafeVarargs + public static <T> Predicate<T> allOf(final Predicate<? super T>... components) { + return Predicates.<T>allOf(Arrays.asList(components)); + } + + /** + * Returns a predicate that evaluates to {@code true} if any one of its components evaluates to + * {@code true}. The components are evaluated in order, and evaluation will be "short-circuited" + * as soon as a true predicate is found. + */ + public static <T> Predicate<T> anyOf(final Iterable<Predicate<? super T>> components) { return new Predicate<T>() { @Override public boolean apply(T input) { @@ -144,8 +155,19 @@ public final class Predicates { } /** - * Returns a predicate that evaluates to {@code true} on a {@link UiElement} - * if its {@code attribute} is {@code true}. + * Returns a predicate that evaluates to {@code true} if any one of its components evaluates to + * {@code true}. The components are evaluated in order, and evaluation will be "short-circuited" + * as soon as a true predicate is found. + */ + @SuppressWarnings("RedundantTypeArguments") // Some compilers cannot infer <T> + @SafeVarargs + public static <T> Predicate<T> anyOf(final Predicate<? super T>... components) { + return Predicates.<T>anyOf(Arrays.asList(components)); + } + + /** + * Returns a predicate that evaluates to {@code true} on a {@link UiElement} if its {@code + * attribute} is {@code true}. */ public static Predicate<UiElement> attributeTrue(final Attribute attribute) { return new Predicate<UiElement>() { @@ -163,8 +185,8 @@ public final class Predicates { } /** - * Returns a predicate that evaluates to {@code true} on a {@link UiElement} - * if its {@code attribute} is {@code false}. + * Returns a predicate that evaluates to {@code true} on a {@link UiElement} if its {@code + * attribute} is {@code false}. */ public static Predicate<UiElement> attributeFalse(final Attribute attribute) { return new Predicate<UiElement>() { @@ -182,8 +204,8 @@ public final class Predicates { } /** - * Returns a predicate that evaluates to {@code true} on a {@link UiElement} - * if its {@code attribute} equals {@code expected}. + * Returns a predicate that evaluates to {@code true} on a {@link UiElement} if its {@code + * attribute} equals {@code expected}. */ public static Predicate<UiElement> attributeEquals(final Attribute attribute, final Object expected) { @@ -202,10 +224,11 @@ public final class Predicates { } /** - * Returns a predicate that evaluates to {@code true} on a {@link UiElement} - * if its {@code attribute} matches {@code regex}. + * Returns a predicate that evaluates to {@code true} on a {@link UiElement} if its {@code + * attribute} matches {@code regex}. */ - public static Predicate<UiElement> attributeMatches(final Attribute attribute, final String regex) { + public static Predicate<UiElement> attributeMatches(final Attribute attribute, + final String regex) { return new Predicate<UiElement>() { @Override public boolean apply(UiElement element) { @@ -221,8 +244,8 @@ public final class Predicates { } /** - * Returns a predicate that evaluates to {@code true} on a {@link UiElement} - * if its {@code attribute} contains {@code substring}. + * Returns a predicate that evaluates to {@code true} on a {@link UiElement} if its {@code + * attribute} contains {@code substring}. */ public static Predicate<UiElement> attributeContains(final Attribute attribute, final String substring) { @@ -240,7 +263,8 @@ public final class Predicates { }; } - public static Predicate<UiElement> withParent(final Predicate<? super UiElement> parentPredicate) { + public static Predicate<UiElement> withParent( + final Predicate<? super UiElement> parentPredicate) { return new Predicate<UiElement>() { @Override public boolean apply(UiElement element) { @@ -277,7 +301,8 @@ public final class Predicates { }; } - public static Predicate<UiElement> withSibling(final Predicate<? super UiElement> siblingPredicate) { + public static Predicate<UiElement> withSibling( + final Predicate<? super UiElement> siblingPredicate) { return new Predicate<UiElement>() { @Override public boolean apply(UiElement element) { @@ -318,4 +343,6 @@ public final class Predicates { } }; } + + } diff --git a/src/io/appium/droiddriver/helpers/DroidDrivers.java b/src/io/appium/droiddriver/helpers/DroidDrivers.java index 7725bf5..e55d595 100644 --- a/src/io/appium/droiddriver/helpers/DroidDrivers.java +++ b/src/io/appium/droiddriver/helpers/DroidDrivers.java @@ -21,9 +21,9 @@ import android.app.Instrumentation; import android.os.Build; import io.appium.droiddriver.DroidDriver; +import io.appium.droiddriver.duo.DuoDriver; import io.appium.droiddriver.exceptions.DroidDriverException; import io.appium.droiddriver.instrumentation.InstrumentationDriver; -import io.appium.droiddriver.uiautomation.UiAutomationDriver; import io.appium.droiddriver.util.InstrumentationUtils; /** @@ -83,7 +83,7 @@ public class DroidDrivers { // If "dd.driver" is not specified, return default. if (hasUiAutomation()) { checkUiAutomation(); - return new UiAutomationDriver(instrumentation); + return new DuoDriver(); } return new InstrumentationDriver(instrumentation); } diff --git a/src/io/appium/droiddriver/helpers/SingleRun.java b/src/io/appium/droiddriver/helpers/SingleRun.java index 5ffd21e..714c777 100644 --- a/src/io/appium/droiddriver/helpers/SingleRun.java +++ b/src/io/appium/droiddriver/helpers/SingleRun.java @@ -24,7 +24,7 @@ import java.util.concurrent.atomic.AtomicBoolean; * a class effect. */ public abstract class SingleRun { - private AtomicBoolean hasRun = new AtomicBoolean(); + private final AtomicBoolean hasRun = new AtomicBoolean(); /** * Calls {@link #run()} if it is the first time this method is called upon this instance. diff --git a/src/io/appium/droiddriver/instrumentation/ViewElement.java b/src/io/appium/droiddriver/instrumentation/ViewElement.java index e706362..ab87817 100644 --- a/src/io/appium/droiddriver/instrumentation/ViewElement.java +++ b/src/io/appium/droiddriver/instrumentation/ViewElement.java @@ -16,6 +16,8 @@ package io.appium.droiddriver.instrumentation; +import static io.appium.droiddriver.util.Strings.charSequenceToString; + import android.content.res.Resources; import android.graphics.Rect; import android.view.View; @@ -40,8 +42,6 @@ import io.appium.droiddriver.finders.Attribute; import io.appium.droiddriver.util.InstrumentationUtils; import io.appium.droiddriver.util.Preconditions; -import static io.appium.droiddriver.util.Strings.charSequenceToString; - /** * A UiElement that is backed by a View. */ diff --git a/src/io/appium/droiddriver/runner/MinSdkVersion.java b/src/io/appium/droiddriver/runner/MinSdkVersion.java index c1ea2e9..a05b3fc 100644 --- a/src/io/appium/droiddriver/runner/MinSdkVersion.java +++ b/src/io/appium/droiddriver/runner/MinSdkVersion.java @@ -16,14 +16,14 @@ package io.appium.droiddriver.runner; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; + import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.TYPE; - /** * This annotation indicates that its target needs a minimum SDK version * specified as its value. diff --git a/src/io/appium/droiddriver/runner/UseUiAutomation.java b/src/io/appium/droiddriver/runner/UseUiAutomation.java index 316ac8f..66ef880 100644 --- a/src/io/appium/droiddriver/runner/UseUiAutomation.java +++ b/src/io/appium/droiddriver/runner/UseUiAutomation.java @@ -16,14 +16,14 @@ package io.appium.droiddriver.runner; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; + import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.TYPE; - /** * This annotation indicates that its target needs * {@link android.app.UiAutomation}. It is effectively equivalent to diff --git a/src/io/appium/droiddriver/scroll/DynamicSentinelStrategy.java b/src/io/appium/droiddriver/scroll/DynamicSentinelStrategy.java index 051cfa7..b42b60d 100644 --- a/src/io/appium/droiddriver/scroll/DynamicSentinelStrategy.java +++ b/src/io/appium/droiddriver/scroll/DynamicSentinelStrategy.java @@ -39,7 +39,7 @@ public class DynamicSentinelStrategy extends SentinelStrategy { /** * Interface for determining whether sentinel is updated. */ - public static interface IsUpdatedStrategy { + public interface IsUpdatedStrategy { /** * Returns whether {@code newSentinel} is updated from {@code oldSentinel}. */ diff --git a/src/io/appium/droiddriver/scroll/StepBasedScroller.java b/src/io/appium/droiddriver/scroll/StepBasedScroller.java index 6dbc79e..11c42f4 100644 --- a/src/io/appium/droiddriver/scroll/StepBasedScroller.java +++ b/src/io/appium/droiddriver/scroll/StepBasedScroller.java @@ -15,6 +15,8 @@ */ package io.appium.droiddriver.scroll; +import static io.appium.droiddriver.scroll.Direction.LogicalDirection.BACKWARD; + import android.util.Log; import io.appium.droiddriver.DroidDriver; @@ -29,8 +31,6 @@ import io.appium.droiddriver.scroll.Direction.DirectionConverter; import io.appium.droiddriver.scroll.Direction.PhysicalDirection; import io.appium.droiddriver.util.Logs; -import static io.appium.droiddriver.scroll.Direction.LogicalDirection.BACKWARD; - /** * A {@link Scroller} that looks for the desired item in the currently shown * content of the scrollable container, otherwise scrolls the container one step diff --git a/src/io/appium/droiddriver/uiautomation/UiAutomationElement.java b/src/io/appium/droiddriver/uiautomation/UiAutomationElement.java index cf7449e..5b99131 100644 --- a/src/io/appium/droiddriver/uiautomation/UiAutomationElement.java +++ b/src/io/appium/droiddriver/uiautomation/UiAutomationElement.java @@ -16,6 +16,8 @@ package io.appium.droiddriver.uiautomation; +import static io.appium.droiddriver.util.Strings.charSequenceToString; + import android.annotation.TargetApi; import android.app.UiAutomation; import android.app.UiAutomation.AccessibilityEventFilter; @@ -37,8 +39,6 @@ import io.appium.droiddriver.finders.Attribute; import io.appium.droiddriver.uiautomation.UiAutomationContext.UiAutomationCallable; import io.appium.droiddriver.util.Preconditions; -import static io.appium.droiddriver.util.Strings.charSequenceToString; - /** * A UiElement that gets attributes via the Accessibility API. */ @@ -96,9 +96,9 @@ public class UiAutomationElement extends BaseUiElement<AccessibilityNodeInfo, Ui put(attribs, Attribute.BOUNDS, getBounds(node)); attributes = Collections.unmodifiableMap(attribs); - // Order matters as getVisibleBounds depends on visible + // Order matters as findVisibleBounds depends on visible visible = node.isVisibleToUser(); - visibleBounds = getVisibleBounds(node); + visibleBounds = findVisibleBounds(); List<UiAutomationElement> mutableChildren = buildChildren(node); this.children = mutableChildren == null ? null : Collections.unmodifiableList(mutableChildren); } @@ -132,19 +132,19 @@ public class UiAutomationElement extends BaseUiElement<AccessibilityNodeInfo, Ui return rect; } - private Rect getVisibleBounds(AccessibilityNodeInfo node) { + private Rect findVisibleBounds() { if (!visible) { return new Rect(); } - Rect visibleBounds = getBounds(); + Rect foundBounds = getBounds(); UiAutomationElement parent = getParent(); - Rect parentBounds; while (parent != null) { - parentBounds = parent.getBounds(); - visibleBounds.intersect(parentBounds); + if (!foundBounds.intersect(parent.getBounds())) { + return new Rect(); + } parent = parent.getParent(); } - return visibleBounds; + return foundBounds; } @Override diff --git a/src/io/appium/droiddriver/validators/DefaultAccessibilityValidator.java b/src/io/appium/droiddriver/validators/DefaultAccessibilityValidator.java index 1ce3649..b78d0a5 100644 --- a/src/io/appium/droiddriver/validators/DefaultAccessibilityValidator.java +++ b/src/io/appium/droiddriver/validators/DefaultAccessibilityValidator.java @@ -41,14 +41,8 @@ public class DefaultAccessibilityValidator implements Validator { // Logic from TalkBack private static boolean isAccessibilityFocusable(UiElement element) { - if (isActionableForAccessibility(element)) { - return true; - } - - if (isTopLevelScrollItem(element) && (isSpeakingNode(element))) { - return true; - } - return false; + return isActionableForAccessibility(element) + || (isTopLevelScrollItem(element) && isSpeakingNode(element)); } private static boolean isTopLevelScrollItem(UiElement element) { |