From 17342a5115d7575d44a99fed9c7032e3ab316dcc Mon Sep 17 00:00:00 2001 From: Kevin Jin Date: Fri, 18 Apr 2014 15:28:36 -0700 Subject: remove deps on Guava This is to simplify the build and deployment set-up for DroidDriver clients. Change-Id: I02238d8721d4d3a505a851138c40cb086d2ff11f --- src/com/google/android/droiddriver/UiElement.java | 2 +- .../droiddriver/actions/SingleKeyAction.java | 4 +- .../android/droiddriver/actions/SwipeAction.java | 9 +- .../android/droiddriver/actions/TextAction.java | 6 +- .../android/droiddriver/base/BaseUiElement.java | 30 ++-- .../android/droiddriver/base/DefaultPoller.java | 9 +- src/com/google/android/droiddriver/finders/By.java | 125 +++----------- .../android/droiddriver/finders/ByAttribute.java | 20 +-- .../android/droiddriver/finders/ByXPath.java | 37 +++-- .../android/droiddriver/finders/ChainFinder.java | 2 +- .../google/android/droiddriver/finders/Finder.java | 2 +- .../android/droiddriver/finders/MatchFinder.java | 17 +- .../android/droiddriver/finders/Predicate.java | 49 ++++++ .../android/droiddriver/finders/Predicates.java | 179 +++++++++++++++++++++ .../google/android/droiddriver/finders/XPaths.java | 8 +- .../droiddriver/helpers/UnrecoverableFailure.java | 1 - .../instrumentation/InstrumentationContext.java | 4 +- .../instrumentation/InstrumentationDriver.java | 3 +- .../droiddriver/instrumentation/ViewElement.java | 37 ++--- .../android/droiddriver/runner/TestRunner.java | 6 +- .../scroll/DynamicSentinelStrategy.java | 4 +- .../droiddriver/scroll/SentinelStrategy.java | 14 +- .../uiautomation/UiAutomationContext.java | 6 +- .../uiautomation/UiAutomationDriver.java | 3 +- .../uiautomation/UiAutomationElement.java | 19 ++- .../android/droiddriver/util/ActivityUtils.java | 11 +- src/com/google/android/droiddriver/util/Logs.java | 5 +- .../android/droiddriver/util/Preconditions.java | 40 +++++ .../google/android/droiddriver/util/Strings.java | 66 ++++++++ .../google/android/droiddriver/util/TextUtils.java | 26 --- 30 files changed, 481 insertions(+), 263 deletions(-) create mode 100644 src/com/google/android/droiddriver/finders/Predicate.java create mode 100644 src/com/google/android/droiddriver/finders/Predicates.java create mode 100644 src/com/google/android/droiddriver/util/Preconditions.java create mode 100644 src/com/google/android/droiddriver/util/Strings.java delete mode 100644 src/com/google/android/droiddriver/util/TextUtils.java (limited to 'src') diff --git a/src/com/google/android/droiddriver/UiElement.java b/src/com/google/android/droiddriver/UiElement.java index 924197f..a2e7017 100644 --- a/src/com/google/android/droiddriver/UiElement.java +++ b/src/com/google/android/droiddriver/UiElement.java @@ -22,10 +22,10 @@ import com.google.android.droiddriver.actions.Action; import com.google.android.droiddriver.actions.InputInjector; import com.google.android.droiddriver.exceptions.ElementNotVisibleException; import com.google.android.droiddriver.finders.Attribute; +import com.google.android.droiddriver.finders.Predicate; import com.google.android.droiddriver.instrumentation.InstrumentationDriver; import com.google.android.droiddriver.scroll.Direction.PhysicalDirection; import com.google.android.droiddriver.uiautomation.UiAutomationDriver; -import com.google.common.base.Predicate; import java.util.List; diff --git a/src/com/google/android/droiddriver/actions/SingleKeyAction.java b/src/com/google/android/droiddriver/actions/SingleKeyAction.java index 9faba80..853840e 100644 --- a/src/com/google/android/droiddriver/actions/SingleKeyAction.java +++ b/src/com/google/android/droiddriver/actions/SingleKeyAction.java @@ -22,7 +22,7 @@ import android.view.KeyEvent; import com.google.android.droiddriver.UiElement; import com.google.android.droiddriver.util.Events; -import com.google.common.base.Objects; +import com.google.android.droiddriver.util.Strings; /** * An action to press a single key. While it is convenient for navigating the @@ -70,6 +70,6 @@ public class SingleKeyAction extends KeyAction { String keyCodeString = Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB_MR1 ? String.valueOf(keyCode) : KeyEvent.keyCodeToString(keyCode); - return Objects.toStringHelper(this).addValue(keyCodeString).toString(); + return Strings.toStringHelper(this).addValue(keyCodeString).toString(); } } diff --git a/src/com/google/android/droiddriver/actions/SwipeAction.java b/src/com/google/android/droiddriver/actions/SwipeAction.java index 71241bb..b946e9f 100644 --- a/src/com/google/android/droiddriver/actions/SwipeAction.java +++ b/src/com/google/android/droiddriver/actions/SwipeAction.java @@ -30,9 +30,8 @@ import com.google.android.droiddriver.UiElement; import com.google.android.droiddriver.exceptions.ActionException; import com.google.android.droiddriver.scroll.Direction.PhysicalDirection; import com.google.android.droiddriver.util.Events; -import com.google.common.base.Objects; -import com.google.common.base.Objects.ToStringHelper; -import com.google.common.primitives.Ints; +import com.google.android.droiddriver.util.Strings; +import com.google.android.droiddriver.util.Strings.ToStringHelper; /** * A {@link ScrollAction} that swipes the touch screen. Note the scroll @@ -165,7 +164,7 @@ public class SwipeAction extends ScrollAction { float topMarginRatio, float leftMarginRatio, float bottomMarginRatio, float rightMarginRatio) { super(timeoutMillis); this.direction = direction; - this.steps = Ints.max(2, steps); + this.steps = Math.max(2, steps); this.drag = drag; this.topMarginRatio = topMarginRatio; this.bottomMarginRatio = bottomMarginRatio; @@ -242,7 +241,7 @@ public class SwipeAction extends ScrollAction { @Override public String toString() { - ToStringHelper toStringHelper = Objects.toStringHelper(this); + ToStringHelper toStringHelper = Strings.toStringHelper(this); toStringHelper.addValue(direction); toStringHelper.add("steps", steps); if (drag) { diff --git a/src/com/google/android/droiddriver/actions/TextAction.java b/src/com/google/android/droiddriver/actions/TextAction.java index 35f13bd..586ad4e 100644 --- a/src/com/google/android/droiddriver/actions/TextAction.java +++ b/src/com/google/android/droiddriver/actions/TextAction.java @@ -23,8 +23,8 @@ import android.view.KeyEvent; import com.google.android.droiddriver.UiElement; import com.google.android.droiddriver.exceptions.ActionException; -import com.google.common.base.Objects; -import com.google.common.base.Preconditions; +import com.google.android.droiddriver.util.Preconditions; +import com.google.android.droiddriver.util.Strings; /** * An action to type text. @@ -80,6 +80,6 @@ public class TextAction extends KeyAction { @Override public String toString() { - return Objects.toStringHelper(this).addValue(text).toString(); + return Strings.toStringHelper(this).addValue(text).toString(); } } diff --git a/src/com/google/android/droiddriver/base/BaseUiElement.java b/src/com/google/android/droiddriver/base/BaseUiElement.java index 0db6c6a..1478505 100644 --- a/src/com/google/android/droiddriver/base/BaseUiElement.java +++ b/src/com/google/android/droiddriver/base/BaseUiElement.java @@ -25,15 +25,15 @@ import com.google.android.droiddriver.actions.SwipeAction; import com.google.android.droiddriver.actions.TextAction; import com.google.android.droiddriver.exceptions.ElementNotVisibleException; import com.google.android.droiddriver.finders.Attribute; +import com.google.android.droiddriver.finders.Predicate; +import com.google.android.droiddriver.finders.Predicates; import com.google.android.droiddriver.scroll.Direction.PhysicalDirection; import com.google.android.droiddriver.util.Logs; -import com.google.common.base.Objects; -import com.google.common.base.Objects.ToStringHelper; -import com.google.common.base.Predicate; -import com.google.common.base.Predicates; -import com.google.common.collect.Collections2; -import com.google.common.collect.ImmutableList; +import com.google.android.droiddriver.util.Strings; +import com.google.android.droiddriver.util.Strings.ToStringHelper; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; @@ -234,20 +234,26 @@ public abstract class BaseUiElement implements UiElement { public List getChildren(Predicate predicate) { List children = getChildren(); if (children == null) { - return ImmutableList.of(); + return Collections.emptyList(); } - if (predicate == null || predicate.equals(Predicates.alwaysTrue())) { + if (predicate == null || predicate.equals(Predicates.any())) { return children; } - return ImmutableList.copyOf(Collections2.filter(children, predicate)); + List filteredChildren = new ArrayList(children.size()); + for (BaseUiElement child : children) { + if (predicate.apply(child)) { + filteredChildren.add(child); + } + } + return Collections.unmodifiableList(filteredChildren); } @Override public String toString() { - ToStringHelper toStringHelper = Objects.toStringHelper(this); - for (Attribute attr : Attribute.values()) { - addAttribute(toStringHelper, attr, get(attr)); + ToStringHelper toStringHelper = Strings.toStringHelper(this); + for (Map.Entry entry : getAttributes().entrySet()) { + addAttribute(toStringHelper, entry.getKey(), entry.getValue()); } if (!isVisible()) { toStringHelper.addValue(ATTRIB_NOT_VISIBLE); diff --git a/src/com/google/android/droiddriver/base/DefaultPoller.java b/src/com/google/android/droiddriver/base/DefaultPoller.java index 923e1b6..c6d69c5 100644 --- a/src/com/google/android/droiddriver/base/DefaultPoller.java +++ b/src/com/google/android/droiddriver/base/DefaultPoller.java @@ -22,17 +22,16 @@ import com.google.android.droiddriver.DroidDriver; import com.google.android.droiddriver.Poller; import com.google.android.droiddriver.exceptions.TimeoutException; import com.google.android.droiddriver.finders.Finder; -import com.google.common.collect.Lists; -import com.google.common.primitives.Longs; import java.util.Collection; +import java.util.LinkedList; /** * Default implementation of a {@link Poller}. */ public class DefaultPoller implements Poller { - private final Collection timeoutListeners = Lists.newLinkedList(); - private final Collection pollingListeners = Lists.newLinkedList(); + private final Collection timeoutListeners = new LinkedList(); + private final Collection pollingListeners = new LinkedList(); private long timeoutMillis = 10000; private long intervalMillis = 500; @@ -85,7 +84,7 @@ public class DefaultPoller implements Poller { throw new TimeoutException(String.format( "Timed out after %d milliseconds waiting for %s %s", timeoutMillis, finder, checker)); } - SystemClock.sleep(Longs.min(intervalMillis, remainingMillis)); + SystemClock.sleep(Math.min(intervalMillis, remainingMillis)); } } diff --git a/src/com/google/android/droiddriver/finders/By.java b/src/com/google/android/droiddriver/finders/By.java index 5e7f322..e23a244 100644 --- a/src/com/google/android/droiddriver/finders/By.java +++ b/src/com/google/android/droiddriver/finders/By.java @@ -16,28 +16,16 @@ package com.google.android.droiddriver.finders; -import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.android.droiddriver.util.Preconditions.checkNotNull; import com.google.android.droiddriver.UiElement; import com.google.android.droiddriver.exceptions.ElementNotFoundException; -import com.google.common.base.Joiner; -import com.google.common.base.Objects; -import com.google.common.base.Predicate; -import com.google.common.base.Predicates; -import com.google.common.collect.Lists; - -import java.util.List; /** * Convenience methods to create commonly used finders. */ public class By { - private static final MatchFinder ANY = new MatchFinder(null) { - @Override - public String toString() { - return "any"; - } - }; + private static final MatchFinder ANY = new MatchFinder(null); /** Matches any UiElement. */ public static MatchFinder any() { @@ -48,7 +36,7 @@ public class By { public static final MatchStrategy OBJECT_EQUALS = new MatchStrategy() { @Override public boolean match(Object expected, Object actual) { - return Objects.equal(actual, expected); + return actual == expected || (actual != null && actual.equals(expected)); } @Override @@ -246,16 +234,15 @@ public class By { return new ChainFinder(first, second); } - private static List> getPredicates(MatchFinder... finders) { - List> predicates = - Lists.newArrayListWithExpectedSize(finders.length); - for (MatchFinder finder : finders) { - predicates.add(finder.predicate); + private static Predicate[] getPredicates(MatchFinder... finders) { + @SuppressWarnings("unchecked") + Predicate[] predicates = new Predicate[finders.length]; + for (int i = 0; i < finders.length; i++) { + predicates[i] = finders[i].predicate; } return predicates; } - // Hamcrest style finder aggregators /** * Evaluates given {@finders} in short-circuit fashion in the order * they are passed. Costly finders (for example those returned by with* @@ -265,12 +252,7 @@ public class By { * @return a finder that is the logical conjunction of given finders */ public static MatchFinder allOf(final MatchFinder... finders) { - return new MatchFinder(Predicates.and(getPredicates(finders))) { - @Override - public String toString() { - return "allOf(" + Joiner.on(", ").join(finders) + ")"; - } - }; + return new MatchFinder(Predicates.allOf(getPredicates(finders))); } /** @@ -282,110 +264,43 @@ public class By { * @return a finder that is the logical disjunction of given finders */ public static MatchFinder anyOf(final MatchFinder... finders) { - return new MatchFinder(Predicates.or(getPredicates(finders))) { - @Override - public String toString() { - return "anyOf(" + Joiner.on(", ").join(finders) + ")"; - } - }; + return new MatchFinder(Predicates.anyOf(getPredicates(finders))); } /** * Matches a UiElement whose parent matches the given parentFinder. For * complex cases, consider {@link #xpath}. */ - public static MatchFinder withParent(final MatchFinder parentFinder) { + public static MatchFinder withParent(MatchFinder parentFinder) { checkNotNull(parentFinder); - return new MatchFinder(new Predicate() { - @Override - public boolean apply(UiElement element) { - UiElement parent = element.getParent(); - return parent != null && parentFinder.matches(parent); - } - }) { - @Override - public String toString() { - return "withParent(" + parentFinder + ")"; - } - }; + return new MatchFinder(Predicates.withParent(parentFinder.predicate)); } /** * Matches a UiElement whose ancestor matches the given ancestorFinder. For * complex cases, consider {@link #xpath}. */ - public static MatchFinder withAncestor(final MatchFinder ancestorFinder) { + public static MatchFinder withAncestor(MatchFinder ancestorFinder) { checkNotNull(ancestorFinder); - return new MatchFinder(new Predicate() { - @Override - public boolean apply(UiElement element) { - UiElement parent = element.getParent(); - while (parent != null) { - if (ancestorFinder.matches(parent)) { - return true; - } - parent = parent.getParent(); - } - return false; - } - }) { - @Override - public String toString() { - return "withAncestor(" + ancestorFinder + ")"; - } - }; + return new MatchFinder(Predicates.withAncestor(ancestorFinder.predicate)); } /** * Matches a UiElement which has a visible sibling matching the given * siblingFinder. This could be inefficient; consider {@link #xpath}. */ - public static MatchFinder withSibling(final MatchFinder siblingFinder) { + public static MatchFinder withSibling(MatchFinder siblingFinder) { checkNotNull(siblingFinder); - return new MatchFinder(new Predicate() { - @Override - public boolean apply(UiElement element) { - UiElement parent = element.getParent(); - if (parent == null) { - return false; - } - for (UiElement sibling : parent.getChildren(UiElement.VISIBLE)) { - if (sibling != element && siblingFinder.matches(sibling)) { - return true; - } - } - return false; - } - }) { - @Override - public String toString() { - return "withSibling(" + siblingFinder + ")"; - } - }; + return new MatchFinder(Predicates.withSibling(siblingFinder.predicate)); } /** * Matches a UiElement which has a visible child matching the given * childFinder. This could be inefficient; consider {@link #xpath}. */ - public static MatchFinder withChild(final MatchFinder childFinder) { + public static MatchFinder withChild(MatchFinder childFinder) { checkNotNull(childFinder); - return new MatchFinder(new Predicate() { - @Override - public boolean apply(UiElement element) { - for (UiElement child : element.getChildren(UiElement.VISIBLE)) { - if (childFinder.matches(child)) { - return true; - } - } - return false; - } - }) { - @Override - public String toString() { - return "withChild(" + childFinder + ")"; - } - }; + return new MatchFinder(Predicates.withChild(childFinder.predicate)); } /** @@ -404,12 +319,12 @@ public class By { return false; } } - }) { + @Override public String toString() { return "withDescendant(" + descendantFinder + ")"; } - }; + }); } private By() {} diff --git a/src/com/google/android/droiddriver/finders/ByAttribute.java b/src/com/google/android/droiddriver/finders/ByAttribute.java index a797a6d..8790334 100644 --- a/src/com/google/android/droiddriver/finders/ByAttribute.java +++ b/src/com/google/android/droiddriver/finders/ByAttribute.java @@ -15,19 +15,12 @@ */ package com.google.android.droiddriver.finders; -import static com.google.common.base.Preconditions.checkNotNull; - import com.google.android.droiddriver.UiElement; -import com.google.common.base.Predicate; /** * Matches UiElement by a single attribute. */ public class ByAttribute extends MatchFinder { - private final Attribute attribute; - private final MatchStrategy strategy; - private final T expected; - protected ByAttribute(final Attribute attribute, final MatchStrategy strategy, final T expected) { super(new Predicate() { @@ -36,14 +29,11 @@ public class ByAttribute extends MatchFinder { T value = element.get(attribute); return strategy.match(expected, value); } - }); - this.attribute = checkNotNull(attribute); - this.strategy = checkNotNull(strategy); - this.expected = checkNotNull(expected); - } - @Override - public String toString() { - return String.format("{%s %s %s}", attribute, strategy, expected); + @Override + public String toString() { + return String.format("{%s %s %s}", attribute, strategy, expected); + } + }); } } diff --git a/src/com/google/android/droiddriver/finders/ByXPath.java b/src/com/google/android/droiddriver/finders/ByXPath.java index fce8f0d..30cc251 100644 --- a/src/com/google/android/droiddriver/finders/ByXPath.java +++ b/src/com/google/android/droiddriver/finders/ByXPath.java @@ -23,17 +23,16 @@ import com.google.android.droiddriver.exceptions.DroidDriverException; import com.google.android.droiddriver.exceptions.ElementNotFoundException; import com.google.android.droiddriver.util.FileUtils; import com.google.android.droiddriver.util.Logs; -import com.google.common.base.Objects; -import com.google.common.base.Preconditions; -import com.google.common.base.Predicate; -import com.google.common.collect.BiMap; -import com.google.common.collect.HashBiMap; +import com.google.android.droiddriver.util.Preconditions; +import com.google.android.droiddriver.util.Strings; import org.w3c.dom.DOMException; import org.w3c.dom.Document; import org.w3c.dom.Element; import java.io.BufferedOutputStream; +import java.util.HashMap; +import java.util.Map; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; @@ -55,12 +54,16 @@ public class ByXPath implements Finder { private static final XPath XPATH_COMPILER = XPathFactory.newInstance().newXPath(); // document needs to be static so that when buildDomNode is called recursively // on children they are in the same document to be appended. - // TODO: move the below two to DroidDriverContext? private static Document document; - private static BiMap domBiMap = HashBiMap.create(); + // The two maps should be kept in sync + private static final Map TO_DOM_MAP = + new HashMap(); + private static final Map FROM_DOM_MAP = + new HashMap(); public static void clearData() { - domBiMap.clear(); + TO_DOM_MAP.clear(); + FROM_DOM_MAP.clear(); document = null; } @@ -78,7 +81,7 @@ public class ByXPath implements Finder { @Override public String toString() { - return Objects.toStringHelper(this).addValue(xPathString).toString(); + return Strings.toStringHelper(this).addValue(xPathString).toString(); } @Override @@ -92,7 +95,7 @@ public class ByXPath implements Finder { throw new ElementNotFoundException(this); } - UiElement match = domBiMap.inverse().get(foundNode); + UiElement match = FROM_DOM_MAP.get(foundNode); Logs.log(Log.INFO, "Found match: " + match); return match; } catch (XPathExpressionException e) { @@ -122,7 +125,7 @@ public class ByXPath implements Finder { * Returns the DOM node representing this UiElement. */ private static Element getDomNode(BaseUiElement uiElement, Predicate predicate) { - Element domNode = domBiMap.get(uiElement); + Element domNode = TO_DOM_MAP.get(uiElement); if (domNode == null) { domNode = buildDomNode(uiElement, predicate); } @@ -136,7 +139,8 @@ public class ByXPath implements Finder { className = "UNKNOWN"; } Element element = getDocument().createElement(XPaths.tag(className)); - domBiMap.put(uiElement, element); + TO_DOM_MAP.put(uiElement, element); + FROM_DOM_MAP.put(element, uiElement); setAttribute(element, Attribute.CLASS, className); setAttribute(element, Attribute.RESOURCE_ID, uiElement.getResourceId()); @@ -191,15 +195,16 @@ public class ByXPath implements Finder { } public static boolean dumpDom(String path, BaseUiElement uiElement) { - // find() filters invisible UiElements, but this is for debugging and - // invisible UiElements may be of interest. - clearData(); BufferedOutputStream bos = null; try { bos = FileUtils.open(path); Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - transformer.transform(new DOMSource(getDomNode(uiElement, null)), new StreamResult(bos)); + // find() filters invisible UiElements, but this is for debugging and + // invisible UiElements may be of interest. + clearData(); + Element domNode = getDomNode(uiElement, null); + transformer.transform(new DOMSource(domNode), new StreamResult(bos)); Logs.log(Log.INFO, "Wrote dom to " + path); } catch (Exception e) { Logs.log(Log.ERROR, e, "Failed to transform node"); diff --git a/src/com/google/android/droiddriver/finders/ChainFinder.java b/src/com/google/android/droiddriver/finders/ChainFinder.java index db6bb47..6e42903 100644 --- a/src/com/google/android/droiddriver/finders/ChainFinder.java +++ b/src/com/google/android/droiddriver/finders/ChainFinder.java @@ -17,7 +17,7 @@ package com.google.android.droiddriver.finders; import com.google.android.droiddriver.UiElement; -import com.google.common.base.Preconditions; +import com.google.android.droiddriver.util.Preconditions; /** * Finds UiElement by applying Finders in turn: using the UiElement returned by diff --git a/src/com/google/android/droiddriver/finders/Finder.java b/src/com/google/android/droiddriver/finders/Finder.java index 884b4f4..7c56d25 100644 --- a/src/com/google/android/droiddriver/finders/Finder.java +++ b/src/com/google/android/droiddriver/finders/Finder.java @@ -39,7 +39,7 @@ public interface Finder { * *

* It is recommended that this method return the description of the finder, - * for example, "ByAttribute{text equals OK}". + * for example, "{text equals OK}". */ @Override String toString(); diff --git a/src/com/google/android/droiddriver/finders/MatchFinder.java b/src/com/google/android/droiddriver/finders/MatchFinder.java index 33fe699..1ee60e0 100644 --- a/src/com/google/android/droiddriver/finders/MatchFinder.java +++ b/src/com/google/android/droiddriver/finders/MatchFinder.java @@ -21,33 +21,26 @@ import android.util.Log; import com.google.android.droiddriver.UiElement; import com.google.android.droiddriver.exceptions.ElementNotFoundException; import com.google.android.droiddriver.util.Logs; -import com.google.common.base.Predicate; -import com.google.common.base.Predicates; /** * Traverses the UiElement tree and returns the first UiElement satisfying * {@link #predicate}. */ -public abstract class MatchFinder implements Finder { +public class MatchFinder implements Finder { protected final Predicate predicate; protected MatchFinder(Predicate predicate) { if (predicate == null) { - this.predicate = Predicates.alwaysTrue(); + this.predicate = Predicates.any(); } else { this.predicate = predicate; } } - /** - * {@inheritDoc} - * - *

- * It is recommended that this method return the description of the finder, - * for example, "ByAttribute{text equals OK}". - */ @Override - public abstract String toString(); + public String toString() { + return predicate.toString(); + } @Override public UiElement find(UiElement context) { diff --git a/src/com/google/android/droiddriver/finders/Predicate.java b/src/com/google/android/droiddriver/finders/Predicate.java new file mode 100644 index 0000000..18b3e66 --- /dev/null +++ b/src/com/google/android/droiddriver/finders/Predicate.java @@ -0,0 +1,49 @@ +/* + * 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.finders; + +/** + * Determines a true or false value for a given input. + * + * This is replicated from the open-source Guava libraries. + *

+ * Many apps use Guava. If a test apk also contains a copy of Guava, duplicated + * classes in app and test apks may cause error at run-time: + * "Class ref in pre-verified class resolved to unexpected implementation". To + * simplify the build and deployment set-up, DroidDriver copies the code of some + * Guava classes (often simplified) to this package such that it does not depend + * on Guava. + *

+ */ +public interface Predicate { + /** + * Returns the result of applying this predicate to {@code input}. + */ + boolean apply(T input); + + /** + * {@inheritDoc} + * + *

+ * It is recommended that this method return the description of this + * Predicate. + *

+ */ + @Override + String toString(); +} diff --git a/src/com/google/android/droiddriver/finders/Predicates.java b/src/com/google/android/droiddriver/finders/Predicates.java new file mode 100644 index 0000000..ecfafdd --- /dev/null +++ b/src/com/google/android/droiddriver/finders/Predicates.java @@ -0,0 +1,179 @@ +/* + * 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.finders; + +import android.text.TextUtils; + +import com.google.android.droiddriver.UiElement; + +/** + * Static utility methods pertaining to {@code Predicate} instances. + */ +public final class Predicates { + private Predicates() {} + + private static final Predicate ANY = new Predicate() { + @Override + public boolean apply(Object o) { + return true; + } + + @Override + public String toString() { + return "any"; + } + }; + + /** + * Returns a predicate that always evaluates to {@code true}. + */ + @SuppressWarnings("unchecked") + public static Predicate any() { + return (Predicate) ANY; + } + + /** + * 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. + */ + public static Predicate allOf( + @SuppressWarnings("unchecked") final Predicate... components) { + return new Predicate() { + @Override + public boolean apply(T input) { + for (Predicate each : components) { + if (!each.apply(input)) { + return false; + } + } + return true; + } + + @Override + public String toString() { + return "allOf(" + TextUtils.join(", ", 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 Predicate anyOf( + @SuppressWarnings("unchecked") final Predicate... components) { + return new Predicate() { + @Override + public boolean apply(T input) { + for (Predicate each : components) { + if (each.apply(input)) { + return true; + } + } + return false; + } + + @Override + public String toString() { + return "anyOf(" + TextUtils.join(", ", components) + ")"; + } + }; + } + + public static Predicate withParent(final Predicate parentPredicate) { + return new Predicate() { + @Override + public boolean apply(UiElement element) { + UiElement parent = element.getParent(); + return parent != null && parentPredicate.apply(parent); + } + + @Override + public String toString() { + return "withParent(" + parentPredicate + ")"; + } + }; + } + + public static Predicate withAncestor( + final Predicate ancestorPredicate) { + return new Predicate() { + @Override + public boolean apply(UiElement element) { + UiElement parent = element.getParent(); + while (parent != null) { + if (ancestorPredicate.apply(parent)) { + return true; + } + parent = parent.getParent(); + } + return false; + } + + @Override + public String toString() { + return "withAncestor(" + ancestorPredicate + ")"; + } + }; + } + + public static Predicate withSibling(final Predicate siblingPredicate) { + return new Predicate() { + @Override + public boolean apply(UiElement element) { + UiElement parent = element.getParent(); + if (parent == null) { + return false; + } + for (UiElement sibling : parent.getChildren(UiElement.VISIBLE)) { + if (sibling != element && siblingPredicate.apply(sibling)) { + return true; + } + } + return false; + } + + @Override + public String toString() { + return "withSibling(" + siblingPredicate + ")"; + } + }; + } + + public static Predicate withChild(final Predicate childPredicate) { + return new Predicate() { + @Override + public boolean apply(UiElement element) { + for (UiElement child : element.getChildren(UiElement.VISIBLE)) { + if (childPredicate.apply(child)) { + return true; + } + } + return false; + } + + @Override + public String toString() { + return "withChild(" + childPredicate + ")"; + } + }; + } +} diff --git a/src/com/google/android/droiddriver/finders/XPaths.java b/src/com/google/android/droiddriver/finders/XPaths.java index 3680c54..ef97d2d 100644 --- a/src/com/google/android/droiddriver/finders/XPaths.java +++ b/src/com/google/android/droiddriver/finders/XPaths.java @@ -16,8 +16,7 @@ package com.google.android.droiddriver.finders; -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Joiner; +import android.text.TextUtils; /** * Convenience methods and constants for XPath. @@ -44,7 +43,7 @@ public class XPaths { * this to build XPath instead of String literals. */ public static String tag(Class clazz) { - return tag(clazz.getName()); + return tag(clazz.getSimpleName()); } private static String simpleClassName(String name) { @@ -116,7 +115,6 @@ public class XPaths { * produce very long XPath expressions if a value contains a long run of * double quotes. */ - @VisibleForTesting static String quoteXPathLiteral(String value) { // if the value contains only single or double quotes, construct an XPath // literal @@ -133,7 +131,7 @@ public class XPaths { // concat("foo", '"', "bar") StringBuilder sb = new StringBuilder(); sb.append("concat(\""); - Joiner.on("\",'\"',\"").appendTo(sb, value.split("\"")); + sb.append(TextUtils.join("\",'\"',\"", value.split("\""))); sb.append("\")"); return sb.toString(); } diff --git a/src/com/google/android/droiddriver/helpers/UnrecoverableFailure.java b/src/com/google/android/droiddriver/helpers/UnrecoverableFailure.java index e8de98e..390af39 100644 --- a/src/com/google/android/droiddriver/helpers/UnrecoverableFailure.java +++ b/src/com/google/android/droiddriver/helpers/UnrecoverableFailure.java @@ -16,7 +16,6 @@ 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 diff --git a/src/com/google/android/droiddriver/instrumentation/InstrumentationContext.java b/src/com/google/android/droiddriver/instrumentation/InstrumentationContext.java index f68dc6e..52e423a 100644 --- a/src/com/google/android/droiddriver/instrumentation/InstrumentationContext.java +++ b/src/com/google/android/droiddriver/instrumentation/InstrumentationContext.java @@ -26,12 +26,12 @@ import com.google.android.droiddriver.actions.InputInjector; import com.google.android.droiddriver.base.DroidDriverContext; import com.google.android.droiddriver.exceptions.ActionException; import com.google.android.droiddriver.finders.ByXPath; -import com.google.common.collect.MapMaker; import java.util.Map; +import java.util.WeakHashMap; class InstrumentationContext extends DroidDriverContext { - private final Map map = new MapMaker().weakKeys().weakValues().makeMap(); + private final Map map = new WeakHashMap(); private final InstrumentationDriver driver; private final InputInjector injector; diff --git a/src/com/google/android/droiddriver/instrumentation/InstrumentationDriver.java b/src/com/google/android/droiddriver/instrumentation/InstrumentationDriver.java index 47635e6..adf14e2 100644 --- a/src/com/google/android/droiddriver/instrumentation/InstrumentationDriver.java +++ b/src/com/google/android/droiddriver/instrumentation/InstrumentationDriver.java @@ -31,7 +31,6 @@ import com.google.android.droiddriver.exceptions.DroidDriverException; import com.google.android.droiddriver.exceptions.TimeoutException; import com.google.android.droiddriver.util.ActivityUtils; import com.google.android.droiddriver.util.Logs; -import com.google.common.primitives.Longs; /** * Implementation of DroidDriver that is driven via instrumentation. @@ -103,7 +102,7 @@ public class InstrumentationDriver extends BaseDroidDriver { throw new TimeoutException(String.format( "Timed out after %d milliseconds waiting for foreground activity", timeoutMillis)); } - SystemClock.sleep(Longs.min(250, remainingMillis)); + SystemClock.sleep(Math.min(250, remainingMillis)); } } diff --git a/src/com/google/android/droiddriver/instrumentation/ViewElement.java b/src/com/google/android/droiddriver/instrumentation/ViewElement.java index 0b1f360..e38929a 100644 --- a/src/com/google/android/droiddriver/instrumentation/ViewElement.java +++ b/src/com/google/android/droiddriver/instrumentation/ViewElement.java @@ -16,7 +16,7 @@ package com.google.android.droiddriver.instrumentation; -import static com.google.android.droiddriver.util.TextUtils.charSequenceToString; +import static com.google.android.droiddriver.util.Strings.charSequenceToString; import android.content.res.Resources; import android.graphics.Rect; @@ -30,13 +30,12 @@ import com.google.android.droiddriver.actions.InputInjector; import com.google.android.droiddriver.base.BaseUiElement; import com.google.android.droiddriver.exceptions.DroidDriverException; import com.google.android.droiddriver.finders.Attribute; -import com.google.common.base.Function; -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; +import com.google.android.droiddriver.util.Preconditions; +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumMap; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.FutureTask; @@ -47,7 +46,7 @@ import java.util.concurrent.FutureTask; public class ViewElement extends BaseUiElement { private static class SnapshotViewAttributesRunnable implements Runnable { private final View view; - final Map attribs = Maps.newEnumMap(Attribute.class); + final Map attribs = new EnumMap(Attribute.class); boolean visible; Rect visibleBounds; List childViews; @@ -171,7 +170,7 @@ public class ViewElement extends BaseUiElement { } ViewGroup group = (ViewGroup) view; int childCount = group.getChildCount(); - childViews = Lists.newArrayListWithExpectedSize(childCount); + childViews = new ArrayList(childCount); for (int i = 0; i < childCount; i++) { View child = group.getChildAt(i); if (child != null) { @@ -181,7 +180,7 @@ public class ViewElement extends BaseUiElement { } } - private static final Map CLASS_NAME_OVERRIDES = Maps.newHashMap(); + private static final Map CLASS_NAME_OVERRIDES = new HashMap(); /** * Typically users find the class name to use in tests using SDK tool @@ -228,16 +227,18 @@ public class ViewElement extends BaseUiElement { throw new DroidDriverException(attributesSnapshot.exception); } - attributes = ImmutableMap.copyOf(attributesSnapshot.attribs); + attributes = Collections.unmodifiableMap(attributesSnapshot.attribs); this.visibleBounds = attributesSnapshot.visibleBounds; this.visible = attributesSnapshot.visible; - this.children = - attributesSnapshot.childViews == null ? null : ImmutableList.copyOf(Lists.transform( - attributesSnapshot.childViews, new Function() { - public ViewElement apply(View input) { - return context.getUiElement(input, ViewElement.this); - } - })); + if (attributesSnapshot.childViews == null) { + this.children = null; + } else { + List children = new ArrayList(attributesSnapshot.childViews.size()); + for (View childView : attributesSnapshot.childViews) { + children.add(context.getUiElement(childView, this)); + } + this.children = Collections.unmodifiableList(children); + } } @Override diff --git a/src/com/google/android/droiddriver/runner/TestRunner.java b/src/com/google/android/droiddriver/runner/TestRunner.java index 6dc78c3..5047e6f 100644 --- a/src/com/google/android/droiddriver/runner/TestRunner.java +++ b/src/com/google/android/droiddriver/runner/TestRunner.java @@ -27,15 +27,15 @@ import android.util.Log; import com.android.internal.util.Predicate; import com.google.android.droiddriver.helpers.DroidDrivers; import com.google.android.droiddriver.util.ActivityUtils; +import com.google.android.droiddriver.util.ActivityUtils.Supplier; import com.google.android.droiddriver.util.Logs; -import com.google.common.base.Supplier; -import com.google.common.collect.Lists; import junit.framework.AssertionFailedError; import junit.framework.Test; import junit.framework.TestListener; import java.lang.annotation.Annotation; +import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -122,7 +122,7 @@ public class TestRunner extends InstrumentationTestRunner { // Overrides InstrumentationTestRunner List> getBuilderRequirements() { - List> requirements = Lists.newArrayList(); + List> requirements = new ArrayList>(); requirements.add(new Predicate() { @Override public boolean apply(TestMethod arg0) { diff --git a/src/com/google/android/droiddriver/scroll/DynamicSentinelStrategy.java b/src/com/google/android/droiddriver/scroll/DynamicSentinelStrategy.java index 673d26b..95778d0 100644 --- a/src/com/google/android/droiddriver/scroll/DynamicSentinelStrategy.java +++ b/src/com/google/android/droiddriver/scroll/DynamicSentinelStrategy.java @@ -25,7 +25,7 @@ import com.google.android.droiddriver.finders.Finder; import com.google.android.droiddriver.scroll.Direction.DirectionConverter; import com.google.android.droiddriver.scroll.Direction.PhysicalDirection; import com.google.android.droiddriver.util.Logs; -import com.google.common.base.Objects; +import com.google.android.droiddriver.util.Strings; /** * Determines whether scrolling is possible by checking whether the sentinel @@ -117,7 +117,7 @@ public class DynamicSentinelStrategy extends BaseSentinelStrategy { @Override public String toString() { - return Objects.toStringHelper(this).addValue(uniqueStringFinder).toString(); + return Strings.toStringHelper(this).addValue(uniqueStringFinder).toString(); } } diff --git a/src/com/google/android/droiddriver/scroll/SentinelStrategy.java b/src/com/google/android/droiddriver/scroll/SentinelStrategy.java index 0330844..f74e8a6 100644 --- a/src/com/google/android/droiddriver/scroll/SentinelStrategy.java +++ b/src/com/google/android/droiddriver/scroll/SentinelStrategy.java @@ -16,8 +16,8 @@ package com.google.android.droiddriver.scroll; import com.google.android.droiddriver.UiElement; -import com.google.common.base.Predicate; -import com.google.common.base.Predicates; +import com.google.android.droiddriver.finders.Predicate; +import com.google.android.droiddriver.finders.Predicates; import java.util.List; @@ -63,7 +63,7 @@ public interface SentinelStrategy extends ScrollStepStrategy { public MorePredicateGetter(Getter original, Predicate extraPredicate, String extraDescription) { - super(Predicates.and(original.predicate, extraPredicate), extraDescription + super(Predicates.allOf(original.predicate, extraPredicate), extraDescription + original.description); this.original = original; } @@ -78,7 +78,7 @@ public interface SentinelStrategy extends ScrollStepStrategy { * Returns the first child as the sentinel. */ public static final Getter FIRST_CHILD_GETTER = - new Getter(Predicates.alwaysTrue(), "FIRST_CHILD") { + new Getter(Predicates.any(), "FIRST_CHILD") { @Override protected UiElement getSentinel(List children) { return children.isEmpty() ? null : children.get(0); @@ -87,7 +87,7 @@ public interface SentinelStrategy extends ScrollStepStrategy { /** * Returns the last child as the sentinel. */ - public static final Getter LAST_CHILD_GETTER = new Getter(Predicates.alwaysTrue(), "LAST_CHILD") { + public static final Getter LAST_CHILD_GETTER = new Getter(Predicates.any(), "LAST_CHILD") { @Override protected UiElement getSentinel(List children) { return children.isEmpty() ? null : children.get(children.size() - 1); @@ -103,7 +103,7 @@ public interface SentinelStrategy extends ScrollStepStrategy { * uiautomatorviewer does, but could be a problem with InstrumentationDriver. *

*/ - public static final Getter SECOND_LAST_CHILD_GETTER = new Getter(Predicates.alwaysTrue(), + public static final Getter SECOND_LAST_CHILD_GETTER = new Getter(Predicates.any(), "SECOND_LAST_CHILD") { @Override protected UiElement getSentinel(List children) { @@ -114,7 +114,7 @@ public interface SentinelStrategy extends ScrollStepStrategy { * Returns the second child as the sentinel. Useful when the activity shows a * fixed first child. */ - public static final Getter SECOND_CHILD_GETTER = new Getter(Predicates.alwaysTrue(), + public static final Getter SECOND_CHILD_GETTER = new Getter(Predicates.any(), "SECOND_CHILD") { @Override protected UiElement getSentinel(List children) { diff --git a/src/com/google/android/droiddriver/uiautomation/UiAutomationContext.java b/src/com/google/android/droiddriver/uiautomation/UiAutomationContext.java index 35a4483..fcb7a94 100644 --- a/src/com/google/android/droiddriver/uiautomation/UiAutomationContext.java +++ b/src/com/google/android/droiddriver/uiautomation/UiAutomationContext.java @@ -25,13 +25,13 @@ 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; import java.util.Map; +import java.util.WeakHashMap; class UiAutomationContext extends DroidDriverContext { - private final Map map = new MapMaker().weakKeys() - .weakValues().makeMap(); + private final Map map = + new WeakHashMap(); private final UiAutomation uiAutomation; private final InputInjector injector; private final UiAutomationDriver driver; diff --git a/src/com/google/android/droiddriver/uiautomation/UiAutomationDriver.java b/src/com/google/android/droiddriver/uiautomation/UiAutomationDriver.java index ad30693..d465816 100644 --- a/src/com/google/android/droiddriver/uiautomation/UiAutomationDriver.java +++ b/src/com/google/android/droiddriver/uiautomation/UiAutomationDriver.java @@ -28,7 +28,6 @@ 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; /** * Implementation of DroidDriver that is driven via the accessibility layer. @@ -92,7 +91,7 @@ public class UiAutomationDriver extends BaseDroidDriver { String.format("Timed out after %d milliseconds waiting for root AccessibilityNodeInfo", timeoutMillis)); } - SystemClock.sleep(Longs.min(250, remainingMillis)); + SystemClock.sleep(Math.min(250, remainingMillis)); } } diff --git a/src/com/google/android/droiddriver/uiautomation/UiAutomationElement.java b/src/com/google/android/droiddriver/uiautomation/UiAutomationElement.java index 5e55148..9a2b427 100644 --- a/src/com/google/android/droiddriver/uiautomation/UiAutomationElement.java +++ b/src/com/google/android/droiddriver/uiautomation/UiAutomationElement.java @@ -16,7 +16,7 @@ package com.google.android.droiddriver.uiautomation; -import static com.google.android.droiddriver.util.TextUtils.charSequenceToString; +import static com.google.android.droiddriver.util.Strings.charSequenceToString; import android.app.UiAutomation; import android.app.UiAutomation.AccessibilityEventFilter; @@ -28,12 +28,11 @@ 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; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; +import com.google.android.droiddriver.util.Preconditions; +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumMap; import java.util.List; import java.util.Map; import java.util.concurrent.FutureTask; @@ -70,7 +69,7 @@ public class UiAutomationElement extends BaseUiElement { Preconditions.checkNotNull(node); this.parent = parent; - Map attribs = Maps.newEnumMap(Attribute.class); + Map attribs = new EnumMap(Attribute.class); put(attribs, Attribute.PACKAGE, charSequenceToString(node.getPackageName())); put(attribs, Attribute.CLASS, charSequenceToString(node.getClassName())); put(attribs, Attribute.TEXT, charSequenceToString(node.getText())); @@ -92,13 +91,13 @@ public class UiAutomationElement extends BaseUiElement { } put(attribs, Attribute.SELECTED, node.isSelected()); put(attribs, Attribute.BOUNDS, getBounds(node)); - attributes = ImmutableMap.copyOf(attribs); + attributes = Collections.unmodifiableMap(attribs); // Order matters as getVisibleBounds depends on visible visible = node.isVisibleToUser(); visibleBounds = getVisibleBounds(node); List mutableChildren = buildChildren(context, node); - this.children = mutableChildren == null ? null : ImmutableList.copyOf(mutableChildren); + this.children = mutableChildren == null ? null : Collections.unmodifiableList(mutableChildren); } private void put(Map attribs, Attribute key, Object value) { @@ -114,7 +113,7 @@ public class UiAutomationElement extends BaseUiElement { if (childCount == 0) { children = null; } else { - children = Lists.newArrayListWithExpectedSize(childCount); + children = new ArrayList(childCount); for (int i = 0; i < childCount; i++) { AccessibilityNodeInfo child = node.getChild(i); if (child != null) { diff --git a/src/com/google/android/droiddriver/util/ActivityUtils.java b/src/com/google/android/droiddriver/util/ActivityUtils.java index 466caf9..c0f553f 100644 --- a/src/com/google/android/droiddriver/util/ActivityUtils.java +++ b/src/com/google/android/droiddriver/util/ActivityUtils.java @@ -19,12 +19,21 @@ package com.google.android.droiddriver.util; import android.app.Activity; import com.google.android.droiddriver.instrumentation.InstrumentationDriver; -import com.google.common.base.Supplier; /** * Static helper methods for retrieving activities. */ public class ActivityUtils { + public interface Supplier { + /** + * Retrieves an instance of the appropriate type. The returned object may or + * may not be a new instance, depending on the implementation. + * + * @return an instance of the appropriate type + */ + T get(); + } + private static Supplier runningActivitySupplier; /** diff --git a/src/com/google/android/droiddriver/util/Logs.java b/src/com/google/android/droiddriver/util/Logs.java index e376b73..e08ee10 100644 --- a/src/com/google/android/droiddriver/util/Logs.java +++ b/src/com/google/android/droiddriver/util/Logs.java @@ -16,10 +16,9 @@ package com.google.android.droiddriver.util; +import android.text.TextUtils; import android.util.Log; -import com.google.common.base.Joiner; - /** * Internal helper for logging. */ @@ -32,7 +31,7 @@ public class Logs { Log.d( TAG, String.format("Invoking %s.%s(%s)", self.getClass().getSimpleName(), method, - Joiner.on(", ").join(args))); + TextUtils.join(", ", args))); } } diff --git a/src/com/google/android/droiddriver/util/Preconditions.java b/src/com/google/android/droiddriver/util/Preconditions.java new file mode 100644 index 0000000..aaf545d --- /dev/null +++ b/src/com/google/android/droiddriver/util/Preconditions.java @@ -0,0 +1,40 @@ +/* + * 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.util; + +/** + * Simple static methods to be called at the start of your own methods to verify + * correct arguments and state. + */ +public final class Preconditions { + private Preconditions() {} + + /** + * Ensures that an object reference passed as a parameter to the calling + * method is not null. + * + * @param reference an object reference + * @return the non-null reference that was validated + * @throws NullPointerException if {@code reference} is null + */ + public static T checkNotNull(T reference) { + if (reference == null) { + throw new NullPointerException(); + } + return reference; + } +} diff --git a/src/com/google/android/droiddriver/util/Strings.java b/src/com/google/android/droiddriver/util/Strings.java new file mode 100644 index 0000000..ea75238 --- /dev/null +++ b/src/com/google/android/droiddriver/util/Strings.java @@ -0,0 +1,66 @@ +/* + * 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.util; + +/** + * Static helper methods for manipulating strings. + */ +public class Strings { + public static String charSequenceToString(CharSequence input) { + return input == null ? null : input.toString(); + } + + public static ToStringHelper toStringHelper(Object self) { + return new ToStringHelper(self.getClass().getSimpleName()); + } + + public static final class ToStringHelper { + private final StringBuilder builder; + private boolean needsSeparator = false; + + /** + * Use {@link #toStringHelper(Object)} to create an instance. + */ + private ToStringHelper(String className) { + this.builder = new StringBuilder(32).append(className).append('{'); + } + + public ToStringHelper addValue(Object value) { + maybeAppendSeparator().append(value); + return this; + } + + public ToStringHelper add(String name, Object value) { + maybeAppendSeparator().append(name).append('=').append(value); + return this; + } + + @Override + public String toString() { + return builder.append('}').toString(); + } + + private StringBuilder maybeAppendSeparator() { + if (needsSeparator) { + return builder.append(", "); + } else { + needsSeparator = true; + return builder; + } + } + } +} diff --git a/src/com/google/android/droiddriver/util/TextUtils.java b/src/com/google/android/droiddriver/util/TextUtils.java deleted file mode 100644 index b709018..0000000 --- a/src/com/google/android/droiddriver/util/TextUtils.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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.util; - -/** - * Static helper methods for manipulating strings. - */ -public class TextUtils { - public static String charSequenceToString(CharSequence input) { - return input == null ? null : input.toString(); - } -} -- cgit v1.2.3