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