diff options
30 files changed, 520 insertions, 197 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 0b6a57f..9a38622 100644 --- a/src/io/appium/droiddriver/finders/By.java +++ b/src/io/appium/droiddriver/finders/By.java @@ -16,6 +16,8 @@ package io.appium.droiddriver.finders; +import static io.appium.droiddriver.util.Preconditions.checkNotNull; + import android.content.Context; import java.util.ArrayList; @@ -25,8 +27,6 @@ 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. */ diff --git a/src/io/appium/droiddriver/finders/Predicates.java b/src/io/appium/droiddriver/finders/Predicates.java index f32b365..0d2d9df 100644 --- a/src/io/appium/droiddriver/finders/Predicates.java +++ b/src/io/appium/droiddriver/finders/Predicates.java @@ -124,6 +124,7 @@ public final class Predicates { * {@code true}. The components are evaluated in order, and evaluation will be "short-circuited" * as soon as a false predicate is found. */ + @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)); @@ -158,6 +159,7 @@ public final class Predicates { * {@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)); 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 c011749..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,21 +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(); - if (!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) { |