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.text.method.cts; 18 19 import static org.junit.Assert.assertTrue; 20 21 import android.text.InputType; 22 import android.text.method.BaseKeyListener; 23 import android.view.KeyEvent; 24 import android.widget.TextView.BufferType; 25 26 import androidx.test.ext.junit.runners.AndroidJUnit4; 27 import androidx.test.filters.MediumTest; 28 29 import org.junit.Test; 30 import org.junit.runner.RunWith; 31 32 /** 33 * Test backspace key handling of {@link android.text.method.BaseKeyListener}. 34 */ 35 @MediumTest 36 @RunWith(AndroidJUnit4.class) 37 public class BackspaceTest extends KeyListenerTestCase { 38 private static final BaseKeyListener mKeyListener = new BaseKeyListener() { 39 public int getInputType() { 40 return InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL; 41 } 42 }; 43 44 // Sync the state to the TextView and call onKeyDown with KEYCODE_DEL key event. 45 // Then update the state to the result of TextView. backspace(final EditorState state, int modifiers)46 private void backspace(final EditorState state, int modifiers) throws Throwable { 47 mActivityRule.runOnUiThread(() -> { 48 mTextView.setText(state.mText, BufferType.EDITABLE); 49 mTextView.setKeyListener(mKeyListener); 50 mTextView.setSelection(state.mSelectionStart, state.mSelectionEnd); 51 }); 52 mInstrumentation.waitForIdleSync(); 53 assertTrue(mTextView.hasWindowFocus()); 54 55 final KeyEvent keyEvent = getKey(KeyEvent.KEYCODE_DEL, modifiers); 56 mActivityRule.runOnUiThread(() -> mTextView.onKeyDown(keyEvent.getKeyCode(), keyEvent)); 57 mInstrumentation.waitForIdleSync(); 58 59 state.mText = mTextView.getText(); 60 state.mSelectionStart = mTextView.getSelectionStart(); 61 state.mSelectionEnd = mTextView.getSelectionEnd(); 62 } 63 64 @Test testCRLF()65 public void testCRLF() throws Throwable { 66 EditorState state = new EditorState(); 67 68 // U+000A is LINE FEED. 69 state.setByString("U+000A |"); 70 backspace(state, 0); 71 state.assertEquals("|"); 72 73 // U+000D is CARRIAGE RETURN. 74 state.setByString("U+000D |"); 75 backspace(state, 0); 76 state.assertEquals("|"); 77 78 state.setByString("U+000D U+000A |"); 79 backspace(state, 0); 80 state.assertEquals("|"); 81 82 state.setByString("U+000A U+000D |"); 83 backspace(state, 0); 84 state.assertEquals("U+000A |"); 85 backspace(state, 0); 86 state.assertEquals("|"); 87 } 88 89 @Test testSurrogatePairs()90 public void testSurrogatePairs() throws Throwable { 91 EditorState state = new EditorState(); 92 93 state.setByString("U+1F441 |"); 94 backspace(state, 0); 95 state.assertEquals("|"); 96 97 state.setByString("U+1F441 U+1F5E8 |"); 98 backspace(state, 0); 99 state.assertEquals("U+1F441 |"); 100 backspace(state, 0); 101 state.assertEquals("|"); 102 } 103 104 @Test testReplacementSpan()105 public void testReplacementSpan() throws Throwable { 106 EditorState state = new EditorState(); 107 108 // ReplacementSpan will be set to "()" region. 109 state.setByString("'abc' ( 'de' ) 'fg' |"); 110 backspace(state, 0); 111 state.assertEquals("'abc' ( 'de' ) 'f' |"); 112 backspace(state, 0); 113 state.assertEquals("'abc' ( 'de' ) |"); 114 backspace(state, 0); 115 state.assertEquals("'abc' |"); 116 backspace(state, 0); 117 state.assertEquals("'ab' |"); 118 backspace(state, 0); 119 state.assertEquals("'a' |"); 120 backspace(state, 0); 121 state.assertEquals("|"); 122 123 state.setByString("'abc' [ ( 'de' ) ] 'fg'"); 124 backspace(state, 0); 125 state.assertEquals("'abc' | 'fg'"); 126 backspace(state, 0); 127 state.assertEquals("'ab' | 'fg'"); 128 backspace(state, 0); 129 state.assertEquals("'a' | 'fg'"); 130 backspace(state, 0); 131 state.assertEquals("| 'fg'"); 132 backspace(state, 0); 133 state.assertEquals("| 'fg'"); 134 135 state.setByString("'ab' [ 'c' ( 'de' ) 'f' ] 'g'"); 136 backspace(state, 0); 137 state.assertEquals("'ab' | 'g'"); 138 backspace(state, 0); 139 state.assertEquals("'a' | 'g'"); 140 backspace(state, 0); 141 state.assertEquals("| 'g'"); 142 backspace(state, 0); 143 state.assertEquals("| 'g'"); 144 } 145 146 @Test testCombiningEnclosingKeycaps()147 public void testCombiningEnclosingKeycaps() throws Throwable { 148 EditorState state = new EditorState(); 149 150 // U+20E3 is COMBINING ENCLOSING KEYCAP. 151 state.setByString("'1' U+20E3 |"); 152 backspace(state, 0); 153 state.assertEquals("|"); 154 155 // Variation selector before COMBINING ECLOSING KEYCAP 156 state.setByString("'1' U+FE0E U+20E3 |"); 157 backspace(state, 0); 158 state.assertEquals("|"); 159 } 160 161 @Test testVariationSelector()162 public void testVariationSelector() throws Throwable { 163 EditorState state = new EditorState(); 164 165 // U+FE0F is VARIATION SELECTOR-16. 166 state.setByString("'#' U+FE0F |"); 167 backspace(state, 0); 168 state.assertEquals("|"); 169 170 // U+E0100 is VARIATION SELECTOR-17. 171 state.setByString("U+845B U+E0100 |"); 172 backspace(state, 0); 173 state.assertEquals("|"); 174 } 175 176 @Test testFlags()177 public void testFlags() throws Throwable { 178 EditorState state = new EditorState(); 179 180 // U+1F1FA is REGIONAL INDICATOR SYMBOL LETTER U. 181 // U+1F1F8 is REGIONAL INDICATOR SYMBOL LETTER S. 182 state.setByString("U+1F1FA U+1F1F8 |"); 183 backspace(state, 0); 184 state.assertEquals("|"); 185 186 state.setByString("'a' U+1F1FA U+1F1F8 |"); 187 backspace(state, 0); 188 state.assertEquals("'a' |"); 189 backspace(state, 0); 190 state.assertEquals("|"); 191 192 state.setByString("U+1F1FA U+1F1F8 U+1F1FA U+1F1F8 |"); 193 backspace(state, 0); 194 state.assertEquals("U+1F1FA U+1F1F8 |"); 195 backspace(state, 0); 196 state.assertEquals("|"); 197 198 state.setByString("'a' U+1F1FA U+1F1F8 'b' U+1F1FA U+1F1F8 |"); 199 backspace(state, 0); 200 state.assertEquals("'a' U+1F1FA U+1F1F8 'b' |"); 201 backspace(state, 0); 202 state.assertEquals("'a' U+1F1FA U+1F1F8 |"); 203 backspace(state, 0); 204 state.assertEquals("'a' |"); 205 backspace(state, 0); 206 state.assertEquals("|"); 207 208 // Single tag_base character 209 // U+1F3F4 is WAVING BLACK FLAG. This can be a tag_base character. 210 state.setByString("'a' U+1F3F4 U+1F3F4 'b' |"); 211 backspace(state, 0); 212 state.assertEquals("'a' U+1F3F4 U+1F3F4 |"); 213 backspace(state, 0); 214 state.assertEquals("'a' U+1F3F4 |"); 215 backspace(state, 0); 216 state.assertEquals("'a' |"); 217 218 // U+E0067 is TAG LATIN SMALL LETTER G. This can be a part of tag_spec. 219 // U+E0062 is TAG LATIN SMALL LETTER B. This can be a part of tag_spec. 220 // U+E0073 is TAG LATIN SMALL LETTER S. This can be a part of tag_spec. 221 // U+E0063 is TAG LATIN SMALL LETTER C. This can be a part of tag_spec. 222 // U+E0074 is TAG LATIN SMALL LETTER T. This can be a part of tag_spec. 223 // U+E007F is CANCEL TAG. This is a tag_term character. 224 final String scotland = "U+1F3F4 U+E0067 U+E0062 U+E0073 U+E0063 U+E0074 U+E007F "; 225 226 state.setByString("'a' " + scotland + scotland + "'b' |"); 227 backspace(state, 0); 228 state.assertEquals("'a' " + scotland + scotland + "|"); 229 backspace(state, 0); 230 state.assertEquals("'a' " + scotland + "|"); 231 backspace(state, 0); 232 state.assertEquals("'a' |"); 233 234 } 235 } 236