Loading api/test-current.txt +7 −0 Original line number Diff line number Diff line Loading @@ -41721,6 +41721,13 @@ package android.text { field public static final java.lang.Object SELECTION_START; } public static final class Selection.MemoryTextWatcher implements android.text.TextWatcher { ctor public Selection.MemoryTextWatcher(); method public void afterTextChanged(android.text.Editable); method public void beforeTextChanged(java.lang.CharSequence, int, int, int); method public void onTextChanged(java.lang.CharSequence, int, int, int); } public abstract interface SpanWatcher implements android.text.NoCopySpan { method public abstract void onSpanAdded(android.text.Spannable, java.lang.Object, int, int); method public abstract void onSpanChanged(android.text.Spannable, java.lang.Object, int, int, int, int); core/java/android/text/Selection.java +128 −55 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package android.text; import android.annotation.TestApi; import java.text.BreakIterator; Loading @@ -35,9 +37,9 @@ public class Selection { * there is no selection or cursor. */ public static final int getSelectionStart(CharSequence text) { if (text instanceof Spanned) if (text instanceof Spanned) { return ((Spanned) text).getSpanStart(SELECTION_START); else } return -1; } Loading @@ -46,9 +48,16 @@ public class Selection { * there is no selection or cursor. */ public static final int getSelectionEnd(CharSequence text) { if (text instanceof Spanned) if (text instanceof Spanned) { return ((Spanned) text).getSpanStart(SELECTION_END); else } return -1; } private static int getSelectionMemory(CharSequence text) { if (text instanceof Spanned) { return ((Spanned) text).getSpanStart(SELECTION_MEMORY); } return -1; } Loading @@ -65,6 +74,14 @@ public class Selection { * to <code>stop</code>. */ public static void setSelection(Spannable text, int start, int stop) { setSelection(text, start, stop, -1); } /** * Set the selection anchor to <code>start</code>, the selection edge * to <code>stop</code> and the memory horizontal to <code>memory</code>. */ private static void setSelection(Spannable text, int start, int stop, int memory) { // int len = text.length(); // start = pin(start, 0, len); XXX remove unless we really need it // stop = pin(stop, 0, len); Loading @@ -75,8 +92,56 @@ public class Selection { if (ostart != start || oend != stop) { text.setSpan(SELECTION_START, start, start, Spanned.SPAN_POINT_POINT | Spanned.SPAN_INTERMEDIATE); text.setSpan(SELECTION_END, stop, stop, Spanned.SPAN_POINT_POINT); text.setSpan(SELECTION_END, stop, stop, Spanned.SPAN_POINT_POINT); updateMemory(text, memory); } } /** * Update the memory position for text. This is used to ensure vertical navigation of lines * with different lengths behaves as expected and remembers the longest horizontal position * seen during a vertical traversal. */ private static void updateMemory(Spannable text, int memory) { if (memory > -1) { int currentMemory = getSelectionMemory(text); if (memory != currentMemory) { text.setSpan(SELECTION_MEMORY, memory, memory, Spanned.SPAN_POINT_POINT); if (currentMemory == -1) { // This is the first value, create a watcher. final TextWatcher watcher = new MemoryTextWatcher(); text.setSpan(watcher, 0, text.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); } } } else { removeMemory(text); } } private static void removeMemory(Spannable text) { text.removeSpan(SELECTION_MEMORY); MemoryTextWatcher[] watchers = text.getSpans(0, text.length(), MemoryTextWatcher.class); for (MemoryTextWatcher watcher : watchers) { text.removeSpan(watcher); } } /** * @hide */ @TestApi public static final class MemoryTextWatcher implements TextWatcher { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {} @Override public void onTextChanged(CharSequence s, int start, int before, int count) {} @Override public void afterTextChanged(Editable s) { s.removeSpan(SELECTION_MEMORY); s.removeSpan(this); } } Loading @@ -98,9 +163,18 @@ public class Selection { * Move the selection edge to offset <code>index</code>. */ public static final void extendSelection(Spannable text, int index) { if (text.getSpanStart(SELECTION_END) != index) extendSelection(text, index, -1); } /** * Move the selection edge to offset <code>index</code> and update the memory horizontal. */ private static void extendSelection(Spannable text, int index, int memory) { if (text.getSpanStart(SELECTION_END) != index) { text.setSpan(SELECTION_END, index, index, Spanned.SPAN_POINT_POINT); } updateMemory(text, memory); } /** * Remove the selection or cursor, if any, from the text. Loading @@ -108,6 +182,7 @@ public class Selection { public static final void removeSelection(Spannable text) { text.removeSpan(SELECTION_START); text.removeSpan(SELECTION_END); removeMemory(text); } /* Loading Loading @@ -138,17 +213,8 @@ public class Selection { int line = layout.getLineForOffset(end); if (line > 0) { int move; if (layout.getParagraphDirection(line) == layout.getParagraphDirection(line - 1)) { float h = layout.getPrimaryHorizontal(end); move = layout.getOffsetForHorizontal(line - 1, h); } else { move = layout.getLineStart(line - 1); } setSelection(text, move); setSelectionAndMemory( text, layout, line, end, -1 /* direction */, false /* extend */); return true; } else if (end != 0) { setSelection(text, 0); Loading @@ -159,6 +225,40 @@ public class Selection { return false; } /** * Calculate the movement and memory positions needed, and set or extend the selection. */ private static void setSelectionAndMemory(Spannable text, Layout layout, int line, int end, int direction, boolean extend) { int move; int newMemory; if (layout.getParagraphDirection(line) == layout.getParagraphDirection(line + direction)) { int memory = getSelectionMemory(text); if (memory > -1) { // We have a memory position float h = layout.getPrimaryHorizontal(memory); move = layout.getOffsetForHorizontal(line + direction, h); newMemory = memory; } else { // Create a new memory position float h = layout.getPrimaryHorizontal(end); move = layout.getOffsetForHorizontal(line + direction, h); newMemory = end; } } else { move = layout.getLineStart(line + direction); newMemory = -1; } if (extend) { extendSelection(text, move, newMemory); } else { setSelection(text, move, move, newMemory); } } /** * Move the cursor to the buffer offset physically below the current * offset, to the end of the buffer if it is on the bottom line but Loading @@ -184,17 +284,8 @@ public class Selection { int line = layout.getLineForOffset(end); if (line < layout.getLineCount() - 1) { int move; if (layout.getParagraphDirection(line) == layout.getParagraphDirection(line + 1)) { float h = layout.getPrimaryHorizontal(end); move = layout.getOffsetForHorizontal(line + 1, h); } else { move = layout.getLineStart(line + 1); } setSelection(text, move); setSelectionAndMemory( text, layout, line, end, 1 /* direction */, false /* extend */); return true; } else if (end != text.length()) { setSelection(text, text.length()); Loading Loading @@ -263,17 +354,7 @@ public class Selection { int line = layout.getLineForOffset(end); if (line > 0) { int move; if (layout.getParagraphDirection(line) == layout.getParagraphDirection(line - 1)) { float h = layout.getPrimaryHorizontal(end); move = layout.getOffsetForHorizontal(line - 1, h); } else { move = layout.getLineStart(line - 1); } extendSelection(text, move); setSelectionAndMemory(text, layout, line, end, -1 /* direction */, true /* extend */); return true; } else if (end != 0) { extendSelection(text, 0); Loading @@ -292,20 +373,10 @@ public class Selection { int line = layout.getLineForOffset(end); if (line < layout.getLineCount() - 1) { int move; if (layout.getParagraphDirection(line) == layout.getParagraphDirection(line + 1)) { float h = layout.getPrimaryHorizontal(end); move = layout.getOffsetForHorizontal(line + 1, h); } else { move = layout.getLineStart(line + 1); } extendSelection(text, move); setSelectionAndMemory(text, layout, line, end, 1 /* direction */, true /* extend */); return true; } else if (end != text.length()) { extendSelection(text, text.length()); extendSelection(text, text.length(), -1); return true; } Loading Loading @@ -466,6 +537,8 @@ public class Selection { private static final class START implements NoCopySpan { } private static final class END implements NoCopySpan { } private static final class MEMORY implements NoCopySpan { } private static final Object SELECTION_MEMORY = new MEMORY(); /* * Public constants Loading Loading
api/test-current.txt +7 −0 Original line number Diff line number Diff line Loading @@ -41721,6 +41721,13 @@ package android.text { field public static final java.lang.Object SELECTION_START; } public static final class Selection.MemoryTextWatcher implements android.text.TextWatcher { ctor public Selection.MemoryTextWatcher(); method public void afterTextChanged(android.text.Editable); method public void beforeTextChanged(java.lang.CharSequence, int, int, int); method public void onTextChanged(java.lang.CharSequence, int, int, int); } public abstract interface SpanWatcher implements android.text.NoCopySpan { method public abstract void onSpanAdded(android.text.Spannable, java.lang.Object, int, int); method public abstract void onSpanChanged(android.text.Spannable, java.lang.Object, int, int, int, int);
core/java/android/text/Selection.java +128 −55 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package android.text; import android.annotation.TestApi; import java.text.BreakIterator; Loading @@ -35,9 +37,9 @@ public class Selection { * there is no selection or cursor. */ public static final int getSelectionStart(CharSequence text) { if (text instanceof Spanned) if (text instanceof Spanned) { return ((Spanned) text).getSpanStart(SELECTION_START); else } return -1; } Loading @@ -46,9 +48,16 @@ public class Selection { * there is no selection or cursor. */ public static final int getSelectionEnd(CharSequence text) { if (text instanceof Spanned) if (text instanceof Spanned) { return ((Spanned) text).getSpanStart(SELECTION_END); else } return -1; } private static int getSelectionMemory(CharSequence text) { if (text instanceof Spanned) { return ((Spanned) text).getSpanStart(SELECTION_MEMORY); } return -1; } Loading @@ -65,6 +74,14 @@ public class Selection { * to <code>stop</code>. */ public static void setSelection(Spannable text, int start, int stop) { setSelection(text, start, stop, -1); } /** * Set the selection anchor to <code>start</code>, the selection edge * to <code>stop</code> and the memory horizontal to <code>memory</code>. */ private static void setSelection(Spannable text, int start, int stop, int memory) { // int len = text.length(); // start = pin(start, 0, len); XXX remove unless we really need it // stop = pin(stop, 0, len); Loading @@ -75,8 +92,56 @@ public class Selection { if (ostart != start || oend != stop) { text.setSpan(SELECTION_START, start, start, Spanned.SPAN_POINT_POINT | Spanned.SPAN_INTERMEDIATE); text.setSpan(SELECTION_END, stop, stop, Spanned.SPAN_POINT_POINT); text.setSpan(SELECTION_END, stop, stop, Spanned.SPAN_POINT_POINT); updateMemory(text, memory); } } /** * Update the memory position for text. This is used to ensure vertical navigation of lines * with different lengths behaves as expected and remembers the longest horizontal position * seen during a vertical traversal. */ private static void updateMemory(Spannable text, int memory) { if (memory > -1) { int currentMemory = getSelectionMemory(text); if (memory != currentMemory) { text.setSpan(SELECTION_MEMORY, memory, memory, Spanned.SPAN_POINT_POINT); if (currentMemory == -1) { // This is the first value, create a watcher. final TextWatcher watcher = new MemoryTextWatcher(); text.setSpan(watcher, 0, text.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); } } } else { removeMemory(text); } } private static void removeMemory(Spannable text) { text.removeSpan(SELECTION_MEMORY); MemoryTextWatcher[] watchers = text.getSpans(0, text.length(), MemoryTextWatcher.class); for (MemoryTextWatcher watcher : watchers) { text.removeSpan(watcher); } } /** * @hide */ @TestApi public static final class MemoryTextWatcher implements TextWatcher { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {} @Override public void onTextChanged(CharSequence s, int start, int before, int count) {} @Override public void afterTextChanged(Editable s) { s.removeSpan(SELECTION_MEMORY); s.removeSpan(this); } } Loading @@ -98,9 +163,18 @@ public class Selection { * Move the selection edge to offset <code>index</code>. */ public static final void extendSelection(Spannable text, int index) { if (text.getSpanStart(SELECTION_END) != index) extendSelection(text, index, -1); } /** * Move the selection edge to offset <code>index</code> and update the memory horizontal. */ private static void extendSelection(Spannable text, int index, int memory) { if (text.getSpanStart(SELECTION_END) != index) { text.setSpan(SELECTION_END, index, index, Spanned.SPAN_POINT_POINT); } updateMemory(text, memory); } /** * Remove the selection or cursor, if any, from the text. Loading @@ -108,6 +182,7 @@ public class Selection { public static final void removeSelection(Spannable text) { text.removeSpan(SELECTION_START); text.removeSpan(SELECTION_END); removeMemory(text); } /* Loading Loading @@ -138,17 +213,8 @@ public class Selection { int line = layout.getLineForOffset(end); if (line > 0) { int move; if (layout.getParagraphDirection(line) == layout.getParagraphDirection(line - 1)) { float h = layout.getPrimaryHorizontal(end); move = layout.getOffsetForHorizontal(line - 1, h); } else { move = layout.getLineStart(line - 1); } setSelection(text, move); setSelectionAndMemory( text, layout, line, end, -1 /* direction */, false /* extend */); return true; } else if (end != 0) { setSelection(text, 0); Loading @@ -159,6 +225,40 @@ public class Selection { return false; } /** * Calculate the movement and memory positions needed, and set or extend the selection. */ private static void setSelectionAndMemory(Spannable text, Layout layout, int line, int end, int direction, boolean extend) { int move; int newMemory; if (layout.getParagraphDirection(line) == layout.getParagraphDirection(line + direction)) { int memory = getSelectionMemory(text); if (memory > -1) { // We have a memory position float h = layout.getPrimaryHorizontal(memory); move = layout.getOffsetForHorizontal(line + direction, h); newMemory = memory; } else { // Create a new memory position float h = layout.getPrimaryHorizontal(end); move = layout.getOffsetForHorizontal(line + direction, h); newMemory = end; } } else { move = layout.getLineStart(line + direction); newMemory = -1; } if (extend) { extendSelection(text, move, newMemory); } else { setSelection(text, move, move, newMemory); } } /** * Move the cursor to the buffer offset physically below the current * offset, to the end of the buffer if it is on the bottom line but Loading @@ -184,17 +284,8 @@ public class Selection { int line = layout.getLineForOffset(end); if (line < layout.getLineCount() - 1) { int move; if (layout.getParagraphDirection(line) == layout.getParagraphDirection(line + 1)) { float h = layout.getPrimaryHorizontal(end); move = layout.getOffsetForHorizontal(line + 1, h); } else { move = layout.getLineStart(line + 1); } setSelection(text, move); setSelectionAndMemory( text, layout, line, end, 1 /* direction */, false /* extend */); return true; } else if (end != text.length()) { setSelection(text, text.length()); Loading Loading @@ -263,17 +354,7 @@ public class Selection { int line = layout.getLineForOffset(end); if (line > 0) { int move; if (layout.getParagraphDirection(line) == layout.getParagraphDirection(line - 1)) { float h = layout.getPrimaryHorizontal(end); move = layout.getOffsetForHorizontal(line - 1, h); } else { move = layout.getLineStart(line - 1); } extendSelection(text, move); setSelectionAndMemory(text, layout, line, end, -1 /* direction */, true /* extend */); return true; } else if (end != 0) { extendSelection(text, 0); Loading @@ -292,20 +373,10 @@ public class Selection { int line = layout.getLineForOffset(end); if (line < layout.getLineCount() - 1) { int move; if (layout.getParagraphDirection(line) == layout.getParagraphDirection(line + 1)) { float h = layout.getPrimaryHorizontal(end); move = layout.getOffsetForHorizontal(line + 1, h); } else { move = layout.getLineStart(line + 1); } extendSelection(text, move); setSelectionAndMemory(text, layout, line, end, 1 /* direction */, true /* extend */); return true; } else if (end != text.length()) { extendSelection(text, text.length()); extendSelection(text, text.length(), -1); return true; } Loading Loading @@ -466,6 +537,8 @@ public class Selection { private static final class START implements NoCopySpan { } private static final class END implements NoCopySpan { } private static final class MEMORY implements NoCopySpan { } private static final Object SELECTION_MEMORY = new MEMORY(); /* * Public constants Loading