Merge "Make up/down movement of multilength lines remember position"
This commit is contained in:
committed by
Android (Google) Code Review
commit
725e2924cc
@@ -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);
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package android.text;
|
||||
|
||||
import android.annotation.TestApi;
|
||||
|
||||
import java.text.BreakIterator;
|
||||
|
||||
|
||||
@@ -35,10 +37,10 @@ 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;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -46,10 +48,17 @@ 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;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static int getSelectionMemory(CharSequence text) {
|
||||
if (text instanceof Spanned) {
|
||||
return ((Spanned) text).getSpanStart(SELECTION_MEMORY);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -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);
|
||||
@@ -74,9 +91,57 @@ 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);
|
||||
Spanned.SPAN_POINT_POINT | Spanned.SPAN_INTERMEDIATE);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,8 +163,17 @@ 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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,6 +182,7 @@ public class Selection {
|
||||
public static final void removeSelection(Spannable text) {
|
||||
text.removeSpan(SELECTION_START);
|
||||
text.removeSpan(SELECTION_END);
|
||||
removeMemory(text);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -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);
|
||||
@@ -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
|
||||
@@ -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());
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user