aboutsummaryrefslogtreecommitdiff
path: root/src/com/google
diff options
context:
space:
mode:
authorKevin Jin <kjin@google.com>2014-03-10 17:38:55 -0700
committerKevin Jin <kjin@google.com>2014-03-10 18:12:51 -0700
commit1d0f3c02fc3673159f2b6496823fd7b9228b7891 (patch)
tree0041a4f9f56be50a372cd579bb0388fafda1e836 /src/com/google
parenteacc6c8c1f05ad4c6d9ca4c612204240b9dc1d4e (diff)
downloaddroiddriver-1d0f3c02fc3673159f2b6496823fd7b9228b7891.tar.gz
Wraps calls to UiAutomation API.
Currently supports fail-fast if UiAutomation throws IllegalStateException. Change-Id: I1e6472d113a63b14d3615ef0084ea00d209f7e63
Diffstat (limited to 'src/com/google')
-rw-r--r--src/com/google/android/droiddriver/exceptions/UnrecoverableException.java35
-rw-r--r--src/com/google/android/droiddriver/helpers/BaseDroidDriverTest.java3
-rw-r--r--src/com/google/android/droiddriver/helpers/UnrecoverableFailure.java7
-rw-r--r--src/com/google/android/droiddriver/instrumentation/InstrumentationContext.java2
-rw-r--r--src/com/google/android/droiddriver/scroll/AccessibilityEventScrollStepStrategy.java3
-rw-r--r--src/com/google/android/droiddriver/uiautomation/UiAutomationContext.java29
-rw-r--r--src/com/google/android/droiddriver/uiautomation/UiAutomationDriver.java30
-rw-r--r--src/com/google/android/droiddriver/uiautomation/UiAutomationElement.java42
-rw-r--r--src/com/google/android/droiddriver/uiautomation/UiAutomationUiDevice.java12
9 files changed, 130 insertions, 33 deletions
diff --git a/src/com/google/android/droiddriver/exceptions/UnrecoverableException.java b/src/com/google/android/droiddriver/exceptions/UnrecoverableException.java
new file mode 100644
index 0000000..c3b069f
--- /dev/null
+++ b/src/com/google/android/droiddriver/exceptions/UnrecoverableException.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2013 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 com.google.android.droiddriver.exceptions;
+
+import com.google.android.droiddriver.helpers.BaseDroidDriverTest;
+
+/**
+ * When an {@link UnrecoverableException} occurs, the rest of the tests are
+ * going to fail as well, therefore running them only adds noise to the report.
+ * {@link BaseDroidDriverTest} will skip remaining tests when this is thrown.
+ */
+@SuppressWarnings("serial")
+public class UnrecoverableException extends RuntimeException {
+ public UnrecoverableException(String message) {
+ super(message);
+ }
+
+ public UnrecoverableException(Throwable throwable) {
+ super(throwable);
+ }
+}
diff --git a/src/com/google/android/droiddriver/helpers/BaseDroidDriverTest.java b/src/com/google/android/droiddriver/helpers/BaseDroidDriverTest.java
index 4f125c8..ca5ac99 100644
--- a/src/com/google/android/droiddriver/helpers/BaseDroidDriverTest.java
+++ b/src/com/google/android/droiddriver/helpers/BaseDroidDriverTest.java
@@ -22,6 +22,7 @@ import android.os.Debug;
import android.util.Log;
import com.google.android.droiddriver.DroidDriver;
+import com.google.android.droiddriver.exceptions.UnrecoverableException;
import com.google.android.droiddriver.util.FileUtils;
import com.google.android.droiddriver.util.Logs;
@@ -97,7 +98,7 @@ public abstract class BaseDroidDriverTest<T extends Activity> extends
}
try {
- if (failure instanceof UnrecoverableFailure) {
+ if (failure instanceof UnrecoverableException) {
skipRemainingTests = true;
}
if (failure instanceof OutOfMemoryError) {
diff --git a/src/com/google/android/droiddriver/helpers/UnrecoverableFailure.java b/src/com/google/android/droiddriver/helpers/UnrecoverableFailure.java
index 9adbac8..e8de98e 100644
--- a/src/com/google/android/droiddriver/helpers/UnrecoverableFailure.java
+++ b/src/com/google/android/droiddriver/helpers/UnrecoverableFailure.java
@@ -16,11 +16,18 @@
package com.google.android.droiddriver.helpers;
+import com.google.android.droiddriver.helpers.BaseDroidDriverTest;
+
/**
* When an {@code UnrecoverableFailure} occurs, the rest of the tests are going
* to fail as well, therefore running them only adds noise to the report.
* {@link BaseDroidDriverTest} will skip remaining tests when this is thrown.
+ *
+ * @deprecated Use
+ * {@link com.google.android.droiddriver.exceptions.UnrecoverableException}
+ * instead.
*/
+@Deprecated
@SuppressWarnings("serial")
public class UnrecoverableFailure extends RuntimeException {
public UnrecoverableFailure(String message) {
diff --git a/src/com/google/android/droiddriver/instrumentation/InstrumentationContext.java b/src/com/google/android/droiddriver/instrumentation/InstrumentationContext.java
index a549a0f..f68dc6e 100644
--- a/src/com/google/android/droiddriver/instrumentation/InstrumentationContext.java
+++ b/src/com/google/android/droiddriver/instrumentation/InstrumentationContext.java
@@ -63,7 +63,7 @@ class InstrumentationContext extends DroidDriverContext {
return injector;
}
- public ViewElement getUiElement(View view, ViewElement parent) {
+ ViewElement getUiElement(View view, ViewElement parent) {
ViewElement element = map.get(view);
if (element == null) {
element = new ViewElement(this, view, parent);
diff --git a/src/com/google/android/droiddriver/scroll/AccessibilityEventScrollStepStrategy.java b/src/com/google/android/droiddriver/scroll/AccessibilityEventScrollStepStrategy.java
index f945d55..a678d37 100644
--- a/src/com/google/android/droiddriver/scroll/AccessibilityEventScrollStepStrategy.java
+++ b/src/com/google/android/droiddriver/scroll/AccessibilityEventScrollStepStrategy.java
@@ -23,6 +23,7 @@ import android.view.accessibility.AccessibilityEvent;
import com.google.android.droiddriver.DroidDriver;
import com.google.android.droiddriver.UiElement;
import com.google.android.droiddriver.actions.SwipeAction;
+import com.google.android.droiddriver.exceptions.UnrecoverableException;
import com.google.android.droiddriver.finders.Finder;
import com.google.android.droiddriver.scroll.Direction.Axis;
import com.google.android.droiddriver.scroll.Direction.DirectionConverter;
@@ -175,6 +176,8 @@ public class AccessibilityEventScrollStepStrategy implements ScrollStepStrategy
doScroll(container, direction);
}
}, filter, scrollEventTimeoutMillis);
+ } catch (IllegalStateException e) {
+ throw new UnrecoverableException(e);
} catch (TimeoutException e) {
// We expect this because LastScrollEventFilter.accept always returns false.
}
diff --git a/src/com/google/android/droiddriver/uiautomation/UiAutomationContext.java b/src/com/google/android/droiddriver/uiautomation/UiAutomationContext.java
index ac114cd..35a4483 100644
--- a/src/com/google/android/droiddriver/uiautomation/UiAutomationContext.java
+++ b/src/com/google/android/droiddriver/uiautomation/UiAutomationContext.java
@@ -23,6 +23,7 @@ import android.view.accessibility.AccessibilityNodeInfo;
import com.google.android.droiddriver.actions.InputInjector;
import com.google.android.droiddriver.base.DroidDriverContext;
+import com.google.android.droiddriver.exceptions.UnrecoverableException;
import com.google.android.droiddriver.finders.ByXPath;
import com.google.common.collect.MapMaker;
@@ -41,8 +42,13 @@ class UiAutomationContext extends DroidDriverContext {
this.driver = driver;
this.injector = new InputInjector() {
@Override
- public boolean injectInputEvent(InputEvent event) {
- return uiAutomation.injectInputEvent(event, true /* sync */);
+ public boolean injectInputEvent(final InputEvent event) {
+ return callUiAutomation(new UiAutomationCallable<Boolean>() {
+ @Override
+ public Boolean call(UiAutomation uiAutomation) {
+ return uiAutomation.injectInputEvent(event, true /* sync */);
+ }
+ });
}
};
}
@@ -57,7 +63,7 @@ class UiAutomationContext extends DroidDriverContext {
return injector;
}
- public UiAutomationElement getUiElement(AccessibilityNodeInfo node, UiAutomationElement parent) {
+ UiAutomationElement getUiElement(AccessibilityNodeInfo node, UiAutomationElement parent) {
UiAutomationElement element = map.get(node);
if (element == null) {
element = new UiAutomationElement(this, node, parent);
@@ -72,7 +78,20 @@ class UiAutomationContext extends DroidDriverContext {
ByXPath.clearData();
}
- public UiAutomation getUiAutomation() {
- return uiAutomation;
+ interface UiAutomationCallable<T> {
+ T call(UiAutomation uiAutomation);
+ }
+
+ /*
+ * Wraps calls to UiAutomation API. Currently supports fail-fast if
+ * UiAutomation throws IllegalStateException, which occurs when the connection
+ * to UiAutomation service is lost.
+ */
+ <T> T callUiAutomation(UiAutomationCallable<T> uiAutomationCallable) {
+ try {
+ return uiAutomationCallable.call(uiAutomation);
+ } catch (IllegalStateException e) {
+ throw new UnrecoverableException(e);
+ }
}
}
diff --git a/src/com/google/android/droiddriver/uiautomation/UiAutomationDriver.java b/src/com/google/android/droiddriver/uiautomation/UiAutomationDriver.java
index 5089acf..ad30693 100644
--- a/src/com/google/android/droiddriver/uiautomation/UiAutomationDriver.java
+++ b/src/com/google/android/droiddriver/uiautomation/UiAutomationDriver.java
@@ -26,6 +26,7 @@ import android.view.accessibility.AccessibilityNodeInfo;
import com.google.android.droiddriver.base.BaseDroidDriver;
import com.google.android.droiddriver.exceptions.TimeoutException;
+import com.google.android.droiddriver.uiautomation.UiAutomationContext.UiAutomationCallable;
import com.google.android.droiddriver.util.Logs;
import com.google.common.primitives.Longs;
@@ -42,11 +43,9 @@ public class UiAutomationDriver extends BaseDroidDriver {
private static final long QUIET_TIME_TO_BE_CONSIDERD_IDLE_STATE = 500;// ms
private final UiAutomationContext context;
- private final UiAutomation uiAutomation;
private final UiAutomationUiDevice uiDevice;
public UiAutomationDriver(Instrumentation instrumentation) {
- this.uiAutomation = instrumentation.getUiAutomation();
this.context = new UiAutomationContext(instrumentation, this);
this.uiDevice = new UiAutomationUiDevice(context);
}
@@ -62,15 +61,28 @@ public class UiAutomationDriver extends BaseDroidDriver {
}
private AccessibilityNodeInfo getRootNode() {
- long timeoutMillis = getPoller().getTimeoutMillis();
- try {
- uiAutomation.waitForIdle(QUIET_TIME_TO_BE_CONSIDERD_IDLE_STATE, timeoutMillis);
- } catch (java.util.concurrent.TimeoutException e) {
- throw new TimeoutException(e);
- }
+ final long timeoutMillis = getPoller().getTimeoutMillis();
+ context.callUiAutomation(new UiAutomationCallable<Void>() {
+ @Override
+ public Void call(UiAutomation uiAutomation) {
+ try {
+ uiAutomation.waitForIdle(QUIET_TIME_TO_BE_CONSIDERD_IDLE_STATE, timeoutMillis);
+ return null;
+ } catch (java.util.concurrent.TimeoutException e) {
+ throw new TimeoutException(e);
+ }
+ }
+ });
+
long end = SystemClock.uptimeMillis() + timeoutMillis;
while (true) {
- AccessibilityNodeInfo root = uiAutomation.getRootInActiveWindow();
+ AccessibilityNodeInfo root =
+ context.callUiAutomation(new UiAutomationCallable<AccessibilityNodeInfo>() {
+ @Override
+ public AccessibilityNodeInfo call(UiAutomation uiAutomation) {
+ return uiAutomation.getRootInActiveWindow();
+ }
+ });
if (root != null) {
return root;
}
diff --git a/src/com/google/android/droiddriver/uiautomation/UiAutomationElement.java b/src/com/google/android/droiddriver/uiautomation/UiAutomationElement.java
index 9a56fbe..8b81485 100644
--- a/src/com/google/android/droiddriver/uiautomation/UiAutomationElement.java
+++ b/src/com/google/android/droiddriver/uiautomation/UiAutomationElement.java
@@ -18,6 +18,7 @@ package com.google.android.droiddriver.uiautomation;
import static com.google.android.droiddriver.util.TextUtils.charSequenceToString;
+import android.app.UiAutomation;
import android.app.UiAutomation.AccessibilityEventFilter;
import android.graphics.Rect;
import android.view.accessibility.AccessibilityEvent;
@@ -26,6 +27,7 @@ import android.view.accessibility.AccessibilityNodeInfo;
import com.google.android.droiddriver.actions.InputInjector;
import com.google.android.droiddriver.base.BaseUiElement;
import com.google.android.droiddriver.finders.Attribute;
+import com.google.android.droiddriver.uiautomation.UiAutomationContext.UiAutomationCallable;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -170,21 +172,29 @@ public class UiAutomationElement extends BaseUiElement {
}
@Override
- protected void doPerformAndWait(FutureTask<Boolean> futureTask, long timeoutMillis) {
- try {
- context.getUiAutomation().executeAndWaitForEvent(futureTask, ANY_EVENT_FILTER, timeoutMillis);
- } catch (TimeoutException e) {
- // This is for sync'ing with Accessibility API on best-effort because
- // it is not reliable.
- // Exception is ignored here. Tests will fail anyways if this is
- // critical.
- // Actions should usually trigger some AccessibilityEvent's, but some
- // widgets fail to do so, resulting in stale AccessibilityNodeInfo's. As a
- // work-around, force to clear the AccessibilityNodeInfoCache.
- // A legitimate case of no AccessibilityEvent is when scrolling has
- // reached the end, but we cannot tell whether it's legitimate or the
- // widget has bugs, so clearAccessibilityNodeInfoCache anyways.
- context.getDriver().clearAccessibilityNodeInfoCacheHack();
- }
+ protected void doPerformAndWait(final FutureTask<Boolean> futureTask, final long timeoutMillis) {
+ context.callUiAutomation(new UiAutomationCallable<Void>() {
+
+ @Override
+ public Void call(UiAutomation uiAutomation) {
+ try {
+ uiAutomation.executeAndWaitForEvent(futureTask, ANY_EVENT_FILTER, timeoutMillis);
+ } catch (TimeoutException e) {
+ // This is for sync'ing with Accessibility API on best-effort because
+ // it is not reliable.
+ // Exception is ignored here. Tests will fail anyways if this is
+ // critical.
+ // Actions should usually trigger some AccessibilityEvent's, but some
+ // widgets fail to do so, resulting in stale AccessibilityNodeInfo's.
+ // As a work-around, force to clear the AccessibilityNodeInfoCache.
+ // A legitimate case of no AccessibilityEvent is when scrolling has
+ // reached the end, but we cannot tell whether it's legitimate or the
+ // widget has bugs, so clearAccessibilityNodeInfoCache anyways.
+ context.getDriver().clearAccessibilityNodeInfoCacheHack();
+ }
+ return null;
+ }
+
+ });
}
}
diff --git a/src/com/google/android/droiddriver/uiautomation/UiAutomationUiDevice.java b/src/com/google/android/droiddriver/uiautomation/UiAutomationUiDevice.java
index bb28c68..a376cb6 100644
--- a/src/com/google/android/droiddriver/uiautomation/UiAutomationUiDevice.java
+++ b/src/com/google/android/droiddriver/uiautomation/UiAutomationUiDevice.java
@@ -16,10 +16,13 @@
package com.google.android.droiddriver.uiautomation;
+import android.app.UiAutomation;
import android.graphics.Bitmap;
import android.util.Log;
import com.google.android.droiddriver.base.BaseUiDevice;
+import com.google.android.droiddriver.exceptions.UnrecoverableException;
+import com.google.android.droiddriver.uiautomation.UiAutomationContext.UiAutomationCallable;
import com.google.android.droiddriver.util.Logs;
class UiAutomationUiDevice extends BaseUiDevice {
@@ -32,7 +35,14 @@ class UiAutomationUiDevice extends BaseUiDevice {
@Override
protected Bitmap takeScreenshot() {
try {
- return context.getUiAutomation().takeScreenshot();
+ return context.callUiAutomation(new UiAutomationCallable<Bitmap>() {
+ @Override
+ public Bitmap call(UiAutomation uiAutomation) {
+ return uiAutomation.takeScreenshot();
+ }
+ });
+ } catch (UnrecoverableException e) {
+ throw e;
} catch (Throwable e) {
Logs.log(Log.ERROR, e);
return null;