Merge "Update the public APIs for finding views by text to optionally use content description."
This commit is contained in:
committed by
Android (Google) Code Review
commit
df82905cf3
@ -22920,7 +22920,7 @@ package android.view {
|
||||
method public android.view.View findFocus();
|
||||
method public final android.view.View findViewById(int);
|
||||
method public final android.view.View findViewWithTag(java.lang.Object);
|
||||
method public void findViewsWithText(java.util.ArrayList<android.view.View>, java.lang.CharSequence);
|
||||
method public void findViewsWithText(java.util.ArrayList<android.view.View>, java.lang.CharSequence, int);
|
||||
method protected boolean fitSystemWindows(android.graphics.Rect);
|
||||
method public boolean fitsSystemWindows();
|
||||
method public android.view.View focusSearch(int);
|
||||
@ -23249,6 +23249,8 @@ package android.view {
|
||||
field protected static final int[] ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET;
|
||||
field protected static final int[] ENABLED_STATE_SET;
|
||||
field protected static final int[] ENABLED_WINDOW_FOCUSED_STATE_SET;
|
||||
field public static final int FIND_VIEWS_WITH_CONTENT_DESCRIPTION = 2; // 0x2
|
||||
field public static final int FIND_VIEWS_WITH_TEXT = 1; // 0x1
|
||||
field public static final int FOCUSABLES_ALL = 0; // 0x0
|
||||
field public static final int FOCUSABLES_TOUCH_MODE = 1; // 0x1
|
||||
field protected static final int[] FOCUSED_SELECTED_STATE_SET;
|
||||
|
@ -45,6 +45,7 @@ import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.FloatProperty;
|
||||
import android.util.LocaleUtil;
|
||||
@ -1927,6 +1928,20 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
|
||||
*/
|
||||
public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x0000FFFF;
|
||||
|
||||
/**
|
||||
* Find views that render the specified text.
|
||||
*
|
||||
* @see #findViewsWithText(ArrayList, CharSequence, int)
|
||||
*/
|
||||
public static final int FIND_VIEWS_WITH_TEXT = 0x00000001;
|
||||
|
||||
/**
|
||||
* Find find views that contain the specified content description.
|
||||
*
|
||||
* @see #findViewsWithText(ArrayList, CharSequence, int)
|
||||
*/
|
||||
public static final int FIND_VIEWS_WITH_CONTENT_DESCRIPTION = 0x00000002;
|
||||
|
||||
/**
|
||||
* Controls the over-scroll mode for this view.
|
||||
* See {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)},
|
||||
@ -5132,12 +5147,28 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
|
||||
|
||||
/**
|
||||
* Finds the Views that contain given text. The containment is case insensitive.
|
||||
* As View's text is considered any text content that View renders.
|
||||
* The search is performed by either the text that the View renders or the content
|
||||
* description that describes the view for accessibility purposes and the view does
|
||||
* not render or both. Clients can specify how the search is to be performed via
|
||||
* passing the {@link #FIND_VIEWS_WITH_TEXT} and
|
||||
* {@link #FIND_VIEWS_WITH_CONTENT_DESCRIPTION} flags.
|
||||
*
|
||||
* @param outViews The output list of matching Views.
|
||||
* @param text The text to match against.
|
||||
* @param searched The text to match against.
|
||||
*
|
||||
* @see #FIND_VIEWS_WITH_TEXT
|
||||
* @see #FIND_VIEWS_WITH_CONTENT_DESCRIPTION
|
||||
* @see #setContentDescription(CharSequence)
|
||||
*/
|
||||
public void findViewsWithText(ArrayList<View> outViews, CharSequence text) {
|
||||
public void findViewsWithText(ArrayList<View> outViews, CharSequence searched, int flags) {
|
||||
if ((flags & FIND_VIEWS_WITH_CONTENT_DESCRIPTION) != 0 && !TextUtils.isEmpty(searched)
|
||||
&& !TextUtils.isEmpty(mContentDescription)) {
|
||||
String searchedLowerCase = searched.toString().toLowerCase();
|
||||
String contentDescriptionLowerCase = mContentDescription.toString().toLowerCase();
|
||||
if (contentDescriptionLowerCase.contains(searchedLowerCase)) {
|
||||
outViews.add(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -802,13 +802,15 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
|
||||
}
|
||||
|
||||
@Override
|
||||
public void findViewsWithText(ArrayList<View> outViews, CharSequence text) {
|
||||
public void findViewsWithText(ArrayList<View> outViews, CharSequence text, int flags) {
|
||||
super.findViewsWithText(outViews, text, flags);
|
||||
final int childrenCount = mChildrenCount;
|
||||
final View[] children = mChildren;
|
||||
for (int i = 0; i < childrenCount; i++) {
|
||||
View child = children[i];
|
||||
if ((child.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) {
|
||||
child.findViewsWithText(outViews, text);
|
||||
if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
|
||||
&& (child.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) {
|
||||
child.findViewsWithText(outViews, text, flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4661,7 +4661,8 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|
||||
return;
|
||||
}
|
||||
|
||||
root.findViewsWithText(foundViews, text);
|
||||
root.findViewsWithText(foundViews, text, View.FIND_VIEWS_WITH_TEXT
|
||||
| View.FIND_VIEWS_WITH_CONTENT_DESCRIPTION);
|
||||
if (foundViews.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
@ -261,6 +261,7 @@ public class AccessibilityNodeInfo implements Parcelable {
|
||||
* Finds {@link AccessibilityNodeInfo}s by text. The match is case
|
||||
* insensitive containment. The search is relative to this info i.e.
|
||||
* this info is the root of the traversed tree.
|
||||
*
|
||||
* <p>
|
||||
* <strong>Note:</strong> It is a client responsibility to recycle the
|
||||
* received info by calling {@link AccessibilityNodeInfo#recycle()}
|
||||
|
@ -8677,18 +8677,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
}
|
||||
|
||||
@Override
|
||||
public void findViewsWithText(ArrayList<View> outViews, CharSequence searched) {
|
||||
if (TextUtils.isEmpty(searched)) {
|
||||
return;
|
||||
}
|
||||
CharSequence thisText = getText();
|
||||
if (TextUtils.isEmpty(thisText)) {
|
||||
return;
|
||||
}
|
||||
String searchedLowerCase = searched.toString().toLowerCase();
|
||||
String thisTextLowerCase = thisText.toString().toLowerCase();
|
||||
if (thisTextLowerCase.contains(searchedLowerCase)) {
|
||||
outViews.add(this);
|
||||
public void findViewsWithText(ArrayList<View> outViews, CharSequence searched, int flags) {
|
||||
super.findViewsWithText(outViews, searched, flags);
|
||||
if (!outViews.contains(this) && (flags & FIND_VIEWS_WITH_TEXT) != 0
|
||||
&& !TextUtils.isEmpty(searched) && !TextUtils.isEmpty(mText)) {
|
||||
String searchedLowerCase = searched.toString().toLowerCase();
|
||||
String textLowerCase = mText.toString().toLowerCase();
|
||||
if (textLowerCase.contains(searchedLowerCase)) {
|
||||
outViews.add(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,6 +70,7 @@
|
||||
android:layout_width="160px"
|
||||
android:layout_height="100px"
|
||||
android:text="@string/button6"
|
||||
android:contentDescription="contentDescription"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
|
@ -147,6 +147,29 @@ public class InterrogationActivityTest
|
||||
}
|
||||
}
|
||||
|
||||
@LargeTest
|
||||
public void testFindAccessibilityNodeInfoByViewTextContentDescription() throws Exception {
|
||||
beforeClassIfNeeded();
|
||||
final long startTimeMillis = SystemClock.uptimeMillis();
|
||||
try {
|
||||
// bring up the activity
|
||||
getActivity();
|
||||
|
||||
// find a view by text
|
||||
List<AccessibilityNodeInfo> buttons = AccessibilityInteractionClient.getInstance()
|
||||
.findAccessibilityNodeInfosByViewTextInActiveWindow(getConnection(),
|
||||
"contentDescription");
|
||||
assertEquals(1, buttons.size());
|
||||
} finally {
|
||||
afterClassIfNeeded();
|
||||
if (DEBUG) {
|
||||
final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
|
||||
Log.i(LOG_TAG, "testFindAccessibilityNodeInfoByViewTextContentDescription: "
|
||||
+ elapsedTimeMillis + "ms");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@LargeTest
|
||||
public void testTraverseAllViews() throws Exception {
|
||||
beforeClassIfNeeded();
|
||||
|
@ -489,14 +489,16 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
|
||||
if (oldService != null) {
|
||||
tryRemoveServiceLocked(oldService);
|
||||
}
|
||||
// Now this service is enabled.
|
||||
mEnabledServices.add(componentName);
|
||||
// Also make sure this service is the only one.
|
||||
Settings.Secure.putString(mContext.getContentResolver(),
|
||||
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
|
||||
componentName.flattenToString());
|
||||
// This API is intended for testing so enable accessibility to make
|
||||
// sure clients can start poking with the window content.
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_ENABLED, 1);
|
||||
// Also disable all accessibility services to avoid interference
|
||||
// with the tests.
|
||||
Settings.Secure.putString(mContext.getContentResolver(),
|
||||
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, "");
|
||||
}
|
||||
AccessibilityServiceInfo accessibilityServiceInfo = new AccessibilityServiceInfo();
|
||||
accessibilityServiceInfo.eventTypes = AccessibilityEvent.TYPES_ALL_MASK;
|
||||
|
Reference in New Issue
Block a user