1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.view.inputmethod.cts; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertFalse; 21 import static org.junit.Assert.assertNotNull; 22 import static org.junit.Assert.assertNull; 23 import static org.junit.Assert.assertTrue; 24 25 import android.content.ClipDescription; 26 import android.net.Uri; 27 import android.os.Bundle; 28 import android.support.test.InstrumentationRegistry; 29 import android.support.test.filters.MediumTest; 30 import android.support.test.runner.AndroidJUnit4; 31 import android.text.Editable; 32 import android.text.Selection; 33 import android.text.Spannable; 34 import android.text.SpannableString; 35 import android.text.Spanned; 36 import android.text.TextUtils; 37 import android.view.View; 38 import android.view.inputmethod.BaseInputConnection; 39 import android.view.inputmethod.CompletionInfo; 40 import android.view.inputmethod.ExtractedTextRequest; 41 import android.view.inputmethod.InputContentInfo; 42 import android.view.inputmethod.InputMethodManager; 43 import android.view.inputmethod.cts.util.InputConnectionTestUtils; 44 45 import org.junit.Test; 46 import org.junit.runner.RunWith; 47 48 @MediumTest 49 @RunWith(AndroidJUnit4.class) 50 public class BaseInputConnectionTest { 51 52 private static BaseInputConnection createBaseInputConnection() { 53 final View view = new View(InstrumentationRegistry.getTargetContext()); 54 return new BaseInputConnection(view, true); 55 } 56 57 @Test 58 public void testDefaultMethods() { 59 // These methods are default to return fixed result. 60 final BaseInputConnection connection = createBaseInputConnection(); 61 62 assertFalse(connection.beginBatchEdit()); 63 assertFalse(connection.endBatchEdit()); 64 65 // only fit for test default implementation of commitCompletion. 66 int completionId = 1; 67 String completionString = "commitCompletion test"; 68 assertFalse(connection.commitCompletion(new CompletionInfo(completionId, 69 0, completionString))); 70 71 assertNull(connection.getExtractedText(new ExtractedTextRequest(), 0)); 72 73 // only fit for test default implementation of performEditorAction. 74 int actionCode = 1; 75 int actionId = 2; 76 String action = "android.intent.action.MAIN"; 77 assertTrue(connection.performEditorAction(actionCode)); 78 assertFalse(connection.performContextMenuAction(actionId)); 79 assertFalse(connection.performPrivateCommand(action, new Bundle())); 80 } 81 82 @Test 83 public void testOpComposingSpans() { 84 Spannable text = new SpannableString("Test ComposingSpans"); 85 BaseInputConnection.setComposingSpans(text); 86 assertTrue(BaseInputConnection.getComposingSpanStart(text) > -1); 87 assertTrue(BaseInputConnection.getComposingSpanEnd(text) > -1); 88 BaseInputConnection.removeComposingSpans(text); 89 assertTrue(BaseInputConnection.getComposingSpanStart(text) == -1); 90 assertTrue(BaseInputConnection.getComposingSpanEnd(text) == -1); 91 } 92 93 /** 94 * getEditable: Return the target of edit operations. The default implementation 95 * returns its own fake editable that is just used for composing text. 96 * clearMetaKeyStates: Default implementation uses 97 * MetaKeyKeyListener#clearMetaKeyState(long, int) to clear the state. 98 * BugId:1738511 99 * commitText: Default implementation replaces any existing composing text with the given 100 * text. 101 * deleteSurroundingText: The default implementation performs the deletion around the current 102 * selection position of the editable text. 103 * getCursorCapsMode: The default implementation uses TextUtils.getCapsMode to get the 104 * cursor caps mode for the current selection position in the editable text. 105 * TextUtils.getCapsMode is tested fully in TextUtilsTest#testGetCapsMode. 106 * getTextBeforeCursor, getTextAfterCursor: The default implementation performs the deletion 107 * around the current selection position of the editable text. 108 * setSelection: changes the selection position in the current editable text. 109 */ 110 @Test 111 public void testOpTextMethods() { 112 final BaseInputConnection connection = createBaseInputConnection(); 113 114 // return is an default Editable instance with empty source 115 final Editable text = connection.getEditable(); 116 assertNotNull(text); 117 assertEquals(0, text.length()); 118 119 // Test commitText, not dummy mode 120 CharSequence str = "TestCommit "; 121 Editable inputText = Editable.Factory.getInstance().newEditable(str); 122 connection.commitText(inputText, inputText.length()); 123 final Editable text2 = connection.getEditable(); 124 int strLength = str.length(); 125 assertEquals(strLength, text2.length()); 126 assertEquals(str.toString(), text2.toString()); 127 assertEquals(TextUtils.CAP_MODE_WORDS, 128 connection.getCursorCapsMode(TextUtils.CAP_MODE_WORDS)); 129 int offLength = 3; 130 CharSequence expected = str.subSequence(strLength - offLength, strLength); 131 assertEquals(expected.toString(), connection.getTextBeforeCursor(offLength, 132 BaseInputConnection.GET_TEXT_WITH_STYLES).toString()); 133 connection.setSelection(0, 0); 134 expected = str.subSequence(0, offLength); 135 assertEquals(expected.toString(), connection.getTextAfterCursor(offLength, 136 BaseInputConnection.GET_TEXT_WITH_STYLES).toString()); 137 138 // Test deleteSurroundingText 139 int end = text2.length(); 140 connection.setSelection(end, end); 141 // Delete the ending space 142 assertTrue(connection.deleteSurroundingText(1, 2)); 143 Editable text3 = connection.getEditable(); 144 assertEquals(strLength - 1, text3.length()); 145 String expectedDelString = "TestCommit"; 146 assertEquals(expectedDelString, text3.toString()); 147 } 148 149 /** 150 * finishComposingText: The default implementation removes the composing state from the 151 * current editable text. 152 * setComposingText: The default implementation places the given text into the editable, 153 * replacing any existing composing text 154 */ 155 @Test 156 public void testFinishComposingText() { 157 final BaseInputConnection connection = createBaseInputConnection(); 158 CharSequence str = "TestFinish"; 159 Editable inputText = Editable.Factory.getInstance().newEditable(str); 160 connection.commitText(inputText, inputText.length()); 161 final Editable text = connection.getEditable(); 162 // Test finishComposingText, not dummy mode 163 BaseInputConnection.setComposingSpans(text); 164 assertTrue(BaseInputConnection.getComposingSpanStart(text) > -1); 165 assertTrue(BaseInputConnection.getComposingSpanEnd(text) > -1); 166 connection.finishComposingText(); 167 assertTrue(BaseInputConnection.getComposingSpanStart(text) == -1); 168 assertTrue(BaseInputConnection.getComposingSpanEnd(text) == -1); 169 } 170 171 /** 172 * Updates InputMethodManager with the current fullscreen mode. 173 */ 174 @Test 175 public void testReportFullscreenMode() { 176 final InputMethodManager imm = InstrumentationRegistry.getInstrumentation() 177 .getTargetContext().getSystemService(InputMethodManager.class); 178 final BaseInputConnection connection = createBaseInputConnection(); 179 connection.reportFullscreenMode(false); 180 assertFalse(imm.isFullscreenMode()); 181 connection.reportFullscreenMode(true); 182 // Only IMEs are allowed to report full-screen mode. Calling this method from the 183 // application should have no effect. 184 assertFalse(imm.isFullscreenMode()); 185 } 186 187 /** 188 * An utility method to create an instance of {@link BaseInputConnection} in the full editor 189 * mode with an initial text and selection range. 190 * 191 * @param source the initial text. 192 * @return {@link BaseInputConnection} instantiated in the full editor mode with {@code source} 193 * and selection range from {@code selectionStart} to {@code selectionEnd} 194 */ 195 private static BaseInputConnection createConnectionWithSelection(CharSequence source) { 196 final int selectionStart = Selection.getSelectionStart(source); 197 final int selectionEnd = Selection.getSelectionEnd(source); 198 final Editable editable = Editable.Factory.getInstance().newEditable(source); 199 Selection.setSelection(editable, selectionStart, selectionEnd); 200 final View view = new View(InstrumentationRegistry.getTargetContext()); 201 return new BaseInputConnection(view, true) { 202 @Override 203 public Editable getEditable() { 204 return editable; 205 } 206 }; 207 } 208 209 private static void verifyDeleteSurroundingTextMain(final String initialState, 210 final int deleteBefore, final int deleteAfter, final String expectedState) { 211 final CharSequence source = InputConnectionTestUtils.formatString(initialState); 212 final BaseInputConnection ic = createConnectionWithSelection(source); 213 ic.deleteSurroundingText(deleteBefore, deleteAfter); 214 215 final CharSequence expectedString = InputConnectionTestUtils.formatString(expectedState); 216 final int expectedSelectionStart = Selection.getSelectionStart(expectedString); 217 final int expectedSelectionEnd = Selection.getSelectionEnd(expectedString); 218 219 // It is sufficient to check the surrounding text up to source.length() characters, because 220 // InputConnection.deleteSurroundingText() is not supposed to increase the text length. 221 final int retrievalLength = source.length(); 222 if (expectedSelectionStart == 0) { 223 assertTrue(TextUtils.isEmpty(ic.getTextBeforeCursor(retrievalLength, 0))); 224 } else { 225 assertEquals(expectedString.subSequence(0, expectedSelectionStart).toString(), 226 ic.getTextBeforeCursor(retrievalLength, 0).toString()); 227 } 228 if (expectedSelectionStart == expectedSelectionEnd) { 229 assertTrue(TextUtils.isEmpty(ic.getSelectedText(0))); // null is allowed. 230 } else { 231 assertEquals(expectedString.subSequence(expectedSelectionStart, 232 expectedSelectionEnd).toString(), ic.getSelectedText(0).toString()); 233 } 234 if (expectedSelectionEnd == expectedString.length()) { 235 assertTrue(TextUtils.isEmpty(ic.getTextAfterCursor(retrievalLength, 0))); 236 } else { 237 assertEquals(expectedString.subSequence(expectedSelectionEnd, 238 expectedString.length()).toString(), 239 ic.getTextAfterCursor(retrievalLength, 0).toString()); 240 } 241 } 242 243 /** 244 * Tests {@link BaseInputConnection#deleteSurroundingText(int, int)} comprehensively. 245 */ 246 @Test 247 public void testDeleteSurroundingText() { 248 verifyDeleteSurroundingTextMain("012[]3456789", 0, 0, "012[]3456789"); 249 verifyDeleteSurroundingTextMain("012[]3456789", -1, -1, "012[]3456789"); 250 verifyDeleteSurroundingTextMain("012[]3456789", 1, 2, "01[]56789"); 251 verifyDeleteSurroundingTextMain("012[]3456789", 10, 1, "[]456789"); 252 verifyDeleteSurroundingTextMain("012[]3456789", 1, 10, "01[]"); 253 verifyDeleteSurroundingTextMain("[]0123456789", 3, 3, "[]3456789"); 254 verifyDeleteSurroundingTextMain("0123456789[]", 3, 3, "0123456[]"); 255 verifyDeleteSurroundingTextMain("012[345]6789", 0, 0, "012[345]6789"); 256 verifyDeleteSurroundingTextMain("012[345]6789", -1, -1, "012[345]6789"); 257 verifyDeleteSurroundingTextMain("012[345]6789", 1, 2, "01[345]89"); 258 verifyDeleteSurroundingTextMain("012[345]6789", 10, 1, "[345]789"); 259 verifyDeleteSurroundingTextMain("012[345]6789", 1, 10, "01[345]"); 260 verifyDeleteSurroundingTextMain("[012]3456789", 3, 3, "[012]6789"); 261 verifyDeleteSurroundingTextMain("0123456[789]", 3, 3, "0123[789]"); 262 verifyDeleteSurroundingTextMain("[0123456789]", 0, 0, "[0123456789]"); 263 verifyDeleteSurroundingTextMain("[0123456789]", 1, 1, "[0123456789]"); 264 265 // Surrogate characters do not have any special meanings. Validating the character sequence 266 // is beyond the goal of this API. 267 verifyDeleteSurroundingTextMain("0<>[]3456789", 1, 0, "0<[]3456789"); 268 verifyDeleteSurroundingTextMain("0<>[]3456789", 2, 0, "0[]3456789"); 269 verifyDeleteSurroundingTextMain("0<>[]3456789", 3, 0, "[]3456789"); 270 verifyDeleteSurroundingTextMain("012[]<>56789", 0, 1, "012[]>56789"); 271 verifyDeleteSurroundingTextMain("012[]<>56789", 0, 2, "012[]56789"); 272 verifyDeleteSurroundingTextMain("012[]<>56789", 0, 3, "012[]6789"); 273 verifyDeleteSurroundingTextMain("0<<[]3456789", 1, 0, "0<[]3456789"); 274 verifyDeleteSurroundingTextMain("0<<[]3456789", 2, 0, "0[]3456789"); 275 verifyDeleteSurroundingTextMain("0<<[]3456789", 3, 0, "[]3456789"); 276 verifyDeleteSurroundingTextMain("012[]<<56789", 0, 1, "012[]<56789"); 277 verifyDeleteSurroundingTextMain("012[]<<56789", 0, 2, "012[]56789"); 278 verifyDeleteSurroundingTextMain("012[]<<56789", 0, 3, "012[]6789"); 279 verifyDeleteSurroundingTextMain("0>>[]3456789", 1, 0, "0>[]3456789"); 280 verifyDeleteSurroundingTextMain("0>>[]3456789", 2, 0, "0[]3456789"); 281 verifyDeleteSurroundingTextMain("0>>[]3456789", 3, 0, "[]3456789"); 282 verifyDeleteSurroundingTextMain("012[]>>56789", 0, 1, "012[]>56789"); 283 verifyDeleteSurroundingTextMain("012[]>>56789", 0, 2, "012[]56789"); 284 verifyDeleteSurroundingTextMain("012[]>>56789", 0, 3, "012[]6789"); 285 } 286 287 private static void verifyDeleteSurroundingTextInCodePointsMain(String initialState, 288 int deleteBeforeInCodePoints, int deleteAfterInCodePoints, String expectedState) { 289 final CharSequence source = InputConnectionTestUtils.formatString(initialState); 290 final BaseInputConnection ic = createConnectionWithSelection(source); 291 ic.deleteSurroundingTextInCodePoints(deleteBeforeInCodePoints, deleteAfterInCodePoints); 292 293 final CharSequence expectedString = InputConnectionTestUtils.formatString(expectedState); 294 final int expectedSelectionStart = Selection.getSelectionStart(expectedString); 295 final int expectedSelectionEnd = Selection.getSelectionEnd(expectedString); 296 297 // It is sufficient to check the surrounding text up to source.length() characters, because 298 // InputConnection.deleteSurroundingTextInCodePoints() is not supposed to increase the text 299 // length. 300 final int retrievalLength = source.length(); 301 if (expectedSelectionStart == 0) { 302 assertTrue(TextUtils.isEmpty(ic.getTextBeforeCursor(retrievalLength, 0))); 303 } else { 304 assertEquals(expectedString.subSequence(0, expectedSelectionStart).toString(), 305 ic.getTextBeforeCursor(retrievalLength, 0).toString()); 306 } 307 if (expectedSelectionStart == expectedSelectionEnd) { 308 assertTrue(TextUtils.isEmpty(ic.getSelectedText(0))); // null is allowed. 309 } else { 310 assertEquals(expectedString.subSequence(expectedSelectionStart, 311 expectedSelectionEnd).toString(), ic.getSelectedText(0).toString()); 312 } 313 if (expectedSelectionEnd == expectedString.length()) { 314 assertTrue(TextUtils.isEmpty(ic.getTextAfterCursor(retrievalLength, 0))); 315 } else { 316 assertEquals(expectedString.subSequence(expectedSelectionEnd, 317 expectedString.length()).toString(), 318 ic.getTextAfterCursor(retrievalLength, 0).toString()); 319 } 320 } 321 322 /** 323 * Tests {@link BaseInputConnection#deleteSurroundingTextInCodePoints(int, int)} 324 * comprehensively. 325 */ 326 @Test 327 public void testDeleteSurroundingTextInCodePoints() { 328 verifyDeleteSurroundingTextInCodePointsMain("012[]3456789", 0, 0, "012[]3456789"); 329 verifyDeleteSurroundingTextInCodePointsMain("012[]3456789", -1, -1, "012[]3456789"); 330 verifyDeleteSurroundingTextInCodePointsMain("012[]3456789", 1, 2, "01[]56789"); 331 verifyDeleteSurroundingTextInCodePointsMain("012[]3456789", 10, 1, "[]456789"); 332 verifyDeleteSurroundingTextInCodePointsMain("012[]3456789", 1, 10, "01[]"); 333 verifyDeleteSurroundingTextInCodePointsMain("[]0123456789", 3, 3, "[]3456789"); 334 verifyDeleteSurroundingTextInCodePointsMain("0123456789[]", 3, 3, "0123456[]"); 335 verifyDeleteSurroundingTextInCodePointsMain("012[345]6789", 0, 0, "012[345]6789"); 336 verifyDeleteSurroundingTextInCodePointsMain("012[345]6789", -1, -1, "012[345]6789"); 337 verifyDeleteSurroundingTextInCodePointsMain("012[345]6789", 1, 2, "01[345]89"); 338 verifyDeleteSurroundingTextInCodePointsMain("012[345]6789", 10, 1, "[345]789"); 339 verifyDeleteSurroundingTextInCodePointsMain("012[345]6789", 1, 10, "01[345]"); 340 verifyDeleteSurroundingTextInCodePointsMain("[012]3456789", 3, 3, "[012]6789"); 341 verifyDeleteSurroundingTextInCodePointsMain("0123456[789]", 3, 3, "0123[789]"); 342 verifyDeleteSurroundingTextInCodePointsMain("[0123456789]", 0, 0, "[0123456789]"); 343 verifyDeleteSurroundingTextInCodePointsMain("[0123456789]", 1, 1, "[0123456789]"); 344 345 verifyDeleteSurroundingTextInCodePointsMain("0<>[]3456789", 1, 0, "0[]3456789"); 346 verifyDeleteSurroundingTextInCodePointsMain("0<>[]3456789", 2, 0, "[]3456789"); 347 verifyDeleteSurroundingTextInCodePointsMain("0<>[]3456789", 3, 0, "[]3456789"); 348 verifyDeleteSurroundingTextInCodePointsMain("012[]<>56789", 0, 1, "012[]56789"); 349 verifyDeleteSurroundingTextInCodePointsMain("012[]<>56789", 0, 2, "012[]6789"); 350 verifyDeleteSurroundingTextInCodePointsMain("012[]<>56789", 0, 3, "012[]789"); 351 352 verifyDeleteSurroundingTextInCodePointsMain("[]<><><><><>", 0, 0, "[]<><><><><>"); 353 verifyDeleteSurroundingTextInCodePointsMain("[]<><><><><>", 0, 1, "[]<><><><>"); 354 verifyDeleteSurroundingTextInCodePointsMain("[]<><><><><>", 0, 2, "[]<><><>"); 355 verifyDeleteSurroundingTextInCodePointsMain("[]<><><><><>", 0, 3, "[]<><>"); 356 verifyDeleteSurroundingTextInCodePointsMain("[]<><><><><>", 0, 4, "[]<>"); 357 verifyDeleteSurroundingTextInCodePointsMain("[]<><><><><>", 0, 5, "[]"); 358 verifyDeleteSurroundingTextInCodePointsMain("[]<><><><><>", 0, 6, "[]"); 359 verifyDeleteSurroundingTextInCodePointsMain("[]<><><><><>", 0, 1000, "[]"); 360 verifyDeleteSurroundingTextInCodePointsMain("<><><><><>[]", 0, 0, "<><><><><>[]"); 361 verifyDeleteSurroundingTextInCodePointsMain("<><><><><>[]", 1, 0, "<><><><>[]"); 362 verifyDeleteSurroundingTextInCodePointsMain("<><><><><>[]", 2, 0, "<><><>[]"); 363 verifyDeleteSurroundingTextInCodePointsMain("<><><><><>[]", 3, 0, "<><>[]"); 364 verifyDeleteSurroundingTextInCodePointsMain("<><><><><>[]", 4, 0, "<>[]"); 365 verifyDeleteSurroundingTextInCodePointsMain("<><><><><>[]", 5, 0, "[]"); 366 verifyDeleteSurroundingTextInCodePointsMain("<><><><><>[]", 6, 0, "[]"); 367 verifyDeleteSurroundingTextInCodePointsMain("<><><><><>[]", 1000, 0, "[]"); 368 369 verifyDeleteSurroundingTextInCodePointsMain("0<<[]3456789", 1, 0, "0<<[]3456789"); 370 verifyDeleteSurroundingTextInCodePointsMain("0<<[]3456789", 2, 0, "0<<[]3456789"); 371 verifyDeleteSurroundingTextInCodePointsMain("0<<[]3456789", 3, 0, "0<<[]3456789"); 372 verifyDeleteSurroundingTextInCodePointsMain("012[]<<56789", 0, 1, "012[]<<56789"); 373 verifyDeleteSurroundingTextInCodePointsMain("012[]<<56789", 0, 2, "012[]<<56789"); 374 verifyDeleteSurroundingTextInCodePointsMain("012[]<<56789", 0, 3, "012[]<<56789"); 375 verifyDeleteSurroundingTextInCodePointsMain("0>>[]3456789", 1, 0, "0>>[]3456789"); 376 verifyDeleteSurroundingTextInCodePointsMain("0>>[]3456789", 2, 0, "0>>[]3456789"); 377 verifyDeleteSurroundingTextInCodePointsMain("0>>[]3456789", 3, 0, "0>>[]3456789"); 378 verifyDeleteSurroundingTextInCodePointsMain("012[]>>56789", 0, 1, "012[]>>56789"); 379 verifyDeleteSurroundingTextInCodePointsMain("012[]>>56789", 0, 2, "012[]>>56789"); 380 verifyDeleteSurroundingTextInCodePointsMain("012[]>>56789", 0, 3, "012[]>>56789"); 381 verifyDeleteSurroundingTextInCodePointsMain("01<[]>456789", 1, 0, "01<[]>456789"); 382 verifyDeleteSurroundingTextInCodePointsMain("01<[]>456789", 0, 1, "01<[]>456789"); 383 verifyDeleteSurroundingTextInCodePointsMain("<12[]3456789", 1, 0, "<1[]3456789"); 384 verifyDeleteSurroundingTextInCodePointsMain("<12[]3456789", 2, 0, "<[]3456789"); 385 verifyDeleteSurroundingTextInCodePointsMain("<12[]3456789", 3, 0, "<12[]3456789"); 386 verifyDeleteSurroundingTextInCodePointsMain("<<>[]3456789", 1, 0, "<[]3456789"); 387 verifyDeleteSurroundingTextInCodePointsMain("<<>[]3456789", 2, 0, "<<>[]3456789"); 388 verifyDeleteSurroundingTextInCodePointsMain("<<>[]3456789", 3, 0, "<<>[]3456789"); 389 verifyDeleteSurroundingTextInCodePointsMain("012[]34>6789", 0, 1, "012[]4>6789"); 390 verifyDeleteSurroundingTextInCodePointsMain("012[]34>6789", 0, 2, "012[]>6789"); 391 verifyDeleteSurroundingTextInCodePointsMain("012[]34>6789", 0, 3, "012[]34>6789"); 392 verifyDeleteSurroundingTextInCodePointsMain("012[]<>>6789", 0, 1, "012[]>6789"); 393 verifyDeleteSurroundingTextInCodePointsMain("012[]<>>6789", 0, 2, "012[]<>>6789"); 394 verifyDeleteSurroundingTextInCodePointsMain("012[]<>>6789", 0, 3, "012[]<>>6789"); 395 396 // Atomicity test. 397 verifyDeleteSurroundingTextInCodePointsMain("0<<[]3456789", 1, 1, "0<<[]3456789"); 398 verifyDeleteSurroundingTextInCodePointsMain("0<<[]3456789", 2, 1, "0<<[]3456789"); 399 verifyDeleteSurroundingTextInCodePointsMain("0<<[]3456789", 3, 1, "0<<[]3456789"); 400 verifyDeleteSurroundingTextInCodePointsMain("012[]<<56789", 1, 1, "012[]<<56789"); 401 verifyDeleteSurroundingTextInCodePointsMain("012[]<<56789", 1, 2, "012[]<<56789"); 402 verifyDeleteSurroundingTextInCodePointsMain("012[]<<56789", 1, 3, "012[]<<56789"); 403 verifyDeleteSurroundingTextInCodePointsMain("0>>[]3456789", 1, 1, "0>>[]3456789"); 404 verifyDeleteSurroundingTextInCodePointsMain("0>>[]3456789", 2, 1, "0>>[]3456789"); 405 verifyDeleteSurroundingTextInCodePointsMain("0>>[]3456789", 3, 1, "0>>[]3456789"); 406 verifyDeleteSurroundingTextInCodePointsMain("012[]>>56789", 1, 1, "012[]>>56789"); 407 verifyDeleteSurroundingTextInCodePointsMain("012[]>>56789", 1, 2, "012[]>>56789"); 408 verifyDeleteSurroundingTextInCodePointsMain("012[]>>56789", 1, 3, "012[]>>56789"); 409 verifyDeleteSurroundingTextInCodePointsMain("01<[]>456789", 1, 1, "01<[]>456789"); 410 411 // Do not verify the character sequences in the selected region. 412 verifyDeleteSurroundingTextInCodePointsMain("01[><]456789", 1, 0, "0[><]456789"); 413 verifyDeleteSurroundingTextInCodePointsMain("01[><]456789", 0, 1, "01[><]56789"); 414 verifyDeleteSurroundingTextInCodePointsMain("01[><]456789", 1, 1, "0[><]56789"); 415 } 416 417 @Test 418 public void testCloseConnection() { 419 final BaseInputConnection connection = createBaseInputConnection(); 420 421 final CharSequence source = "0123456789"; 422 connection.commitText(source, source.length()); 423 connection.setComposingRegion(2, 5); 424 final Editable text = connection.getEditable(); 425 assertEquals(2, BaseInputConnection.getComposingSpanStart(text)); 426 assertEquals(5, BaseInputConnection.getComposingSpanEnd(text)); 427 428 // BaseInputConnection#closeConnection() must clear the on-going composition. 429 connection.closeConnection(); 430 assertEquals(-1, BaseInputConnection.getComposingSpanStart(text)); 431 assertEquals(-1, BaseInputConnection.getComposingSpanEnd(text)); 432 } 433 434 @Test 435 public void testGetHandler() { 436 final BaseInputConnection connection = createBaseInputConnection(); 437 438 // BaseInputConnection must not implement getHandler(). 439 assertNull(connection.getHandler()); 440 } 441 442 @Test 443 public void testCommitContent() { 444 final BaseInputConnection connection = createBaseInputConnection(); 445 446 final InputContentInfo inputContentInfo = new InputContentInfo( 447 Uri.parse("content://com.example/path"), 448 new ClipDescription("sample content", new String[]{"image/png"}), 449 Uri.parse("https://example.com")); 450 // The default implementation should do nothing and just return false. 451 assertFalse(connection.commitContent(inputContentInfo, 0 /* flags */, null /* opts */)); 452 } 453 454 @Test 455 public void testGetSelectedText_wrongSelection() { 456 final BaseInputConnection connection = createBaseInputConnection(); 457 Editable editable = connection.getEditable(); 458 editable.append("hello"); 459 editable.setSpan(Selection.SELECTION_START, 4, 4, Spanned.SPAN_POINT_POINT); 460 editable.removeSpan(Selection.SELECTION_END); 461 462 // Should not crash. 463 connection.getSelectedText(0); 464 } 465 } 466