diff options
| author | Svetoslav Ganov <svetoslavganov@google.com> | 2012-05-10 04:14:53 -0700 |
|---|---|---|
| committer | Svetoslav Ganov <svetoslavganov@google.com> | 2012-05-10 12:28:04 -0700 |
| commit | a1dc761c8322355eb1bb71d3d6c9c603c1d1fc0f (patch) | |
| tree | 19887c9a0d1c4ee83117d3324360cf88da2c96d0 /core/java | |
| parent | 1bc1b8a5b8a0c5fbcd670d1963235de27a5ccec4 (diff) | |
| download | frameworks_base-a1dc761c8322355eb1bb71d3d6c9c603c1d1fc0f.zip frameworks_base-a1dc761c8322355eb1bb71d3d6c9c603c1d1fc0f.tar.gz frameworks_base-a1dc761c8322355eb1bb71d3d6c9c603c1d1fc0f.tar.bz2 | |
Adding scroll actions to accessibility node info.
1. Scrolling actions are crucial for enabling a gesture based
traversal of the UI and specifically scrollable containers
especially lists and anything backed by an adapter. Since
accessibility focus can land only attached views, it cannot
visit views for adapter items not shown on the screen.
Auto scrolling the list as a result of putting access focus
ot a list item does not work well since the user may get
trapped in a long list. Adding an accessibility node provider
to emit virtual views for one view before the first and one
after the last is complex and suffers the limitation of trapping
the user. Accessibility service need an explicit scroll actions
which may be performed upon an explicit user action. Hence,
the user is informed for the start/end of the visible part of
the list and he makes a deliberate choice to scroll. This will
benefit also people developing Braille devices since they can
scroll the content without telling the user to stop using the
Braille controller and take the device out of his pocket to scroll
and go back to the Braille controller.
NOTE: Without these action large portions of the screen will be
hard to access since users will have to touch and explore to
find and scroll the list.
Change-Id: Iafcf54d4967893205872b3649025a4e347a299ed
Diffstat (limited to 'core/java')
| -rw-r--r-- | core/java/android/view/accessibility/AccessibilityNodeInfo.java | 24 | ||||
| -rw-r--r-- | core/java/android/widget/AbsListView.java | 27 | ||||
| -rw-r--r-- | core/java/android/widget/HorizontalScrollView.java | 35 | ||||
| -rw-r--r-- | core/java/android/widget/ScrollView.java | 35 |
4 files changed, 119 insertions, 2 deletions
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java index 6b14ba5..0517d4b 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java @@ -205,6 +205,16 @@ public class AccessibilityNodeInfo implements Parcelable { public static final int ACTION_PREVIOUS_HTML_ELEMENT = 0x00000800; /** + * Action to scroll the node content forward. + */ + public static final int ACTION_SCROLL_FORWARD = 0x00001000; + + /** + * Action to scroll the node content backward. + */ + public static final int ACTION_SCROLL_BACKWARD = 0x00002000; + + /** * Argument for which movement granularity to be used when traversing the node text. * <p> * <strong>Type:</strong> int<br> @@ -569,6 +579,16 @@ public class AccessibilityNodeInfo implements Parcelable { * @see AccessibilityNodeInfo#ACTION_CLEAR_FOCUS * @see AccessibilityNodeInfo#ACTION_SELECT * @see AccessibilityNodeInfo#ACTION_CLEAR_SELECTION + * @see AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS + * @see AccessibilityNodeInfo#ACTION_CLEAR_ACCESSIBILITY_FOCUS + * @see AccessibilityNodeInfo#ACTION_CLICK + * @see AccessibilityNodeInfo#ACTION_LONG_CLICK + * @see AccessibilityNodeInfo#ACTION_NEXT_AT_MOVEMENT_GRANULARITY + * @see AccessibilityNodeInfo#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY + * @see AccessibilityNodeInfo#ACTION_NEXT_HTML_ELEMENT + * @see AccessibilityNodeInfo#ACTION_PREVIOUS_HTML_ELEMENT + * @see AccessibilityNodeInfo#ACTION_SCROLL_FORWARD + * @see AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD */ public int getActions() { return mActions; @@ -1578,6 +1598,10 @@ public class AccessibilityNodeInfo implements Parcelable { return "ACTION_NEXT_HTML_ELEMENT"; case ACTION_PREVIOUS_HTML_ELEMENT: return "ACTION_PREVIOUS_HTML_ELEMENT"; + case ACTION_SCROLL_FORWARD: + return "ACTION_SCROLL_FORWARD"; + case ACTION_SCROLL_BACKWARD: + return "ACTION_SCROLL_BACKWARD"; default: throw new IllegalArgumentException("Unknown action: " + action); } diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 3aafba5..c4e1bf5 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -1355,6 +1355,33 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfo(info); info.setClassName(AbsListView.class.getName()); + if (getFirstVisiblePosition() > 0) { + info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD); + } + if (getLastVisiblePosition() < getCount() - 1) { + info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD); + } + } + + @Override + public boolean performAccessibilityAction(int action, Bundle arguments) { + switch (action) { + case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: { + if (getLastVisiblePosition() < getCount() - 1) { + final int viewportHeight = getHeight() - mListPadding.top - mListPadding.bottom; + smoothScrollBy(viewportHeight, PositionScroller.SCROLL_DURATION); + return true; + } + } return false; + case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: { + if (mFirstPosition > 0) { + final int viewportHeight = getHeight() - mListPadding.top - mListPadding.bottom; + smoothScrollBy(-viewportHeight, PositionScroller.SCROLL_DURATION); + return true; + } + } return false; + } + return super.performAccessibilityAction(action, arguments); } /** diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java index 1986450..ffabd1d 100644 --- a/core/java/android/widget/HorizontalScrollView.java +++ b/core/java/android/widget/HorizontalScrollView.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Rect; +import android.os.Bundle; import android.util.AttributeSet; import android.view.FocusFinder; import android.view.InputDevice; @@ -737,10 +738,42 @@ public class HorizontalScrollView extends FrameLayout { } @Override + public boolean performAccessibilityAction(int action, Bundle arguments) { + switch (action) { + case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: { + final int viewportWidth = getWidth() - mPaddingLeft - mPaddingRight; + final int targetScrollX = Math.min(mScrollX + viewportWidth, getScrollRange()); + if (targetScrollX != mScrollX) { + smoothScrollTo(targetScrollX, 0); + return true; + } + } return false; + case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: { + final int viewportWidth = getWidth() - mPaddingLeft - mPaddingRight; + final int targetScrollX = Math.max(0, mScrollX - viewportWidth); + if (targetScrollX != mScrollX) { + smoothScrollTo(targetScrollX, 0); + return true; + } + } return false; + } + return super.performAccessibilityAction(action, arguments); + } + + @Override public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfo(info); info.setClassName(HorizontalScrollView.class.getName()); - info.setScrollable(getScrollRange() > 0); + final int scrollRange = getScrollRange(); + if (scrollRange > 0) { + info.setScrollable(true); + if (mScrollX > 0) { + info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD); + } + if (mScrollX < scrollRange) { + info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD); + } + } } @Override diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java index f912c66..b398ce4 100644 --- a/core/java/android/widget/ScrollView.java +++ b/core/java/android/widget/ScrollView.java @@ -22,6 +22,7 @@ import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Rect; +import android.os.Bundle; import android.os.StrictMode; import android.util.AttributeSet; import android.view.FocusFinder; @@ -740,10 +741,42 @@ public class ScrollView extends FrameLayout { } @Override + public boolean performAccessibilityAction(int action, Bundle arguments) { + switch (action) { + case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: { + final int viewportHeight = getHeight() - mPaddingBottom - mPaddingTop; + final int targetScrollY = Math.min(mScrollY + viewportHeight, getScrollRange()); + if (targetScrollY != mScrollY) { + smoothScrollTo(0, targetScrollY); + return true; + } + } return false; + case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: { + final int viewportHeight = getHeight() - mPaddingBottom - mPaddingTop; + final int targetScrollY = Math.max(mScrollY - viewportHeight, 0); + if (targetScrollY != mScrollY) { + smoothScrollTo(0, targetScrollY); + return true; + } + } return false; + } + return super.performAccessibilityAction(action, arguments); + } + + @Override public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfo(info); info.setClassName(ScrollView.class.getName()); - info.setScrollable(getScrollRange() > 0); + final int scrollRange = getScrollRange(); + if (scrollRange > 0) { + info.setScrollable(true); + if (mScrollY > 0) { + info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD); + } + if (mScrollY < scrollRange) { + info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD); + } + } } @Override |
