| /* |
| * Copyright (C) 2008 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.view.inputmethod.cts; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertNull; |
| import static org.junit.Assert.assertTrue; |
| |
| import android.content.ClipDescription; |
| import android.net.Uri; |
| import android.os.Bundle; |
| import android.text.Editable; |
| import android.text.Selection; |
| import android.text.Spannable; |
| import android.text.SpannableString; |
| import android.text.Spanned; |
| import android.text.TextUtils; |
| import android.view.View; |
| import android.view.inputmethod.BaseInputConnection; |
| import android.view.inputmethod.CompletionInfo; |
| import android.view.inputmethod.ExtractedTextRequest; |
| import android.view.inputmethod.InputContentInfo; |
| import android.view.inputmethod.InputMethodManager; |
| import android.view.inputmethod.cts.util.InputConnectionTestUtils; |
| |
| import androidx.test.InstrumentationRegistry; |
| import androidx.test.filters.MediumTest; |
| import androidx.test.runner.AndroidJUnit4; |
| |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| |
| @MediumTest |
| @RunWith(AndroidJUnit4.class) |
| public class BaseInputConnectionTest { |
| |
| private static BaseInputConnection createBaseInputConnection() { |
| final View view = new View(InstrumentationRegistry.getTargetContext()); |
| return new BaseInputConnection(view, true); |
| } |
| |
| @Test |
| public void testDefaultMethods() { |
| // These methods are default to return fixed result. |
| final BaseInputConnection connection = createBaseInputConnection(); |
| |
| assertFalse(connection.beginBatchEdit()); |
| assertFalse(connection.endBatchEdit()); |
| |
| // only fit for test default implementation of commitCompletion. |
| int completionId = 1; |
| String completionString = "commitCompletion test"; |
| assertFalse(connection.commitCompletion(new CompletionInfo(completionId, |
| 0, completionString))); |
| |
| assertNull(connection.getExtractedText(new ExtractedTextRequest(), 0)); |
| |
| // only fit for test default implementation of performEditorAction. |
| int actionCode = 1; |
| int actionId = 2; |
| String action = "android.intent.action.MAIN"; |
| assertTrue(connection.performEditorAction(actionCode)); |
| assertFalse(connection.performContextMenuAction(actionId)); |
| assertFalse(connection.performPrivateCommand(action, new Bundle())); |
| } |
| |
| @Test |
| public void testOpComposingSpans() { |
| Spannable text = new SpannableString("Test ComposingSpans"); |
| BaseInputConnection.setComposingSpans(text); |
| assertTrue(BaseInputConnection.getComposingSpanStart(text) > -1); |
| assertTrue(BaseInputConnection.getComposingSpanEnd(text) > -1); |
| BaseInputConnection.removeComposingSpans(text); |
| assertTrue(BaseInputConnection.getComposingSpanStart(text) == -1); |
| assertTrue(BaseInputConnection.getComposingSpanEnd(text) == -1); |
| } |
| |
| /** |
| * getEditable: Return the target of edit operations. The default implementation |
| * returns its own fake editable that is just used for composing text. |
| * clearMetaKeyStates: Default implementation uses |
| * MetaKeyKeyListener#clearMetaKeyState(long, int) to clear the state. |
| * BugId:1738511 |
| * commitText: Default implementation replaces any existing composing text with the given |
| * text. |
| * deleteSurroundingText: The default implementation performs the deletion around the current |
| * selection position of the editable text. |
| * getCursorCapsMode: The default implementation uses TextUtils.getCapsMode to get the |
| * cursor caps mode for the current selection position in the editable text. |
| * TextUtils.getCapsMode is tested fully in TextUtilsTest#testGetCapsMode. |
| * getTextBeforeCursor, getTextAfterCursor: The default implementation performs the deletion |
| * around the current selection position of the editable text. |
| * setSelection: changes the selection position in the current editable text. |
| */ |
| @Test |
| public void testOpTextMethods() { |
| final BaseInputConnection connection = createBaseInputConnection(); |
| |
| // return is an default Editable instance with empty source |
| final Editable text = connection.getEditable(); |
| assertNotNull(text); |
| assertEquals(0, text.length()); |
| |
| // Test commitText, not dummy mode |
| CharSequence str = "TestCommit "; |
| Editable inputText = Editable.Factory.getInstance().newEditable(str); |
| connection.commitText(inputText, inputText.length()); |
| final Editable text2 = connection.getEditable(); |
| int strLength = str.length(); |
| assertEquals(strLength, text2.length()); |
| assertEquals(str.toString(), text2.toString()); |
| assertEquals(TextUtils.CAP_MODE_WORDS, |
| connection.getCursorCapsMode(TextUtils.CAP_MODE_WORDS)); |
| int offLength = 3; |
| CharSequence expected = str.subSequence(strLength - offLength, strLength); |
| assertEquals(expected.toString(), connection.getTextBeforeCursor(offLength, |
| BaseInputConnection.GET_TEXT_WITH_STYLES).toString()); |
| connection.setSelection(0, 0); |
| expected = str.subSequence(0, offLength); |
| assertEquals(expected.toString(), connection.getTextAfterCursor(offLength, |
| BaseInputConnection.GET_TEXT_WITH_STYLES).toString()); |
| |
| // Test deleteSurroundingText |
| int end = text2.length(); |
| connection.setSelection(end, end); |
| // Delete the ending space |
| assertTrue(connection.deleteSurroundingText(1, 2)); |
| Editable text3 = connection.getEditable(); |
| assertEquals(strLength - 1, text3.length()); |
| String expectedDelString = "TestCommit"; |
| assertEquals(expectedDelString, text3.toString()); |
| } |
| |
| /** |
| * finishComposingText: The default implementation removes the composing state from the |
| * current editable text. |
| * setComposingText: The default implementation places the given text into the editable, |
| * replacing any existing composing text |
| */ |
| @Test |
| public void testFinishComposingText() { |
| final BaseInputConnection connection = createBaseInputConnection(); |
| CharSequence str = "TestFinish"; |
| Editable inputText = Editable.Factory.getInstance().newEditable(str); |
| connection.commitText(inputText, inputText.length()); |
| final Editable text = connection.getEditable(); |
| // Test finishComposingText, not dummy mode |
| BaseInputConnection.setComposingSpans(text); |
| assertTrue(BaseInputConnection.getComposingSpanStart(text) > -1); |
| assertTrue(BaseInputConnection.getComposingSpanEnd(text) > -1); |
| connection.finishComposingText(); |
| assertTrue(BaseInputConnection.getComposingSpanStart(text) == -1); |
| assertTrue(BaseInputConnection.getComposingSpanEnd(text) == -1); |
| } |
| |
| /** |
| * Updates InputMethodManager with the current fullscreen mode. |
| */ |
| @Test |
| public void testReportFullscreenMode() { |
| final InputMethodManager imm = InstrumentationRegistry.getInstrumentation() |
| .getTargetContext().getSystemService(InputMethodManager.class); |
| final BaseInputConnection connection = createBaseInputConnection(); |
| connection.reportFullscreenMode(false); |
| assertFalse(imm.isFullscreenMode()); |
| connection.reportFullscreenMode(true); |
| // Only IMEs are allowed to report full-screen mode. Calling this method from the |
| // application should have no effect. |
| assertFalse(imm.isFullscreenMode()); |
| } |
| |
| /** |
| * An utility method to create an instance of {@link BaseInputConnection} in the full editor |
| * mode with an initial text and selection range. |
| * |
| * @param source the initial text. |
| * @return {@link BaseInputConnection} instantiated in the full editor mode with {@code source} |
| * and selection range from {@code selectionStart} to {@code selectionEnd} |
| */ |
| private static BaseInputConnection createConnectionWithSelection(CharSequence source) { |
| final int selectionStart = Selection.getSelectionStart(source); |
| final int selectionEnd = Selection.getSelectionEnd(source); |
| final Editable editable = Editable.Factory.getInstance().newEditable(source); |
| Selection.setSelection(editable, selectionStart, selectionEnd); |
| final View view = new View(InstrumentationRegistry.getTargetContext()); |
| return new BaseInputConnection(view, true) { |
| @Override |
| public Editable getEditable() { |
| return editable; |
| } |
| }; |
| } |
| |
| private static void verifyDeleteSurroundingTextMain(final String initialState, |
| final int deleteBefore, final int deleteAfter, final String expectedState) { |
| final CharSequence source = InputConnectionTestUtils.formatString(initialState); |
| final BaseInputConnection ic = createConnectionWithSelection(source); |
| ic.deleteSurroundingText(deleteBefore, deleteAfter); |
| |
| final CharSequence expectedString = InputConnectionTestUtils.formatString(expectedState); |
| final int expectedSelectionStart = Selection.getSelectionStart(expectedString); |
| final int expectedSelectionEnd = Selection.getSelectionEnd(expectedString); |
| |
| // It is sufficient to check the surrounding text up to source.length() characters, because |
| // InputConnection.deleteSurroundingText() is not supposed to increase the text length. |
| final int retrievalLength = source.length(); |
| if (expectedSelectionStart == 0) { |
| assertTrue(TextUtils.isEmpty(ic.getTextBeforeCursor(retrievalLength, 0))); |
| } else { |
| assertEquals(expectedString.subSequence(0, expectedSelectionStart).toString(), |
| ic.getTextBeforeCursor(retrievalLength, 0).toString()); |
| } |
| if (expectedSelectionStart == expectedSelectionEnd) { |
| assertTrue(TextUtils.isEmpty(ic.getSelectedText(0))); // null is allowed. |
| } else { |
| assertEquals(expectedString.subSequence(expectedSelectionStart, |
| expectedSelectionEnd).toString(), ic.getSelectedText(0).toString()); |
| } |
| if (expectedSelectionEnd == expectedString.length()) { |
| assertTrue(TextUtils.isEmpty(ic.getTextAfterCursor(retrievalLength, 0))); |
| } else { |
| assertEquals(expectedString.subSequence(expectedSelectionEnd, |
| expectedString.length()).toString(), |
| ic.getTextAfterCursor(retrievalLength, 0).toString()); |
| } |
| } |
| |
| /** |
| * Tests {@link BaseInputConnection#deleteSurroundingText(int, int)} comprehensively. |
| */ |
| @Test |
| public void testDeleteSurroundingText() { |
| verifyDeleteSurroundingTextMain("012[]3456789", 0, 0, "012[]3456789"); |
| verifyDeleteSurroundingTextMain("012[]3456789", -1, -1, "012[]3456789"); |
| verifyDeleteSurroundingTextMain("012[]3456789", 1, 2, "01[]56789"); |
| verifyDeleteSurroundingTextMain("012[]3456789", 10, 1, "[]456789"); |
| verifyDeleteSurroundingTextMain("012[]3456789", 1, 10, "01[]"); |
| verifyDeleteSurroundingTextMain("[]0123456789", 3, 3, "[]3456789"); |
| verifyDeleteSurroundingTextMain("0123456789[]", 3, 3, "0123456[]"); |
| verifyDeleteSurroundingTextMain("012[345]6789", 0, 0, "012[345]6789"); |
| verifyDeleteSurroundingTextMain("012[345]6789", -1, -1, "012[345]6789"); |
| verifyDeleteSurroundingTextMain("012[345]6789", 1, 2, "01[345]89"); |
| verifyDeleteSurroundingTextMain("012[345]6789", 10, 1, "[345]789"); |
| verifyDeleteSurroundingTextMain("012[345]6789", 1, 10, "01[345]"); |
| verifyDeleteSurroundingTextMain("[012]3456789", 3, 3, "[012]6789"); |
| verifyDeleteSurroundingTextMain("0123456[789]", 3, 3, "0123[789]"); |
| verifyDeleteSurroundingTextMain("[0123456789]", 0, 0, "[0123456789]"); |
| verifyDeleteSurroundingTextMain("[0123456789]", 1, 1, "[0123456789]"); |
| |
| // Surrogate characters do not have any special meanings. Validating the character sequence |
| // is beyond the goal of this API. |
| verifyDeleteSurroundingTextMain("0<>[]3456789", 1, 0, "0<[]3456789"); |
| verifyDeleteSurroundingTextMain("0<>[]3456789", 2, 0, "0[]3456789"); |
| verifyDeleteSurroundingTextMain("0<>[]3456789", 3, 0, "[]3456789"); |
| verifyDeleteSurroundingTextMain("012[]<>56789", 0, 1, "012[]>56789"); |
| verifyDeleteSurroundingTextMain("012[]<>56789", 0, 2, "012[]56789"); |
| verifyDeleteSurroundingTextMain("012[]<>56789", 0, 3, "012[]6789"); |
| verifyDeleteSurroundingTextMain("0<<[]3456789", 1, 0, "0<[]3456789"); |
| verifyDeleteSurroundingTextMain("0<<[]3456789", 2, 0, "0[]3456789"); |
| verifyDeleteSurroundingTextMain("0<<[]3456789", 3, 0, "[]3456789"); |
| verifyDeleteSurroundingTextMain("012[]<<56789", 0, 1, "012[]<56789"); |
| verifyDeleteSurroundingTextMain("012[]<<56789", 0, 2, "012[]56789"); |
| verifyDeleteSurroundingTextMain("012[]<<56789", 0, 3, "012[]6789"); |
| verifyDeleteSurroundingTextMain("0>>[]3456789", 1, 0, "0>[]3456789"); |
| verifyDeleteSurroundingTextMain("0>>[]3456789", 2, 0, "0[]3456789"); |
| verifyDeleteSurroundingTextMain("0>>[]3456789", 3, 0, "[]3456789"); |
| verifyDeleteSurroundingTextMain("012[]>>56789", 0, 1, "012[]>56789"); |
| verifyDeleteSurroundingTextMain("012[]>>56789", 0, 2, "012[]56789"); |
| verifyDeleteSurroundingTextMain("012[]>>56789", 0, 3, "012[]6789"); |
| } |
| |
| private static void verifyDeleteSurroundingTextInCodePointsMain(String initialState, |
| int deleteBeforeInCodePoints, int deleteAfterInCodePoints, String expectedState) { |
| final CharSequence source = InputConnectionTestUtils.formatString(initialState); |
| final BaseInputConnection ic = createConnectionWithSelection(source); |
| ic.deleteSurroundingTextInCodePoints(deleteBeforeInCodePoints, deleteAfterInCodePoints); |
| |
| final CharSequence expectedString = InputConnectionTestUtils.formatString(expectedState); |
| final int expectedSelectionStart = Selection.getSelectionStart(expectedString); |
| final int expectedSelectionEnd = Selection.getSelectionEnd(expectedString); |
| |
| // It is sufficient to check the surrounding text up to source.length() characters, because |
| // InputConnection.deleteSurroundingTextInCodePoints() is not supposed to increase the text |
| // length. |
| final int retrievalLength = source.length(); |
| if (expectedSelectionStart == 0) { |
| assertTrue(TextUtils.isEmpty(ic.getTextBeforeCursor(retrievalLength, 0))); |
| } else { |
| assertEquals(expectedString.subSequence(0, expectedSelectionStart).toString(), |
| ic.getTextBeforeCursor(retrievalLength, 0).toString()); |
| } |
| if (expectedSelectionStart == expectedSelectionEnd) { |
| assertTrue(TextUtils.isEmpty(ic.getSelectedText(0))); // null is allowed. |
| } else { |
| assertEquals(expectedString.subSequence(expectedSelectionStart, |
| expectedSelectionEnd).toString(), ic.getSelectedText(0).toString()); |
| } |
| if (expectedSelectionEnd == expectedString.length()) { |
| assertTrue(TextUtils.isEmpty(ic.getTextAfterCursor(retrievalLength, 0))); |
| } else { |
| assertEquals(expectedString.subSequence(expectedSelectionEnd, |
| expectedString.length()).toString(), |
| ic.getTextAfterCursor(retrievalLength, 0).toString()); |
| } |
| } |
| |
| /** |
| * Tests {@link BaseInputConnection#deleteSurroundingTextInCodePoints(int, int)} |
| * comprehensively. |
| */ |
| @Test |
| public void testDeleteSurroundingTextInCodePoints() { |
| verifyDeleteSurroundingTextInCodePointsMain("012[]3456789", 0, 0, "012[]3456789"); |
| verifyDeleteSurroundingTextInCodePointsMain("012[]3456789", -1, -1, "012[]3456789"); |
| verifyDeleteSurroundingTextInCodePointsMain("012[]3456789", 1, 2, "01[]56789"); |
| verifyDeleteSurroundingTextInCodePointsMain("012[]3456789", 10, 1, "[]456789"); |
| verifyDeleteSurroundingTextInCodePointsMain("012[]3456789", 1, 10, "01[]"); |
| verifyDeleteSurroundingTextInCodePointsMain("[]0123456789", 3, 3, "[]3456789"); |
| verifyDeleteSurroundingTextInCodePointsMain("0123456789[]", 3, 3, "0123456[]"); |
| verifyDeleteSurroundingTextInCodePointsMain("012[345]6789", 0, 0, "012[345]6789"); |
| verifyDeleteSurroundingTextInCodePointsMain("012[345]6789", -1, -1, "012[345]6789"); |
| verifyDeleteSurroundingTextInCodePointsMain("012[345]6789", 1, 2, "01[345]89"); |
| verifyDeleteSurroundingTextInCodePointsMain("012[345]6789", 10, 1, "[345]789"); |
| verifyDeleteSurroundingTextInCodePointsMain("012[345]6789", 1, 10, "01[345]"); |
| verifyDeleteSurroundingTextInCodePointsMain("[012]3456789", 3, 3, "[012]6789"); |
| verifyDeleteSurroundingTextInCodePointsMain("0123456[789]", 3, 3, "0123[789]"); |
| verifyDeleteSurroundingTextInCodePointsMain("[0123456789]", 0, 0, "[0123456789]"); |
| verifyDeleteSurroundingTextInCodePointsMain("[0123456789]", 1, 1, "[0123456789]"); |
| |
| verifyDeleteSurroundingTextInCodePointsMain("0<>[]3456789", 1, 0, "0[]3456789"); |
| verifyDeleteSurroundingTextInCodePointsMain("0<>[]3456789", 2, 0, "[]3456789"); |
| verifyDeleteSurroundingTextInCodePointsMain("0<>[]3456789", 3, 0, "[]3456789"); |
| verifyDeleteSurroundingTextInCodePointsMain("012[]<>56789", 0, 1, "012[]56789"); |
| verifyDeleteSurroundingTextInCodePointsMain("012[]<>56789", 0, 2, "012[]6789"); |
| verifyDeleteSurroundingTextInCodePointsMain("012[]<>56789", 0, 3, "012[]789"); |
| |
| verifyDeleteSurroundingTextInCodePointsMain("[]<><><><><>", 0, 0, "[]<><><><><>"); |
| verifyDeleteSurroundingTextInCodePointsMain("[]<><><><><>", 0, 1, "[]<><><><>"); |
| verifyDeleteSurroundingTextInCodePointsMain("[]<><><><><>", 0, 2, "[]<><><>"); |
| verifyDeleteSurroundingTextInCodePointsMain("[]<><><><><>", 0, 3, "[]<><>"); |
| verifyDeleteSurroundingTextInCodePointsMain("[]<><><><><>", 0, 4, "[]<>"); |
| verifyDeleteSurroundingTextInCodePointsMain("[]<><><><><>", 0, 5, "[]"); |
| verifyDeleteSurroundingTextInCodePointsMain("[]<><><><><>", 0, 6, "[]"); |
| verifyDeleteSurroundingTextInCodePointsMain("[]<><><><><>", 0, 1000, "[]"); |
| verifyDeleteSurroundingTextInCodePointsMain("<><><><><>[]", 0, 0, "<><><><><>[]"); |
| verifyDeleteSurroundingTextInCodePointsMain("<><><><><>[]", 1, 0, "<><><><>[]"); |
| verifyDeleteSurroundingTextInCodePointsMain("<><><><><>[]", 2, 0, "<><><>[]"); |
| verifyDeleteSurroundingTextInCodePointsMain("<><><><><>[]", 3, 0, "<><>[]"); |
| verifyDeleteSurroundingTextInCodePointsMain("<><><><><>[]", 4, 0, "<>[]"); |
| verifyDeleteSurroundingTextInCodePointsMain("<><><><><>[]", 5, 0, "[]"); |
| verifyDeleteSurroundingTextInCodePointsMain("<><><><><>[]", 6, 0, "[]"); |
| verifyDeleteSurroundingTextInCodePointsMain("<><><><><>[]", 1000, 0, "[]"); |
| |
| verifyDeleteSurroundingTextInCodePointsMain("0<<[]3456789", 1, 0, "0<<[]3456789"); |
| verifyDeleteSurroundingTextInCodePointsMain("0<<[]3456789", 2, 0, "0<<[]3456789"); |
| verifyDeleteSurroundingTextInCodePointsMain("0<<[]3456789", 3, 0, "0<<[]3456789"); |
| verifyDeleteSurroundingTextInCodePointsMain("012[]<<56789", 0, 1, "012[]<<56789"); |
| verifyDeleteSurroundingTextInCodePointsMain("012[]<<56789", 0, 2, "012[]<<56789"); |
| verifyDeleteSurroundingTextInCodePointsMain("012[]<<56789", 0, 3, "012[]<<56789"); |
| verifyDeleteSurroundingTextInCodePointsMain("0>>[]3456789", 1, 0, "0>>[]3456789"); |
| verifyDeleteSurroundingTextInCodePointsMain("0>>[]3456789", 2, 0, "0>>[]3456789"); |
| verifyDeleteSurroundingTextInCodePointsMain("0>>[]3456789", 3, 0, "0>>[]3456789"); |
| verifyDeleteSurroundingTextInCodePointsMain("012[]>>56789", 0, 1, "012[]>>56789"); |
| verifyDeleteSurroundingTextInCodePointsMain("012[]>>56789", 0, 2, "012[]>>56789"); |
| verifyDeleteSurroundingTextInCodePointsMain("012[]>>56789", 0, 3, "012[]>>56789"); |
| verifyDeleteSurroundingTextInCodePointsMain("01<[]>456789", 1, 0, "01<[]>456789"); |
| verifyDeleteSurroundingTextInCodePointsMain("01<[]>456789", 0, 1, "01<[]>456789"); |
| verifyDeleteSurroundingTextInCodePointsMain("<12[]3456789", 1, 0, "<1[]3456789"); |
| verifyDeleteSurroundingTextInCodePointsMain("<12[]3456789", 2, 0, "<[]3456789"); |
| verifyDeleteSurroundingTextInCodePointsMain("<12[]3456789", 3, 0, "<12[]3456789"); |
| verifyDeleteSurroundingTextInCodePointsMain("<<>[]3456789", 1, 0, "<[]3456789"); |
| verifyDeleteSurroundingTextInCodePointsMain("<<>[]3456789", 2, 0, "<<>[]3456789"); |
| verifyDeleteSurroundingTextInCodePointsMain("<<>[]3456789", 3, 0, "<<>[]3456789"); |
| verifyDeleteSurroundingTextInCodePointsMain("012[]34>6789", 0, 1, "012[]4>6789"); |
| verifyDeleteSurroundingTextInCodePointsMain("012[]34>6789", 0, 2, "012[]>6789"); |
| verifyDeleteSurroundingTextInCodePointsMain("012[]34>6789", 0, 3, "012[]34>6789"); |
| verifyDeleteSurroundingTextInCodePointsMain("012[]<>>6789", 0, 1, "012[]>6789"); |
| verifyDeleteSurroundingTextInCodePointsMain("012[]<>>6789", 0, 2, "012[]<>>6789"); |
| verifyDeleteSurroundingTextInCodePointsMain("012[]<>>6789", 0, 3, "012[]<>>6789"); |
| |
| // Atomicity test. |
| verifyDeleteSurroundingTextInCodePointsMain("0<<[]3456789", 1, 1, "0<<[]3456789"); |
| verifyDeleteSurroundingTextInCodePointsMain("0<<[]3456789", 2, 1, "0<<[]3456789"); |
| verifyDeleteSurroundingTextInCodePointsMain("0<<[]3456789", 3, 1, "0<<[]3456789"); |
| verifyDeleteSurroundingTextInCodePointsMain("012[]<<56789", 1, 1, "012[]<<56789"); |
| verifyDeleteSurroundingTextInCodePointsMain("012[]<<56789", 1, 2, "012[]<<56789"); |
| verifyDeleteSurroundingTextInCodePointsMain("012[]<<56789", 1, 3, "012[]<<56789"); |
| verifyDeleteSurroundingTextInCodePointsMain("0>>[]3456789", 1, 1, "0>>[]3456789"); |
| verifyDeleteSurroundingTextInCodePointsMain("0>>[]3456789", 2, 1, "0>>[]3456789"); |
| verifyDeleteSurroundingTextInCodePointsMain("0>>[]3456789", 3, 1, "0>>[]3456789"); |
| verifyDeleteSurroundingTextInCodePointsMain("012[]>>56789", 1, 1, "012[]>>56789"); |
| verifyDeleteSurroundingTextInCodePointsMain("012[]>>56789", 1, 2, "012[]>>56789"); |
| verifyDeleteSurroundingTextInCodePointsMain("012[]>>56789", 1, 3, "012[]>>56789"); |
| verifyDeleteSurroundingTextInCodePointsMain("01<[]>456789", 1, 1, "01<[]>456789"); |
| |
| // Do not verify the character sequences in the selected region. |
| verifyDeleteSurroundingTextInCodePointsMain("01[><]456789", 1, 0, "0[><]456789"); |
| verifyDeleteSurroundingTextInCodePointsMain("01[><]456789", 0, 1, "01[><]56789"); |
| verifyDeleteSurroundingTextInCodePointsMain("01[><]456789", 1, 1, "0[><]56789"); |
| } |
| |
| @Test |
| public void testCloseConnection() { |
| final BaseInputConnection connection = createBaseInputConnection(); |
| |
| final CharSequence source = "0123456789"; |
| connection.commitText(source, source.length()); |
| connection.setComposingRegion(2, 5); |
| final Editable text = connection.getEditable(); |
| assertEquals(2, BaseInputConnection.getComposingSpanStart(text)); |
| assertEquals(5, BaseInputConnection.getComposingSpanEnd(text)); |
| |
| // BaseInputConnection#closeConnection() must clear the on-going composition. |
| connection.closeConnection(); |
| assertEquals(-1, BaseInputConnection.getComposingSpanStart(text)); |
| assertEquals(-1, BaseInputConnection.getComposingSpanEnd(text)); |
| } |
| |
| @Test |
| public void testGetHandler() { |
| final BaseInputConnection connection = createBaseInputConnection(); |
| |
| // BaseInputConnection must not implement getHandler(). |
| assertNull(connection.getHandler()); |
| } |
| |
| @Test |
| public void testCommitContent() { |
| final BaseInputConnection connection = createBaseInputConnection(); |
| |
| final InputContentInfo inputContentInfo = new InputContentInfo( |
| Uri.parse("content://com.example/path"), |
| new ClipDescription("sample content", new String[]{"image/png"}), |
| Uri.parse("https://example.com")); |
| // The default implementation should do nothing and just return false. |
| assertFalse(connection.commitContent(inputContentInfo, 0 /* flags */, null /* opts */)); |
| } |
| |
| @Test |
| public void testGetSelectedText_wrongSelection() { |
| final BaseInputConnection connection = createBaseInputConnection(); |
| Editable editable = connection.getEditable(); |
| editable.append("hello"); |
| editable.setSpan(Selection.SELECTION_START, 4, 4, Spanned.SPAN_POINT_POINT); |
| editable.removeSpan(Selection.SELECTION_END); |
| |
| // Should not crash. |
| connection.getSelectedText(0); |
| } |
| } |