aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore7
-rw-r--r--Android.mk16
-rw-r--r--build.gradle9
-rw-r--r--contributing.md9
-rw-r--r--contributing_aosp.md20
-rw-r--r--droiddriver-android_support_test/Android.mk19
-rw-r--r--droiddriver-android_support_test/build.gradle14
-rw-r--r--gradle/wrapper/gradle-wrapper.jarbin0 -> 51018 bytes
-rw-r--r--gradle/wrapper/gradle-wrapper.properties6
-rwxr-xr-xgradlew164
-rw-r--r--gradlew.bat90
-rw-r--r--manualtest/Android.mk17
-rw-r--r--manualtest/build.gradle15
-rw-r--r--manualtest/src/io/appium/droiddriver/manualtest/ManualTest.java4
-rw-r--r--src/io/appium/droiddriver/base/AbstractDroidDriver.java86
-rw-r--r--src/io/appium/droiddriver/base/BaseDroidDriver.java61
-rw-r--r--src/io/appium/droiddriver/base/CompositeDroidDriver.java59
-rw-r--r--src/io/appium/droiddriver/duo/DuoDriver.java57
-rw-r--r--src/io/appium/droiddriver/finders/Attribute.java2
-rw-r--r--src/io/appium/droiddriver/finders/By.java139
-rw-r--r--src/io/appium/droiddriver/finders/Predicates.java85
-rw-r--r--src/io/appium/droiddriver/helpers/DroidDrivers.java4
-rw-r--r--src/io/appium/droiddriver/helpers/SingleRun.java2
-rw-r--r--src/io/appium/droiddriver/instrumentation/ViewElement.java4
-rw-r--r--src/io/appium/droiddriver/runner/MinSdkVersion.java6
-rw-r--r--src/io/appium/droiddriver/runner/UseUiAutomation.java6
-rw-r--r--src/io/appium/droiddriver/scroll/DynamicSentinelStrategy.java2
-rw-r--r--src/io/appium/droiddriver/scroll/StepBasedScroller.java4
-rw-r--r--src/io/appium/droiddriver/uiautomation/UiAutomationElement.java20
-rw-r--r--src/io/appium/droiddriver/validators/DefaultAccessibilityValidator.java10
30 files changed, 654 insertions, 283 deletions
diff --git a/.gitignore b/.gitignore
index 3d0ebbd..93237bf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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
new file mode 100644
index 0000000..c97a8bd
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.jar
Binary files differ
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
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000..91a7e26
--- /dev/null
+++ b/gradlew
@@ -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) {