Fix to precompile regex in UiSelector
Also added public UiSelector#resourceIdMatches
Change-Id: Ieb8a5d6fcdfdfa8c52c6ad3f2f202ec7ed4e69a5
diff --git a/uiautomator/api/current.txt b/uiautomator/api/current.txt
index 1bc6a72..9d39975 100644
--- a/uiautomator/api/current.txt
+++ b/uiautomator/api/current.txt
@@ -189,6 +189,7 @@
method public com.android.uiautomator.core.UiSelector packageName(java.lang.String);
method public com.android.uiautomator.core.UiSelector packageNameMatches(java.lang.String);
method public com.android.uiautomator.core.UiSelector resourceId(java.lang.String);
+ method public com.android.uiautomator.core.UiSelector resourceIdMatches(java.lang.String);
method public com.android.uiautomator.core.UiSelector scrollable(boolean);
method public com.android.uiautomator.core.UiSelector selected(boolean);
method public com.android.uiautomator.core.UiSelector text(java.lang.String);
diff --git a/uiautomator/library/core-src/com/android/uiautomator/core/UiSelector.java b/uiautomator/library/core-src/com/android/uiautomator/core/UiSelector.java
index a5b188a..b7f5fa7 100644
--- a/uiautomator/library/core-src/com/android/uiautomator/core/UiSelector.java
+++ b/uiautomator/library/core-src/com/android/uiautomator/core/UiSelector.java
@@ -19,6 +19,8 @@
import android.util.SparseArray;
import android.view.accessibility.AccessibilityNodeInfo;
+import java.util.regex.Pattern;
+
/**
* This class provides the mechanism for tests to describe the UI elements they
* intend to target. A UI element has many properties associated with it such as
@@ -60,6 +62,7 @@
static final int SELECTOR_PACKAGE_NAME_REGEX = 28;
static final int SELECTOR_RESOURCE_ID = 29;
static final int SELECTOR_CHECKABLE = 30;
+ static final int SELECTOR_RESOURCE_ID_REGEX = 31;
private SparseArray<Object> mSelectorAttributes = new SparseArray<Object>();
@@ -79,17 +82,17 @@
protected UiSelector cloneSelector() {
UiSelector ret = new UiSelector();
ret.mSelectorAttributes = mSelectorAttributes.clone();
- if(hasChildSelector())
+ if (hasChildSelector())
ret.mSelectorAttributes.put(SELECTOR_CHILD, new UiSelector(getChildSelector()));
- if(hasParentSelector())
+ if (hasParentSelector())
ret.mSelectorAttributes.put(SELECTOR_PARENT, new UiSelector(getParentSelector()));
- if(hasPatternSelector())
+ if (hasPatternSelector())
ret.mSelectorAttributes.put(SELECTOR_PATTERN, new UiSelector(getPatternSelector()));
return ret;
}
static UiSelector patternBuilder(UiSelector selector) {
- if(!selector.hasPatternSelector()) {
+ if (!selector.hasPatternSelector()) {
return new UiSelector().patternSelector(selector);
}
return selector;
@@ -128,7 +131,7 @@
* @since API Level 17
*/
public UiSelector textMatches(String regex) {
- return buildSelector(SELECTOR_TEXT_REGEX, regex);
+ return buildSelector(SELECTOR_TEXT_REGEX, Pattern.compile(regex));
}
/**
@@ -183,7 +186,7 @@
* @since API Level 17
*/
public UiSelector classNameMatches(String regex) {
- return buildSelector(SELECTOR_CLASS_REGEX, regex);
+ return buildSelector(SELECTOR_CLASS_REGEX, Pattern.compile(regex));
}
/**
@@ -235,7 +238,7 @@
* @since API Level 17
*/
public UiSelector descriptionMatches(String regex) {
- return buildSelector(SELECTOR_DESCRIPTION_REGEX, regex);
+ return buildSelector(SELECTOR_DESCRIPTION_REGEX, Pattern.compile(regex));
}
/**
@@ -292,6 +295,18 @@
}
/**
+ * Set the search criteria to match the resourceId
+ * of the widget
+ *
+ * @param regex a regular expression
+ * @return UiSelector with the specified search criteria
+ * @since API Level 18
+ */
+ public UiSelector resourceIdMatches(String regex) {
+ return buildSelector(SELECTOR_RESOURCE_ID_REGEX, Pattern.compile(regex));
+ }
+
+ /**
* Set the search criteria to match the widget by its node
* index in the layout hierarchy.
*
@@ -566,7 +581,7 @@
* @since API Level 17
*/
public UiSelector packageNameMatches(String regex) {
- return buildSelector(SELECTOR_PACKAGE_NAME_REGEX, regex);
+ return buildSelector(SELECTOR_PACKAGE_NAME_REGEX, Pattern.compile(regex));
}
/**
@@ -575,7 +590,7 @@
*/
private UiSelector buildSelector(int selectorId, Object selectorValue) {
UiSelector selector = new UiSelector(this);
- if(selectorId == SELECTOR_CHILD || selectorId == SELECTOR_PARENT)
+ if (selectorId == SELECTOR_CHILD || selectorId == SELECTOR_PARENT)
selector.getLastSubSelector().mSelectorAttributes.put(selectorId, selectorValue);
else
selector.mSelectorAttributes.put(selectorId, selectorValue);
@@ -593,7 +608,7 @@
*/
UiSelector getChildSelector() {
UiSelector selector = (UiSelector)mSelectorAttributes.get(UiSelector.SELECTOR_CHILD, null);
- if(selector != null)
+ if (selector != null)
return new UiSelector(selector);
return null;
}
@@ -601,7 +616,7 @@
UiSelector getPatternSelector() {
UiSelector selector =
(UiSelector)mSelectorAttributes.get(UiSelector.SELECTOR_PATTERN, null);
- if(selector != null)
+ if (selector != null)
return new UiSelector(selector);
return null;
}
@@ -609,7 +624,7 @@
UiSelector getContainerSelector() {
UiSelector selector =
(UiSelector)mSelectorAttributes.get(UiSelector.SELECTOR_CONTAINER, null);
- if(selector != null)
+ if (selector != null)
return new UiSelector(selector);
return null;
}
@@ -617,7 +632,7 @@
UiSelector getParentSelector() {
UiSelector selector =
(UiSelector) mSelectorAttributes.get(UiSelector.SELECTOR_PARENT, null);
- if(selector != null)
+ if (selector != null)
return new UiSelector(selector);
return null;
}
@@ -638,6 +653,10 @@
return (Integer) mSelectorAttributes.get(criterion, 0);
}
+ Pattern getPattern(int criterion) {
+ return (Pattern) mSelectorAttributes.get(criterion, null);
+ }
+
boolean isMatchFor(AccessibilityNodeInfo node, int index) {
int size = mSelectorAttributes.size();
for(int x = 0; x < size; x++) {
@@ -645,7 +664,7 @@
int criterion = mSelectorAttributes.keyAt(x);
switch(criterion) {
case UiSelector.SELECTOR_INDEX:
- if(index != this.getInt(criterion))
+ if (index != this.getInt(criterion))
return false;
break;
case UiSelector.SELECTOR_CHECKED:
@@ -661,7 +680,7 @@
break;
case UiSelector.SELECTOR_CLASS_REGEX:
s = node.getClassName();
- if (s == null || !s.toString().matches(getString(criterion))) {
+ if (s == null || !getPattern(criterion).matcher(s).matches()) {
return false;
}
break;
@@ -682,68 +701,68 @@
break;
case UiSelector.SELECTOR_CONTAINS_DESCRIPTION:
s = node.getContentDescription();
- if(s == null || !s.toString().toLowerCase()
+ if (s == null || !s.toString().toLowerCase()
.contains(getString(criterion).toLowerCase())) {
return false;
}
break;
case UiSelector.SELECTOR_START_DESCRIPTION:
s = node.getContentDescription();
- if(s == null || !s.toString().toLowerCase()
+ if (s == null || !s.toString().toLowerCase()
.startsWith(getString(criterion).toLowerCase())) {
return false;
}
break;
case UiSelector.SELECTOR_DESCRIPTION:
s = node.getContentDescription();
- if(s == null || !s.toString().contentEquals(getString(criterion))) {
+ if (s == null || !s.toString().contentEquals(getString(criterion))) {
return false;
}
break;
case UiSelector.SELECTOR_DESCRIPTION_REGEX:
s = node.getContentDescription();
- if(s == null || !s.toString().matches(getString(criterion))) {
+ if (s == null || !getPattern(criterion).matcher(s).matches()) {
return false;
}
break;
case UiSelector.SELECTOR_CONTAINS_TEXT:
s = node.getText();
- if(s == null || !s.toString().toLowerCase()
+ if (s == null || !s.toString().toLowerCase()
.contains(getString(criterion).toLowerCase())) {
return false;
}
break;
case UiSelector.SELECTOR_START_TEXT:
s = node.getText();
- if(s == null || !s.toString().toLowerCase()
+ if (s == null || !s.toString().toLowerCase()
.startsWith(getString(criterion).toLowerCase())) {
return false;
}
break;
case UiSelector.SELECTOR_TEXT:
s = node.getText();
- if(s == null || !s.toString().contentEquals(getString(criterion))) {
+ if (s == null || !s.toString().contentEquals(getString(criterion))) {
return false;
}
break;
case UiSelector.SELECTOR_TEXT_REGEX:
s = node.getText();
- if(s == null || !s.toString().matches(getString(criterion))) {
+ if (s == null || !getPattern(criterion).matcher(s).matches()) {
return false;
}
break;
case UiSelector.SELECTOR_ENABLED:
- if(node.isEnabled() != getBoolean(criterion)) {
+ if (node.isEnabled() != getBoolean(criterion)) {
return false;
}
break;
case UiSelector.SELECTOR_FOCUSABLE:
- if(node.isFocusable() != getBoolean(criterion)) {
+ if (node.isFocusable() != getBoolean(criterion)) {
return false;
}
break;
case UiSelector.SELECTOR_FOCUSED:
- if(node.isFocused() != getBoolean(criterion)) {
+ if (node.isFocused() != getBoolean(criterion)) {
return false;
}
break;
@@ -751,23 +770,23 @@
break; //TODO: do we need this for AccessibilityNodeInfo.id?
case UiSelector.SELECTOR_PACKAGE_NAME:
s = node.getPackageName();
- if(s == null || !s.toString().contentEquals(getString(criterion))) {
+ if (s == null || !s.toString().contentEquals(getString(criterion))) {
return false;
}
break;
case UiSelector.SELECTOR_PACKAGE_NAME_REGEX:
s = node.getPackageName();
- if(s == null || !s.toString().matches(getString(criterion))) {
+ if (s == null || !getPattern(criterion).matcher(s).matches()) {
return false;
}
break;
case UiSelector.SELECTOR_SCROLLABLE:
- if(node.isScrollable() != getBoolean(criterion)) {
+ if (node.isScrollable() != getBoolean(criterion)) {
return false;
}
break;
case UiSelector.SELECTOR_SELECTED:
- if(node.isSelected() != getBoolean(criterion)) {
+ if (node.isSelected() != getBoolean(criterion)) {
return false;
}
break;
@@ -777,6 +796,12 @@
return false;
}
break;
+ case UiSelector.SELECTOR_RESOURCE_ID_REGEX:
+ s = node.getViewIdResourceName();
+ if (s == null || !getPattern(criterion).matcher(s).matches()) {
+ return false;
+ }
+ break;
}
}
return matchOrUpdateInstance();
@@ -787,13 +812,13 @@
int currentSelectorInstance = 0;
// matched attributes - now check for matching instance number
- if(mSelectorAttributes.indexOfKey(UiSelector.SELECTOR_INSTANCE) >= 0) {
+ if (mSelectorAttributes.indexOfKey(UiSelector.SELECTOR_INSTANCE) >= 0) {
currentSelectorInstance =
(Integer)mSelectorAttributes.get(UiSelector.SELECTOR_INSTANCE);
}
// instance is required. Add count if not already counting
- if(mSelectorAttributes.indexOfKey(UiSelector.SELECTOR_COUNT) >= 0) {
+ if (mSelectorAttributes.indexOfKey(UiSelector.SELECTOR_COUNT) >= 0) {
currentSelectorCounter = (Integer)mSelectorAttributes.get(UiSelector.SELECTOR_COUNT);
}
@@ -814,7 +839,7 @@
* @return true if is leaf.
*/
boolean isLeaf() {
- if(mSelectorAttributes.indexOfKey(UiSelector.SELECTOR_CHILD) < 0 &&
+ if (mSelectorAttributes.indexOfKey(UiSelector.SELECTOR_CHILD) < 0 &&
mSelectorAttributes.indexOfKey(UiSelector.SELECTOR_PARENT) < 0) {
return true;
}
@@ -822,28 +847,28 @@
}
boolean hasChildSelector() {
- if(mSelectorAttributes.indexOfKey(UiSelector.SELECTOR_CHILD) < 0) {
+ if (mSelectorAttributes.indexOfKey(UiSelector.SELECTOR_CHILD) < 0) {
return false;
}
return true;
}
boolean hasPatternSelector() {
- if(mSelectorAttributes.indexOfKey(UiSelector.SELECTOR_PATTERN) < 0) {
+ if (mSelectorAttributes.indexOfKey(UiSelector.SELECTOR_PATTERN) < 0) {
return false;
}
return true;
}
boolean hasContainerSelector() {
- if(mSelectorAttributes.indexOfKey(UiSelector.SELECTOR_CONTAINER) < 0) {
+ if (mSelectorAttributes.indexOfKey(UiSelector.SELECTOR_CONTAINER) < 0) {
return false;
}
return true;
}
boolean hasParentSelector() {
- if(mSelectorAttributes.indexOfKey(UiSelector.SELECTOR_PARENT) < 0) {
+ if (mSelectorAttributes.indexOfKey(UiSelector.SELECTOR_PARENT) < 0) {
return false;
}
return true;
@@ -857,15 +882,15 @@
* @return last UiSelector in chain
*/
private UiSelector getLastSubSelector() {
- if(mSelectorAttributes.indexOfKey(UiSelector.SELECTOR_CHILD) >= 0) {
+ if (mSelectorAttributes.indexOfKey(UiSelector.SELECTOR_CHILD) >= 0) {
UiSelector child = (UiSelector)mSelectorAttributes.get(UiSelector.SELECTOR_CHILD);
- if(child.getLastSubSelector() == null) {
+ if (child.getLastSubSelector() == null) {
return child;
}
return child.getLastSubSelector();
- } else if(mSelectorAttributes.indexOfKey(UiSelector.SELECTOR_PARENT) >= 0) {
+ } else if (mSelectorAttributes.indexOfKey(UiSelector.SELECTOR_PARENT) >= 0) {
UiSelector parent = (UiSelector)mSelectorAttributes.get(UiSelector.SELECTOR_PARENT);
- if(parent.getLastSubSelector() == null) {
+ if (parent.getLastSubSelector() == null) {
return parent;
}
return parent.getLastSubSelector();
@@ -955,25 +980,25 @@
builder.append("ID=").append(mSelectorAttributes.valueAt(i));
break;
case SELECTOR_CHILD:
- if(all)
+ if (all)
builder.append("CHILD=").append(mSelectorAttributes.valueAt(i));
else
builder.append("CHILD[..]");
break;
case SELECTOR_PATTERN:
- if(all)
+ if (all)
builder.append("PATTERN=").append(mSelectorAttributes.valueAt(i));
else
builder.append("PATTERN[..]");
break;
case SELECTOR_CONTAINER:
- if(all)
+ if (all)
builder.append("CONTAINER=").append(mSelectorAttributes.valueAt(i));
else
builder.append("CONTAINER[..]");
break;
case SELECTOR_PARENT:
- if(all)
+ if (all)
builder.append("PARENT=").append(mSelectorAttributes.valueAt(i));
else
builder.append("PARENT[..]");
@@ -990,6 +1015,9 @@
case SELECTOR_RESOURCE_ID:
builder.append("RESOURCE_ID=").append(mSelectorAttributes.valueAt(i));
break;
+ case SELECTOR_RESOURCE_ID_REGEX:
+ builder.append("RESOURCE_ID_REGEX=").append(mSelectorAttributes.valueAt(i));
+ break;
default:
builder.append("UNDEFINED="+criterion+" ").append(mSelectorAttributes.valueAt(i));
}