1 /* 2 * Copyright (C) 2009 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.assertNotEquals; 22 import static org.junit.Assert.assertNotNull; 23 import static org.junit.Assert.assertNull; 24 import static org.junit.Assert.assertTrue; 25 import static org.junit.Assert.fail; 26 27 import android.os.Bundle; 28 import android.os.LocaleList; 29 import android.os.Parcel; 30 import android.platform.test.annotations.AppModeSdkSandbox; 31 import android.platform.test.annotations.RequiresFlagsEnabled; 32 import android.platform.test.flag.junit.CheckFlagsRule; 33 import android.platform.test.flag.junit.DeviceFlagsValueProvider; 34 import android.test.MoreAsserts; 35 import android.text.SpannableStringBuilder; 36 import android.text.TextUtils; 37 import android.util.StringBuilderPrinter; 38 import android.view.MotionEvent; 39 import android.view.autofill.AutofillId; 40 import android.view.inputmethod.DeleteGesture; 41 import android.view.inputmethod.EditorInfo; 42 import android.view.inputmethod.Flags; 43 import android.view.inputmethod.HandwritingGesture; 44 import android.view.inputmethod.InputConnection; 45 import android.view.inputmethod.InsertGesture; 46 import android.view.inputmethod.PreviewableHandwritingGesture; 47 import android.view.inputmethod.SelectGesture; 48 import android.view.inputmethod.SurroundingText; 49 50 import androidx.test.filters.SmallTest; 51 52 import com.android.compatibility.common.util.ApiTest; 53 54 import org.junit.Rule; 55 import org.junit.Test; 56 57 import java.util.ArrayList; 58 import java.util.Arrays; 59 import java.util.HashSet; 60 import java.util.List; 61 import java.util.Set; 62 import java.util.stream.Collectors; 63 import java.util.stream.Stream; 64 65 @SmallTest 66 @AppModeSdkSandbox(reason = "Allow test in the SDK sandbox (does not prevent other modes).") 67 public final class EditorInfoTest { 68 69 @Rule 70 public final CheckFlagsRule mCheckFlagsRule = 71 DeviceFlagsValueProvider.createCheckFlagsRule(); 72 private static final int TEST_TEXT_LENGTH = 2048; 73 /** A text with 1 million chars! This is way too long. */ 74 private static final int OVER_SIZED_TEXT_LENGTH = 1 * 1024 * 1024; 75 /** To get the longest available text from getInitialText methods. */ 76 private static final int REQUEST_LONGEST_AVAILABLE_TEXT = OVER_SIZED_TEXT_LENGTH; // 77 78 @Test 79 @ApiTest(apis = {"android.view.inputmethod.EditorInfo#setSupportedHandwritingGestures", 80 "android.view.inputmethod.EditorInfo#setInitialToolType", 81 "android.view.inputmethod.EditorInfo#getSupportedHandwritingGestures", 82 "android.view.inputmethod.EditorInfo#getInitialToolType"}) testEditorInfo()83 public void testEditorInfo() { 84 EditorInfo info = new EditorInfo(); 85 CharSequence testInitialText = createTestText(TEST_TEXT_LENGTH); 86 87 info.actionId = 1; 88 info.actionLabel = "actionLabel"; 89 info.fieldId = 2; 90 info.fieldName = "fieldName"; 91 info.hintText = "hintText"; 92 info.imeOptions = EditorInfo.IME_FLAG_NO_ENTER_ACTION; 93 info.initialCapsMode = TextUtils.CAP_MODE_CHARACTERS; 94 info.initialSelEnd = 10; 95 info.initialSelStart = 0; 96 info.inputType = EditorInfo.TYPE_MASK_CLASS; 97 info.label = "label"; 98 info.packageName = "android.view.cts"; 99 info.privateImeOptions = "privateIme"; 100 Bundle b = new Bundle(); 101 info.setInitialSurroundingText(testInitialText); 102 String key = "bundleKey"; 103 String value = "bundleValue"; 104 b.putString(key, value); 105 info.extras = b; 106 info.hintLocales = LocaleList.forLanguageTags("en-PH,en-US"); 107 info.contentMimeTypes = new String[]{"image/gif", "image/png"}; 108 info.setInitialToolType(MotionEvent.TOOL_TYPE_FINGER); 109 info.setSupportedHandwritingGestures(Arrays.asList(SelectGesture.class)); 110 info.setSupportedHandwritingGesturePreviews( 111 Stream.of(SelectGesture.class).collect(Collectors.toSet())); 112 113 assertEquals(0, info.describeContents()); 114 115 Parcel p = Parcel.obtain(); 116 info.writeToParcel(p, 0); 117 p.setDataPosition(0); 118 EditorInfo targetInfo = EditorInfo.CREATOR.createFromParcel(p); 119 p.recycle(); 120 assertEquals(info.actionId, targetInfo.actionId); 121 assertEquals(info.fieldId, targetInfo.fieldId); 122 assertEquals(info.fieldName, targetInfo.fieldName); 123 assertEquals(info.imeOptions, targetInfo.imeOptions); 124 assertEquals(info.initialCapsMode, targetInfo.initialCapsMode); 125 assertEquals(info.initialSelEnd, targetInfo.initialSelEnd); 126 assertEquals(info.initialSelStart, targetInfo.initialSelStart); 127 assertEquals(info.inputType, targetInfo.inputType); 128 assertEquals(info.packageName, targetInfo.packageName); 129 assertEquals(info.privateImeOptions, targetInfo.privateImeOptions); 130 assertTrue(TextUtils.equals(testInitialText, concatInitialSurroundingText(targetInfo))); 131 assertEquals(info.hintText.toString(), targetInfo.hintText.toString()); 132 assertEquals(info.actionLabel.toString(), targetInfo.actionLabel.toString()); 133 assertEquals(info.label.toString(), targetInfo.label.toString()); 134 assertEquals(info.extras.getString(key), targetInfo.extras.getString(key)); 135 assertEquals(info.hintLocales, targetInfo.hintLocales); 136 assertEquals(info.getInitialToolType(), targetInfo.getInitialToolType()); 137 assertEquals(info.getSupportedHandwritingGestures(), 138 targetInfo.getSupportedHandwritingGestures()); 139 MoreAsserts.assertEquals(info.contentMimeTypes, targetInfo.contentMimeTypes); 140 141 StringBuilder sb = new StringBuilder(); 142 StringBuilderPrinter sbPrinter = new StringBuilderPrinter(sb); 143 String prefix = "TestEditorInfo"; 144 info.dump(sbPrinter, prefix); 145 146 assertFalse(TextUtils.isEmpty(sb.toString())); 147 assertFalse(sb.toString().contains(testInitialText)); 148 } 149 150 @ApiTest(apis = {"android.view.inputmethod.EditorInfo#setSupportedHandwritingGestures", 151 "android.view.inputmethod.EditorInfo#getSupportedHandwritingGestures"}) 152 @Test testSupportedHandwritingGestures()153 public void testSupportedHandwritingGestures() { 154 EditorInfo info = new EditorInfo(); 155 info.setSupportedHandwritingGestures(new ArrayList<>()); 156 assertTrue(info.getSupportedHandwritingGestures().isEmpty()); 157 158 info.setSupportedHandwritingGestures(Arrays.asList(SelectGesture.class)); 159 assertEquals(info.getSupportedHandwritingGestures().get(0), SelectGesture.class); 160 161 info.setSupportedHandwritingGestures(Arrays.asList(SelectGesture.class, InsertGesture.class, 162 DeleteGesture.class)); 163 List<Class<? extends HandwritingGesture>> gestures = info.getSupportedHandwritingGestures(); 164 assertEquals(gestures.size(), 3); 165 assertTrue(gestures.contains(SelectGesture.class)); 166 assertTrue(gestures.contains(DeleteGesture.class)); 167 assertTrue(gestures.contains(InsertGesture.class)); 168 } 169 170 @ApiTest(apis = {"android.view.inputmethod.EditorInfo#setSupportedHandwritingGesturePreviews", 171 "android.view.inputmethod.EditorInfo#getSupportedHandwritingGesturePreviews", 172 "android.view.inputmethod.EditorInfo#getSupportedHandwritingGestures"}) 173 @Test testSupportedHandwritingGesturePreviews()174 public void testSupportedHandwritingGesturePreviews() { 175 EditorInfo info = new EditorInfo(); 176 info.setSupportedHandwritingGesturePreviews(new HashSet<>()); 177 assertTrue(info.getSupportedHandwritingGesturePreviews().isEmpty()); 178 179 Set<Class<? extends PreviewableHandwritingGesture>> selectGestureSet = 180 Stream.of(SelectGesture.class).collect(Collectors.toSet()); 181 info.setSupportedHandwritingGesturePreviews(selectGestureSet); 182 assertEquals(info.getSupportedHandwritingGesturePreviews(), selectGestureSet); 183 184 assertNotEquals(info.getSupportedHandwritingGesturePreviews(), 185 new HashSet<>(info.getSupportedHandwritingGestures())); 186 187 info.setSupportedHandwritingGesturePreviews( 188 Stream.of(SelectGesture.class, DeleteGesture.class).collect(Collectors.toSet())); 189 Set<Class<? extends PreviewableHandwritingGesture>> gestures = 190 info.getSupportedHandwritingGesturePreviews(); 191 assertEquals(gestures.size(), 2); 192 assertTrue(gestures.contains(SelectGesture.class)); 193 assertTrue(gestures.contains(DeleteGesture.class)); 194 } 195 196 /** 197 * Test {@link EditorInfo#isStylusHandwritingEnabled()}. 198 */ 199 @ApiTest(apis = {"android.view.inputmethod.EditorInfo#setStylusHandwritingEnabled", 200 "android.view.inputmethod.EditorInfo#isStylusHandwritingEnabled"}) 201 @Test 202 @RequiresFlagsEnabled(Flags.FLAG_EDITORINFO_HANDWRITING_ENABLED) testStylusHandwritingEnabled()203 public void testStylusHandwritingEnabled() { 204 EditorInfo info = new EditorInfo(); 205 info.setStylusHandwritingEnabled(true); 206 assertTrue(info.isStylusHandwritingEnabled()); 207 Parcel p = Parcel.obtain(); 208 info.writeToParcel(p, 0 /* flags */); 209 p.setDataPosition(0); 210 EditorInfo targetInfo = EditorInfo.CREATOR.createFromParcel(p); 211 p.recycle(); 212 assertEquals(info.isStylusHandwritingEnabled(), targetInfo.isStylusHandwritingEnabled()); 213 } 214 215 /* 216 * Test EditorInfo#autofillId. 217 */ 218 @ApiTest( 219 apis = { 220 "android.view.inputmethod.EditorInfo#setAutofillId", 221 "android.view.inputmethod.EditorInfo#getAutofillId" 222 }) 223 @Test 224 @RequiresFlagsEnabled(Flags.FLAG_PUBLIC_AUTOFILL_ID_IN_EDITORINFO) testAutofillId()225 public void testAutofillId() { 226 EditorInfo info = new EditorInfo(); 227 info.setAutofillId(new AutofillId(1)); 228 Parcel p = Parcel.obtain(); 229 info.writeToParcel(p, 0 /* flags */); 230 p.setDataPosition(0); 231 EditorInfo targetInfo = EditorInfo.CREATOR.createFromParcel(p); 232 p.recycle(); 233 assertEquals(info.getAutofillId(), targetInfo.getAutofillId()); 234 } 235 236 @Test testNullHintLocals()237 public void testNullHintLocals() { 238 EditorInfo info = new EditorInfo(); 239 info.hintLocales = null; 240 Parcel p = Parcel.obtain(); 241 info.writeToParcel(p, 0); 242 p.setDataPosition(0); 243 EditorInfo targetInfo = EditorInfo.CREATOR.createFromParcel(p); 244 p.recycle(); 245 assertNull(targetInfo.hintLocales); 246 } 247 248 @Test testInitialSurroundingText_nullInput_throwsException()249 public void testInitialSurroundingText_nullInput_throwsException() { 250 final EditorInfo info = new EditorInfo(); 251 252 try { 253 info.setInitialSurroundingText(null); 254 fail("Shall not take null input"); 255 } catch (NullPointerException expected) { 256 // Expected behavior, nothing to do. 257 } 258 } 259 260 @Test testInitialSurroundingText_passwordTypes_notObtain()261 public void testInitialSurroundingText_passwordTypes_notObtain() { 262 final EditorInfo info = new EditorInfo(); 263 final CharSequence testInitialText = createTestText(/* size= */ 10); 264 info.initialSelStart = 1; 265 info.initialSelEnd = 2; 266 267 // Text password type 268 info.inputType = (EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_VARIATION_PASSWORD); 269 270 info.setInitialSurroundingText(testInitialText); 271 272 assertExpectedTextLength(info, 273 /* expectBeforeCursorLength= */null, 274 /* expectSelectionLength= */null, 275 /* expectAfterCursorLength= */null, 276 /* expectSurroundingText= */null); 277 278 // Web password type 279 info.inputType = (EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_VARIATION_WEB_PASSWORD); 280 281 info.setInitialSurroundingText(testInitialText); 282 283 assertExpectedTextLength(info, 284 /* expectBeforeCursorLength= */null, 285 /* expectSelectionLength= */null, 286 /* expectAfterCursorLength= */null, 287 /* expectSurroundingText= */null); 288 289 // Number password type 290 info.inputType = (EditorInfo.TYPE_CLASS_NUMBER | EditorInfo.TYPE_NUMBER_VARIATION_PASSWORD); 291 292 info.setInitialSurroundingText(testInitialText); 293 294 assertExpectedTextLength(info, 295 /* expectBeforeCursorLength= */null, 296 /* expectSelectionLength= */null, 297 /* expectAfterCursorLength= */null, 298 /* expectSurroundingText= */null); 299 } 300 301 @Test testInitialSurroundingText_cursorAtHead_emptyBeforeCursorText()302 public void testInitialSurroundingText_cursorAtHead_emptyBeforeCursorText() { 303 final EditorInfo info = new EditorInfo(); 304 final CharSequence testText = createTestText(TEST_TEXT_LENGTH); 305 final int selLength = 10; 306 info.initialSelStart = 0; 307 info.initialSelEnd = info.initialSelStart + selLength; 308 final int expectedTextBeforeCursorLength = 0; 309 final int expectedTextAfterCursorLength = testText.length() - selLength; 310 final SurroundingText expectedSurroundingText = 311 new SurroundingText(testText, info.initialSelStart, info.initialSelEnd, 0); 312 313 info.setInitialSurroundingText(testText); 314 315 assertExpectedTextLength(info, expectedTextBeforeCursorLength, selLength, 316 expectedTextAfterCursorLength, expectedSurroundingText); 317 } 318 319 @Test testInitialSurroundingText_cursorAtTail_emptyAfterCursorText()320 public void testInitialSurroundingText_cursorAtTail_emptyAfterCursorText() { 321 final EditorInfo info = new EditorInfo(); 322 final CharSequence testText = createTestText(TEST_TEXT_LENGTH); 323 final int selLength = 10; 324 info.initialSelStart = testText.length() - selLength; 325 info.initialSelEnd = testText.length(); 326 final int expectedTextBeforeCursorLength = testText.length() - selLength; 327 final int expectedTextAfterCursorLength = 0; 328 final SurroundingText expectedSurroundingText = 329 new SurroundingText(testText, info.initialSelStart, info.initialSelEnd, 0); 330 331 info.setInitialSurroundingText(testText); 332 333 assertExpectedTextLength(info, expectedTextBeforeCursorLength, selLength, 334 expectedTextAfterCursorLength, expectedSurroundingText); 335 } 336 337 @Test testInitialSurroundingText_noSelection_emptySelectionText()338 public void testInitialSurroundingText_noSelection_emptySelectionText() { 339 final EditorInfo info = new EditorInfo(); 340 final CharSequence testText = createTestText(TEST_TEXT_LENGTH); 341 final int selLength = 0; 342 info.initialSelStart = 0; 343 info.initialSelEnd = info.initialSelStart + selLength; 344 final int expectedTextBeforeCursorLength = 0; 345 final int expectedTextAfterCursorLength = testText.length(); 346 final SurroundingText expectedSurroundingText = 347 new SurroundingText(testText, info.initialSelStart, info.initialSelEnd, 0); 348 349 info.setInitialSurroundingText(testText); 350 351 assertExpectedTextLength(info, expectedTextBeforeCursorLength, selLength, 352 expectedTextAfterCursorLength, expectedSurroundingText); 353 } 354 355 @Test testInitialSurroundingText_overSizedSelection_keepsBeforeAfterTextValid()356 public void testInitialSurroundingText_overSizedSelection_keepsBeforeAfterTextValid() { 357 final EditorInfo info = new EditorInfo(); 358 final CharSequence testText = createTestText(OVER_SIZED_TEXT_LENGTH); 359 final int selLength = OVER_SIZED_TEXT_LENGTH - 2; 360 info.initialSelStart = 1; 361 info.initialSelEnd = info.initialSelStart + selLength; 362 final int expectedTextBeforeCursorLength = 1; 363 final int expectedTextAfterCursorLength = 1; 364 final int offset = info.initialSelStart - expectedTextBeforeCursorLength; 365 final CharSequence beforeCursor = testText.subSequence(offset, 366 offset + expectedTextBeforeCursorLength); 367 final CharSequence afterCursor = testText.subSequence(info.initialSelEnd, 368 testText.length()); 369 final CharSequence surroundingText = TextUtils.concat(beforeCursor, afterCursor); 370 final SurroundingText expectedSurroundingText = 371 new SurroundingText(surroundingText, info.initialSelStart, info.initialSelStart, 0); 372 373 info.setInitialSurroundingText(testText); 374 375 assertExpectedTextLength(info, expectedTextBeforeCursorLength, 376 /* expectSelectionLength= */null, expectedTextAfterCursorLength, 377 expectedSurroundingText); 378 379 } 380 381 @Test testInitialSurroundingSubText_keepsOriginalCursorPosition()382 public void testInitialSurroundingSubText_keepsOriginalCursorPosition() { 383 final EditorInfo info = new EditorInfo(); 384 final String prefixString = "prefix"; 385 final CharSequence subText = createTestText(TEST_TEXT_LENGTH); 386 final CharSequence originalText = TextUtils.concat(prefixString, subText); 387 final int selLength = 2; 388 info.initialSelStart = originalText.length() / 2; 389 info.initialSelEnd = info.initialSelStart + selLength; 390 final CharSequence expectedTextBeforeCursor = createExpectedText(/* startNumber= */0, 391 info.initialSelStart - prefixString.length()); 392 final CharSequence expectedSelectedText = createExpectedText( 393 info.initialSelStart - prefixString.length(), selLength); 394 final CharSequence expectedTextAfterCursor = createExpectedText( 395 info.initialSelEnd - prefixString.length(), 396 originalText.length() - info.initialSelEnd); 397 final SurroundingText expectedSurroundingText = new SurroundingText( 398 TextUtils.concat(expectedTextBeforeCursor, expectedSelectedText, 399 expectedTextAfterCursor), 400 info.initialSelStart - prefixString.length(), 401 info.initialSelStart - prefixString.length() + selLength, 402 prefixString.length()); 403 404 info.setInitialSurroundingSubText(subText, prefixString.length()); 405 406 assertTrue(TextUtils.equals(expectedTextBeforeCursor, 407 info.getInitialTextBeforeCursor(REQUEST_LONGEST_AVAILABLE_TEXT, 408 InputConnection.GET_TEXT_WITH_STYLES))); 409 assertTrue(TextUtils.equals(expectedSelectedText, 410 info.getInitialSelectedText(InputConnection.GET_TEXT_WITH_STYLES))); 411 assertTrue(TextUtils.equals(expectedTextAfterCursor, 412 info.getInitialTextAfterCursor(REQUEST_LONGEST_AVAILABLE_TEXT, 413 InputConnection.GET_TEXT_WITH_STYLES))); 414 SurroundingText surroundingText = info.getInitialSurroundingText( 415 REQUEST_LONGEST_AVAILABLE_TEXT, 416 REQUEST_LONGEST_AVAILABLE_TEXT, 417 InputConnection.GET_TEXT_WITH_STYLES); 418 assertNotNull(surroundingText); 419 assertTrue(TextUtils.equals(expectedSurroundingText.getText(), surroundingText.getText())); 420 assertEquals(expectedSurroundingText.getSelectionStart(), 421 surroundingText.getSelectionStart()); 422 assertEquals(expectedSurroundingText.getSelectionEnd(), surroundingText.getSelectionEnd()); 423 } 424 assertExpectedTextLength(EditorInfo editorInfo, Integer expectBeforeCursorLength, Integer expectSelectionLength, Integer expectAfterCursorLength, SurroundingText expectSurroundingText)425 private static void assertExpectedTextLength(EditorInfo editorInfo, 426 Integer expectBeforeCursorLength, Integer expectSelectionLength, 427 Integer expectAfterCursorLength, 428 SurroundingText expectSurroundingText) { 429 final CharSequence textBeforeCursor = 430 editorInfo.getInitialTextBeforeCursor(REQUEST_LONGEST_AVAILABLE_TEXT, 431 InputConnection.GET_TEXT_WITH_STYLES); 432 final CharSequence selectedText = 433 editorInfo.getInitialSelectedText(InputConnection.GET_TEXT_WITH_STYLES); 434 final CharSequence textAfterCursor = 435 editorInfo.getInitialTextAfterCursor(REQUEST_LONGEST_AVAILABLE_TEXT, 436 InputConnection.GET_TEXT_WITH_STYLES); 437 final SurroundingText surroundingText = editorInfo.getInitialSurroundingText( 438 REQUEST_LONGEST_AVAILABLE_TEXT, 439 REQUEST_LONGEST_AVAILABLE_TEXT, 440 InputConnection.GET_TEXT_WITH_STYLES); 441 442 if (expectBeforeCursorLength == null) { 443 assertNull(textBeforeCursor); 444 } else { 445 assertEquals(expectBeforeCursorLength.intValue(), textBeforeCursor.length()); 446 } 447 448 if (expectSelectionLength == null) { 449 assertNull(selectedText); 450 } else { 451 assertEquals(expectSelectionLength.intValue(), selectedText.length()); 452 } 453 454 if (expectAfterCursorLength == null) { 455 assertNull(textAfterCursor); 456 } else { 457 assertEquals(expectAfterCursorLength.intValue(), textAfterCursor.length()); 458 } 459 460 if (expectSurroundingText == null) { 461 assertNull(surroundingText); 462 } else { 463 assertTrue(TextUtils.equals( 464 expectSurroundingText.getText(), surroundingText.getText())); 465 assertEquals(expectSurroundingText.getSelectionStart(), 466 surroundingText.getSelectionStart()); 467 assertEquals(expectSurroundingText.getSelectionEnd(), 468 surroundingText.getSelectionEnd()); 469 assertEquals(expectSurroundingText.getOffset(), surroundingText.getOffset()); 470 } 471 } 472 createTestText(int size)473 private static CharSequence createTestText(int size) { 474 final SpannableStringBuilder builder = new SpannableStringBuilder(); 475 for (int i = 0; i < size; i++) { 476 builder.append(Integer.toString(i % 10)); 477 } 478 return builder; 479 } 480 createExpectedText(int startNumber, int length)481 private static CharSequence createExpectedText(int startNumber, int length) { 482 final SpannableStringBuilder builder = new SpannableStringBuilder(); 483 for (int i = startNumber; i < startNumber + length; i++) { 484 builder.append(Integer.toString(i % 10)); 485 } 486 return builder; 487 } 488 concatInitialSurroundingText(EditorInfo info)489 private static CharSequence concatInitialSurroundingText(EditorInfo info) { 490 final CharSequence textBeforeCursor = 491 nullToEmpty(info.getInitialTextBeforeCursor(REQUEST_LONGEST_AVAILABLE_TEXT, 492 InputConnection.GET_TEXT_WITH_STYLES)); 493 final CharSequence selectedText = 494 nullToEmpty(info.getInitialSelectedText(InputConnection.GET_TEXT_WITH_STYLES)); 495 final CharSequence textAfterCursor = 496 nullToEmpty(info.getInitialTextAfterCursor(REQUEST_LONGEST_AVAILABLE_TEXT, 497 InputConnection.GET_TEXT_WITH_STYLES)); 498 499 return TextUtils.concat(textBeforeCursor, selectedText, textAfterCursor); 500 } 501 nullToEmpty(CharSequence source)502 private static CharSequence nullToEmpty(CharSequence source) { 503 return (source == null) ? new SpannableStringBuilder("") : source; 504 } 505 } 506