Accessibility services cannot obtain the source of an event coming from a root namespace descendant.
1. The user can touch the screen at an arbitrary location potentially crossing the root namespace bounday which will send an accessibility event to accessibility services and they should be able to obtain the event source. Also accessibility ids are guaranteed to be unique in the window. Added a package scoped findViewByAccessibilityId method that dives into nested root namespaces. 2. Added accessibility support to the AnalogClock. bug:5405934 Change-Id: I84edcb554bae41aafcbbc2723c5e62c1ef8a6ddf
This commit is contained in:
@@ -12092,6 +12092,39 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
|
||||
return findViewTraversal(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a view by its unuque and stable accessibility id.
|
||||
*
|
||||
* @param accessibilityId The searched accessibility id.
|
||||
* @return The found view.
|
||||
*/
|
||||
final View findViewByAccessibilityId(int accessibilityId) {
|
||||
if (accessibilityId < 0) {
|
||||
return null;
|
||||
}
|
||||
return findViewByAccessibilityIdTraversal(accessibilityId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the traversal to find a view by its unuque and stable accessibility id.
|
||||
*
|
||||
* <strong>Note:</strong>This method does not stop at the root namespace
|
||||
* boundary since the user can touch the screen at an arbitrary location
|
||||
* potentially crossing the root namespace bounday which will send an
|
||||
* accessibility event to accessibility services and they should be able
|
||||
* to obtain the event source. Also accessibility ids are guaranteed to be
|
||||
* unique in the window.
|
||||
*
|
||||
* @param accessibilityId The accessibility id.
|
||||
* @return The found view.
|
||||
*/
|
||||
View findViewByAccessibilityIdTraversal(int accessibilityId) {
|
||||
if (getAccessibilityViewId() == accessibilityId) {
|
||||
return this;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for a child view with the given tag. If this view has the given
|
||||
* tag, return this view.
|
||||
|
||||
@@ -821,6 +821,24 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
View findViewByAccessibilityIdTraversal(int accessibilityId) {
|
||||
View foundView = super.findViewByAccessibilityIdTraversal(accessibilityId);
|
||||
if (foundView != null) {
|
||||
return foundView;
|
||||
}
|
||||
final int childrenCount = mChildrenCount;
|
||||
final View[] children = mChildren;
|
||||
for (int i = 0; i < childrenCount; i++) {
|
||||
View child = children[i];
|
||||
foundView = child.findViewByAccessibilityIdTraversal(accessibilityId);
|
||||
if (foundView != null) {
|
||||
return foundView;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
|
||||
@@ -74,7 +74,6 @@ import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.Scroller;
|
||||
|
||||
import com.android.internal.policy.PolicyManager;
|
||||
import com.android.internal.util.Predicate;
|
||||
import com.android.internal.view.BaseSurfaceHolder;
|
||||
import com.android.internal.view.IInputMethodCallback;
|
||||
import com.android.internal.view.IInputMethodSession;
|
||||
@@ -4462,9 +4461,6 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|
||||
final class AccessibilityInteractionController {
|
||||
private static final int POOL_SIZE = 5;
|
||||
|
||||
private FindByAccessibilitytIdPredicate mFindByAccessibilityIdPredicate =
|
||||
new FindByAccessibilitytIdPredicate();
|
||||
|
||||
private ArrayList<AccessibilityNodeInfo> mTempAccessibilityNodeInfoList =
|
||||
new ArrayList<AccessibilityNodeInfo>();
|
||||
|
||||
@@ -4551,11 +4547,8 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|
||||
|
||||
AccessibilityNodeInfo info = null;
|
||||
try {
|
||||
FindByAccessibilitytIdPredicate predicate = mFindByAccessibilityIdPredicate;
|
||||
predicate.init(accessibilityId);
|
||||
View root = ViewRootImpl.this.mView;
|
||||
View target = root.findViewByPredicate(predicate);
|
||||
if (target != null && target.getVisibility() == View.VISIBLE) {
|
||||
View target = findViewByAccessibilityId(accessibilityId);
|
||||
if (target != null) {
|
||||
info = target.createAccessibilityNodeInfo();
|
||||
}
|
||||
} finally {
|
||||
@@ -4794,25 +4787,12 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|
||||
if (root == null) {
|
||||
return null;
|
||||
}
|
||||
mFindByAccessibilityIdPredicate.init(accessibilityId);
|
||||
View foundView = root.findViewByPredicate(mFindByAccessibilityIdPredicate);
|
||||
if (foundView == null || foundView.getVisibility() != View.VISIBLE) {
|
||||
View foundView = root.findViewByAccessibilityId(accessibilityId);
|
||||
if (foundView != null && foundView.getVisibility() != View.VISIBLE) {
|
||||
return null;
|
||||
}
|
||||
return foundView;
|
||||
}
|
||||
|
||||
private final class FindByAccessibilitytIdPredicate implements Predicate<View> {
|
||||
public int mSearchedId;
|
||||
|
||||
public void init(int searchedId) {
|
||||
mSearchedId = searchedId;
|
||||
}
|
||||
|
||||
public boolean apply(View view) {
|
||||
return (view.getAccessibilityViewId() == mSearchedId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class SendWindowContentChangedAccessibilityEvent implements Runnable {
|
||||
|
||||
@@ -25,6 +25,7 @@ import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Handler;
|
||||
import android.text.format.DateUtils;
|
||||
import android.text.format.Time;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
@@ -228,6 +229,8 @@ public class AnalogClock extends View {
|
||||
mMinutes = minute + second / 60.0f;
|
||||
mHour = hour + mMinutes / 60.0f;
|
||||
mChanged = true;
|
||||
|
||||
updateContentDescription(mCalendar);
|
||||
}
|
||||
|
||||
private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
|
||||
@@ -243,4 +246,11 @@ public class AnalogClock extends View {
|
||||
invalidate();
|
||||
}
|
||||
};
|
||||
|
||||
private void updateContentDescription(Time time) {
|
||||
final int flags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_24HOUR;
|
||||
String contentDescription = DateUtils.formatDateTime(mContext,
|
||||
time.toMillis(false), flags);
|
||||
setContentDescription(contentDescription);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,9 +237,7 @@ public class TimePicker extends FrameLayout {
|
||||
}
|
||||
|
||||
// set the content descriptions
|
||||
if (AccessibilityManager.getInstance(mContext).isEnabled()) {
|
||||
setContentDescriptions();
|
||||
}
|
||||
setContentDescriptions();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user