diff options
| author | Alan Viverette <alanv@google.com> | 2015-03-25 13:09:20 -0700 |
|---|---|---|
| committer | Alan Viverette <alanv@google.com> | 2015-03-30 12:15:25 -0700 |
| commit | 34457f51e0a19555a7b9c6df6803ee1aa04c51b8 (patch) | |
| tree | adef41dd0534559cb429c7f92fdf609fd37392cd /core/java | |
| parent | 60b674e07bf7346a673abd4a5f40bddeca16e7ff (diff) | |
| download | frameworks_base-34457f51e0a19555a7b9c6df6803ee1aa04c51b8.zip frameworks_base-34457f51e0a19555a7b9c6df6803ee1aa04c51b8.tar.gz frameworks_base-34457f51e0a19555a7b9c6df6803ee1aa04c51b8.tar.bz2 | |
Fix ViewRootImpl handling of content changes, fix ViewPager parenting
Previously content changes were only handled if they came directly from
the focused host, which meant that changes that occurred higher in the
tree were ignored. As a result, scrolling in ViewPager that contained
virtual nodes would fail to update the focus position.
Change-Id: I028bd8c670f1210339da331626e1986c5b5d4b87
Diffstat (limited to 'core/java')
| -rw-r--r-- | core/java/android/view/View.java | 2 | ||||
| -rw-r--r-- | core/java/android/view/ViewRootImpl.java | 96 | ||||
| -rw-r--r-- | core/java/com/android/internal/widget/ViewPager.java | 121 |
3 files changed, 119 insertions, 100 deletions
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 887187a..a69384a 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -9959,6 +9959,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @param oldt Previous vertical scroll origin. */ protected void onScrollChanged(int l, int t, int oldl, int oldt) { + notifySubtreeAccessibilityStateChangedIfNeeded(); + if (AccessibilityManager.getInstance(mContext).isEnabled()) { postSendViewScrolledAccessibilityEventCallback(); } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 294174a..4158340 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -6268,41 +6268,79 @@ public final class ViewRootImpl implements ViewParent, case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED: { - if (mAccessibilityFocusedHost != null && mAccessibilityFocusedVirtualView != null) { - // We care only for changes rooted in the focused host. - final long eventSourceId = event.getSourceNodeId(); - final int hostViewId = AccessibilityNodeInfo.getAccessibilityViewId( - eventSourceId); - if (hostViewId != mAccessibilityFocusedHost.getAccessibilityViewId()) { - break; - } - - // We only care about changes that may change the virtual focused view bounds. - final int changes = event.getContentChangeTypes(); - if ((changes & AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) != 0 - || changes == AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED) { - AccessibilityNodeProvider provider = mAccessibilityFocusedHost - .getAccessibilityNodeProvider(); - if (provider != null) { - final int virtualChildId = AccessibilityNodeInfo.getVirtualDescendantId( - mAccessibilityFocusedVirtualView.getSourceNodeId()); - if (virtualChildId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID) { - mAccessibilityFocusedVirtualView = provider - .createAccessibilityNodeInfo( - AccessibilityNodeProvider.HOST_VIEW_ID); - } else { - mAccessibilityFocusedVirtualView = provider - .createAccessibilityNodeInfo(virtualChildId); - } - } - } - } + handleWindowContentChangedEvent(event); } break; } mAccessibilityManager.sendAccessibilityEvent(event); return true; } + /** + * Updates the focused virtual view, when necessary, in response to a + * content changed event. + * <p> + * This is necessary to get updated bounds after a position change. + * + * @param event an accessibility event of type + * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} + */ + private void handleWindowContentChangedEvent(AccessibilityEvent event) { + // No virtual view focused, nothing to do here. + if (mAccessibilityFocusedHost == null || mAccessibilityFocusedVirtualView == null) { + return; + } + + // If we have a node but no provider, abort. + final AccessibilityNodeProvider provider = + mAccessibilityFocusedHost.getAccessibilityNodeProvider(); + if (provider == null) { + // TODO: Should we clear the focused virtual view? + return; + } + + // We only care about change types that may affect the bounds of the + // focused virtual view. + final int changes = event.getContentChangeTypes(); + if ((changes & AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) == 0 + && changes != AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED) { + return; + } + + final long eventSourceNodeId = event.getSourceNodeId(); + final int changedViewId = AccessibilityNodeInfo.getAccessibilityViewId(eventSourceNodeId); + + // Search up the tree for subtree containment. + boolean hostInSubtree = false; + View root = mAccessibilityFocusedHost; + while (root != null && !hostInSubtree) { + if (changedViewId == root.getAccessibilityViewId()) { + hostInSubtree = true; + } else { + final ViewParent parent = root.getParent(); + if (parent instanceof View) { + root = (View) parent; + } else { + root = null; + } + } + } + + // We care only about changes in subtrees containing the host view. + if (!hostInSubtree) { + return; + } + + final long focusedSourceNodeId = mAccessibilityFocusedVirtualView.getSourceNodeId(); + int focusedChildId = AccessibilityNodeInfo.getVirtualDescendantId(focusedSourceNodeId); + if (focusedChildId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID) { + // TODO: Should we clear the focused virtual view? + focusedChildId = AccessibilityNodeProvider.HOST_VIEW_ID; + } + + // Refresh the node for the focused virtual view. + mAccessibilityFocusedVirtualView = provider.createAccessibilityNodeInfo(focusedChildId); + } + @Override public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) { postSendWindowContentChangedCallback(source, changeType); diff --git a/core/java/com/android/internal/widget/ViewPager.java b/core/java/com/android/internal/widget/ViewPager.java index 8018942..8d66191 100644 --- a/core/java/com/android/internal/widget/ViewPager.java +++ b/core/java/com/android/internal/widget/ViewPager.java @@ -42,6 +42,7 @@ import android.view.ViewGroup; import android.view.ViewParent; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; +import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; import android.view.accessibility.AccessibilityRecord; import android.view.animation.Interpolator; import android.widget.EdgeEffect; @@ -371,8 +372,6 @@ public class ViewPager extends ViewGroup { mCloseEnough = (int) (CLOSE_ENOUGH * density); mDefaultGutterSize = (int) (DEFAULT_GUTTER_SIZE * density); - setAccessibilityDelegate(new MyAccessibilityDelegate()); - if (getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); } @@ -2695,29 +2694,6 @@ public class ViewPager extends ViewGroup { } @Override - public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { - // Dispatch scroll events from this ViewPager. - if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) { - return super.dispatchPopulateAccessibilityEvent(event); - } - - // Dispatch all other accessibility events from the current page. - final int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) { - final View child = getChildAt(i); - if (child.getVisibility() == VISIBLE) { - final ItemInfo ii = infoForChild(child); - if (ii != null && ii.position == mCurItem && - child.dispatchPopulateAccessibilityEvent(event)) { - return true; - } - } - } - - return false; - } - - @Override protected ViewGroup.LayoutParams generateDefaultLayoutParams() { return new LayoutParams(); } @@ -2737,60 +2713,63 @@ public class ViewPager extends ViewGroup { return new LayoutParams(getContext(), attrs); } - class MyAccessibilityDelegate extends AccessibilityDelegate { - @Override - public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { - super.onInitializeAccessibilityEvent(host, event); - event.setClassName(ViewPager.class.getName()); - final AccessibilityRecord record = AccessibilityRecord.obtain(); - record.setScrollable(canScroll()); - if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED - && mAdapter != null) { - record.setItemCount(mAdapter.getCount()); - record.setFromIndex(mCurItem); - record.setToIndex(mCurItem); - } + @Override + public void onInitializeAccessibilityEvent(AccessibilityEvent event) { + super.onInitializeAccessibilityEvent(event); + + event.setClassName(ViewPager.class.getName()); + event.setScrollable(canScroll()); + + if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED && mAdapter != null) { + event.setItemCount(mAdapter.getCount()); + event.setFromIndex(mCurItem); + event.setToIndex(mCurItem); } + } - @Override - public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { - super.onInitializeAccessibilityNodeInfo(host, info); - info.setClassName(ViewPager.class.getName()); - info.setScrollable(canScroll()); - if (canScrollHorizontally(1)) { - info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD); - } - if (canScrollHorizontally(-1)) { - info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD); - } + @Override + public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(info); + + info.setClassName(ViewPager.class.getName()); + info.setScrollable(canScroll()); + + if (canScrollHorizontally(1)) { + info.addAction(AccessibilityAction.ACTION_SCROLL_FORWARD); } - @Override - public boolean performAccessibilityAction(View host, int action, Bundle args) { - if (super.performAccessibilityAction(host, action, args)) { - return true; - } - switch (action) { - case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: { - if (canScrollHorizontally(1)) { - setCurrentItem(mCurItem + 1); - return true; - } - } return false; - case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: { - if (canScrollHorizontally(-1)) { - setCurrentItem(mCurItem - 1); - return true; - } - } return false; - } - return false; + if (canScrollHorizontally(-1)) { + info.addAction(AccessibilityAction.ACTION_SCROLL_BACKWARD); } + } - private boolean canScroll() { - return (mAdapter != null) && (mAdapter.getCount() > 1); + @Override + public boolean performAccessibilityAction(int action, Bundle args) { + if (super.performAccessibilityAction(action, args)) { + return true; } + + switch (action) { + case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: + if (canScrollHorizontally(1)) { + setCurrentItem(mCurItem + 1); + return true; + } + return false; + case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: + if (canScrollHorizontally(-1)) { + setCurrentItem(mCurItem - 1); + return true; + } + return false; + } + + return false; + } + + private boolean canScroll() { + return mAdapter != null && mAdapter.getCount() > 1; } private class PagerObserver extends DataSetObserver { |
