summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
authorAlan Viverette <alanv@google.com>2015-03-25 13:09:20 -0700
committerAlan Viverette <alanv@google.com>2015-03-30 12:15:25 -0700
commit34457f51e0a19555a7b9c6df6803ee1aa04c51b8 (patch)
treeadef41dd0534559cb429c7f92fdf609fd37392cd /core/java
parent60b674e07bf7346a673abd4a5f40bddeca16e7ff (diff)
downloadframeworks_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.java2
-rw-r--r--core/java/android/view/ViewRootImpl.java96
-rw-r--r--core/java/com/android/internal/widget/ViewPager.java121
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 {