diff --git a/core/api/current.txt b/core/api/current.txt index 29d4915a4953a..812ce175db503 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -50464,6 +50464,7 @@ package android.view.inputmethod { method public int describeContents(); method public void dump(android.util.Printer, String); method @Nullable public CharSequence getInitialSelectedText(int); + method @Nullable public android.view.inputmethod.SurroundingText getInitialSurroundingText(@IntRange(from=0) int, @IntRange(from=0) int, int); method @Nullable public CharSequence getInitialTextAfterCursor(int, int); method @Nullable public CharSequence getInitialTextBeforeCursor(int, int); method public final void makeCompatible(int); diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java index 1cf25a77fa38a..2df75f6570db1 100644 --- a/core/java/android/view/inputmethod/EditorInfo.java +++ b/core/java/android/view/inputmethod/EditorInfo.java @@ -25,6 +25,7 @@ import static android.view.inputmethod.EditorInfoProto.PRIVATE_IME_OPTIONS; import static android.view.inputmethod.EditorInfoProto.TARGET_INPUT_METHOD_USER_ID; import android.annotation.IntDef; +import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -36,7 +37,6 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.UserHandle; import android.text.InputType; -import android.text.ParcelableSpan; import android.text.TextUtils; import android.util.Printer; import android.util.proto.ProtoOutputStream; @@ -44,6 +44,7 @@ import android.view.View; import android.view.autofill.AutofillId; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.Preconditions; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -563,8 +564,9 @@ public class EditorInfo implements InputType, Parcelable { @VisibleForTesting static final int MAX_INITIAL_SELECTION_LENGTH = MEMORY_EFFICIENT_TEXT_LENGTH / 2; - @NonNull - private InitialSurroundingText mInitialSurroundingText = new InitialSurroundingText(); + @Nullable + private SurroundingText mInitialSurroundingText = null; + /** * Editors may use this method to provide initial input text to IMEs. As the surrounding text @@ -607,6 +609,12 @@ public class EditorInfo implements InputType, Parcelable { public void setInitialSurroundingSubText(@NonNull CharSequence subText, int subTextStart) { Objects.requireNonNull(subText); + // For privacy protection reason, we don't carry password inputs to IMEs. + if (isPasswordInputType(inputType)) { + mInitialSurroundingText = null; + return; + } + // Swap selection start and end if necessary. final int subTextSelStart = initialSelStart > initialSelEnd ? initialSelEnd - subTextStart : initialSelStart - subTextStart; @@ -616,23 +624,17 @@ public class EditorInfo implements InputType, Parcelable { final int subTextLength = subText.length(); // Unknown or invalid selection. if (subTextStart < 0 || subTextSelStart < 0 || subTextSelEnd > subTextLength) { - mInitialSurroundingText = new InitialSurroundingText(); - return; - } - - // For privacy protection reason, we don't carry password inputs to IMEs. - if (isPasswordInputType(inputType)) { - mInitialSurroundingText = new InitialSurroundingText(); + mInitialSurroundingText = null; return; } if (subTextLength <= MEMORY_EFFICIENT_TEXT_LENGTH) { - mInitialSurroundingText = new InitialSurroundingText(subText, subTextSelStart, - subTextSelEnd); + mInitialSurroundingText = new SurroundingText(subText, subTextSelStart, + subTextSelEnd, subTextStart); return; } - trimLongSurroundingText(subText, subTextSelStart, subTextSelEnd); + trimLongSurroundingText(subText, subTextSelStart, subTextSelEnd, subTextStart); } /** @@ -651,8 +653,10 @@ public class EditorInfo implements InputType, Parcelable { * @param subText The long text that needs to be trimmed. * @param selStart The text offset of the start of the selection. * @param selEnd The text offset of the end of the selection + * @param subTextStart The position that the input text got trimmed. */ - private void trimLongSurroundingText(CharSequence subText, int selStart, int selEnd) { + private void trimLongSurroundingText(CharSequence subText, int selStart, int selEnd, + int subTextStart) { final int sourceSelLength = selEnd - selStart; // When the selected text is too long, drop it. final int newSelLength = (sourceSelLength > MAX_INITIAL_SELECTION_LENGTH) @@ -702,10 +706,13 @@ public class EditorInfo implements InputType, Parcelable { // obj. newBeforeCursorHead = 0; final int newSelHead = newBeforeCursorHead + newBeforeCursorLength; - mInitialSurroundingText = new InitialSurroundingText( - newInitialSurroundingText, newSelHead, newSelHead + newSelLength); + final int newOffset = subTextStart + selStart - newSelHead; + mInitialSurroundingText = new SurroundingText( + newInitialSurroundingText, newSelHead, newSelHead + newSelLength, + newOffset); } + /** * Get length characters of text before the current cursor position. May be * {@code null} when the protocol is not supported. @@ -720,7 +727,17 @@ public class EditorInfo implements InputType, Parcelable { */ @Nullable public CharSequence getInitialTextBeforeCursor(int length, int flags) { - return mInitialSurroundingText.getInitialTextBeforeCursor(length, flags); + if (mInitialSurroundingText == null) { + return null; + } + + int selStart = Math.min(mInitialSurroundingText.getSelectionStart(), + mInitialSurroundingText.getSelectionEnd()); + int n = Math.min(length, selStart); + return ((flags & InputConnection.GET_TEXT_WITH_STYLES) != 0) + ? mInitialSurroundingText.getText().subSequence(selStart - n, selStart) + : TextUtils.substring(mInitialSurroundingText.getText(), selStart - n, + selStart); } /** @@ -735,6 +752,10 @@ public class EditorInfo implements InputType, Parcelable { */ @Nullable public CharSequence getInitialSelectedText(int flags) { + if (mInitialSurroundingText == null) { + return null; + } + // Swap selection start and end if necessary. final int correctedTextSelStart = initialSelStart > initialSelEnd ? initialSelEnd : initialSelStart; @@ -742,11 +763,21 @@ public class EditorInfo implements InputType, Parcelable { ? initialSelStart : initialSelEnd; final int sourceSelLength = correctedTextSelEnd - correctedTextSelStart; - if (initialSelStart < 0 || initialSelEnd < 0 - || mInitialSurroundingText.getSelectionLength() != sourceSelLength) { + int selStart = mInitialSurroundingText.getSelectionStart(); + int selEnd = mInitialSurroundingText.getSelectionEnd(); + if (selStart > selEnd) { + int tmp = selStart; + selStart = selEnd; + selEnd = tmp; + } + final int selLength = selEnd - selStart; + if (initialSelStart < 0 || initialSelEnd < 0 || selLength != sourceSelLength) { return null; } - return mInitialSurroundingText.getInitialSelectedText(flags); + + return ((flags & InputConnection.GET_TEXT_WITH_STYLES) != 0) + ? mInitialSurroundingText.getText().subSequence(selStart, selEnd) + : TextUtils.substring(mInitialSurroundingText.getText(), selStart, selEnd); } /** @@ -763,7 +794,79 @@ public class EditorInfo implements InputType, Parcelable { */ @Nullable public CharSequence getInitialTextAfterCursor(int length, int flags) { - return mInitialSurroundingText.getInitialTextAfterCursor(length, flags); + if (mInitialSurroundingText == null) { + return null; + } + + int surroundingTextLength = mInitialSurroundingText.getText().length(); + int selEnd = Math.max(mInitialSurroundingText.getSelectionStart(), + mInitialSurroundingText.getSelectionEnd()); + int n = Math.min(length, surroundingTextLength - selEnd); + return ((flags & InputConnection.GET_TEXT_WITH_STYLES) != 0) + ? mInitialSurroundingText.getText().subSequence(selEnd, selEnd + n) + : TextUtils.substring(mInitialSurroundingText.getText(), selEnd, selEnd + n); + } + + /** + * Gets the surrounding text around the current cursor, with beforeLength characters + * of text before the cursor (start of the selection), afterLength characters of text + * after the cursor (end of the selection), and all of the selected text. + * + *

The initial surrounding text for return could be trimmed if oversize. Fundamental trimming + * rules are:

+ * + * + *

For example, the subText can be viewed as TextBeforeCursor + Selection + TextAfterCursor. + * The result could be:

+ *
    + *
  1. (maybeTrimmedAtHead)TextBeforeCursor + Selection + * + TextAfterCursor(maybeTrimmedAtTail)
  2. + *
  3. (maybeTrimmedAtHead)TextBeforeCursor + TextAfterCursor(maybeTrimmedAtTail)
  4. + *
+ * + * @param beforeLength The expected length of the text before the cursor. + * @param afterLength The expected length of the text after the cursor. + * @param flags Supplies additional options controlling how the text is returned. May be either + * {@code 0} or {@link InputConnection#GET_TEXT_WITH_STYLES}. + * @return an {@link android.view.inputmethod.SurroundingText} object describing the surrounding + * text and state of selection, or {@code null} if the editor or system could not support this + * protocol. + * @throws IllegalArgumentException if {@code beforeLength} or {@code afterLength} is negative. + */ + @Nullable + public SurroundingText getInitialSurroundingText( + @IntRange(from = 0) int beforeLength, @IntRange(from = 0) int afterLength, + @InputConnection.GetTextType int flags) { + Preconditions.checkArgumentNonnegative(beforeLength); + Preconditions.checkArgumentNonnegative(afterLength); + + if (mInitialSurroundingText == null) { + return null; + } + + int length = mInitialSurroundingText.getText().length(); + int selStart = mInitialSurroundingText.getSelectionStart(); + int selEnd = mInitialSurroundingText.getSelectionEnd(); + if (selStart > selEnd) { + int tmp = selStart; + selStart = selEnd; + selEnd = tmp; + } + + int before = Math.min(beforeLength, selStart); + int after = Math.min(selEnd + afterLength, length); + int offset = selStart - before; + CharSequence newText = ((flags & InputConnection.GET_TEXT_WITH_STYLES) != 0) + ? mInitialSurroundingText.getText().subSequence(offset, after) + : TextUtils.substring(mInitialSurroundingText.getText(), offset, after); + int newSelEnd = Math.min(selEnd - offset, length); + return new SurroundingText(newText, before, newSelEnd, + mInitialSurroundingText.getOffset() + offset); } private static boolean isCutOnSurrogate(CharSequence sourceText, int cutPosition, @@ -893,7 +996,10 @@ public class EditorInfo implements InputType, Parcelable { dest.writeInt(fieldId); dest.writeString(fieldName); dest.writeBundle(extras); - mInitialSurroundingText.writeToParcel(dest, flags); + dest.writeBoolean(mInitialSurroundingText != null); + if (mInitialSurroundingText != null) { + mInitialSurroundingText.writeToParcel(dest, flags); + } if (hintLocales != null) { hintLocales.writeToParcel(dest, flags); } else { @@ -925,9 +1031,11 @@ public class EditorInfo implements InputType, Parcelable { res.fieldId = source.readInt(); res.fieldName = source.readString(); res.extras = source.readBundle(); - InitialSurroundingText initialSurroundingText = - InitialSurroundingText.CREATOR.createFromParcel(source); - res.mInitialSurroundingText = initialSurroundingText; + boolean hasInitialSurroundingText = source.readBoolean(); + if (hasInitialSurroundingText) { + res.mInitialSurroundingText = + SurroundingText.CREATOR.createFromParcel(source); + } LocaleList hintLocales = LocaleList.CREATOR.createFromParcel(source); res.hintLocales = hintLocales.isEmpty() ? null : hintLocales; res.contentMimeTypes = source.readStringArray(); @@ -943,120 +1051,4 @@ public class EditorInfo implements InputType, Parcelable { public int describeContents() { return 0; } - - static final class InitialSurroundingText implements Parcelable { - @Nullable final CharSequence mSurroundingText; - final int mSelectionHead; - final int mSelectionEnd; - - InitialSurroundingText() { - mSurroundingText = null; - mSelectionHead = 0; - mSelectionEnd = 0; - } - - InitialSurroundingText(@Nullable CharSequence surroundingText, int selectionHead, - int selectionEnd) { - // Copy the original text (without NoCopySpan) in case the original text is updated - // later. - mSurroundingText = copyWithParcelableSpans(surroundingText); - mSelectionHead = selectionHead; - mSelectionEnd = selectionEnd; - } - - @Nullable - private CharSequence getInitialTextBeforeCursor(int n, int flags) { - if (mSurroundingText == null) { - return null; - } - - final int length = Math.min(n, mSelectionHead); - return ((flags & InputConnection.GET_TEXT_WITH_STYLES) != 0) - ? mSurroundingText.subSequence(mSelectionHead - length, mSelectionHead) - : TextUtils.substring(mSurroundingText, mSelectionHead - length, - mSelectionHead); - } - - @Nullable - private CharSequence getInitialSelectedText(int flags) { - if (mSurroundingText == null) { - return null; - } - - return ((flags & InputConnection.GET_TEXT_WITH_STYLES) != 0) - ? mSurroundingText.subSequence(mSelectionHead, mSelectionEnd) - : TextUtils.substring(mSurroundingText, mSelectionHead, mSelectionEnd); - } - - @Nullable - private CharSequence getInitialTextAfterCursor(int n, int flags) { - if (mSurroundingText == null) { - return null; - } - - final int length = Math.min(n, mSurroundingText.length() - mSelectionEnd); - return ((flags & InputConnection.GET_TEXT_WITH_STYLES) != 0) - ? mSurroundingText.subSequence(mSelectionEnd, mSelectionEnd + length) - : TextUtils.substring(mSurroundingText, mSelectionEnd, mSelectionEnd + length); - } - - private int getSelectionLength() { - return mSelectionEnd - mSelectionHead; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - TextUtils.writeToParcel(mSurroundingText, dest, flags); - dest.writeInt(mSelectionHead); - dest.writeInt(mSelectionEnd); - } - - public static final @android.annotation.NonNull Parcelable.Creator - CREATOR = new Parcelable.Creator() { - @Override - public InitialSurroundingText createFromParcel(Parcel source) { - final CharSequence initialText = - TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); - final int selectionHead = source.readInt(); - final int selectionEnd = source.readInt(); - - return new InitialSurroundingText(initialText, selectionHead, selectionEnd); - } - - @Override - public InitialSurroundingText[] newArray(int size) { - return new InitialSurroundingText[size]; - } - }; - - /** - * Create a copy of the given {@link CharSequence} object, with completely copy - * {@link ParcelableSpan} instances. - * - * @param source the original {@link CharSequence} to be copied. - * @return the copied {@link CharSequence}. {@code null} if {@code source} is {@code null}. - */ - @Nullable - private static CharSequence copyWithParcelableSpans(@Nullable CharSequence source) { - if (source == null) { - return null; - } - Parcel parcel = null; - try { - parcel = Parcel.obtain(); - TextUtils.writeToParcel(source, parcel, /* parcelableFlags= */ 0); - parcel.setDataPosition(0); - return TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); - } finally { - if (parcel != null) { - parcel.recycle(); - } - } - } - } -} +} \ No newline at end of file diff --git a/core/java/android/view/inputmethod/SurroundingText.java b/core/java/android/view/inputmethod/SurroundingText.java index 94e05a830b850..c85a18a1df794 100644 --- a/core/java/android/view/inputmethod/SurroundingText.java +++ b/core/java/android/view/inputmethod/SurroundingText.java @@ -18,6 +18,7 @@ package android.view.inputmethod; import android.annotation.IntRange; import android.annotation.NonNull; +import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; @@ -74,7 +75,7 @@ public final class SurroundingText implements Parcelable { public SurroundingText(@NonNull final CharSequence text, @IntRange(from = 0) int selectionStart, @IntRange(from = 0) int selectionEnd, @IntRange(from = -1) int offset) { - mText = text; + mText = copyWithParcelableSpans(text); mSelectionStart = selectionStart; mSelectionEnd = selectionEnd; mOffset = offset; @@ -155,4 +156,29 @@ public final class SurroundingText implements Parcelable { return new SurroundingText[size]; } }; + + /** + * Create a copy of the given {@link CharSequence} object, with completely copy + * {@link ParcelableSpan} instances. + * + * @param source the original {@link CharSequence} to be copied. + * @return the copied {@link CharSequence}. {@code null} if {@code source} is {@code null}. + */ + @Nullable + private static CharSequence copyWithParcelableSpans(@Nullable CharSequence source) { + if (source == null) { + return null; + } + Parcel parcel = null; + try { + parcel = Parcel.obtain(); + TextUtils.writeToParcel(source, parcel, /* parcelableFlags= */ 0); + parcel.setDataPosition(0); + return TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); + } finally { + if (parcel != null) { + parcel.recycle(); + } + } + } } diff --git a/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java b/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java index 92fb52837c362..c636912ee98d0 100644 --- a/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java +++ b/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java @@ -109,11 +109,15 @@ public class EditorInfoTest { editorInfo.initialSelEnd = editorInfo.initialSelStart + selectionLength; final int expectedTextBeforeCursorLength = 0; final int expectedTextAfterCursorLength = testText.length(); + final SurroundingText expectedSurroundingText = + new SurroundingText(testText, editorInfo.initialSelStart, + editorInfo.initialSelEnd, 0); + editorInfo.setInitialSurroundingText(testText); assertExpectedTextLength(editorInfo, expectedTextBeforeCursorLength, selectionLength, - expectedTextAfterCursorLength); + expectedTextAfterCursorLength, expectedSurroundingText); } @Test @@ -125,11 +129,14 @@ public class EditorInfoTest { editorInfo.initialSelEnd = testText.length(); final int expectedTextBeforeCursorLength = testText.length(); final int expectedTextAfterCursorLength = 0; + final SurroundingText expectedSurroundingText = + new SurroundingText(testText, editorInfo.initialSelStart, + editorInfo.initialSelEnd, 0); editorInfo.setInitialSurroundingText(testText); assertExpectedTextLength(editorInfo, expectedTextBeforeCursorLength, selectionLength, - expectedTextAfterCursorLength); + expectedTextAfterCursorLength, expectedSurroundingText); } @Test @@ -141,11 +148,14 @@ public class EditorInfoTest { editorInfo.initialSelEnd = editorInfo.initialSelStart + selectionLength; final int expectedTextBeforeCursorLength = editorInfo.initialSelStart; final int expectedTextAfterCursorLength = testText.length() - editorInfo.initialSelEnd; + final SurroundingText expectedSurroundingText = + new SurroundingText(testText, editorInfo.initialSelStart, + editorInfo.initialSelEnd, 0); editorInfo.setInitialSurroundingText(testText); assertExpectedTextLength(editorInfo, expectedTextBeforeCursorLength, selectionLength, - expectedTextAfterCursorLength); + expectedTextAfterCursorLength, expectedSurroundingText); } @Test @@ -158,11 +168,14 @@ public class EditorInfoTest { final int expectedTextBeforeCursorLength = testText.length() / 2; final int expectedTextAfterCursorLength = testText.length() - testText.length() / 2 - selectionLength; - + final SurroundingText expectedSurroundingText = + new SurroundingText(testText, + editorInfo.initialSelEnd, + editorInfo.initialSelStart , 0); editorInfo.setInitialSurroundingText(testText); assertExpectedTextLength(editorInfo, expectedTextBeforeCursorLength, selectionLength, - expectedTextAfterCursorLength); + expectedTextAfterCursorLength, expectedSurroundingText); } @Test @@ -174,9 +187,10 @@ public class EditorInfoTest { editorInfo.setInitialSurroundingText(testText); assertExpectedTextLength(editorInfo, - /* expectBeforeCursorLength= */null, - /* expectSelectionLength= */null, - /* expectAfterCursorLength= */null); + /* expectBeforeCursorLength= */ null, + /* expectSelectionLength= */ null, + /* expectAfterCursorLength= */ null, + /* expectSurroundingText= */ null); } @Test @@ -190,11 +204,23 @@ public class EditorInfoTest { (int) (0.8 * (EditorInfo.MEMORY_EFFICIENT_TEXT_LENGTH - selectionLength))); final int expectedTextAfterCursorLength = EditorInfo.MEMORY_EFFICIENT_TEXT_LENGTH - expectedTextBeforeCursorLength - selectionLength; + final int offset = editorInfo.initialSelStart - expectedTextBeforeCursorLength; + final CharSequence beforeCursor = testText.subSequence( + offset, offset + expectedTextBeforeCursorLength); + final CharSequence afterCursor = testText.subSequence(editorInfo.initialSelEnd, + editorInfo.initialSelEnd + expectedTextAfterCursorLength); + final CharSequence selectedText = testText.subSequence(editorInfo.initialSelStart, + editorInfo.initialSelEnd); + + final SurroundingText expectedSurroundingText = + new SurroundingText(TextUtils.concat(beforeCursor, selectedText, afterCursor), + expectedTextBeforeCursorLength, + expectedTextBeforeCursorLength + selectionLength, offset); editorInfo.setInitialSurroundingText(testText); assertExpectedTextLength(editorInfo, expectedTextBeforeCursorLength, selectionLength, - expectedTextAfterCursorLength); + expectedTextAfterCursorLength, expectedSurroundingText); } @Test @@ -207,11 +233,22 @@ public class EditorInfoTest { final int expectedTextBeforeCursorLength = Math.min(editorInfo.initialSelStart, (int) (0.8 * EditorInfo.MEMORY_EFFICIENT_TEXT_LENGTH)); final int expectedTextAfterCursorLength = testText.length() - editorInfo.initialSelEnd; + final CharSequence before = testText.subSequence( + editorInfo.initialSelStart - expectedTextBeforeCursorLength, + expectedTextBeforeCursorLength); + final CharSequence after = testText.subSequence(editorInfo.initialSelEnd, + editorInfo.initialSelEnd + expectedTextAfterCursorLength); + final SurroundingText expectedSurroundingText = + new SurroundingText(TextUtils.concat(before, after), + expectedTextBeforeCursorLength, + expectedTextBeforeCursorLength, + editorInfo.initialSelStart - expectedTextBeforeCursorLength); editorInfo.setInitialSurroundingText(testText); assertExpectedTextLength(editorInfo, expectedTextBeforeCursorLength, - /* expectSelectionLength= */null, expectedTextAfterCursorLength); + /* expectSelectionLength= */null, expectedTextAfterCursorLength, + expectedSurroundingText); } @Test @@ -269,6 +306,19 @@ public class EditorInfoTest { InputConnection.GET_TEXT_WITH_STYLES), targetEditorInfo.getInitialTextAfterCursor(LONG_EXP_TEXT_LENGTH, InputConnection.GET_TEXT_WITH_STYLES))); + + final SurroundingText sourceSurroundingText = sourceEditorInfo.getInitialSurroundingText( + LONG_EXP_TEXT_LENGTH, LONG_EXP_TEXT_LENGTH, InputConnection.GET_TEXT_WITH_STYLES); + final SurroundingText targetSurroundingText = targetEditorInfo.getInitialSurroundingText( + LONG_EXP_TEXT_LENGTH, LONG_EXP_TEXT_LENGTH, InputConnection.GET_TEXT_WITH_STYLES); + + assertTrue(TextUtils.equals(sourceSurroundingText.getText(), + targetSurroundingText.getText())); + assertEquals(sourceSurroundingText.getSelectionStart(), + targetSurroundingText.getSelectionStart()); + assertEquals(sourceSurroundingText.getSelectionEnd(), + targetSurroundingText.getSelectionEnd()); + assertEquals(sourceSurroundingText.getOffset(), targetSurroundingText.getOffset()); } @Test @@ -338,7 +388,8 @@ public class EditorInfoTest { private static void assertExpectedTextLength(EditorInfo editorInfo, @Nullable Integer expectBeforeCursorLength, @Nullable Integer expectSelectionLength, - @Nullable Integer expectAfterCursorLength) { + @Nullable Integer expectAfterCursorLength, + @Nullable SurroundingText expectSurroundingText) { final CharSequence textBeforeCursor = editorInfo.getInitialTextBeforeCursor(LONG_EXP_TEXT_LENGTH, InputConnection.GET_TEXT_WITH_STYLES); @@ -347,6 +398,10 @@ public class EditorInfoTest { final CharSequence textAfterCursor = editorInfo.getInitialTextAfterCursor(LONG_EXP_TEXT_LENGTH, InputConnection.GET_TEXT_WITH_STYLES); + final SurroundingText surroundingText = editorInfo.getInitialSurroundingText( + LONG_EXP_TEXT_LENGTH, + LONG_EXP_TEXT_LENGTH, + InputConnection.GET_TEXT_WITH_STYLES); if (expectBeforeCursorLength == null) { assertNull(textBeforeCursor); @@ -365,6 +420,18 @@ public class EditorInfoTest { } else { assertEquals(expectAfterCursorLength.intValue(), textAfterCursor.length()); } + + if (expectSurroundingText == null) { + assertNull(surroundingText); + } else { + assertTrue(TextUtils.equals( + expectSurroundingText.getText(), surroundingText.getText())); + assertEquals(expectSurroundingText.getSelectionStart(), + surroundingText.getSelectionStart()); + assertEquals(expectSurroundingText.getSelectionEnd(), + surroundingText.getSelectionEnd()); + assertEquals(expectSurroundingText.getOffset(), surroundingText.getOffset()); + } } private static CharSequence createTestText(int surroundingLength) {