summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Svetoslav Ganov <svetoslavganov@google.com> 2012-05-29 09:15:30 -0700
committer Svetoslav Ganov <svetoslavganov@google.com> 2012-05-29 15:16:19 -0700
commit39f2aee640eea62b43fa79f28dec3a962e5cb065 (patch)
tree0195879c55bb7823f5fe43e17fd7a39a66cfe1bd
parenta587b890bb0c2f800fe4dfd3267f26366d00d32c (diff)
Updating the behaviour of accessibility text iterators.
1. Iterators were skipping content on reversing direction. 2. The cursor was positioned at the beginning of the next text segment when moving forward and at end of the previous text segment when moving backwards. This is incorrect and now the cursor is positioned at the end of the segment when moving forward and at the beginning when moving backward. 3. The cursor position was not properly set when reaching the end/start of the text. 4. The iterators were reporting strictly the next/previous segment even if the cursor is within such a segment. Thus, when traversing some content may be skipped. Now moving forward moves the selection to the next segment end and the start position is either the old index if it was within a segment or the start of the segment. Same in reverse. bug:6575099 Change-Id: Ib48a649cec53910339baf831a75e26440be6e576
-rw-r--r--core/java/android/view/AccessibilityIterators.java168
-rw-r--r--core/java/android/view/View.java31
-rw-r--r--core/java/android/widget/AccessibilityIterators.java77
-rw-r--r--core/java/android/widget/TextView.java10
4 files changed, 128 insertions, 158 deletions
diff --git a/core/java/android/view/AccessibilityIterators.java b/core/java/android/view/AccessibilityIterators.java
index cd54f249f47c..2a7dc181def1 100644
--- a/core/java/android/view/AccessibilityIterators.java
+++ b/core/java/android/view/AccessibilityIterators.java
@@ -47,7 +47,6 @@ public final class AccessibilityIterators {
* @hide
*/
public static abstract class AbstractTextSegmentIterator implements TextSegmentIterator {
- protected static final int DONE = -1;
protected String mText;
@@ -104,20 +103,20 @@ public final class AccessibilityIterators {
if (offset >= textLegth) {
return null;
}
- int start = -1;
- if (offset < 0) {
- offset = 0;
- if (mImpl.isBoundary(offset)) {
- start = offset;
- }
- }
+ int start = offset;
if (start < 0) {
- start = mImpl.following(offset);
+ start = 0;
}
- if (start < 0) {
- return null;
+ while (!mImpl.isBoundary(start)) {
+ start = mImpl.following(start);
+ if (start == BreakIterator.DONE) {
+ return null;
+ }
}
final int end = mImpl.following(start);
+ if (end == BreakIterator.DONE) {
+ return null;
+ }
return getRange(start, end);
}
@@ -130,20 +129,20 @@ public final class AccessibilityIterators {
if (offset <= 0) {
return null;
}
- int end = -1;
- if (offset > mText.length()) {
- offset = mText.length();
- if (mImpl.isBoundary(offset)) {
- end = offset;
- }
+ int end = offset;
+ if (end > textLegth) {
+ end = textLegth;
}
- if (end < 0) {
- end = mImpl.preceding(offset);
+ while (!mImpl.isBoundary(end)) {
+ end = mImpl.preceding(end);
+ if (end == BreakIterator.DONE) {
+ return null;
+ }
}
- if (end < 0) {
+ final int start = mImpl.preceding(end);
+ if (start == BreakIterator.DONE) {
return null;
}
- final int start = mImpl.preceding(end);
return getRange(start, end);
}
@@ -195,25 +194,20 @@ public final class AccessibilityIterators {
if (offset >= mText.length()) {
return null;
}
- int start = -1;
- if (offset < 0) {
- offset = 0;
- if (mImpl.isBoundary(offset) && isLetterOrDigit(offset)) {
- start = offset;
- }
- }
+ int start = offset;
if (start < 0) {
- while ((offset = mImpl.following(offset)) != DONE) {
- if (isLetterOrDigit(offset)) {
- start = offset;
- break;
- }
+ start = 0;
+ }
+ while (!isLetterOrDigit(start) && !isStartBoundary(start)) {
+ start = mImpl.following(start);
+ if (start == BreakIterator.DONE) {
+ return null;
}
}
- if (start < 0) {
+ final int end = mImpl.following(start);
+ if (end == BreakIterator.DONE || !isEndBoundary(end)) {
return null;
}
- final int end = mImpl.following(start);
return getRange(start, end);
}
@@ -226,28 +220,33 @@ public final class AccessibilityIterators {
if (offset <= 0) {
return null;
}
- int end = -1;
- if (offset > mText.length()) {
- offset = mText.length();
- if (mImpl.isBoundary(offset) && offset > 0 && isLetterOrDigit(offset - 1)) {
- end = offset;
- }
+ int end = offset;
+ if (end > textLegth) {
+ end = textLegth;
}
- if (end < 0) {
- while ((offset = mImpl.preceding(offset)) != DONE) {
- if (offset > 0 && isLetterOrDigit(offset - 1)) {
- end = offset;
- break;
- }
+ while (end > 0 && !isLetterOrDigit(end - 1) && !isEndBoundary(end)) {
+ end = mImpl.preceding(end);
+ if (end == BreakIterator.DONE) {
+ return null;
}
}
- if (end < 0) {
+ final int start = mImpl.preceding(end);
+ if (start == BreakIterator.DONE || !isStartBoundary(start)) {
return null;
}
- final int start = mImpl.preceding(end);
return getRange(start, end);
}
+ private boolean isStartBoundary(int index) {
+ return isLetterOrDigit(index)
+ && (index == 0 || !isLetterOrDigit(index - 1));
+ }
+
+ private boolean isEndBoundary(int index) {
+ return (index > 0 && isLetterOrDigit(index - 1))
+ && (index == mText.length() || !isLetterOrDigit(index));
+ }
+
private boolean isLetterOrDigit(int index) {
if (index >= 0 && index < mText.length()) {
final int codePoint = mText.codePointAt(index);
@@ -276,31 +275,19 @@ public final class AccessibilityIterators {
if (offset >= textLength) {
return null;
}
- int start = -1;
- if (offset < 0) {
- start = 0;
- } else {
- for (int i = offset + 1; i < textLength; i++) {
- if (mText.charAt(i) == '\n') {
- start = i;
- break;
- }
- }
- }
+ int start = offset;
if (start < 0) {
- return null;
+ start = 0;
}
- while (start < textLength && mText.charAt(start) == '\n') {
+ while (start < textLength && mText.charAt(start) == '\n'
+ && !isStartBoundary(start)) {
start++;
}
- int end = start;
- for (int i = end + 1; i < textLength; i++) {
- end = i;
- if (mText.charAt(i) == '\n') {
- break;
- }
+ if (start >= textLength) {
+ return null;
}
- while (end < textLength && mText.charAt(end) == '\n') {
+ int end = start + 1;
+ while (end < textLength && !isEndBoundary(end)) {
end++;
}
return getRange(start, end);
@@ -315,38 +302,31 @@ public final class AccessibilityIterators {
if (offset <= 0) {
return null;
}
- int end = -1;
- if (offset > mText.length()) {
- end = mText.length();
- } else {
- if (offset > 0 && mText.charAt(offset - 1) == '\n') {
- offset--;
- }
- for (int i = offset - 1; i >= 0; i--) {
- if (i > 0 && mText.charAt(i - 1) == '\n') {
- end = i;
- break;
- }
- }
+ int end = offset;
+ if (end > textLength) {
+ end = textLength;
+ }
+ while(end > 0 && mText.charAt(end - 1) == '\n' && !isEndBoundary(end)) {
+ end--;
}
if (end <= 0) {
return null;
}
- int start = end;
- while (start > 0 && mText.charAt(start - 1) == '\n') {
+ int start = end - 1;
+ while (start > 0 && !isStartBoundary(start)) {
start--;
}
- if (start == 0 && mText.charAt(start) == '\n') {
- return null;
- }
- for (int i = start - 1; i >= 0; i--) {
- start = i;
- if (start > 0 && mText.charAt(i - 1) == '\n') {
- break;
- }
- }
- start = Math.max(0, start);
return getRange(start, end);
}
+
+ private boolean isStartBoundary(int index) {
+ return (mText.charAt(index) != '\n'
+ && (index == 0 || mText.charAt(index - 1) == '\n'));
+ }
+
+ private boolean isEndBoundary(int index) {
+ return (index > 0 && mText.charAt(index - 1) != '\n'
+ && (index == mText.length() || mText.charAt(index) == '\n'));
+ }
}
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 20eef11de8bc..49efea36b208 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1596,7 +1596,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
/**
* @hide
*/
- private int mAccessibilityCursorPosition = -1;
+ private int mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED;
/**
* The view's tag.
@@ -2468,6 +2468,11 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
public static final int FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS = 0x00000004;
/**
+ * The undefined cursor position.
+ */
+ private static final int ACCESSIBILITY_CURSOR_POSITION_UNDEFINED = -1;
+
+ /**
* Indicates that the screen has changed state and is now off.
*
* @see #onScreenStateChanged(int)
@@ -6202,7 +6207,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
notifyAccessibilityStateChanged();
// Clear the text navigation state.
- setAccessibilityCursorPosition(-1);
+ setAccessibilityCursorPosition(ACCESSIBILITY_CURSOR_POSITION_UNDEFINED);
}
// Clear the global reference of accessibility focus if this
// view or any of its descendants had accessibility focus.
@@ -6252,6 +6257,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
void clearAccessibilityFocusNoCallbacks() {
if ((mPrivateFlags2 & ACCESSIBILITY_FOCUSED) != 0) {
mPrivateFlags2 &= ~ACCESSIBILITY_FOCUSED;
+ setAccessibilityCursorPosition(ACCESSIBILITY_CURSOR_POSITION_UNDEFINED);
invalidate();
}
}
@@ -6681,12 +6687,11 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
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);
+ setAccessibilityCursorPosition(end);
sendViewTextTraversedAtGranularityEvent(
AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY,
granularity, start, end);
@@ -6702,16 +6707,26 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
if (iterator == null) {
return false;
}
- final int selectionStart = getAccessibilityCursorPosition();
- final int current = selectionStart >= 0 ? selectionStart : text.length() + 1;
+ int current = getAccessibilityCursorPosition();
+ if (current == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) {
+ current = text.length();
+ } else if (granularity == AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER) {
+ // When traversing by character we always put the cursor after the character
+ // to ease edit and have to compensate before asking the for previous segment.
+ current--;
+ }
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);
+ // Always put the cursor after the character to ease edit.
+ if (granularity == AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER) {
+ setAccessibilityCursorPosition(end);
+ } else {
+ setAccessibilityCursorPosition(start);
+ }
sendViewTextTraversedAtGranularityEvent(
AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY,
granularity, start, end);
diff --git a/core/java/android/widget/AccessibilityIterators.java b/core/java/android/widget/AccessibilityIterators.java
index e800e8df575f..a3d58a4e2060 100644
--- a/core/java/android/widget/AccessibilityIterators.java
+++ b/core/java/android/widget/AccessibilityIterators.java
@@ -56,16 +56,18 @@ final class AccessibilityIterators {
if (offset >= mText.length()) {
return null;
}
- int nextLine = -1;
+ int nextLine;
if (offset < 0) {
nextLine = mLayout.getLineForOffset(0);
} else {
final int currentLine = mLayout.getLineForOffset(offset);
- if (currentLine < mLayout.getLineCount() - 1) {
+ if (getLineEdgeIndex(currentLine, DIRECTION_START) == offset) {
+ nextLine = currentLine;
+ } else {
nextLine = currentLine + 1;
}
}
- if (nextLine < 0) {
+ if (nextLine >= mLayout.getLineCount()) {
return null;
}
final int start = getLineEdgeIndex(nextLine, DIRECTION_START);
@@ -82,12 +84,14 @@ final class AccessibilityIterators {
if (offset <= 0) {
return null;
}
- int previousLine = -1;
+ int previousLine;
if (offset > mText.length()) {
previousLine = mLayout.getLineForOffset(mText.length());
} else {
- final int currentLine = mLayout.getLineForOffset(offset - 1);
- if (currentLine > 0) {
+ final int currentLine = mLayout.getLineForOffset(offset);
+ if (getLineEdgeIndex(currentLine, DIRECTION_END) + 1 == offset) {
+ previousLine = currentLine;
+ } else {
previousLine = currentLine - 1;
}
}
@@ -141,29 +145,18 @@ final class AccessibilityIterators {
return null;
}
- final int currentLine = mLayout.getLineForOffset(offset);
+ final int start = Math.max(0, offset);
+
+ final int currentLine = mLayout.getLineForOffset(start);
final int currentLineTop = mLayout.getLineTop(currentLine);
final int pageHeight = mTempRect.height() - mView.getTotalPaddingTop()
- mView.getTotalPaddingBottom();
+ final int nextPageStartY = currentLineTop + pageHeight;
+ final int lastLineTop = mLayout.getLineTop(mLayout.getLineCount() - 1);
+ final int currentPageEndLine = (nextPageStartY < lastLineTop)
+ ? mLayout.getLineForVertical(nextPageStartY) - 1 : mLayout.getLineCount() - 1;
- final int nextPageStartLine;
- final int nextPageEndLine;
- if (offset < 0) {
- nextPageStartLine = currentLine;
- final int nextPageEndY = currentLineTop + pageHeight;
- nextPageEndLine = mLayout.getLineForVertical(nextPageEndY);
- } else {
- final int nextPageStartY = currentLineTop + pageHeight;
- nextPageStartLine = mLayout.getLineForVertical(nextPageStartY) + 1;
- if (mLayout.getLineTop(nextPageStartLine) <= nextPageStartY) {
- return null;
- }
- final int nextPageEndY = nextPageStartY + pageHeight;
- nextPageEndLine = mLayout.getLineForVertical(nextPageEndY);
- }
-
- final int start = getLineEdgeIndex(nextPageStartLine, DIRECTION_START);
- final int end = getLineEdgeIndex(nextPageEndLine, DIRECTION_END) + 1;
+ final int end = getLineEdgeIndex(currentPageEndLine, DIRECTION_END) + 1;
return getRange(start, end);
}
@@ -181,37 +174,17 @@ final class AccessibilityIterators {
return null;
}
- final int currentLine = mLayout.getLineForOffset(offset);
+ final int end = Math.min(mText.length(), offset);
+
+ final int currentLine = mLayout.getLineForOffset(end);
final int currentLineTop = mLayout.getLineTop(currentLine);
final int pageHeight = mTempRect.height() - mView.getTotalPaddingTop()
- mView.getTotalPaddingBottom();
+ final int previousPageEndY = currentLineTop - pageHeight;
+ final int currentPageStartLine = (previousPageEndY > 0) ?
+ mLayout.getLineForVertical(previousPageEndY) + 1 : 0;
- final int previousPageStartLine;
- final int previousPageEndLine;
- if (offset > mText.length()) {
- final int prevousPageStartY = mLayout.getHeight() - pageHeight;
- if (prevousPageStartY < 0) {
- return null;
- }
- previousPageStartLine = mLayout.getLineForVertical(prevousPageStartY);
- previousPageEndLine = mLayout.getLineCount() - 1;
- } else {
- final int prevousPageStartY;
- if (offset == mText.length()) {
- prevousPageStartY = mLayout.getHeight() - 2 * pageHeight;
- } else {
- prevousPageStartY = currentLineTop - 2 * pageHeight;
- }
- if (prevousPageStartY < 0) {
- return null;
- }
- previousPageStartLine = mLayout.getLineForVertical(prevousPageStartY);
- final int previousPageEndY = prevousPageStartY + pageHeight;
- previousPageEndLine = mLayout.getLineForVertical(previousPageEndY) - 1;
- }
-
- final int start = getLineEdgeIndex(previousPageStartLine, DIRECTION_START);
- final int end = getLineEdgeIndex(previousPageEndLine, DIRECTION_END) + 1;
+ final int start = getLineEdgeIndex(currentPageStartLine, DIRECTION_START);
return getRange(start, end);
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 81a44fdf09c5..1826341877f3 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -8376,10 +8376,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@Override
public int getAccessibilityCursorPosition() {
if (TextUtils.isEmpty(getContentDescription())) {
- return getSelectionEnd();
- } else {
- return super.getAccessibilityCursorPosition();
+ final int selectionEnd = getSelectionEnd();
+ if (selectionEnd >= 0) {
+ return selectionEnd;
+ }
}
+ return super.getAccessibilityCursorPosition();
}
/**
@@ -8391,7 +8393,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return;
}
if (TextUtils.isEmpty(getContentDescription())) {
- if (index >= 0) {
+ if (index >= 0 && index <= mText.length()) {
Selection.setSelection((Spannable) mText, index);
} else {
Selection.removeSelection((Spannable) mText);