aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKevin Jin <kjin@google.com>2014-06-26 18:56:59 -0700
committerKevin Jin <kjin@google.com>2014-06-27 11:42:34 -0700
commitcf1203b8078bed407ed0035c201746fae136439a (patch)
treee2401a8d6aede6b7493336e313a2f3fb6b295e91 /src
parent27b635e33f18c439d6e511d71c762ae1352b1bc8 (diff)
downloaddroiddriver-cf1203b8078bed407ed0035c201746fae136439a.tar.gz
add validators for exmpted classes and scroll action
Change-Id: Iad22351b46df771e7a9f92edb9d84df44b5fe572
Diffstat (limited to 'src')
-rw-r--r--src/com/google/android/droiddriver/actions/ScrollAction.java23
-rw-r--r--src/com/google/android/droiddriver/actions/SwipeAction.java2
-rw-r--r--src/com/google/android/droiddriver/actions/accessibility/AccessibilityScrollAction.java3
-rw-r--r--src/com/google/android/droiddriver/base/BaseUiElement.java29
-rw-r--r--src/com/google/android/droiddriver/scroll/AccessibilityEventScrollStepStrategy.java8
-rw-r--r--src/com/google/android/droiddriver/uiautomation/AccessibilityDriver.java25
-rw-r--r--src/com/google/android/droiddriver/validators/DefaultAccessibilityValidator.java18
-rw-r--r--src/com/google/android/droiddriver/validators/ExemptRootValidator.java35
-rw-r--r--src/com/google/android/droiddriver/validators/ExemptScrollActionValidator.java37
-rw-r--r--src/com/google/android/droiddriver/validators/ExemptedClassesValidator.java60
-rw-r--r--src/com/google/android/droiddriver/validators/FirstApplicableValidator.java47
-rw-r--r--src/com/google/android/droiddriver/validators/Validator.java12
-rw-r--r--src/com/google/android/droiddriver/validators/VisibilityValidator.java10
13 files changed, 278 insertions, 31 deletions
diff --git a/src/com/google/android/droiddriver/actions/ScrollAction.java b/src/com/google/android/droiddriver/actions/ScrollAction.java
new file mode 100644
index 0000000..6305c83
--- /dev/null
+++ b/src/com/google/android/droiddriver/actions/ScrollAction.java
@@ -0,0 +1,23 @@
+/*
+ * 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.actions;
+
+/**
+ * Marker interface for a scroll action.
+ */
+public interface ScrollAction {
+}
diff --git a/src/com/google/android/droiddriver/actions/SwipeAction.java b/src/com/google/android/droiddriver/actions/SwipeAction.java
index a939536..6837741 100644
--- a/src/com/google/android/droiddriver/actions/SwipeAction.java
+++ b/src/com/google/android/droiddriver/actions/SwipeAction.java
@@ -30,7 +30,7 @@ import com.google.android.droiddriver.util.Strings.ToStringHelper;
/**
* An action that swipes the touch screen.
*/
-public class SwipeAction extends EventAction {
+public class SwipeAction extends EventAction implements ScrollAction {
// Milliseconds between synthesized ACTION_MOVE events.
// Note: ACTION_MOVE_INTERVAL is the minimum interval between injected events;
// the actual interval typically is longer.
diff --git a/src/com/google/android/droiddriver/actions/accessibility/AccessibilityScrollAction.java b/src/com/google/android/droiddriver/actions/accessibility/AccessibilityScrollAction.java
index 88e7517..bdeddc8 100644
--- a/src/com/google/android/droiddriver/actions/accessibility/AccessibilityScrollAction.java
+++ b/src/com/google/android/droiddriver/actions/accessibility/AccessibilityScrollAction.java
@@ -19,13 +19,14 @@ package com.google.android.droiddriver.actions.accessibility;
import android.view.accessibility.AccessibilityNodeInfo;
import com.google.android.droiddriver.UiElement;
+import com.google.android.droiddriver.actions.ScrollAction;
import com.google.android.droiddriver.scroll.Direction.PhysicalDirection;
import com.google.android.droiddriver.util.Strings;
/**
* An {@link AccessibilityAction} that scrolls an UiElement.
*/
-public class AccessibilityScrollAction extends AccessibilityAction {
+public class AccessibilityScrollAction extends AccessibilityAction implements ScrollAction {
private final PhysicalDirection direction;
public AccessibilityScrollAction(PhysicalDirection direction) {
diff --git a/src/com/google/android/droiddriver/base/BaseUiElement.java b/src/com/google/android/droiddriver/base/BaseUiElement.java
index 3d74bdc..3122ba3 100644
--- a/src/com/google/android/droiddriver/base/BaseUiElement.java
+++ b/src/com/google/android/droiddriver/base/BaseUiElement.java
@@ -54,7 +54,7 @@ public abstract class BaseUiElement<R, E extends BaseUiElement<R, E>> implements
public static final String ATTRIB_NOT_VISIBLE = "NotVisible";
private UiElementActor uiElementActor = EventUiElementActor.INSTANCE;
- private Validator[] validators = {};
+ private Validator validator = null;
@SuppressWarnings("unchecked")
@Override
@@ -163,13 +163,17 @@ public abstract class BaseUiElement<R, E extends BaseUiElement<R, E>> implements
@Override
public boolean perform(Action action) {
Logs.call(this, "perform", action);
- if (getParent() != null) {// don't check root
- for (Validator validator : validators) {
- if (!validator.isValid(this)) {
- throw new DroidDriverException(validator + " failed");
- }
+ if (validator != null && validator.isApplicable(this, action)) {
+ String failure = validator.validate(this, action);
+ if (failure != null) {
+ throw new DroidDriverException(toString() + " failed validation: " + failure);
}
}
+
+ // timeoutMillis <= 0 means no need to wait
+ if (action.getTimeoutMillis() <= 0) {
+ return doPerform(action);
+ }
return performAndWait(action);
}
@@ -180,11 +184,6 @@ public abstract class BaseUiElement<R, E extends BaseUiElement<R, E>> implements
protected abstract void doPerformAndWait(FutureTask<Boolean> futureTask, long timeoutMillis);
private boolean performAndWait(final Action action) {
- // timeoutMillis <= 0 means no need to wait
- if (action.getTimeoutMillis() <= 0) {
- return doPerform(action);
- }
-
FutureTask<Boolean> futureTask = new FutureTask<Boolean>(new Callable<Boolean>() {
@Override
public Boolean call() {
@@ -192,6 +191,7 @@ public abstract class BaseUiElement<R, E extends BaseUiElement<R, E>> implements
}
});
doPerformAndWait(futureTask, action.getTimeoutMillis());
+
try {
return futureTask.get();
} catch (ExecutionException e) {
@@ -293,7 +293,10 @@ public abstract class BaseUiElement<R, E extends BaseUiElement<R, E>> implements
this.uiElementActor = uiElementActor;
}
- public void setValidators(Validator[] validators) {
- this.validators = validators;
+ /**
+ * Sets the validator to check when {@link #perform(Action)} is called.
+ */
+ public void setValidator(Validator validator) {
+ this.validator = validator;
}
}
diff --git a/src/com/google/android/droiddriver/scroll/AccessibilityEventScrollStepStrategy.java b/src/com/google/android/droiddriver/scroll/AccessibilityEventScrollStepStrategy.java
index 186bff8..f903746 100644
--- a/src/com/google/android/droiddriver/scroll/AccessibilityEventScrollStepStrategy.java
+++ b/src/com/google/android/droiddriver/scroll/AccessibilityEventScrollStepStrategy.java
@@ -188,11 +188,13 @@ public class AccessibilityEventScrollStepStrategy implements ScrollStepStrategy
@Override
public void doScroll(final UiElement container, final PhysicalDirection direction) {
- // We do not call container.scroll(direction) because container.scroll
- // internally calls UiAutomation.executeAndWaitForEvent which clears the
+ // We do not call container.scroll(direction) because it uses a SwipeAction
+ // with positive tTimeoutMillis. That path calls
+ // UiAutomation.executeAndWaitForEvent which clears the
// AccessibilityEvent Queue, preventing us from fetching the last
// accessibility event to determine if scrolling has finished.
- SwipeAction.toScroll(direction).perform(container);
+ container
+ .perform(new SwipeAction(direction, SwipeAction.getScrollSteps(), false /* drag */, 0L/* timeoutMillis */));
}
/**
diff --git a/src/com/google/android/droiddriver/uiautomation/AccessibilityDriver.java b/src/com/google/android/droiddriver/uiautomation/AccessibilityDriver.java
index 63f6a59..6e7441d 100644
--- a/src/com/google/android/droiddriver/uiautomation/AccessibilityDriver.java
+++ b/src/com/google/android/droiddriver/uiautomation/AccessibilityDriver.java
@@ -20,13 +20,20 @@ import android.app.Instrumentation;
import android.view.accessibility.AccessibilityNodeInfo;
import com.google.android.droiddriver.validators.DefaultAccessibilityValidator;
+import com.google.android.droiddriver.validators.ExemptRootValidator;
+import com.google.android.droiddriver.validators.FirstApplicableValidator;
+import com.google.android.droiddriver.validators.ExemptedClassesValidator;
+import com.google.android.droiddriver.validators.ExemptScrollActionValidator;
import com.google.android.droiddriver.validators.Validator;
/**
* A UiAutomationDriver that validates accessibility.
*/
public class AccessibilityDriver extends UiAutomationDriver {
- private static final Validator[] VALIDATORS = {new DefaultAccessibilityValidator()};
+ private Validator validator = new FirstApplicableValidator(new ExemptRootValidator(),
+ new ExemptScrollActionValidator(), new ExemptedClassesValidator(),
+ // TODO: ImageViewValidator
+ new DefaultAccessibilityValidator());
public AccessibilityDriver(Instrumentation instrumentation) {
super(instrumentation);
@@ -36,7 +43,21 @@ public class AccessibilityDriver extends UiAutomationDriver {
protected UiAutomationElement newUiElement(AccessibilityNodeInfo rawElement,
UiAutomationElement parent) {
UiAutomationElement newUiElement = super.newUiElement(rawElement, parent);
- newUiElement.setValidators(VALIDATORS);
+ newUiElement.setValidator(validator);
return newUiElement;
}
+
+ /**
+ * Gets the current validator.
+ */
+ public Validator getValidator() {
+ return validator;
+ }
+
+ /**
+ * Sets the validator to check.
+ */
+ public void setValidator(Validator validator) {
+ this.validator = validator;
+ }
}
diff --git a/src/com/google/android/droiddriver/validators/DefaultAccessibilityValidator.java b/src/com/google/android/droiddriver/validators/DefaultAccessibilityValidator.java
index e3c0778..b220a1b 100644
--- a/src/com/google/android/droiddriver/validators/DefaultAccessibilityValidator.java
+++ b/src/com/google/android/droiddriver/validators/DefaultAccessibilityValidator.java
@@ -19,20 +19,24 @@ package com.google.android.droiddriver.validators;
import android.text.TextUtils;
import com.google.android.droiddriver.UiElement;
+import com.google.android.droiddriver.actions.Action;
/**
- * Validates accessibility.
+ * Fall-back Validator for accessibility.
*/
-// TODO: Treats various types of UiElement as TalkBack does.
public class DefaultAccessibilityValidator implements Validator {
@Override
- public boolean isValid(UiElement element) {
- return !TextUtils.isEmpty(element.getContentDescription())
- || !TextUtils.isEmpty(element.getText());
+ public boolean isApplicable(UiElement element, Action action) {
+ return true;
}
@Override
- public String toString() {
- return "Check non-empty c ontent description or text";
+ public String validate(UiElement element, Action action) {
+ return hasContentDescriptionOrText(element) ? null : "no content description or text";
+ }
+
+ private boolean hasContentDescriptionOrText(UiElement element) {
+ return !TextUtils.isEmpty(element.getContentDescription())
+ || !TextUtils.isEmpty(element.getText());
}
}
diff --git a/src/com/google/android/droiddriver/validators/ExemptRootValidator.java b/src/com/google/android/droiddriver/validators/ExemptRootValidator.java
new file mode 100644
index 0000000..1846e37
--- /dev/null
+++ b/src/com/google/android/droiddriver/validators/ExemptRootValidator.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.validators;
+
+import com.google.android.droiddriver.UiElement;
+import com.google.android.droiddriver.actions.Action;
+
+/**
+ * Exempts root from validation.
+ */
+public class ExemptRootValidator implements Validator {
+ @Override
+ public boolean isApplicable(UiElement element, Action action) {
+ return element.getParent() == null; // don't check root
+ }
+
+ @Override
+ public String validate(UiElement element, Action action) {
+ return null;
+ }
+}
diff --git a/src/com/google/android/droiddriver/validators/ExemptScrollActionValidator.java b/src/com/google/android/droiddriver/validators/ExemptScrollActionValidator.java
new file mode 100644
index 0000000..d6829ed
--- /dev/null
+++ b/src/com/google/android/droiddriver/validators/ExemptScrollActionValidator.java
@@ -0,0 +1,37 @@
+/*
+ * 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.validators;
+
+import com.google.android.droiddriver.UiElement;
+import com.google.android.droiddriver.actions.Action;
+import com.google.android.droiddriver.actions.ScrollAction;
+
+/**
+ * {@link ScrollAction} is not validated as TalkBack does not check the
+ * container.
+ */
+public class ExemptScrollActionValidator implements Validator {
+ @Override
+ public boolean isApplicable(UiElement element, Action action) {
+ return action instanceof ScrollAction;
+ }
+
+ @Override
+ public String validate(UiElement element, Action action) {
+ return null;
+ }
+}
diff --git a/src/com/google/android/droiddriver/validators/ExemptedClassesValidator.java b/src/com/google/android/droiddriver/validators/ExemptedClassesValidator.java
new file mode 100644
index 0000000..b04ffc5
--- /dev/null
+++ b/src/com/google/android/droiddriver/validators/ExemptedClassesValidator.java
@@ -0,0 +1,60 @@
+/*
+ * 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.validators;
+
+import android.util.Log;
+
+import com.google.android.droiddriver.UiElement;
+import com.google.android.droiddriver.actions.Action;
+import com.google.android.droiddriver.util.Logs;
+
+/**
+ * Always validates the classes that TalkBack always has speech.
+ */
+public class ExemptedClassesValidator implements Validator {
+ private static final Class<?>[] EXEMPTED_CLASSES = {android.widget.Spinner.class,
+ android.widget.EditText.class, android.widget.SeekBar.class,
+ android.widget.AbsListView.class, android.widget.TabWidget.class};
+
+ @Override
+ public boolean isApplicable(UiElement element, Action action) {
+ String className = element.getClassName();
+ if (className == null || className.isEmpty()) {
+ return false;
+ }
+
+ Class<?> elementClass = null;
+ try {
+ elementClass = Class.forName(className);
+ } catch (ClassNotFoundException e) {
+ Logs.log(Log.WARN, e);
+ return false;
+ }
+
+ for (Class<?> clazz : EXEMPTED_CLASSES) {
+ if (clazz.isAssignableFrom(elementClass)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public String validate(UiElement element, Action action) {
+ return null;
+ }
+}
diff --git a/src/com/google/android/droiddriver/validators/FirstApplicableValidator.java b/src/com/google/android/droiddriver/validators/FirstApplicableValidator.java
new file mode 100644
index 0000000..1c89907
--- /dev/null
+++ b/src/com/google/android/droiddriver/validators/FirstApplicableValidator.java
@@ -0,0 +1,47 @@
+/*
+ * 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.validators;
+
+import com.google.android.droiddriver.UiElement;
+import com.google.android.droiddriver.actions.Action;
+
+/**
+ * Iterates an array of validators and validates against the first one that is
+ * applicable. Note the order of validators matters.
+ */
+public class FirstApplicableValidator implements Validator {
+ private final Validator[] validators;
+
+ public FirstApplicableValidator(Validator... validators) {
+ this.validators = validators;
+ }
+
+ @Override
+ public boolean isApplicable(UiElement element, Action action) {
+ return true;
+ }
+
+ @Override
+ public String validate(UiElement element, Action action) {
+ for (Validator validator : validators) {
+ if (validator.isApplicable(element, action)) {
+ return validator.validate(element, action);
+ }
+ }
+ return "no applicable validator";
+ }
+}
diff --git a/src/com/google/android/droiddriver/validators/Validator.java b/src/com/google/android/droiddriver/validators/Validator.java
index f7812ed..4c0debb 100644
--- a/src/com/google/android/droiddriver/validators/Validator.java
+++ b/src/com/google/android/droiddriver/validators/Validator.java
@@ -17,6 +17,7 @@
package com.google.android.droiddriver.validators;
import com.google.android.droiddriver.UiElement;
+import com.google.android.droiddriver.actions.Action;
/**
* Interface for validating a UiElement, checked when an action is performed.
@@ -25,7 +26,14 @@ import com.google.android.droiddriver.UiElement;
*/
public interface Validator {
/**
- * Returns true if {@code element} is valid.
+ * Returns true if this {@link Validator} applies to {@code element} on this
+ * {@code action}.
*/
- boolean isValid(UiElement element);
+ boolean isApplicable(UiElement element, Action action);
+
+ /**
+ * Returns {@code null} if {@code element} is valid on this {@code action},
+ * otherwise a string describing the failure.
+ */
+ String validate(UiElement element, Action action);
}
diff --git a/src/com/google/android/droiddriver/validators/VisibilityValidator.java b/src/com/google/android/droiddriver/validators/VisibilityValidator.java
index 44570cf..df19bd7 100644
--- a/src/com/google/android/droiddriver/validators/VisibilityValidator.java
+++ b/src/com/google/android/droiddriver/validators/VisibilityValidator.java
@@ -17,13 +17,19 @@
package com.google.android.droiddriver.validators;
import com.google.android.droiddriver.UiElement;
+import com.google.android.droiddriver.actions.Action;
/**
* Validates visibility.
*/
public class VisibilityValidator implements Validator {
@Override
- public boolean isValid(UiElement element) {
- return element.isVisible();
+ public boolean isApplicable(UiElement element, Action action) {
+ return true;
+ }
+
+ @Override
+ public String validate(UiElement element, Action action) {
+ return element.isVisible() ? null : "invisible";
}
}