diff options
Diffstat (limited to 'droiddriver-android_support_test')
5 files changed, 227 insertions, 0 deletions
diff --git a/droiddriver-android_support_test/Android.mk b/droiddriver-android_support_test/Android.mk new file mode 100644 index 0000000..22c6c0a --- /dev/null +++ b/droiddriver-android_support_test/Android.mk @@ -0,0 +1,19 @@ +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/AndroidManifest.xml b/droiddriver-android_support_test/AndroidManifest.xml new file mode 100644 index 0000000..f9f47f8 --- /dev/null +++ b/droiddriver-android_support_test/AndroidManifest.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest + package="io.appium.droiddriver.android_support_test"> + +</manifest> diff --git a/droiddriver-android_support_test/build.gradle b/droiddriver-android_support_test/build.gradle new file mode 100644 index 0000000..8dab32a --- /dev/null +++ b/droiddriver-android_support_test/build.gradle @@ -0,0 +1,58 @@ +buildscript { + repositories { + jcenter() + } + dependencies { + // this requires Gradle 2 + classpath 'com.android.tools.build:gradle:1.0.1' + classpath 'com.jakewharton.sdkmanager:gradle-plugin:0.12.0' + } +} + +apply plugin: 'android-sdk-manager' +apply plugin: 'com.android.library' + +repositories { + jcenter() +} + +dependencies { + // During development, this should be set to droiddriver SNAPSHOT + compile 'io.appium:droiddriver:0.9.1' + compile 'com.android.support.test:testing-support-lib:0.1' +} + +tasks.withType(JavaCompile) { + options.compilerArgs << '-Xlint:deprecation' +} + +android { + compileSdkVersion 21 + buildToolsVersion '21.1.2' + + defaultConfig { + minSdkVersion 8 + targetSdkVersion 21 + versionCode 1 + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_7 + targetCompatibility JavaVersion.VERSION_1_7 + } + + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + java.srcDirs = ['src'] + } + } + + lintOptions { + // Aborting on lint errors prevents jenkins from processing the Lint output + // https://wiki.jenkins-ci.org/display/JENKINS/Android%20Lint%20Plugin + abortOnError false + } +} + +//TODO: add script for publishing diff --git a/droiddriver-android_support_test/readme.md b/droiddriver-android_support_test/readme.md new file mode 100644 index 0000000..f4d7ebb --- /dev/null +++ b/droiddriver-android_support_test/readme.md @@ -0,0 +1,5 @@ +# droiddriver-android_support_test + +An optional library that integrates DroidDriver with [the Android Support Test Library](https://code.google.com/p/android-test-kit/wiki/AndroidJUnitRunnerUserGuide). +This is an experimental library because the Android Support Test Library is at early stage and many +APIs are in internal packages.
\ No newline at end of file diff --git a/droiddriver-android_support_test/src/io/appium/droiddriver/android_support_test/D2AndroidJUnitRunner.java b/droiddriver-android_support_test/src/io/appium/droiddriver/android_support_test/D2AndroidJUnitRunner.java new file mode 100644 index 0000000..7924380 --- /dev/null +++ b/droiddriver-android_support_test/src/io/appium/droiddriver/android_support_test/D2AndroidJUnitRunner.java @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2015 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.android_support_test; + +import android.app.Activity; +import android.os.Bundle; +import android.os.Looper; +import android.support.test.internal.runner.lifecycle.ActivityLifecycleMonitorRegistry; +import android.support.test.runner.AndroidJUnitRunner; +import android.support.test.runner.lifecycle.Stage; +import android.util.Log; + +import java.util.Iterator; +import java.util.concurrent.Callable; +import java.util.concurrent.FutureTask; +import java.util.concurrent.TimeUnit; + +import io.appium.droiddriver.exceptions.DroidDriverException; +import io.appium.droiddriver.exceptions.TimeoutException; +import io.appium.droiddriver.helpers.DroidDrivers; +import io.appium.droiddriver.util.ActivityUtils; +import io.appium.droiddriver.util.Logs; + +/** + * Integrates DroidDriver with AndroidJUnitRunner. <p> TODO: support DroidDriver test filter + * annotations. + */ +public class D2AndroidJUnitRunner extends AndroidJUnitRunner { + private static final Callable<Activity> GET_RUNNING_ACTIVITY = new Callable<Activity>() { + @Override + public Activity call() { + Iterator<Activity> activityIterator = ActivityLifecycleMonitorRegistry.getInstance() + .getActivitiesInStage(Stage.RESUMED).iterator(); + return activityIterator.hasNext() ? activityIterator.next() : null; + } + }; + + /** + * {@inheritDoc} <p> Sets the values for the convenience methods {@link + * DroidDrivers#getInstrumentation()} and {@link DroidDrivers#getOptions()}. + */ + @Override + public void onCreate(Bundle arguments) { + DroidDrivers.initInstrumentation(this, arguments); + super.onCreate(arguments); + } + + /** + * {@inheritDoc} <p> Hooks {@link ActivityUtils#setRunningActivitySupplier} to {@link + * ActivityLifecycleMonitorRegistry}. + */ + @Override + public void onStart() { + ActivityUtils.setRunningActivitySupplier(new ActivityUtils.Supplier<Activity>() { + @Override + public Activity get() { + try { + // If this is called on main (UI) thread, don't call runOnMainSync + if (Looper.myLooper() == Looper.getMainLooper()) { + return GET_RUNNING_ACTIVITY.call(); + } + + return runOnMainSyncWithTimeout(GET_RUNNING_ACTIVITY); + } catch (Exception e) { + Logs.log(Log.WARN, e); + return null; + } + } + }); + super.onStart(); + } + + /** + * Runs {@code callable} on the main thread on best-effort basis up to a time limit, which + * defaults to {@code 10000L} and can be set as an <a href= "http://developer.android.com/tools/testing/testing_otheride.html#AMOptionsSyntax"> + * am instrument option</a> under the key {@code dd.runOnMainSyncTimeout}. <p>This is a safer + * variation of {@link #runOnMainSync} because the latter may hang. But it is heavy because a new + * thread is created for each call unless the am command line specifies {@code + * dd.runOnMainSyncTimeout <=0} such as "-e dd.runOnMainSyncTimeout 0".</p>The {@code callable} + * may never run, for example, in case that the main Looper has exited due to uncaught exception. + */ + // TODO: move this to DroidDrivers + // TODO: call runOnMainSync on a single worker thread? + private <V> V runOnMainSyncWithTimeout(Callable<V> callable) { + final RunOnMainSyncFutureTask<V> futureTask = new RunOnMainSyncFutureTask<>(callable); + + String timeoutMillisString = DroidDrivers.getOptions().getString("dd.runOnMainSyncTimeout"); + long timeoutMillis = timeoutMillisString == null? 10000L : Long.parseLong(timeoutMillisString); + if (timeoutMillis <= 0L) { + // Call runOnMainSync on current thread without time limit. + futureTask.runOnMainSyncNoThrow(); + } else { + new Thread() { + @Override + public void run() { + futureTask.runOnMainSyncNoThrow(); + } + }.start(); + } + + try { + return futureTask.get(timeoutMillis, TimeUnit.MILLISECONDS); + } catch (java.util.concurrent.TimeoutException e) { + throw new TimeoutException("Timed out after " + timeoutMillis + + " milliseconds waiting for Instrumentation.runOnMainSync", e); + } catch (Throwable e) { + throw new DroidDriverException(e); + } finally { + futureTask.cancel(false); + } + } + + private class RunOnMainSyncFutureTask<V> extends FutureTask<V> { + public RunOnMainSyncFutureTask(Callable<V> callable) { + super(callable); + } + + public void runOnMainSyncNoThrow() { + try { + runOnMainSync(this); + } catch (Throwable e) { + setException(e); + } + } + } +} |