summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Svetoslav <svetoslavganov@google.com> 2013-06-07 00:04:57 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2013-06-07 00:04:57 +0000
commit494cb689d09a82025b9d892241e62aa149ce3239 (patch)
tree68640872a29eb46afb09aabba2dce498c5acc750
parentfd6f77dc6accdc5d7ae4ffd5bb1d0d82fe448405 (diff)
parent6254f4806dd3db53b7380e77fbb183065685573e (diff)
Merge "Optimizing AccessibilityNodeInfo caching."
-rw-r--r--api/current.txt7
-rw-r--r--core/java/android/view/AccessibilityInteractionController.java4
-rw-r--r--core/java/android/view/View.java164
-rw-r--r--core/java/android/view/ViewGroup.java38
-rw-r--r--core/java/android/view/ViewParent.java9
-rw-r--r--core/java/android/view/ViewRootImpl.java41
-rw-r--r--core/java/android/view/accessibility/AccessibilityEvent.java46
-rw-r--r--core/java/android/view/accessibility/AccessibilityInteractionClient.java18
-rw-r--r--core/java/android/view/accessibility/AccessibilityNodeInfo.java100
-rw-r--r--core/java/android/view/accessibility/AccessibilityNodeInfoCache.java114
-rw-r--r--core/java/android/view/accessibility/AccessibilityRecord.java2
-rw-r--r--core/java/android/widget/AdapterView.java4
-rw-r--r--core/java/android/widget/CheckedTextView.java2
-rw-r--r--core/java/android/widget/CompoundButton.java2
-rw-r--r--core/java/android/widget/TextView.java12
15 files changed, 381 insertions, 182 deletions
diff --git a/api/current.txt b/api/current.txt
index 27038011c81b..87891b51e984 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -27314,6 +27314,7 @@ package android.view.accessibility {
method public int describeContents();
method public static java.lang.String eventTypeToString(int);
method public int getAction();
+ method public int getContentChangeType();
method public long getEventTime();
method public int getEventType();
method public int getMovementGranularity();
@@ -27325,11 +27326,14 @@ package android.view.accessibility {
method public static android.view.accessibility.AccessibilityEvent obtain(android.view.accessibility.AccessibilityEvent);
method public static android.view.accessibility.AccessibilityEvent obtain();
method public void setAction(int);
+ method public void setContentChangeType(int);
method public void setEventTime(long);
method public void setEventType(int);
method public void setMovementGranularity(int);
method public void setPackageName(java.lang.CharSequence);
method public void writeToParcel(android.os.Parcel, int);
+ field public static final int CONTENT_CHANGE_TYPE_NODE = 1; // 0x1
+ field public static final int CONTENT_CHANGE_TYPE_SUBTREE = 0; // 0x0
field public static final android.os.Parcelable.Creator CREATOR;
field public static final int INVALID_POSITION = -1; // 0xffffffff
field public static final deprecated int MAX_TEXT_LENGTH = 500; // 0x1f4
@@ -27391,10 +27395,12 @@ package android.view.accessibility {
method public int getActions();
method public void getBoundsInParent(android.graphics.Rect);
method public void getBoundsInScreen(android.graphics.Rect);
+ method public android.os.Bundle getBundle();
method public android.view.accessibility.AccessibilityNodeInfo getChild(int);
method public int getChildCount();
method public java.lang.CharSequence getClassName();
method public java.lang.CharSequence getContentDescription();
+ method public int getInputType();
method public android.view.accessibility.AccessibilityNodeInfo getLabelFor();
method public android.view.accessibility.AccessibilityNodeInfo getLabeledBy();
method public int getMovementGranularities();
@@ -27438,6 +27444,7 @@ package android.view.accessibility {
method public void setEnabled(boolean);
method public void setFocusable(boolean);
method public void setFocused(boolean);
+ method public void setInputType(int);
method public void setLabelFor(android.view.View);
method public void setLabelFor(android.view.View, int);
method public void setLabeledBy(android.view.View);
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index 2d6453e67b5d..e835a9708169 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -406,6 +406,10 @@ final class AccessibilityInteractionController {
if (host == null || !ViewRootImpl.isViewDescendantOf(host, root)) {
break;
}
+ // The focused view not shown, we failed.
+ if (!isShown(host)) {
+ break;
+ }
// If the host has a provider ask this provider to search for the
// focus instead fetching all provider nodes to do the search here.
AccessibilityNodeProvider provider = host.getAccessibilityNodeProvider();
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 970d041fb324..55a8f747b5b2 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1564,6 +1564,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
private int mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED;
+ SendViewStateChangedAccessibilityEvent mSendViewStateChangedAccessibilityEvent;
+
/**
* The view's tag.
* {@hide}
@@ -2136,13 +2138,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* Flag indicating whether a view has accessibility focus.
*/
- static final int PFLAG2_ACCESSIBILITY_FOCUSED = 0x00000040 << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT;
+ static final int PFLAG2_ACCESSIBILITY_FOCUSED = 0x04000000;
/**
- * Flag indicating whether a view state for accessibility has changed.
+ * Flag whether the accessibility state of the subtree rooted at this view changed.
*/
- static final int PFLAG2_ACCESSIBILITY_STATE_CHANGED = 0x00000080
- << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT;
+ static final int PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED = 0x08000000;
/**
* Flag indicating whether a view failed the quickReject() check in draw(). This condition
@@ -4454,10 +4455,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
onFocusChanged(true, direction, previouslyFocusedRect);
refreshDrawableState();
-
- if (AccessibilityManager.getInstance(mContext).isEnabled()) {
- notifyAccessibilityStateChanged();
- }
}
}
@@ -4561,10 +4558,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (!rootViewRequestFocus()) {
notifyGlobalFocusCleared(this);
}
-
- if (AccessibilityManager.getInstance(mContext).isEnabled()) {
- notifyAccessibilityStateChanged();
- }
}
}
@@ -4593,10 +4586,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
onFocusChanged(false, 0, null);
refreshDrawableState();
-
- if (AccessibilityManager.getInstance(mContext).isEnabled()) {
- notifyAccessibilityStateChanged();
- }
}
}
@@ -4647,9 +4636,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
if (gainFocus) {
- if (AccessibilityManager.getInstance(mContext).isEnabled()) {
- sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
- }
+ sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
+ } else {
+ notifyViewAccessibilityStateChangedIfNeeded();
}
InputMethodManager imm = InputMethodManager.peekInstance();
@@ -4706,6 +4695,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @see AccessibilityDelegate
*/
public void sendAccessibilityEvent(int eventType) {
+ // Excluded views do not send accessibility events.
+ if (!includeForAccessibility()) {
+ return;
+ }
if (mAccessibilityDelegate != null) {
mAccessibilityDelegate.sendAccessibilityEvent(this, eventType);
} else {
@@ -5364,9 +5357,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mContentDescription = contentDescription;
final boolean nonEmptyDesc = contentDescription != null && contentDescription.length() > 0;
if (nonEmptyDesc && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
- setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
+ setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
+ notifySubtreeAccessibilityStateChangedIfNeeded();
+ } else {
+ notifyViewAccessibilityStateChangedIfNeeded();
}
- notifyAccessibilityStateChanged();
}
/**
@@ -6646,7 +6641,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
invalidate();
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
- notifyAccessibilityStateChanged();
return true;
}
return false;
@@ -6709,7 +6703,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_FOCUSED;
invalidate();
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
- notifyAccessibilityStateChanged();
}
}
@@ -6883,11 +6876,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO
*/
public void setImportantForAccessibility(int mode) {
+ final boolean oldIncludeForAccessibility = includeForAccessibility();
if (mode != getImportantForAccessibility()) {
mPrivateFlags2 &= ~PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK;
mPrivateFlags2 |= (mode << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT)
& PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK;
- notifyAccessibilityStateChanged();
+ if (oldIncludeForAccessibility != includeForAccessibility()) {
+ notifySubtreeAccessibilityStateChangedIfNeeded();
+ } else {
+ notifyViewAccessibilityStateChangedIfNeeded();
+ }
}
}
@@ -6994,25 +6992,44 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
- * Notifies accessibility services that some view's important for
- * accessibility state has changed. Note that such notifications
- * are made at most once every
+ * Notifies that the accessibility state of this view changed. The change
+ * is local to this view and does not represent structural changes such
+ * as children and parent. For example, the view became focusable. The
+ * notification is at at most once every
* {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}
- * to avoid unnecessary load to the system. Also once a view has
- * made a notifucation this method is a NOP until the notification has
- * been sent to clients.
+ * to avoid unnecessary load to the system. Also once a view has a pending
+ * notifucation this method is a NOP until the notification has been sent.
*
* @hide
+ */
+ public void notifyViewAccessibilityStateChangedIfNeeded() {
+ if (!AccessibilityManager.getInstance(mContext).isEnabled()) {
+ return;
+ }
+ if (mSendViewStateChangedAccessibilityEvent == null) {
+ mSendViewStateChangedAccessibilityEvent =
+ new SendViewStateChangedAccessibilityEvent();
+ }
+ mSendViewStateChangedAccessibilityEvent.runOrPost();
+ }
+
+ /**
+ * Notifies that the accessibility state of this view changed. The change
+ * is *not* local to this view and does represent structural changes such
+ * as children and parent. For example, the view size changed. The
+ * notification is at at most once every
+ * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}
+ * to avoid unnecessary load to the system. Also once a view has a pending
+ * notifucation this method is a NOP until the notification has been sent.
*
- * TODO: Makse sure this method is called for any view state change
- * that is interesting for accessilility purposes.
+ * @hide
*/
- public void notifyAccessibilityStateChanged() {
+ private void notifySubtreeAccessibilityStateChangedIfNeeded() {
if (!AccessibilityManager.getInstance(mContext).isEnabled()) {
return;
}
- if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_STATE_CHANGED) == 0) {
- mPrivateFlags2 |= PFLAG2_ACCESSIBILITY_STATE_CHANGED;
+ if ((mPrivateFlags2 & PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED) == 0) {
+ mPrivateFlags2 |= PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED;
if (mParent != null) {
mParent.childAccessibilityStateChanged(this);
}
@@ -7020,13 +7037,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
- * Reset the state indicating the this view has requested clients
- * interested in its accessibility state to be notified.
- *
- * @hide
+ * Reset the flag indicating the accessibility state of the subtree rooted
+ * at this view changed.
*/
- public void resetAccessibilityStateChanged() {
- mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_STATE_CHANGED;
+ void resetSubtreeAccessibilityStateChanged() {
+ mPrivateFlags2 &= ~PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED;
}
/**
@@ -7139,7 +7154,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|| getAccessibilitySelectionEnd() != end)
&& (start == end)) {
setAccessibilitySelection(start, end);
- notifyAccessibilityStateChanged();
+ notifyViewAccessibilityStateChangedIfNeeded();
return true;
}
} break;
@@ -8560,6 +8575,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @param mask Constant indicating the bit range that should be changed
*/
void setFlags(int flags, int mask) {
+ final boolean accessibilityEnabled =
+ AccessibilityManager.getInstance(mContext).isEnabled();
+ final boolean oldIncludeForAccessibility = accessibilityEnabled
+ ? includeForAccessibility() : false;
+
int old = mViewFlags;
mViewFlags = (mViewFlags & ~mask) | (flags & mask);
@@ -8584,9 +8604,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
if (mParent != null) mParent.focusableViewAvailable(this);
}
- if (AccessibilityManager.getInstance(mContext).isEnabled()) {
- notifyAccessibilityStateChanged();
- }
}
final int newVisibility = flags & VISIBILITY_MASK;
@@ -8707,10 +8724,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
}
- if (AccessibilityManager.getInstance(mContext).isEnabled()
- && ((changed & FOCUSABLE) != 0 || (changed & CLICKABLE) != 0
- || (changed & LONG_CLICKABLE) != 0 || (changed & ENABLED) != 0)) {
- notifyAccessibilityStateChanged();
+ if (accessibilityEnabled) {
+ if ((changed & FOCUSABLE_MASK) != 0 || (changed & VISIBILITY_MASK) != 0
+ || (changed & CLICKABLE) != 0 || (changed & LONG_CLICKABLE) != 0) {
+ if (oldIncludeForAccessibility != includeForAccessibility()) {
+ notifySubtreeAccessibilityStateChangedIfNeeded();
+ } else {
+ notifyViewAccessibilityStateChangedIfNeeded();
+ }
+ }
+ if ((changed & ENABLED_MASK) != 0) {
+ notifyViewAccessibilityStateChangedIfNeeded();
+ }
}
}
@@ -11757,6 +11782,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
jumpDrawablesToCurrentState();
clearAccessibilityFocus();
+ resetSubtreeAccessibilityStateChanged();
+
if (isFocused()) {
InputMethodManager imm = InputMethodManager.peekInstance();
imm.focusIn(this);
@@ -12052,8 +12079,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mCurrentAnimation = null;
mCurrentScene = null;
-
- resetAccessibilityStateChanged();
}
private void cleanupDraw() {
@@ -14438,6 +14463,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mPrivateFlags |= drawn;
mBackgroundSizeChanged = true;
+
+ notifySubtreeAccessibilityStateChangedIfNeeded();
}
return changed;
}
@@ -15202,9 +15229,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
invalidate(true);
refreshDrawableState();
dispatchSetSelected(selected);
- if (AccessibilityManager.getInstance(mContext).isEnabled()) {
- notifyAccessibilityStateChanged();
- }
+ notifyViewAccessibilityStateChangedIfNeeded();
}
}
@@ -18819,6 +18844,37 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
}
+ private class SendViewStateChangedAccessibilityEvent implements Runnable {
+ private boolean mPosted;
+ private long mLastEventTimeMillis;
+
+ public void run() {
+ mPosted = false;
+ mLastEventTimeMillis = SystemClock.uptimeMillis();
+ if (AccessibilityManager.getInstance(mContext).isEnabled()) {
+ AccessibilityEvent event = AccessibilityEvent.obtain();
+ event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+ event.setContentChangeType(AccessibilityEvent.CONTENT_CHANGE_TYPE_NODE);
+ sendAccessibilityEventUnchecked(event);
+ }
+ }
+
+ public void runOrPost() {
+ if (mPosted) {
+ return;
+ }
+ final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis;
+ final long minEventIntevalMillis =
+ ViewConfiguration.getSendRecurringAccessibilityEventsInterval();
+ if (timeSinceLastMillis >= minEventIntevalMillis) {
+ run();
+ } else {
+ postDelayed(this, minEventIntevalMillis - timeSinceLastMillis);
+ mPosted = true;
+ }
+ }
+ }
+
/**
* Dump all private flags in readable format, useful for documentation and
* sanity checking.
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 119ba729ad18..caed4a27d495 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -1698,16 +1698,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
/**
- * @hide
- */
- @Override
- public void childAccessibilityStateChanged(View child) {
- if (mParent != null) {
- mParent.childAccessibilityStateChanged(child);
- }
- }
-
- /**
* Implement this method to intercept hover events before they are handled
* by child views.
* <p>
@@ -2534,13 +2524,19 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
* @hide
*/
@Override
- public void resetAccessibilityStateChanged() {
- super.resetAccessibilityStateChanged();
+ public void childAccessibilityStateChanged(View root) {
+ if (mParent != null) {
+ mParent.childAccessibilityStateChanged(root);
+ }
+ }
+
+ @Override
+ void resetSubtreeAccessibilityStateChanged() {
+ super.resetSubtreeAccessibilityStateChanged();
View[] children = mChildren;
final int childCount = mChildrenCount;
for (int i = 0; i < childCount; i++) {
- View child = children[i];
- child.resetAccessibilityStateChanged();
+ children[i].resetSubtreeAccessibilityStateChanged();
}
}
@@ -3466,7 +3462,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
private void clearCachedLayoutMode() {
- if (!getBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET)) {
+ if (!hasBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET)) {
mLayoutMode = LAYOUT_MODE_UNDEFINED;
}
}
@@ -3597,6 +3593,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
if (child.hasTransientState()) {
childHasTransientStateChanged(child, true);
}
+
+ if (child.isImportantForAccessibility() && child.getVisibility() != View.GONE) {
+ childAccessibilityStateChanged(child);
+ }
}
private void addInArray(View child, int index) {
@@ -3836,6 +3836,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
onViewRemoved(view);
+
+ if (view.isImportantForAccessibility() && view.getVisibility() != View.GONE) {
+ childAccessibilityStateChanged(view);
+ }
}
/**
@@ -4786,7 +4790,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
setBooleanFlag(FLAG_USE_CHILD_DRAWING_ORDER, enabled);
}
- private boolean getBooleanFlag(int flag) {
+ private boolean hasBooleanFlag(int flag) {
return (mGroupFlags & flag) == flag;
}
@@ -4854,7 +4858,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
void invalidateInheritedLayoutMode(int layoutModeOfRoot) {
if (mLayoutMode == LAYOUT_MODE_UNDEFINED ||
mLayoutMode == layoutModeOfRoot ||
- getBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET)) {
+ hasBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET)) {
return;
}
setLayoutMode(LAYOUT_MODE_UNDEFINED, false);
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index d79aa7efad4d..2ebc1a19ed54 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -292,13 +292,14 @@ public interface ViewParent {
public ViewParent getParentForAccessibility();
/**
- * A child notifies its parent that its state for accessibility has changed.
- * That is some of the child properties reported to accessibility services has
- * changed, hence the interested services have to be notified for the new state.
+ * A child notifies its parent that the accessibility state of a subtree rooted
+ * at a given node changed. That is the structure of the subtree is different.
+ *
+ * @param The root of the changed subtree.
*
* @hide
*/
- public void childAccessibilityStateChanged(View child);
+ public void childAccessibilityStateChanged(View root);
/**
* Tells if this view parent can resolve the layout direction.
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 62e0d3dada03..a5f92de09294 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1728,10 +1728,6 @@ public final class ViewRootImpl implements ViewParent,
if (triggerGlobalLayoutListener) {
attachInfo.mRecomputeGlobalAttributes = false;
attachInfo.mTreeObserver.dispatchOnGlobalLayout();
-
- if (AccessibilityManager.getInstance(host.mContext).isEnabled()) {
- postSendWindowContentChangedCallback(mView);
- }
}
if (computesInternalInsets) {
@@ -5713,15 +5709,7 @@ public final class ViewRootImpl implements ViewParent,
mSendWindowContentChangedAccessibilityEvent =
new SendWindowContentChangedAccessibilityEvent();
}
- View oldSource = mSendWindowContentChangedAccessibilityEvent.mSource;
- if (oldSource == null) {
- mSendWindowContentChangedAccessibilityEvent.mSource = source;
- mHandler.postDelayed(mSendWindowContentChangedAccessibilityEvent,
- ViewConfiguration.getSendRecurringAccessibilityEventsInterval());
- } else {
- mSendWindowContentChangedAccessibilityEvent.mSource =
- getCommonPredecessor(oldSource, source);
- }
+ mSendWindowContentChangedAccessibilityEvent.runOrPost(source);
}
/**
@@ -6405,12 +6393,33 @@ public final class ViewRootImpl implements ViewParent,
private class SendWindowContentChangedAccessibilityEvent implements Runnable {
public View mSource;
+ public long mLastEventTimeMillis;
public void run() {
+ mLastEventTimeMillis = SystemClock.uptimeMillis();
+ if (AccessibilityManager.getInstance(mContext).isEnabled()) {
+ AccessibilityEvent event = AccessibilityEvent.obtain();
+ event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+ event.setContentChangeType(AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE);
+ mSource.sendAccessibilityEventUnchecked(event);
+ }
+ mSource.resetSubtreeAccessibilityStateChanged();
+ mSource = null;
+ }
+
+ public void runOrPost(View source) {
if (mSource != null) {
- mSource.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
- mSource.resetAccessibilityStateChanged();
- mSource = null;
+ mSource = getCommonPredecessor(mSource, source);
+ return;
+ }
+ mSource = source;
+ final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis;
+ final long minEventIntevalMillis =
+ ViewConfiguration.getSendRecurringAccessibilityEventsInterval();
+ if (timeSinceLastMillis >= minEventIntevalMillis) {
+ run();
+ } else {
+ mSource.postDelayed(this, minEventIntevalMillis - timeSinceLastMillis);
}
}
}
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index dbeca1f9bab1..82c8163b3923 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -326,6 +326,7 @@ import java.util.List;
* <em>Properties:</em></br>
* <ul>
* <li>{@link #getEventType()} - The type of the event.</li>
+ * <li>{@link #getContentChangeType()} - The type of content change.</li>
* <li>{@link #getSource()} - The source info (for registered clients).</li>
* <li>{@link #getClassName()} - The class name of the source.</li>
* <li>{@link #getPackageName()} - The package name of the source.</li>
@@ -661,6 +662,18 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
public static final int TYPE_TOUCH_INTERACTION_END = 0x00200000;
/**
+ * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event:
+ * The subtree rooted at the source node changed.
+ */
+ public static final int CONTENT_CHANGE_TYPE_SUBTREE = 0;
+
+ /**
+ * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event:
+ * Only the source node changed.
+ */
+ public static final int CONTENT_CHANGE_TYPE_NODE = 1;
+
+ /**
* Mask for {@link AccessibilityEvent} all types.
*
* @see #TYPE_VIEW_CLICKED
@@ -695,6 +708,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
private long mEventTime;
int mMovementGranularity;
int mAction;
+ int mContentChangeType;
private final ArrayList<AccessibilityRecord> mRecords = new ArrayList<AccessibilityRecord>();
@@ -714,6 +728,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
mEventType = event.mEventType;
mMovementGranularity = event.mMovementGranularity;
mAction = event.mAction;
+ mContentChangeType = event.mContentChangeType;
mEventTime = event.mEventTime;
mPackageName = event.mPackageName;
}
@@ -777,6 +792,33 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
}
/**
+ * Gets the type of node tree change signaled by an
+ * {@link #TYPE_WINDOW_CONTENT_CHANGED} event.
+ *
+ * @see #CONTENT_CHANGE_TYPE_NODE
+ * @see #CONTENT_CHANGE_TYPE_SUBTREE
+ *
+ * @return The change type.
+ */
+ public int getContentChangeType() {
+ return mContentChangeType;
+ }
+
+ /**
+ * Sets the type of node tree change signaled by an
+ * {@link #TYPE_WINDOW_CONTENT_CHANGED} event.
+ *
+ * @see #CONTENT_CHANGE_TYPE_NODE
+ * @see #CONTENT_CHANGE_TYPE_SUBTREE
+ *
+ * @param changeType The change type.
+ */
+ public void setContentChangeType(int changeType) {
+ enforceNotSealed();
+ mContentChangeType = changeType;
+ }
+
+ /**
* Sets the event type.
*
* @param eventType The event type.
@@ -943,6 +985,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
mEventType = 0;
mMovementGranularity = 0;
mAction = 0;
+ mContentChangeType = 0;
mPackageName = null;
mEventTime = 0;
while (!mRecords.isEmpty()) {
@@ -961,6 +1004,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
mEventType = parcel.readInt();
mMovementGranularity = parcel.readInt();
mAction = parcel.readInt();
+ mContentChangeType = parcel.readInt();
mPackageName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
mEventTime = parcel.readLong();
mConnectionId = parcel.readInt();
@@ -1013,6 +1057,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
parcel.writeInt(mEventType);
parcel.writeInt(mMovementGranularity);
parcel.writeInt(mAction);
+ parcel.writeInt(mContentChangeType);
TextUtils.writeToParcel(mPackageName, parcel, 0);
parcel.writeLong(mEventTime);
parcel.writeInt(mConnectionId);
@@ -1074,6 +1119,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
builder.append(super.toString());
if (DEBUG) {
builder.append("\n");
+ builder.append("; ContentChangeType: ").append(mContentChangeType);
builder.append("; sourceWindowId: ").append(mSourceWindowId);
builder.append("; mSourceNodeId: ").append(mSourceNodeId);
for (int i = 0; i < mRecords.size(); i++) {
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 84d7e720b31f..139df3e57af0 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -163,7 +163,7 @@ public final class AccessibilityInteractionClient
public AccessibilityNodeInfo getRootInActiveWindow(int connectionId) {
return findAccessibilityNodeInfoByAccessibilityId(connectionId,
AccessibilityNodeInfo.ACTIVE_WINDOW_ID, AccessibilityNodeInfo.ROOT_NODE_ID,
- AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS);
+ false, AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS);
}
/**
@@ -177,18 +177,22 @@ public final class AccessibilityInteractionClient
* where to start the search. Use
* {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID}
* to start from the root.
+ * @param bypassCache Whether to bypass the cache while looking for the node.
* @param prefetchFlags flags to guide prefetching.
* @return An {@link AccessibilityNodeInfo} if found, null otherwise.
*/
public AccessibilityNodeInfo findAccessibilityNodeInfoByAccessibilityId(int connectionId,
- int accessibilityWindowId, long accessibilityNodeId, int prefetchFlags) {
+ int accessibilityWindowId, long accessibilityNodeId, boolean bypassCache,
+ int prefetchFlags) {
try {
IAccessibilityServiceConnection connection = getConnection(connectionId);
if (connection != null) {
- AccessibilityNodeInfo cachedInfo = sAccessibilityNodeInfoCache.get(
- accessibilityNodeId);
- if (cachedInfo != null) {
- return cachedInfo;
+ if (!bypassCache) {
+ AccessibilityNodeInfo cachedInfo = sAccessibilityNodeInfoCache.get(
+ accessibilityNodeId);
+ if (cachedInfo != null) {
+ return cachedInfo;
+ }
}
final int interactionId = mInteractionIdCounter.getAndIncrement();
final boolean success = connection.findAccessibilityNodeInfoByAccessibilityId(
@@ -350,7 +354,7 @@ public final class AccessibilityInteractionClient
}
} catch (RemoteException re) {
if (DEBUG) {
- Log.w(LOG_TAG, "Error while calling remote findAccessibilityFocus", re);
+ Log.w(LOG_TAG, "Error while calling remote findFocus", re);
}
}
return null;
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index d9c9b69bfced..750e0226f2fe 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -21,6 +21,7 @@ import android.graphics.Rect;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.InputType;
import android.util.Pools.SynchronizedPool;
import android.util.SparseLongArray;
import android.view.View;
@@ -482,6 +483,9 @@ public class AccessibilityNodeInfo implements Parcelable {
private int mTextSelectionStart = UNDEFINED;
private int mTextSelectionEnd = UNDEFINED;
+ private int mInputType = InputType.TYPE_NULL;
+
+ private Bundle mBundle;
private int mConnectionId = UNDEFINED;
@@ -594,16 +598,20 @@ public class AccessibilityNodeInfo implements Parcelable {
* since it represents a view that is no longer in the view tree and should
* be recycled.
* </p>
+ *
+ * @param bypassCache Whether to bypass the cache.
* @return Whether the refresh succeeded.
+ *
+ * @hide
*/
- public boolean refresh() {
+ public boolean refresh(boolean bypassCache) {
enforceSealed();
if (!canPerformRequestOverConnection(mSourceNodeId)) {
return false;
}
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
AccessibilityNodeInfo refreshedInfo = client.findAccessibilityNodeInfoByAccessibilityId(
- mConnectionId, mWindowId, mSourceNodeId, 0);
+ mConnectionId, mWindowId, mSourceNodeId, bypassCache, 0);
if (refreshedInfo == null) {
return false;
}
@@ -613,6 +621,19 @@ public class AccessibilityNodeInfo implements Parcelable {
}
/**
+ * Refreshes this info with the latest state of the view it represents.
+ * <p>
+ * <strong>Note:</strong> If this method returns false this info is obsolete
+ * since it represents a view that is no longer in the view tree and should
+ * be recycled.
+ * </p>
+ * @return Whether the refresh succeeded.
+ */
+ public boolean refresh() {
+ return refresh(false);
+ }
+
+ /**
* @return The ids of the children.
*
* @hide
@@ -652,7 +673,7 @@ public class AccessibilityNodeInfo implements Parcelable {
final long childId = mChildNodeIds.get(index);
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId, mWindowId,
- childId, FLAG_PREFETCH_DESCENDANTS);
+ childId, false, FLAG_PREFETCH_DESCENDANTS);
}
/**
@@ -878,7 +899,7 @@ public class AccessibilityNodeInfo implements Parcelable {
}
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
- mWindowId, mParentNodeId, FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
+ mWindowId, mParentNodeId, false, FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
}
/**
@@ -1470,7 +1491,7 @@ public class AccessibilityNodeInfo implements Parcelable {
}
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
- mWindowId, mLabelForId, FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
+ mWindowId, mLabelForId, false, FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
}
/**
@@ -1527,7 +1548,7 @@ public class AccessibilityNodeInfo implements Parcelable {
}
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
- mWindowId, mLabeledById, FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
+ mWindowId, mLabeledById, false, FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
}
/**
@@ -1600,6 +1621,52 @@ public class AccessibilityNodeInfo implements Parcelable {
}
/**
+ * Gets the input type of the source as defined by {@link InputType}.
+ *
+ * @return The input type.
+ */
+ public int getInputType() {
+ return mInputType;
+ }
+
+ /**
+ * Sets the input type of the source as defined by {@link InputType}.
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an
+ * AccessibilityService.
+ * </p>
+ *
+ * @param inputType The input type.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public void setInputType(int inputType) {
+ mInputType = inputType;
+ }
+
+ /**
+ * Gets an optional bundle with additional data. The bundle
+ * is lazily created and never <code>null</code>.
+ * <p>
+ * <strong>Note:</strong> It is recommended to use the package
+ * name of your application as a prefix for the keys to avoid
+ * collisions which may confuse an accessibility service if the
+ * same key has different meaning when emitted from different
+ * applications.
+ * </p>
+ *
+ * @return The bundle.
+ */
+ public Bundle getBundle() {
+ if (mBundle == null) {
+ mBundle = new Bundle();
+ }
+ return mBundle;
+ }
+
+ /**
* Gets the value of a boolean property.
*
* @param property The property.
@@ -1845,6 +1912,14 @@ public class AccessibilityNodeInfo implements Parcelable {
parcel.writeInt(mTextSelectionStart);
parcel.writeInt(mTextSelectionEnd);
+ parcel.writeInt(mInputType);
+
+ if (mBundle != null) {
+ parcel.writeInt(1);
+ parcel.writeBundle(mBundle);
+ } else {
+ parcel.writeInt(0);
+ }
// Since instances of this class are fetched via synchronous i.e. blocking
// calls in IPCs we always recycle as soon as the instance is marshaled.
@@ -1880,6 +1955,10 @@ public class AccessibilityNodeInfo implements Parcelable {
}
mTextSelectionStart = other.mTextSelectionStart;
mTextSelectionEnd = other.mTextSelectionEnd;
+ mInputType = other.mInputType;
+ if (other.mBundle != null && !other.mBundle.isEmpty()) {
+ getBundle().putAll(other.mBundle);
+ }
}
/**
@@ -1927,6 +2006,11 @@ public class AccessibilityNodeInfo implements Parcelable {
mTextSelectionStart = parcel.readInt();
mTextSelectionEnd = parcel.readInt();
+ mInputType = parcel.readInt();
+
+ if (parcel.readInt() == 1) {
+ getBundle().putAll(parcel.readBundle());
+ }
}
/**
@@ -1953,6 +2037,10 @@ public class AccessibilityNodeInfo implements Parcelable {
mActions = 0;
mTextSelectionStart = UNDEFINED;
mTextSelectionEnd = UNDEFINED;
+ mInputType = InputType.TYPE_NULL;
+ if (mBundle != null) {
+ mBundle.clear();
+ }
}
/**
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java b/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java
index 28518aab8ab9..dded74cd9918 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java
@@ -39,9 +39,9 @@ public class AccessibilityNodeInfoCache {
private static final boolean ENABLED = true;
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = true;
- private static final boolean CHECK_INTEGRITY = true;
+ private static final boolean CHECK_INTEGRITY_IF_DEBUGGABLE_BUILD = true;
private final Object mLock = new Object();
@@ -67,16 +67,12 @@ public class AccessibilityNodeInfoCache {
if (ENABLED) {
final int eventType = event.getEventType();
switch (eventType) {
- case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: {
- // New window so we clear the cache.
- mWindowId = event.getWindowId();
- clear();
- } break;
+ case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER:
case AccessibilityEvent.TYPE_VIEW_HOVER_EXIT: {
final int windowId = event.getWindowId();
+ // If a new window, we clear the cache.
if (mWindowId != windowId) {
- // New window so we clear the cache.
mWindowId = windowId;
clear();
}
@@ -87,34 +83,48 @@ public class AccessibilityNodeInfoCache {
case AccessibilityEvent.TYPE_VIEW_SELECTED:
case AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED:
case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED: {
- // Since we prefetch the descendants of a node we
- // just remove the entire subtree since when the node
- // is fetched we will gets its descendant anyway.
- synchronized (mLock) {
- final long sourceId = event.getSourceNodeId();
- clearSubTreeLocked(sourceId);
- if (eventType == AccessibilityEvent.TYPE_VIEW_FOCUSED) {
- clearSubtreeWithOldInputFocusLocked(sourceId);
- }
- if (eventType == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED) {
- clearSubtreeWithOldAccessibilityFocusLocked(sourceId);
- }
- }
+ refreshCachedNode(event.getSourceNodeId());
} break;
- case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED:
case AccessibilityEvent.TYPE_VIEW_SCROLLED: {
+ clearSubTreeLocked(event.getSourceNodeId());
+ } break;
+ case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED: {
synchronized (mLock) {
- final long accessibilityNodeId = event.getSourceNodeId();
- clearSubTreeLocked(accessibilityNodeId);
+ final long sourceId = event.getSourceNodeId();
+ if (event.getContentChangeType()
+ == AccessibilityEvent.CONTENT_CHANGE_TYPE_NODE) {
+ refreshCachedNode(sourceId);
+ } else {
+ clearSubTreeLocked(sourceId);
+ }
}
} break;
}
- if (Build.IS_DEBUGGABLE && CHECK_INTEGRITY) {
+ if (Build.IS_DEBUGGABLE && CHECK_INTEGRITY_IF_DEBUGGABLE_BUILD) {
checkIntegrity();
}
}
}
+ private void refreshCachedNode(long sourceId) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "Refresing cached node.");
+ }
+ synchronized (mLock) {
+ AccessibilityNodeInfo cachedInfo = mCacheImpl.get(sourceId);
+ // If the source is not in the cache - nothing to do.
+ if (cachedInfo == null) {
+ return;
+ }
+ // The node changed so we will just refresh it right now.
+ if (cachedInfo.refresh(false)) {
+ return;
+ }
+ // Weird, we could not refresh. Just evict the entire sub-tree.
+ clearSubTreeLocked(sourceId);
+ }
+ }
+
/**
* Gets a cached {@link AccessibilityNodeInfo} given its accessibility node id.
*
@@ -131,7 +141,7 @@ public class AccessibilityNodeInfoCache {
info = AccessibilityNodeInfo.obtain(info);
}
if (DEBUG) {
- Log.i(LOG_TAG, "get(" + accessibilityNodeId + ") = " + info);
+// Log.i(LOG_TAG, "get(" + accessibilityNodeId + ") = " + info);
}
return info;
}
@@ -149,7 +159,7 @@ public class AccessibilityNodeInfoCache {
if (ENABLED) {
synchronized(mLock) {
if (DEBUG) {
- Log.i(LOG_TAG, "add(" + info + ")");
+// Log.i(LOG_TAG, "add(" + info + ")");
}
final long sourceId = info.getSourceNodeId();
@@ -212,6 +222,13 @@ public class AccessibilityNodeInfoCache {
* @param rootNodeId The root id.
*/
private void clearSubTreeLocked(long rootNodeId) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "Clearing cached subtree.");
+ }
+ clearSubTreeRecursiveLocked(rootNodeId);
+ }
+
+ private void clearSubTreeRecursiveLocked(long rootNodeId) {
AccessibilityNodeInfo current = mCacheImpl.get(rootNodeId);
if (current == null) {
return;
@@ -221,41 +238,7 @@ public class AccessibilityNodeInfoCache {
final int childCount = childNodeIds.size();
for (int i = 0; i < childCount; i++) {
final long childNodeId = childNodeIds.valueAt(i);
- clearSubTreeLocked(childNodeId);
- }
- }
-
- /**
- * We are enforcing the invariant for a single input focus.
- *
- * @param currentInputFocusId The current input focused node.
- */
- private void clearSubtreeWithOldInputFocusLocked(long currentInputFocusId) {
- final int cacheSize = mCacheImpl.size();
- for (int i = 0; i < cacheSize; i++) {
- AccessibilityNodeInfo info = mCacheImpl.valueAt(i);
- final long infoSourceId = info.getSourceNodeId();
- if (infoSourceId != currentInputFocusId && info.isFocused()) {
- clearSubTreeLocked(infoSourceId);
- return;
- }
- }
- }
-
- /**
- * We are enforcing the invariant for a single accessibility focus.
- *
- * @param currentAccessibilityFocusId The current input focused node.
- */
- private void clearSubtreeWithOldAccessibilityFocusLocked(long currentAccessibilityFocusId) {
- final int cacheSize = mCacheImpl.size();
- for (int i = 0; i < cacheSize; i++) {
- AccessibilityNodeInfo info = mCacheImpl.valueAt(i);
- final long infoSourceId = info.getSourceNodeId();
- if (infoSourceId != currentAccessibilityFocusId && info.isAccessibilityFocused()) {
- clearSubTreeLocked(infoSourceId);
- return;
- }
+ clearSubTreeRecursiveLocked(childNodeId);
}
}
@@ -327,16 +310,17 @@ public class AccessibilityNodeInfoCache {
}
// Check for disconnected nodes or ones from another window.
- final int cacheSize = mCacheImpl.size();
- for (int i = 0; i < cacheSize; i++) {
+ for (int i = 0; i < mCacheImpl.size(); i++) {
AccessibilityNodeInfo info = mCacheImpl.valueAt(i);
if (!seen.contains(info)) {
if (info.getWindowId() == windowId) {
- Log.e(LOG_TAG, "Disconneced node: ");
+ Log.e(LOG_TAG, "Disconneced node: " + info);
} else {
Log.e(LOG_TAG, "Node from: " + info.getWindowId() + " not from:"
+ windowId + " " + info);
}
+ mCacheImpl.removeAt(i);
+ i--;
}
}
}
diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
index 7147c57c8b0d..3fcd2189066f 100644
--- a/core/java/android/view/accessibility/AccessibilityRecord.java
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -164,7 +164,7 @@ public class AccessibilityRecord {
}
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId, mSourceWindowId,
- mSourceNodeId, GET_SOURCE_PREFETCH_FLAGS);
+ mSourceNodeId, false, GET_SOURCE_PREFETCH_FLAGS);
}
/**
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index 502de314051b..4a2df58c5415 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -31,7 +31,6 @@ import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.accessibility.AccessibilityNodeProvider;
/**
* An AdapterView is a view whose children are determined by an {@link Adapter}.
@@ -1034,8 +1033,7 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup {
checkSelectionChanged();
}
- //TODO: Hmm, we do not know the old state so this is sub-optimal
- notifyAccessibilityStateChanged();
+ childAccessibilityStateChanged(this);
}
void checkSelectionChanged() {
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index de8b80d45ec6..f1c3139f094b 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -93,7 +93,7 @@ public class CheckedTextView extends TextView implements Checkable {
if (mChecked != checked) {
mChecked = checked;
refreshDrawableState();
- notifyAccessibilityStateChanged();
+ notifyViewAccessibilityStateChangedIfNeeded();
}
}
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index 452ad1bd3e6f..c4406ac66d69 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -114,7 +114,7 @@ public abstract class CompoundButton extends Button implements Checkable {
if (mChecked != checked) {
mChecked = checked;
refreshDrawableState();
- notifyAccessibilityStateChanged();
+ notifyViewAccessibilityStateChangedIfNeeded();
// Avoid infinite recursions if setChecked() is called from a listener
if (mBroadcasting) {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 12d0c49aca3b..71baa9004680 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -1721,7 +1721,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
setText(mText);
if (hasPasswordTransformationMethod()) {
- notifyAccessibilityStateChanged();
+ notifyViewAccessibilityStateChangedIfNeeded();
}
}
@@ -7318,7 +7318,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*/
protected void onSelectionChanged(int selStart, int selEnd) {
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED);
- notifyAccessibilityStateChanged();
}
/**
@@ -8131,6 +8130,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
info.setEditable(true);
}
+ if (mEditor != null) {
+ info.setInputType(mEditor.mInputType);
+ }
+
if (!TextUtils.isEmpty(mText)) {
info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY);
info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY);
@@ -8163,7 +8166,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
case AccessibilityNodeInfo.ACTION_COPY: {
if (isFocused() && canCopy()) {
if (onTextContextMenuItem(ID_COPY)) {
- notifyAccessibilityStateChanged();
return true;
}
}
@@ -8171,7 +8173,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
case AccessibilityNodeInfo.ACTION_PASTE: {
if (isFocused() && canPaste()) {
if (onTextContextMenuItem(ID_PASTE)) {
- notifyAccessibilityStateChanged();
return true;
}
}
@@ -8179,7 +8180,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
case AccessibilityNodeInfo.ACTION_CUT: {
if (isFocused() && canCut()) {
if (onTextContextMenuItem(ID_CUT)) {
- notifyAccessibilityStateChanged();
return true;
}
}
@@ -8198,7 +8198,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// No arguments clears the selection.
if (start == end && end == -1) {
Selection.removeSelection((Spannable) text);
- notifyAccessibilityStateChanged();
return true;
}
if (start >= 0 && start <= end && end <= text.length()) {
@@ -8207,7 +8206,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (mEditor != null) {
mEditor.startSelectionActionMode();
}
- notifyAccessibilityStateChanged();
return true;
}
}