diff options
Diffstat (limited to 'core/java/android/view/View.java')
| -rw-r--r-- | core/java/android/view/View.java | 168 |
1 files changed, 162 insertions, 6 deletions
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index c054d387d402..5220f2d49ef2 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -47,7 +47,6 @@ import android.os.Parcelable; import android.os.RemoteException; import android.os.SystemClock; import android.os.SystemProperties; -import android.text.TextUtils; import android.util.AttributeSet; import android.util.FloatProperty; import android.util.LocaleUtil; @@ -60,6 +59,10 @@ import android.util.Property; import android.util.SparseArray; import android.util.TypedValue; import android.view.ContextMenu.ContextMenuInfo; +import android.view.AccessibilityIterators.TextSegmentIterator; +import android.view.AccessibilityIterators.CharacterTextSegmentIterator; +import android.view.AccessibilityIterators.WordTextSegmentIterator; +import android.view.AccessibilityIterators.ParagraphTextSegmentIterator; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityEventSource; import android.view.accessibility.AccessibilityManager; @@ -1528,7 +1531,8 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED - | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED; + | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED + | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY; /** * Temporary Rect currently for use in setBackground(). This will probably @@ -1594,6 +1598,11 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal int mAccessibilityViewId = NO_ID; /** + * @hide + */ + private int mAccessibilityCursorPosition = -1; + + /** * The view's tag. * {@hide} * @@ -4699,11 +4708,12 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK); } - if (getContentDescription() != null) { + if (mContentDescription != null && mContentDescription.length() > 0) { info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY); info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY); info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER - | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD); + | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD + | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH); } } @@ -5929,7 +5939,8 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal outViews.add(this); } } else if ((flags & FIND_VIEWS_WITH_CONTENT_DESCRIPTION) != 0 - && !TextUtils.isEmpty(searched) && !TextUtils.isEmpty(mContentDescription)) { + && (searched != null && searched.length() > 0) + && (mContentDescription != null && mContentDescription.length() > 0)) { String searchedLowerCase = searched.toString().toLowerCase(); String contentDescriptionLowerCase = mContentDescription.toString().toLowerCase(); if (contentDescriptionLowerCase.contains(searchedLowerCase)) { @@ -6030,6 +6041,10 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal invalidate(); sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); notifyAccessibilityStateChanged(); + + // Clear the text navigation state. + setAccessibilityCursorPosition(-1); + // Try to move accessibility focus to the input focus. View rootView = getRootView(); if (rootView != null) { @@ -6427,9 +6442,10 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal * possible accessibility actions look at {@link AccessibilityNodeInfo}. * * @param action The action to perform. + * @param arguments Optional action arguments. * @return Whether the action was performed. */ - public boolean performAccessibilityAction(int action, Bundle args) { + public boolean performAccessibilityAction(int action, Bundle arguments) { switch (action) { case AccessibilityNodeInfo.ACTION_CLICK: { if (isClickable()) { @@ -6478,10 +6494,150 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal return true; } } break; + case AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY: { + if (arguments != null) { + final int granularity = arguments.getInt( + AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); + return nextAtGranularity(granularity); + } + } break; + case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: { + if (arguments != null) { + final int granularity = arguments.getInt( + AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); + return previousAtGranularity(granularity); + } + } break; } return false; } + private boolean nextAtGranularity(int granularity) { + CharSequence text = getIterableTextForAccessibility(); + if (text != null && text.length() > 0) { + return false; + } + TextSegmentIterator iterator = getIteratorForGranularity(granularity); + if (iterator == null) { + return false; + } + final int current = getAccessibilityCursorPosition(); + final int[] range = iterator.following(current); + if (range == null) { + setAccessibilityCursorPosition(-1); + return false; + } + final int start = range[0]; + final int end = range[1]; + setAccessibilityCursorPosition(start); + sendViewTextTraversedAtGranularityEvent( + AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, + granularity, start, end); + return true; + } + + private boolean previousAtGranularity(int granularity) { + CharSequence text = getIterableTextForAccessibility(); + if (text != null && text.length() > 0) { + return false; + } + TextSegmentIterator iterator = getIteratorForGranularity(granularity); + if (iterator == null) { + return false; + } + final int selectionStart = getAccessibilityCursorPosition(); + final int current = selectionStart >= 0 ? selectionStart : text.length() + 1; + final int[] range = iterator.preceding(current); + if (range == null) { + setAccessibilityCursorPosition(-1); + return false; + } + final int start = range[0]; + final int end = range[1]; + setAccessibilityCursorPosition(end); + sendViewTextTraversedAtGranularityEvent( + AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, + granularity, start, end); + return true; + } + + /** + * Gets the text reported for accessibility purposes. + * + * @return The accessibility text. + * + * @hide + */ + public CharSequence getIterableTextForAccessibility() { + return mContentDescription; + } + + /** + * @hide + */ + public int getAccessibilityCursorPosition() { + return mAccessibilityCursorPosition; + } + + /** + * @hide + */ + public void setAccessibilityCursorPosition(int position) { + mAccessibilityCursorPosition = position; + } + + private void sendViewTextTraversedAtGranularityEvent(int action, int granularity, + int fromIndex, int toIndex) { + if (mParent == null) { + return; + } + AccessibilityEvent event = AccessibilityEvent.obtain( + AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY); + onInitializeAccessibilityEvent(event); + onPopulateAccessibilityEvent(event); + event.setFromIndex(fromIndex); + event.setToIndex(toIndex); + event.setAction(action); + event.setMovementGranularity(granularity); + mParent.requestSendAccessibilityEvent(this, event); + } + + /** + * @hide + */ + public TextSegmentIterator getIteratorForGranularity(int granularity) { + switch (granularity) { + case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER: { + CharSequence text = getIterableTextForAccessibility(); + if (text != null && text.length() > 0) { + CharacterTextSegmentIterator iterator = + CharacterTextSegmentIterator.getInstance(mContext); + iterator.initialize(text.toString()); + return iterator; + } + } break; + case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD: { + CharSequence text = getIterableTextForAccessibility(); + if (text != null && text.length() > 0) { + WordTextSegmentIterator iterator = + WordTextSegmentIterator.getInstance(mContext); + iterator.initialize(text.toString()); + return iterator; + } + } break; + case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH: { + CharSequence text = getIterableTextForAccessibility(); + if (text != null && text.length() > 0) { + ParagraphTextSegmentIterator iterator = + ParagraphTextSegmentIterator.getInstance(); + iterator.initialize(text.toString()); + return iterator; + } + } break; + } + return null; + } + /** * @hide */ |
