xref: /aosp_15_r20/cts/tests/inputmethod/src/android/view/inputmethod/cts/EditorInfoTest.java (revision b7c941bb3fa97aba169d73cee0bed2de8ac964bf)
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