1 /* 2 * Copyright (C) 2016 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.util; 18 19 import android.text.Editable; 20 import android.text.Selection; 21 import android.text.SpannableStringBuilder; 22 import android.view.View; 23 import android.view.inputmethod.BaseInputConnection; 24 25 import androidx.annotation.NonNull; 26 import androidx.test.platform.app.InstrumentationRegistry; 27 28 public final class InputConnectionTestUtils { 29 30 private static final String U1F427 = "\uD83D\uDC27"; 31 32 /** 33 * A utility function to generate test string for input method APIs. There are several 34 * pre-defined meta characters that are useful for unit tests. 35 * 36 * <p>Pre-defined meta characters:</p> 37 * <dl> 38 * <dl>{@code [}</dl><dd>The text selection starts from here.</dd> 39 * <dl>{@code ]}</dl><dd>The text selection ends at here.</dd> 40 * <dl>{@code <}</dl><dd>Represents a high surrogate character.</dd> 41 * <dl>{@code >}</dl><dd>Represents a low surrogate character.</dd> 42 * </ul> 43 * 44 * <p>Examples: {@code "012[3<>67]89"} will be converted to {@ode "0123HL6789"}, where 45 * {@code "H"} and {@code "L"} indicate certain high and low surrogate characters, respectively, 46 * with selecting {@code "3HL67"}.</p> 47 * 48 * @param formatString 49 * @return A {@link CharSequence} object with text selection specified by the meta characters. 50 */ formatString(final String formatString)51 public static CharSequence formatString(final String formatString) { 52 final SpannableStringBuilder builder = new SpannableStringBuilder(); 53 int selectionStart = -1; 54 int selectionEnd = -1; 55 for (int i = 0; i < formatString.length(); ++i) { 56 final Character c = formatString.charAt(i); 57 switch (c) { 58 case '[': 59 selectionStart = builder.length(); 60 break; 61 case ']': 62 selectionEnd = builder.length(); 63 break; 64 case '<': 65 builder.append(U1F427.charAt(0)); // High surrogate 66 break; 67 case '>': 68 builder.append(U1F427.charAt(1)); // Low surrogate 69 break; 70 default: 71 builder.append(c); 72 break; 73 } 74 } 75 if (selectionStart < 0) { 76 throw new UnsupportedOperationException("Selection marker '[' must be specified."); 77 } 78 if (selectionEnd < 0) { 79 throw new UnsupportedOperationException("Selection marker ']' must be specified."); 80 } 81 Selection.setSelection(builder, selectionStart, selectionEnd); 82 return builder; 83 } 84 85 /** 86 * A utility method to create an instance of {@link BaseInputConnection}. 87 * 88 * @return {@link BaseInputConnection} instantiated in the full editor mode with {@code 89 * editable}. 90 */ createBaseInputConnection()91 public static BaseInputConnection createBaseInputConnection() { 92 final View view = new View(InstrumentationRegistry.getInstrumentation().getTargetContext()); 93 return new BaseInputConnection(view, true); 94 } 95 96 /** 97 * A utility method to create an instance of {@link BaseInputConnection} from {@link Editable}. 98 * 99 * @param editable the initial text. 100 * @return {@link BaseInputConnection} instantiated in the full editor mode with {@code 101 * editable}. 102 */ createBaseInputConnection(@onNull Editable editable)103 public static BaseInputConnection createBaseInputConnection(@NonNull Editable editable) { 104 final View view = new View(InstrumentationRegistry.getInstrumentation().getTargetContext()); 105 return new BaseInputConnection(view, true) { 106 @Override 107 public Editable getEditable() { 108 return editable; 109 } 110 }; 111 } 112 113 /** 114 * A utility method to create an instance of {@link BaseInputConnection} in the full editor mode 115 * with an initial text and selection range. 116 * 117 * @param source the initial text. 118 * @return {@link BaseInputConnection} instantiated in the full editor mode with {@code source} 119 * and selection range from {@code selectionStart} to {@code selectionEnd} 120 */ 121 public static BaseInputConnection createBaseInputConnectionWithSelection(CharSequence source) { 122 final int selectionStart = Selection.getSelectionStart(source); 123 final int selectionEnd = Selection.getSelectionEnd(source); 124 final Editable editable = Editable.Factory.getInstance().newEditable(source); 125 Selection.setSelection(editable, selectionStart, selectionEnd); 126 return createBaseInputConnection(editable); 127 } 128 } 129