diff options
| -rw-r--r-- | core/api/current.txt | 6 | ||||
| -rw-r--r-- | core/java/android/text/Selection.java | 95 | ||||
| -rw-r--r-- | core/java/android/text/method/ArrowKeyMovementMethod.java | 21 | ||||
| -rw-r--r-- | core/java/android/text/method/BaseMovementMethod.java | 29 |
4 files changed, 151 insertions, 0 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index dc5466100265..1cd8253aac36 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -45247,6 +45247,8 @@ package android.text { method public static boolean extendRight(android.text.Spannable, android.text.Layout); method public static final void extendSelection(android.text.Spannable, int); method public static boolean extendToLeftEdge(android.text.Spannable, android.text.Layout); + method public static boolean extendToParagraphEnd(@NonNull android.text.Spannable); + method public static boolean extendToParagraphStart(@NonNull android.text.Spannable); method public static boolean extendToRightEdge(android.text.Spannable, android.text.Layout); method public static boolean extendUp(android.text.Spannable, android.text.Layout); method public static final int getSelectionEnd(CharSequence); @@ -45255,6 +45257,8 @@ package android.text { method public static boolean moveLeft(android.text.Spannable, android.text.Layout); method public static boolean moveRight(android.text.Spannable, android.text.Layout); method public static boolean moveToLeftEdge(android.text.Spannable, android.text.Layout); + method public static boolean moveToParagraphEnd(@NonNull android.text.Spannable, @NonNull android.text.Layout); + method public static boolean moveToParagraphStart(@NonNull android.text.Spannable, @NonNull android.text.Layout); method public static boolean moveToRightEdge(android.text.Spannable, android.text.Layout); method public static boolean moveUp(android.text.Spannable, android.text.Layout); method public static final void removeSelection(android.text.Spannable); @@ -45703,6 +45707,7 @@ package android.text.method { method protected boolean left(android.widget.TextView, android.text.Spannable); method protected boolean lineEnd(android.widget.TextView, android.text.Spannable); method protected boolean lineStart(android.widget.TextView, android.text.Spannable); + method public boolean nextParagraph(@NonNull android.widget.TextView, @NonNull android.text.Spannable); method public boolean onGenericMotionEvent(android.widget.TextView, android.text.Spannable, android.view.MotionEvent); method public boolean onKeyDown(android.widget.TextView, android.text.Spannable, int, android.view.KeyEvent); method public boolean onKeyOther(android.widget.TextView, android.text.Spannable, android.view.KeyEvent); @@ -45712,6 +45717,7 @@ package android.text.method { method public boolean onTrackballEvent(android.widget.TextView, android.text.Spannable, android.view.MotionEvent); method protected boolean pageDown(android.widget.TextView, android.text.Spannable); method protected boolean pageUp(android.widget.TextView, android.text.Spannable); + method public boolean previousParagraph(@NonNull android.widget.TextView, @NonNull android.text.Spannable); method protected boolean right(android.widget.TextView, android.text.Spannable); method protected boolean top(android.widget.TextView, android.text.Spannable); method protected boolean up(android.widget.TextView, android.text.Spannable); diff --git a/core/java/android/text/Selection.java b/core/java/android/text/Selection.java index 57c1d237d4ed..6a54d2378f6c 100644 --- a/core/java/android/text/Selection.java +++ b/core/java/android/text/Selection.java @@ -16,6 +16,7 @@ package android.text; +import android.annotation.NonNull; import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; @@ -346,6 +347,100 @@ public class Selection { return false; } + private static final char PARAGRAPH_SEPARATOR = '\n'; + + /** + * Move the cusrot to the closest paragraph start offset. + * + * @param text the spannable text + * @param layout layout to be used for drawing. + * @return true if the cursor is moved, otherwise false. + */ + public static boolean moveToParagraphStart(@NonNull Spannable text, @NonNull Layout layout) { + int start = getSelectionStart(text); + int end = getSelectionEnd(text); + + if (start != end) { + setSelection(text, chooseHorizontal(layout, -1, start, end)); + return true; + } else { + int to = TextUtils.lastIndexOf(text, PARAGRAPH_SEPARATOR, start - 1); + if (to == -1) { + to = 0; // If not found, use the document start offset as a paragraph start. + } + if (to != end) { + setSelection(text, to); + return true; + } + } + return false; + } + + /** + * Move the cursor to the closest paragraph end offset. + * + * @param text the spannable text + * @param layout layout to be used for drawing. + * @return true if the cursor is moved, otherwise false. + */ + public static boolean moveToParagraphEnd(@NonNull Spannable text, @NonNull Layout layout) { + int start = getSelectionStart(text); + int end = getSelectionEnd(text); + + if (start != end) { + setSelection(text, chooseHorizontal(layout, 1, start, end)); + return true; + } else { + int to = TextUtils.indexOf(text, PARAGRAPH_SEPARATOR, end + 1); + if (to == -1) { + to = text.length(); + } + if (to != end) { + setSelection(text, to); + return true; + } + } + return false; + } + + /** + * Extend the selection to the closest paragraph start offset. + * + * @param text the spannable text + * @return true if the selection is extended, otherwise false + */ + public static boolean extendToParagraphStart(@NonNull Spannable text) { + int end = getSelectionEnd(text); + int to = TextUtils.lastIndexOf(text, PARAGRAPH_SEPARATOR, end - 1); + if (to == -1) { + to = 0; // If not found, use the document start offset as a paragraph start. + } + if (to != end) { + extendSelection(text, to); + return true; + } + return false; + } + + /** + * Extend the selection to the closest paragraph end offset. + * + * @param text the spannable text + * @return true if the selection is extended, otherwise false + */ + public static boolean extendToParagraphEnd(@NonNull Spannable text) { + int end = getSelectionEnd(text); + int to = TextUtils.indexOf(text, PARAGRAPH_SEPARATOR, end + 1); + if (to == -1) { + to = text.length(); + } + if (to != end) { + extendSelection(text, to); + return true; + } + return false; + } + /** * Move the selection end to the buffer offset physically above * the current selection end. diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java index 57fe1315ab5d..d3367d014e7d 100644 --- a/core/java/android/text/method/ArrowKeyMovementMethod.java +++ b/core/java/android/text/method/ArrowKeyMovementMethod.java @@ -16,6 +16,7 @@ package android.text.method; +import android.annotation.NonNull; import android.graphics.Rect; import android.text.Layout; import android.text.Selection; @@ -222,6 +223,26 @@ public class ArrowKeyMovementMethod extends BaseMovementMethod implements Moveme } @Override + public boolean previousParagraph(@NonNull TextView widget, @NonNull Spannable buffer) { + final Layout layout = widget.getLayout(); + if (isSelecting(buffer)) { + return Selection.extendToParagraphStart(buffer); + } else { + return Selection.moveToParagraphStart(buffer, layout); + } + } + + @Override + public boolean nextParagraph(@NonNull TextView widget, @NonNull Spannable buffer) { + final Layout layout = widget.getLayout(); + if (isSelecting(buffer)) { + return Selection.extendToParagraphEnd(buffer); + } else { + return Selection.moveToParagraphEnd(buffer, layout); + } + } + + @Override public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) { int initialScrollX = -1; int initialScrollY = -1; diff --git a/core/java/android/text/method/BaseMovementMethod.java b/core/java/android/text/method/BaseMovementMethod.java index 155a2c4fcfa0..7a4b3a095ae9 100644 --- a/core/java/android/text/method/BaseMovementMethod.java +++ b/core/java/android/text/method/BaseMovementMethod.java @@ -16,6 +16,7 @@ package android.text.method; +import android.annotation.NonNull; import android.text.Layout; import android.text.Spannable; import android.view.InputDevice; @@ -190,6 +191,9 @@ public class BaseMovementMethod implements MovementMethod { } else if (KeyEvent.metaStateHasModifiers(movementMetaState, KeyEvent.META_ALT_ON)) { return top(widget, buffer); + } else if (KeyEvent.metaStateHasModifiers(movementMetaState, + KeyEvent.META_CTRL_ON)) { + return previousParagraph(widget, buffer); } break; @@ -199,6 +203,9 @@ public class BaseMovementMethod implements MovementMethod { } else if (KeyEvent.metaStateHasModifiers(movementMetaState, KeyEvent.META_ALT_ON)) { return bottom(widget, buffer); + } else if (KeyEvent.metaStateHasModifiers(movementMetaState, + KeyEvent.META_CTRL_ON)) { + return nextParagraph(widget, buffer); } break; @@ -399,6 +406,28 @@ public class BaseMovementMethod implements MovementMethod { return false; } + /** + * Performs a previous paragraph movement action. + * + * @param widget the text view + * @param buffer the text buffer + * @return true if the event was handled, otherwise false. + */ + public boolean previousParagraph(@NonNull TextView widget, @NonNull Spannable buffer) { + return false; + } + + /** + * Performs a next paragraph movement action. + * + * @param widget the text view + * @param buffer the text buffer + * @return true if the event was handled, otherwise false. + */ + public boolean nextParagraph(@NonNull TextView widget, @NonNull Spannable buffer) { + return false; + } + private int getTopLine(TextView widget) { return widget.getLayout().getLineForVertical(widget.getScrollY()); } |