diff options
author | Alan Viverette <alanv@google.com> | 2013-09-13 01:45:10 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2013-09-13 01:45:10 +0000 |
commit | 2a65a2839e9b3e59a72348ee088f86cda7df604a (patch) | |
tree | fd29d3025917df88f1854a79bd40bdd38506846e /core/java/android/view | |
parent | b72ff5aa4b8be587bcea82761aa08cd8c14b8b48 (diff) | |
parent | 77e9a28e2faa36f127231b842476d47f9823a83a (diff) | |
download | frameworks_base-2a65a2839e9b3e59a72348ee088f86cda7df604a.zip frameworks_base-2a65a2839e9b3e59a72348ee088f86cda7df604a.tar.gz frameworks_base-2a65a2839e9b3e59a72348ee088f86cda7df604a.tar.bz2 |
Merge "Add live region politeness to View, AccessibilityNodeInfo" into klp-dev
Diffstat (limited to 'core/java/android/view')
-rw-r--r-- | core/java/android/view/View.java | 180 | ||||
-rw-r--r-- | core/java/android/view/ViewGroup.java | 11 | ||||
-rw-r--r-- | core/java/android/view/ViewParent.java | 21 | ||||
-rw-r--r-- | core/java/android/view/ViewRootImpl.java | 17 | ||||
-rw-r--r-- | core/java/android/view/accessibility/AccessibilityEvent.java | 67 | ||||
-rw-r--r-- | core/java/android/view/accessibility/AccessibilityNodeInfo.java | 114 | ||||
-rw-r--r-- | core/java/android/view/accessibility/AccessibilityNodeInfoCache.java | 8 |
7 files changed, 278 insertions, 140 deletions
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 8f8f9c6..a5db6ee 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -2134,6 +2134,50 @@ public class View implements Drawable.Callback, KeyEvent.Callback, << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; /** + * Shift for the bits in {@link #mPrivateFlags2} related to the + * "accessibilityLiveRegion" attribute. + */ + static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT = 22; + + /** + * Live region mode specifying that accessibility services should not + * automatically announce changes to this view. This is the default live + * region mode for most views. + * <p> + * Use with {@link #setAccessibilityLiveRegion(int)}. + */ + public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0x00000000; + + /** + * Live region mode specifying that accessibility services should announce + * changes to this view. + * <p> + * Use with {@link #setAccessibilityLiveRegion(int)}. + */ + public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 0x00000001; + + /** + * Live region mode specifying that accessibility services should interrupt + * ongoing speech to immediately announce changes to this view. + * <p> + * Use with {@link #setAccessibilityLiveRegion(int)}. + */ + public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 0x00000002; + + /** + * The default whether the view is important for accessibility. + */ + static final int ACCESSIBILITY_LIVE_REGION_DEFAULT = ACCESSIBILITY_LIVE_REGION_NONE; + + /** + * Mask for obtaining the bits which specify a view's accessibility live + * region mode. + */ + static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK = (ACCESSIBILITY_LIVE_REGION_NONE + | ACCESSIBILITY_LIVE_REGION_POLITE | ACCESSIBILITY_LIVE_REGION_ASSERTIVE) + << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; + + /** * Flag indicating whether a view has accessibility focus. */ static final int PFLAG2_ACCESSIBILITY_FOCUSED = 0x04000000; @@ -3763,6 +3807,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, setImportantForAccessibility(a.getInt(attr, IMPORTANT_FOR_ACCESSIBILITY_DEFAULT)); break; + case R.styleable.View_accessibilityLiveRegion: + setAccessibilityLiveRegion(a.getInt(attr, ACCESSIBILITY_LIVE_REGION_DEFAULT)); + break; } } @@ -4710,7 +4757,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (gainFocus) { sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); } else { - notifyViewAccessibilityStateChangedIfNeeded(); + notifyViewAccessibilityStateChangedIfNeeded( + AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); } InputMethodManager imm = InputMethodManager.peekInstance(); @@ -5431,7 +5479,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); notifySubtreeAccessibilityStateChangedIfNeeded(); } else { - notifyViewAccessibilityStateChangedIfNeeded(); + notifyViewAccessibilityStateChangedIfNeeded( + AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION); } } @@ -6954,6 +7003,58 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** + * Sets the live region mode for this view. This indicates to accessibility + * services whether they should automatically notify the user about changes + * to the view's content description or text, or to the content descriptions + * or text of the view's children (where applicable). + * <p> + * For example, in a login screen with a TextView that displays an "incorrect + * password" notification, that view should be marked as a live region with + * mode {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. + * <p> + * To disable change notifications for this view, use + * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. This is the default live region + * mode for most views. + * <p> + * To indicate that the user should be notified of changes, use + * {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. + * <p> + * If the view's changes should interrupt ongoing speech and notify the user + * immediately, use {@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE}. + * + * @param mode The live region mode for this view, one of: + * <ul> + * <li>{@link #ACCESSIBILITY_LIVE_REGION_NONE} + * <li>{@link #ACCESSIBILITY_LIVE_REGION_POLITE} + * <li>{@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE} + * </ul> + * @attr ref android.R.styleable#View_accessibilityLiveRegion + */ + public void setAccessibilityLiveRegion(int mode) { + if (mode != getAccessibilityLiveRegion()) { + mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; + mPrivateFlags2 |= (mode << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT) + & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; + notifyViewAccessibilityStateChangedIfNeeded( + AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); + } + } + + /** + * Gets the live region mode for this View. + * + * @return The live region mode for the view. + * + * @attr ref android.R.styleable#View_accessibilityLiveRegion + * + * @see #setAccessibilityLiveRegion(int) + */ + public int getAccessibilityLiveRegion() { + return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK) + >> PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; + } + + /** * Sets how to determine whether this view is important for accessibility * which is if it fires accessibility events and if it is reported to * accessibility services that query the screen. @@ -6975,7 +7076,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (oldIncludeForAccessibility != includeForAccessibility()) { notifySubtreeAccessibilityStateChangedIfNeeded(); } else { - notifyViewAccessibilityStateChangedIfNeeded(); + notifyViewAccessibilityStateChangedIfNeeded( + AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); } } } @@ -6997,7 +7099,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return false; case IMPORTANT_FOR_ACCESSIBILITY_AUTO: return isActionableForAccessibility() || hasListenersForAccessibility() - || getAccessibilityNodeProvider() != null; + || getAccessibilityNodeProvider() != null + || getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE; default: throw new IllegalArgumentException("Unknow important for accessibility mode: " + mode); @@ -7094,7 +7197,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * @hide */ - public void notifyViewAccessibilityStateChangedIfNeeded() { + public void notifyViewAccessibilityStateChangedIfNeeded(int changeType) { if (!AccessibilityManager.getInstance(mContext).isEnabled()) { return; } @@ -7102,7 +7205,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mSendViewStateChangedAccessibilityEvent = new SendViewStateChangedAccessibilityEvent(); } - mSendViewStateChangedAccessibilityEvent.runOrPost(); + mSendViewStateChangedAccessibilityEvent.runOrPost(changeType); } /** @@ -7124,7 +7227,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mPrivateFlags2 |= PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; if (mParent != null) { try { - mParent.childAccessibilityStateChanged(this); + mParent.notifySubtreeAccessibilityStateChanged( + this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE); } catch (AbstractMethodError e) { Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + " does not fully implement ViewParent", e); @@ -7251,7 +7355,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, || getAccessibilitySelectionEnd() != end) && (start == end)) { setAccessibilitySelection(start, end); - notifyViewAccessibilityStateChangedIfNeeded(); + notifyViewAccessibilityStateChangedIfNeeded( + AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); return true; } } break; @@ -8825,11 +8930,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (oldIncludeForAccessibility != includeForAccessibility()) { notifySubtreeAccessibilityStateChangedIfNeeded(); } else { - notifyViewAccessibilityStateChangedIfNeeded(); + notifyViewAccessibilityStateChangedIfNeeded( + AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); } - } - if ((changed & ENABLED_MASK) != 0) { - notifyViewAccessibilityStateChangedIfNeeded(); + } else if ((changed & ENABLED_MASK) != 0) { + notifyViewAccessibilityStateChangedIfNeeded( + AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); } } } @@ -15430,7 +15536,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, invalidate(true); refreshDrawableState(); dispatchSetSelected(selected); - notifyViewAccessibilityStateChangedIfNeeded(); + notifyViewAccessibilityStateChangedIfNeeded( + AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); } } @@ -19172,21 +19279,44 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } private class SendViewStateChangedAccessibilityEvent implements Runnable { + private int mChangeTypes = 0; private boolean mPosted; + private boolean mPostedWithDelay; private long mLastEventTimeMillis; + @Override public void run() { mPosted = false; + mPostedWithDelay = false; mLastEventTimeMillis = SystemClock.uptimeMillis(); if (AccessibilityManager.getInstance(mContext).isEnabled()) { - AccessibilityEvent event = AccessibilityEvent.obtain(); + final AccessibilityEvent event = AccessibilityEvent.obtain(); event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); - event.setContentChangeType(AccessibilityEvent.CONTENT_CHANGE_TYPE_NODE); + event.setContentChangeTypes(mChangeTypes); sendAccessibilityEventUnchecked(event); } + mChangeTypes = 0; } - public void runOrPost() { + public void runOrPost(int changeType) { + mChangeTypes |= changeType; + + // If this is a live region or the child of a live region, collect + // all events from this frame and send them on the next frame. + if (inLiveRegion()) { + // If we're already posted with a delay, remove that. + if (mPostedWithDelay) { + removeCallbacks(this); + mPostedWithDelay = false; + } + // Only post if we're not already posted. + if (!mPosted) { + post(this); + mPosted = true; + } + return; + } + if (mPosted) { return; } @@ -19199,10 +19329,28 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } else { postDelayed(this, minEventIntevalMillis - timeSinceLastMillis); mPosted = true; + mPostedWithDelay = true; } } } + private boolean inLiveRegion() { + if (getAccessibilityLiveRegion() != View.ACCESSIBILITY_LIVE_REGION_NONE) { + return true; + } + + ViewParent parent = getParent(); + while (parent instanceof View) { + if (((View) parent).getAccessibilityLiveRegion() + != View.ACCESSIBILITY_LIVE_REGION_NONE) { + return true; + } + parent = parent.getParent(); + } + + return false; + } + /** * 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 faeee3f..9414237 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -38,6 +38,7 @@ import android.util.Log; import android.util.Pools.SynchronizedPool; import android.util.SparseArray; import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; import android.view.animation.Animation; import android.view.animation.AnimationUtils; @@ -2528,10 +2529,14 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } @Override - public void childAccessibilityStateChanged(View root) { - if (mParent != null) { + public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) { + // If this is a live region, we should send a subtree change event + // from this view. Otherwise, we can let it propagate up. + if (getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE) { + notifyViewAccessibilityStateChangedIfNeeded(changeType); + } else if (mParent != null) { try { - mParent.childAccessibilityStateChanged(root); + mParent.notifySubtreeAccessibilityStateChanged(this, source, changeType); } catch (AbstractMethodError e) { Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + " does not fully implement ViewParent", e); diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java index 35113db..0137693 100644 --- a/core/java/android/view/ViewParent.java +++ b/core/java/android/view/ViewParent.java @@ -309,12 +309,21 @@ public interface ViewParent { public ViewParent getParentForAccessibility(); /** - * 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 root The root of the changed subtree. - */ - public void childAccessibilityStateChanged(View root); + * Notifies a view parent that the accessibility state of one of its + * descendants has changed and that the structure of the subtree is + * different. + * @param child The direct child whose subtree has changed. + * @param source The descendant view that changed. + * @param changeType A bit mask of the types of changes that occurred. One + * or more of: + * <ul> + * <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION} + * <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_SUBTREE} + * <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_TEXT} + * <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_UNDEFINED} + * </ul> + */ + public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType); /** * 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 50d5d45..38f28ae 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -5807,12 +5807,12 @@ public final class ViewRootImpl implements ViewParent, * This event is send at most once every * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}. */ - private void postSendWindowContentChangedCallback(View source) { + private void postSendWindowContentChangedCallback(View source, int changeType) { if (mSendWindowContentChangedAccessibilityEvent == null) { mSendWindowContentChangedAccessibilityEvent = new SendWindowContentChangedAccessibilityEvent(); } - mSendWindowContentChangedAccessibilityEvent.runOrPost(source); + mSendWindowContentChangedAccessibilityEvent.runOrPost(source, changeType); } /** @@ -5884,8 +5884,8 @@ public final class ViewRootImpl implements ViewParent, } @Override - public void childAccessibilityStateChanged(View child) { - postSendWindowContentChangedCallback(child); + public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) { + postSendWindowContentChangedCallback(source, changeType); } @Override @@ -6538,6 +6538,8 @@ public final class ViewRootImpl implements ViewParent, } private class SendWindowContentChangedAccessibilityEvent implements Runnable { + private int mChangeTypes = 0; + public View mSource; public long mLastEventTimeMillis; @@ -6548,7 +6550,7 @@ public final class ViewRootImpl implements ViewParent, mLastEventTimeMillis = SystemClock.uptimeMillis(); AccessibilityEvent event = AccessibilityEvent.obtain(); event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); - event.setContentChangeType(AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE); + event.setContentChangeTypes(mChangeTypes); mSource.sendAccessibilityEventUnchecked(event); } else { mLastEventTimeMillis = 0; @@ -6556,17 +6558,20 @@ public final class ViewRootImpl implements ViewParent, // In any case reset to initial state. mSource.resetSubtreeAccessibilityStateChanged(); mSource = null; + mChangeTypes = 0; } - public void runOrPost(View source) { + public void runOrPost(View source, int changeType) { if (mSource != null) { // If there is no common predecessor, then mSource points to // a removed view, hence in this case always prefer the source. View predecessor = getCommonPredecessor(mSource, source); mSource = (predecessor != null) ? predecessor : source; + mChangeTypes |= changeType; return; } mSource = source; + mChangeTypes = changeType; final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis; final long minEventIntevalMillis = ViewConfiguration.getSendRecurringAccessibilityEventsInterval(); diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java index 82c8163..7e2bffa 100644 --- a/core/java/android/view/accessibility/AccessibilityEvent.java +++ b/core/java/android/view/accessibility/AccessibilityEvent.java @@ -326,7 +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 #getContentChangeTypes()} - The type of content changes.</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> @@ -663,15 +663,27 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par /** * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event: - * The subtree rooted at the source node changed. + * The type of change is not defined. */ - public static final int CONTENT_CHANGE_TYPE_SUBTREE = 0; + public static final int CONTENT_CHANGE_TYPE_UNDEFINED = 0x00000000; /** * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event: - * Only the source node changed. + * A node in the subtree rooted at the source node was added or removed. */ - public static final int CONTENT_CHANGE_TYPE_NODE = 1; + public static final int CONTENT_CHANGE_TYPE_SUBTREE = 0x00000001; + + /** + * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event: + * The node's text changed. + */ + public static final int CONTENT_CHANGE_TYPE_TEXT = 0x00000002; + + /** + * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event: + * The node's content description changed. + */ + public static final int CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION = 0x00000004; /** * Mask for {@link AccessibilityEvent} all types. @@ -708,7 +720,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par private long mEventTime; int mMovementGranularity; int mAction; - int mContentChangeType; + int mContentChangeTypes; private final ArrayList<AccessibilityRecord> mRecords = new ArrayList<AccessibilityRecord>(); @@ -728,7 +740,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par mEventType = event.mEventType; mMovementGranularity = event.mMovementGranularity; mAction = event.mAction; - mContentChangeType = event.mContentChangeType; + mContentChangeTypes = event.mContentChangeTypes; mEventTime = event.mEventTime; mPackageName = event.mPackageName; } @@ -792,30 +804,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. + * Gets the bit mask of change types signaled by an + * {@link #TYPE_WINDOW_CONTENT_CHANGED} event. A single event may represent + * multiple change types. * - * @see #CONTENT_CHANGE_TYPE_NODE - * @see #CONTENT_CHANGE_TYPE_SUBTREE - * - * @return The change type. + * @return The bit mask of change types. One or more of: + * <ul> + * <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION} + * <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_SUBTREE} + * <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_TEXT} + * <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_UNDEFINED} + * </ul> */ - public int getContentChangeType() { - return mContentChangeType; + public int getContentChangeTypes() { + return mContentChangeTypes; } /** - * Sets the type of node tree change signaled by an + * Sets the bit mask of node tree changes signaled by an * {@link #TYPE_WINDOW_CONTENT_CHANGED} event. * - * @see #CONTENT_CHANGE_TYPE_NODE - * @see #CONTENT_CHANGE_TYPE_SUBTREE - * - * @param changeType The change type. + * @param changeTypes The bit mask of change types. + * @throws IllegalStateException If called from an AccessibilityService. + * @see #getContentChangeTypes() */ - public void setContentChangeType(int changeType) { + public void setContentChangeTypes(int changeTypes) { enforceNotSealed(); - mContentChangeType = changeType; + mContentChangeTypes = changeTypes; } /** @@ -985,7 +1000,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par mEventType = 0; mMovementGranularity = 0; mAction = 0; - mContentChangeType = 0; + mContentChangeTypes = 0; mPackageName = null; mEventTime = 0; while (!mRecords.isEmpty()) { @@ -1004,7 +1019,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par mEventType = parcel.readInt(); mMovementGranularity = parcel.readInt(); mAction = parcel.readInt(); - mContentChangeType = parcel.readInt(); + mContentChangeTypes = parcel.readInt(); mPackageName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); mEventTime = parcel.readLong(); mConnectionId = parcel.readInt(); @@ -1057,7 +1072,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par parcel.writeInt(mEventType); parcel.writeInt(mMovementGranularity); parcel.writeInt(mAction); - parcel.writeInt(mContentChangeType); + parcel.writeInt(mContentChangeTypes); TextUtils.writeToParcel(mPackageName, parcel, 0); parcel.writeLong(mEventTime); parcel.writeInt(mConnectionId); @@ -1119,7 +1134,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("; ContentChangeTypes: ").append(mContentChangeTypes); 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/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java index c61516b..9fc37cf 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java @@ -418,19 +418,13 @@ public class AccessibilityNodeInfo implements Parcelable { private static final int BOOLEAN_PROPERTY_EDITABLE = 0x00001000; - private static final int BOOLEAN_PROPERTY_LIVE_REGION = 0x00002000; + private static final int BOOLEAN_PROPERTY_OPENS_POPUP = 0x00002000; - private static final int BOOLEAN_PROPERTY_OPENS_POPUP = 0x00004000; + private static final int BOOLEAN_PROPERTY_DISMISSABLE = 0x00004000; - private static final int BOOLEAN_PROPERTY_EXPANDABLE = 0x00008000; + private static final int BOOLEAN_PROPERTY_MULTI_LINE = 0x00008000; - private static final int BOOLEAN_PROPERTY_EXPANDED = 0x00010000; - - private static final int BOOLEAN_PROPERTY_DISMISSABLE = 0x00020000; - - private static final int BOOLEAN_PROPERTY_MULTI_LINE = 0x00040000; - - private static final int BOOLEAN_PROPERTY_CONTENT_INVALID = 0x00080000; + private static final int BOOLEAN_PROPERTY_CONTENT_INVALID = 0x00010000; /** * Bits that provide the id of a virtual descendant of a view. @@ -517,6 +511,7 @@ public class AccessibilityNodeInfo implements Parcelable { private int mTextSelectionStart = UNDEFINED; private int mTextSelectionEnd = UNDEFINED; private int mInputType = InputType.TYPE_NULL; + private int mLiveRegion = View.ACCESSIBILITY_LIVE_REGION_NONE; private Bundle mExtras; @@ -1471,39 +1466,42 @@ public class AccessibilityNodeInfo implements Parcelable { } /** - * Gets if the node is a live region. + * Gets the node's live region mode. * <p> - * A live region is a node that contains information that is important - * for the user and when it changes the user has to be notified. For - * example, if the user plays a video and the application shows a - * progress indicator with the percentage of buffering, then the progress - * indicator should be marked as a live region. - * </p> + * A live region is a node that contains information that is important for + * the user and when it changes the user should be notified. For example, + * in a login screen with a TextView that displays an "incorrect password" + * notification, that view should be marked as a live region with mode + * {@link View#ACCESSIBILITY_LIVE_REGION_POLITE}. * <p> - * It is the responsibility of the accessibility - * service to monitor this region and notify the user if it changes. - * </p> + * It is the responsibility of the accessibility service to monitor + * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} events indicating + * changes to live region nodes and their children. * - * @return If the node is a live region. + * @return The live region mode, or + * {@link View#ACCESSIBILITY_LIVE_REGION_NONE} if the view is not a + * live region. + * @see android.view.View#getAccessibilityLiveRegion() */ - public boolean isLiveRegion() { - return getBooleanProperty(BOOLEAN_PROPERTY_LIVE_REGION); + public int getLiveRegion() { + return mLiveRegion; } /** - * Sets if the node is a live region for whose changes the user - * should be notified. It is the responsibility of the accessibility - * service to monitor this region and notify the user if it changes. + * Sets the node's live region mode. * <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> + * <strong>Note:</strong> Cannot be called from an + * {@link android.accessibilityservice.AccessibilityService}. This class is + * made immutable before being delivered to an AccessibilityService. * - * @param liveRegion If the node is a live region. + * @param mode The live region mode, or + * {@link View#ACCESSIBILITY_LIVE_REGION_NONE} if the view is not a + * live region. + * @see android.view.View#setAccessibilityLiveRegion(int) */ - public void setLiveRegion(boolean liveRegion) { - setBooleanProperty(BOOLEAN_PROPERTY_LIVE_REGION, liveRegion); + public void setLiveRegion(int mode) { + enforceNotSealed(); + mLiveRegion = mode; } /** @@ -1554,52 +1552,6 @@ public class AccessibilityNodeInfo implements Parcelable { } /** - * Gets if the node can be expanded. - * - * @return If the node can be expanded. - */ - public boolean isExpandable() { - return getBooleanProperty(BOOLEAN_PROPERTY_EXPANDABLE); - } - - /** - * Sets if the node can be expanded. - * <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 expandable If the node can be expanded. - */ - public void setExpandable(boolean expandable) { - setBooleanProperty(BOOLEAN_PROPERTY_EXPANDABLE, expandable); - } - - /** - * Gets if the node is expanded. - * - * @return If the node is expanded. - */ - public boolean isExpanded() { - return getBooleanProperty(BOOLEAN_PROPERTY_EXPANDED); - } - - /** - * Sets if the node is expanded. - * <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 expanded If the node is expanded. - */ - public void setExpanded(boolean expanded) { - setBooleanProperty(BOOLEAN_PROPERTY_EXPANDED, expanded); - } - - /** * Gets if the node can be dismissed. * * @return If the node can be dismissed. @@ -2203,6 +2155,7 @@ public class AccessibilityNodeInfo implements Parcelable { parcel.writeInt(mTextSelectionStart); parcel.writeInt(mTextSelectionEnd); parcel.writeInt(mInputType); + parcel.writeInt(mLiveRegion); if (mExtras != null) { parcel.writeInt(1); @@ -2276,6 +2229,7 @@ public class AccessibilityNodeInfo implements Parcelable { mTextSelectionStart = other.mTextSelectionStart; mTextSelectionEnd = other.mTextSelectionEnd; mInputType = other.mInputType; + mLiveRegion = other.mLiveRegion; if (other.mExtras != null && !other.mExtras.isEmpty()) { getExtras().putAll(other.mExtras); } @@ -2334,6 +2288,7 @@ public class AccessibilityNodeInfo implements Parcelable { mTextSelectionEnd = parcel.readInt(); mInputType = parcel.readInt(); + mLiveRegion = parcel.readInt(); if (parcel.readInt() == 1) { getExtras().putAll(parcel.readBundle()); @@ -2389,6 +2344,7 @@ public class AccessibilityNodeInfo implements Parcelable { mTextSelectionStart = UNDEFINED; mTextSelectionEnd = UNDEFINED; mInputType = InputType.TYPE_NULL; + mLiveRegion = View.ACCESSIBILITY_LIVE_REGION_NONE; if (mExtras != null) { mExtras.clear(); } diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java b/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java index 02d4c8d..6bef78e 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java @@ -91,11 +91,11 @@ public class AccessibilityNodeInfoCache { case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED: { synchronized (mLock) { final long sourceId = event.getSourceNodeId(); - if (event.getContentChangeType() - == AccessibilityEvent.CONTENT_CHANGE_TYPE_NODE) { - refreshCachedNode(sourceId); - } else { + if ((event.getContentChangeTypes() + & AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) != 0) { clearSubTreeLocked(sourceId); + } else { + refreshCachedNode(sourceId); } } } break; |