Loading core/java/android/text/TextUtils.java +23 −3 Original line number Diff line number Diff line Loading @@ -93,7 +93,9 @@ public class TextUtils { private static final String ELLIPSIS_NORMAL = "\u2026"; // HORIZONTAL ELLIPSIS (…) private static final String ELLIPSIS_TWO_DOTS = "\u2025"; // TWO DOT LEADER (‥) private static final int LINE_FEED_CODE_POINT = 10; /** @hide */ public static final int LINE_FEED_CODE_POINT = 10; private static final int NBSP_CODE_POINT = 160; /** Loading Loading @@ -2335,10 +2337,28 @@ public class TextUtils { || codePoint == LINE_FEED_CODE_POINT; } private static boolean isWhiteSpace(int codePoint) { /** @hide */ public static boolean isWhitespace(int codePoint) { return Character.isWhitespace(codePoint) || codePoint == NBSP_CODE_POINT; } /** @hide */ public static boolean isWhitespaceExceptNewline(int codePoint) { return isWhitespace(codePoint) && !isNewline(codePoint); } /** @hide */ public static boolean isPunctuation(int codePoint) { int type = Character.getType(codePoint); return type == Character.CONNECTOR_PUNCTUATION || type == Character.DASH_PUNCTUATION || type == Character.END_PUNCTUATION || type == Character.FINAL_QUOTE_PUNCTUATION || type == Character.INITIAL_QUOTE_PUNCTUATION || type == Character.OTHER_PUNCTUATION || type == Character.START_PUNCTUATION; } /** @hide */ @Nullable public static String withoutPrefix(@Nullable String prefix, @Nullable String str) { Loading Loading @@ -2430,7 +2450,7 @@ public class TextUtils { gettingCleaned.removeRange(offset, offset + codePointLen); } else if (type == Character.CONTROL && !isNewline) { gettingCleaned.removeRange(offset, offset + codePointLen); } else if (trim && !isWhiteSpace(codePoint)) { } else if (trim && !isWhitespace(codePoint)) { // This is only executed if the code point is not removed if (firstNonWhiteSpace == -1) { firstNonWhiteSpace = offset; Loading core/java/android/text/method/WordIterator.java +13 −23 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.icu.text.BreakIterator; import android.os.Build; import android.text.CharSequenceCharacterIterator; import android.text.Selection; import android.text.TextUtils; import java.util.Locale; Loading Loading @@ -275,9 +276,9 @@ public class WordIterator implements Selection.PositionIterator { } /** * If <code>offset</code> is within a group of punctuation as defined * by {@link #isPunctuation(int)}, returns the index of the first character * of that group, otherwise returns BreakIterator.DONE. * If <code>offset</code> is within a group of punctuation as defined by {@link * TextUtils#isPunctuation(int)}, returns the index of the first character of that group, * otherwise returns BreakIterator.DONE. * * @param offset the offset to search from. */ Loading @@ -292,9 +293,9 @@ public class WordIterator implements Selection.PositionIterator { } /** * If <code>offset</code> is within a group of punctuation as defined * by {@link #isPunctuation(int)}, returns the index of the last character * of that group plus one, otherwise returns BreakIterator.DONE. * If <code>offset</code> is within a group of punctuation as defined by {@link * TextUtils#isPunctuation(int)}, returns the index of the last character of that group plus * one, otherwise returns BreakIterator.DONE. * * @param offset the offset to search from. */ Loading @@ -309,8 +310,8 @@ public class WordIterator implements Selection.PositionIterator { } /** * Indicates if the provided offset is after a punctuation character * as defined by {@link #isPunctuation(int)}. * Indicates if the provided offset is after a punctuation character as defined by {@link * TextUtils#isPunctuation(int)}. * * @param offset the offset to check from. * @return Whether the offset is after a punctuation character. Loading @@ -319,14 +320,14 @@ public class WordIterator implements Selection.PositionIterator { public boolean isAfterPunctuation(int offset) { if (mStart < offset && offset <= mEnd) { final int codePoint = Character.codePointBefore(mCharSeq, offset); return isPunctuation(codePoint); return TextUtils.isPunctuation(codePoint); } return false; } /** * Indicates if the provided offset is at a punctuation character * as defined by {@link #isPunctuation(int)}. * Indicates if the provided offset is at a punctuation character as defined by {@link * TextUtils#isPunctuation(int)}. * * @param offset the offset to check from. * @return Whether the offset is at a punctuation character. Loading @@ -335,7 +336,7 @@ public class WordIterator implements Selection.PositionIterator { public boolean isOnPunctuation(int offset) { if (mStart <= offset && offset < mEnd) { final int codePoint = Character.codePointAt(mCharSeq, offset); return isPunctuation(codePoint); return TextUtils.isPunctuation(codePoint); } return false; } Loading Loading @@ -369,17 +370,6 @@ public class WordIterator implements Selection.PositionIterator { return !isOnPunctuation(offset) && isAfterPunctuation(offset); } private static boolean isPunctuation(int cp) { final int type = Character.getType(cp); return (type == Character.CONNECTOR_PUNCTUATION || type == Character.DASH_PUNCTUATION || type == Character.END_PUNCTUATION || type == Character.FINAL_QUOTE_PUNCTUATION || type == Character.INITIAL_QUOTE_PUNCTUATION || type == Character.OTHER_PUNCTUATION || type == Character.START_PUNCTUATION); } private boolean isAfterLetterOrDigit(int offset) { if (mStart < offset && offset <= mEnd) { final int codePoint = Character.codePointBefore(mCharSeq, offset); Loading core/java/android/widget/TextView.java +52 −3 Original line number Diff line number Diff line Loading @@ -9330,9 +9330,58 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (range == null) { return handleGestureFailure(gesture); } getEditableText().delete(range[0], range[1]); Selection.setSelection(getEditableText(), range[0]); // TODO(b/243983058): Delete extra spaces. int start = range[0]; int end = range[1]; // For word granularity, adjust the start and end offsets to remove extra whitespace around // the deleted text. if (gesture.getGranularity() == HandwritingGesture.GRANULARITY_WORD) { // If the deleted text is at the start of the text, the behavior is the same as the case // where the deleted text follows a new line character. int codePointBeforeStart = start > 0 ? Character.codePointBefore(mText, start) : TextUtils.LINE_FEED_CODE_POINT; // If the deleted text is at the end of the text, the behavior is the same as the case // where the deleted text precedes a new line character. int codePointAtEnd = end < mText.length() ? Character.codePointAt(mText, end) : TextUtils.LINE_FEED_CODE_POINT; if (TextUtils.isWhitespaceExceptNewline(codePointBeforeStart) && (TextUtils.isWhitespace(codePointAtEnd) || TextUtils.isPunctuation(codePointAtEnd))) { // Remove whitespace (except new lines) before the deleted text, in these cases: // - There is whitespace following the deleted text // e.g. "one [deleted] three" -> "one | three" -> "one| three" // - There is punctuation following the deleted text // e.g. "one [deleted]!" -> "one |!" -> "one|!" // - There is a new line following the deleted text // e.g. "one [deleted]\n" -> "one |\n" -> "one|\n" // - The deleted text is at the end of the text // e.g. "one [deleted]" -> "one |" -> "one|" // (The pipe | indicates the cursor position.) while (start > 0 && TextUtils.isWhitespaceExceptNewline(codePointBeforeStart)) { start -= Character.charCount(codePointBeforeStart); codePointBeforeStart = Character.codePointBefore(mText, start); } } else if (TextUtils.isWhitespaceExceptNewline(codePointAtEnd) && (TextUtils.isWhitespace(codePointBeforeStart) || TextUtils.isPunctuation(codePointBeforeStart))) { // Remove whitespace (except new lines) after the deleted text, in these cases: // - There is punctuation preceding the deleted text // e.g. "([deleted] two)" -> "(| two)" -> "(|two)" // - There is a new line preceding the deleted text // e.g. "\n[deleted] two" -> "\n| two" -> "\n|two" // - The deleted text is at the start of the text // e.g. "[deleted] two" -> "| two" -> "|two" // (The pipe | indicates the cursor position.) while (end < mText.length() && TextUtils.isWhitespaceExceptNewline(codePointAtEnd)) { end += Character.charCount(codePointAtEnd); codePointAtEnd = Character.codePointAt(mText, end); } } } getEditableText().delete(start, end); Selection.setSelection(getEditableText(), start); return InputConnection.HANDWRITING_GESTURE_RESULT_SUCCESS; } Loading Loading
core/java/android/text/TextUtils.java +23 −3 Original line number Diff line number Diff line Loading @@ -93,7 +93,9 @@ public class TextUtils { private static final String ELLIPSIS_NORMAL = "\u2026"; // HORIZONTAL ELLIPSIS (…) private static final String ELLIPSIS_TWO_DOTS = "\u2025"; // TWO DOT LEADER (‥) private static final int LINE_FEED_CODE_POINT = 10; /** @hide */ public static final int LINE_FEED_CODE_POINT = 10; private static final int NBSP_CODE_POINT = 160; /** Loading Loading @@ -2335,10 +2337,28 @@ public class TextUtils { || codePoint == LINE_FEED_CODE_POINT; } private static boolean isWhiteSpace(int codePoint) { /** @hide */ public static boolean isWhitespace(int codePoint) { return Character.isWhitespace(codePoint) || codePoint == NBSP_CODE_POINT; } /** @hide */ public static boolean isWhitespaceExceptNewline(int codePoint) { return isWhitespace(codePoint) && !isNewline(codePoint); } /** @hide */ public static boolean isPunctuation(int codePoint) { int type = Character.getType(codePoint); return type == Character.CONNECTOR_PUNCTUATION || type == Character.DASH_PUNCTUATION || type == Character.END_PUNCTUATION || type == Character.FINAL_QUOTE_PUNCTUATION || type == Character.INITIAL_QUOTE_PUNCTUATION || type == Character.OTHER_PUNCTUATION || type == Character.START_PUNCTUATION; } /** @hide */ @Nullable public static String withoutPrefix(@Nullable String prefix, @Nullable String str) { Loading Loading @@ -2430,7 +2450,7 @@ public class TextUtils { gettingCleaned.removeRange(offset, offset + codePointLen); } else if (type == Character.CONTROL && !isNewline) { gettingCleaned.removeRange(offset, offset + codePointLen); } else if (trim && !isWhiteSpace(codePoint)) { } else if (trim && !isWhitespace(codePoint)) { // This is only executed if the code point is not removed if (firstNonWhiteSpace == -1) { firstNonWhiteSpace = offset; Loading
core/java/android/text/method/WordIterator.java +13 −23 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.icu.text.BreakIterator; import android.os.Build; import android.text.CharSequenceCharacterIterator; import android.text.Selection; import android.text.TextUtils; import java.util.Locale; Loading Loading @@ -275,9 +276,9 @@ public class WordIterator implements Selection.PositionIterator { } /** * If <code>offset</code> is within a group of punctuation as defined * by {@link #isPunctuation(int)}, returns the index of the first character * of that group, otherwise returns BreakIterator.DONE. * If <code>offset</code> is within a group of punctuation as defined by {@link * TextUtils#isPunctuation(int)}, returns the index of the first character of that group, * otherwise returns BreakIterator.DONE. * * @param offset the offset to search from. */ Loading @@ -292,9 +293,9 @@ public class WordIterator implements Selection.PositionIterator { } /** * If <code>offset</code> is within a group of punctuation as defined * by {@link #isPunctuation(int)}, returns the index of the last character * of that group plus one, otherwise returns BreakIterator.DONE. * If <code>offset</code> is within a group of punctuation as defined by {@link * TextUtils#isPunctuation(int)}, returns the index of the last character of that group plus * one, otherwise returns BreakIterator.DONE. * * @param offset the offset to search from. */ Loading @@ -309,8 +310,8 @@ public class WordIterator implements Selection.PositionIterator { } /** * Indicates if the provided offset is after a punctuation character * as defined by {@link #isPunctuation(int)}. * Indicates if the provided offset is after a punctuation character as defined by {@link * TextUtils#isPunctuation(int)}. * * @param offset the offset to check from. * @return Whether the offset is after a punctuation character. Loading @@ -319,14 +320,14 @@ public class WordIterator implements Selection.PositionIterator { public boolean isAfterPunctuation(int offset) { if (mStart < offset && offset <= mEnd) { final int codePoint = Character.codePointBefore(mCharSeq, offset); return isPunctuation(codePoint); return TextUtils.isPunctuation(codePoint); } return false; } /** * Indicates if the provided offset is at a punctuation character * as defined by {@link #isPunctuation(int)}. * Indicates if the provided offset is at a punctuation character as defined by {@link * TextUtils#isPunctuation(int)}. * * @param offset the offset to check from. * @return Whether the offset is at a punctuation character. Loading @@ -335,7 +336,7 @@ public class WordIterator implements Selection.PositionIterator { public boolean isOnPunctuation(int offset) { if (mStart <= offset && offset < mEnd) { final int codePoint = Character.codePointAt(mCharSeq, offset); return isPunctuation(codePoint); return TextUtils.isPunctuation(codePoint); } return false; } Loading Loading @@ -369,17 +370,6 @@ public class WordIterator implements Selection.PositionIterator { return !isOnPunctuation(offset) && isAfterPunctuation(offset); } private static boolean isPunctuation(int cp) { final int type = Character.getType(cp); return (type == Character.CONNECTOR_PUNCTUATION || type == Character.DASH_PUNCTUATION || type == Character.END_PUNCTUATION || type == Character.FINAL_QUOTE_PUNCTUATION || type == Character.INITIAL_QUOTE_PUNCTUATION || type == Character.OTHER_PUNCTUATION || type == Character.START_PUNCTUATION); } private boolean isAfterLetterOrDigit(int offset) { if (mStart < offset && offset <= mEnd) { final int codePoint = Character.codePointBefore(mCharSeq, offset); Loading
core/java/android/widget/TextView.java +52 −3 Original line number Diff line number Diff line Loading @@ -9330,9 +9330,58 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (range == null) { return handleGestureFailure(gesture); } getEditableText().delete(range[0], range[1]); Selection.setSelection(getEditableText(), range[0]); // TODO(b/243983058): Delete extra spaces. int start = range[0]; int end = range[1]; // For word granularity, adjust the start and end offsets to remove extra whitespace around // the deleted text. if (gesture.getGranularity() == HandwritingGesture.GRANULARITY_WORD) { // If the deleted text is at the start of the text, the behavior is the same as the case // where the deleted text follows a new line character. int codePointBeforeStart = start > 0 ? Character.codePointBefore(mText, start) : TextUtils.LINE_FEED_CODE_POINT; // If the deleted text is at the end of the text, the behavior is the same as the case // where the deleted text precedes a new line character. int codePointAtEnd = end < mText.length() ? Character.codePointAt(mText, end) : TextUtils.LINE_FEED_CODE_POINT; if (TextUtils.isWhitespaceExceptNewline(codePointBeforeStart) && (TextUtils.isWhitespace(codePointAtEnd) || TextUtils.isPunctuation(codePointAtEnd))) { // Remove whitespace (except new lines) before the deleted text, in these cases: // - There is whitespace following the deleted text // e.g. "one [deleted] three" -> "one | three" -> "one| three" // - There is punctuation following the deleted text // e.g. "one [deleted]!" -> "one |!" -> "one|!" // - There is a new line following the deleted text // e.g. "one [deleted]\n" -> "one |\n" -> "one|\n" // - The deleted text is at the end of the text // e.g. "one [deleted]" -> "one |" -> "one|" // (The pipe | indicates the cursor position.) while (start > 0 && TextUtils.isWhitespaceExceptNewline(codePointBeforeStart)) { start -= Character.charCount(codePointBeforeStart); codePointBeforeStart = Character.codePointBefore(mText, start); } } else if (TextUtils.isWhitespaceExceptNewline(codePointAtEnd) && (TextUtils.isWhitespace(codePointBeforeStart) || TextUtils.isPunctuation(codePointBeforeStart))) { // Remove whitespace (except new lines) after the deleted text, in these cases: // - There is punctuation preceding the deleted text // e.g. "([deleted] two)" -> "(| two)" -> "(|two)" // - There is a new line preceding the deleted text // e.g. "\n[deleted] two" -> "\n| two" -> "\n|two" // - The deleted text is at the start of the text // e.g. "[deleted] two" -> "| two" -> "|two" // (The pipe | indicates the cursor position.) while (end < mText.length() && TextUtils.isWhitespaceExceptNewline(codePointAtEnd)) { end += Character.charCount(codePointAtEnd); codePointAtEnd = Character.codePointAt(mText, end); } } } getEditableText().delete(start, end); Selection.setSelection(getEditableText(), start); return InputConnection.HANDWRITING_GESTURE_RESULT_SUCCESS; } Loading