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 17package android.text.method; 18 19import android.app.Activity; 20import android.test.suitebuilder.annotation.SmallTest; 21import android.test.suitebuilder.annotation.Suppress; 22import android.text.InputType; 23import android.text.method.BaseKeyListener; 24import android.text.method.KeyListenerTestCase; 25import android.view.KeyEvent; 26import android.widget.EditText; 27import android.widget.TextView.BufferType; 28 29/** 30 * Test forward delete key handling of {@link android.text.method.BaseKeyListener}. 31 * 32 * Only contains edge cases. For normal cases, see {@see android.text.method.cts.ForwardDeleteTest}. 33 * TODO: introduce test cases for surrogate pairs and replacement span. 34 */ 35public class ForwardDeleteTest extends KeyListenerTestCase { 36 private static final BaseKeyListener mKeyListener = new BaseKeyListener() { 37 public int getInputType() { 38 return InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL; 39 } 40 }; 41 42 // Sync the state to the TextView and call onKeyDown with KEYCODE_FORWARD_DEL key event. 43 // Then update the state to the result of TextView. 44 private void forwardDelete(final EditorState state, int modifiers) { 45 mActivity.runOnUiThread(new Runnable() { 46 public void run() { 47 mTextView.setText(state.mText, BufferType.EDITABLE); 48 mTextView.setKeyListener(mKeyListener); 49 mTextView.setSelection(state.mSelectionStart, state.mSelectionEnd); 50 } 51 }); 52 mInstrumentation.waitForIdleSync(); 53 assertTrue(mTextView.hasWindowFocus()); 54 55 final KeyEvent keyEvent = getKey(KeyEvent.KEYCODE_FORWARD_DEL, modifiers); 56 mActivity.runOnUiThread(new Runnable() { 57 public void run() { 58 mTextView.onKeyDown(keyEvent.getKeyCode(), keyEvent); 59 } 60 }); 61 mInstrumentation.waitForIdleSync(); 62 63 state.mText = mTextView.getText(); 64 state.mSelectionStart = mTextView.getSelectionStart(); 65 state.mSelectionEnd = mTextView.getSelectionEnd(); 66 } 67 68 @SmallTest 69 public void testCombiningEnclosingKeycaps() { 70 EditorState state = new EditorState(); 71 72 // multiple COMBINING ENCLOSING KEYCAP 73 state.setByString("| '1' U+20E3 U+20E3"); 74 forwardDelete(state, 0); 75 state.assertEquals("|"); 76 77 // Isolated COMBINING ENCLOSING KEYCAP 78 state.setByString("| U+20E3"); 79 forwardDelete(state, 0); 80 state.assertEquals("|"); 81 82 // Isolated multiple COMBINING ENCLOSING KEYCAP 83 state.setByString("| U+20E3 U+20E3"); 84 forwardDelete(state, 0); 85 state.assertEquals("|"); 86 } 87 88 @SmallTest 89 public void testVariationSelector() { 90 EditorState state = new EditorState(); 91 92 // Isolated variation selectors 93 state.setByString("| U+FE0F"); 94 forwardDelete(state, 0); 95 state.assertEquals("|"); 96 97 state.setByString("| U+E0100"); 98 forwardDelete(state, 0); 99 state.assertEquals("|"); 100 101 // Isolated multiple variation selectors 102 state.setByString("| U+FE0F U+FE0F"); 103 forwardDelete(state, 0); 104 state.assertEquals("|"); 105 106 state.setByString("| U+FE0F U+E0100"); 107 forwardDelete(state, 0); 108 state.assertEquals("|"); 109 110 state.setByString("| U+E0100 U+FE0F"); 111 forwardDelete(state, 0); 112 state.assertEquals("|"); 113 114 state.setByString("| U+E0100 U+E0100"); 115 forwardDelete(state, 0); 116 state.assertEquals("|"); 117 118 // Multiple variation selectors 119 state.setByString("| '#' U+FE0F U+FE0F"); 120 forwardDelete(state, 0); 121 state.assertEquals("|"); 122 123 state.setByString("| '#' U+FE0F U+E0100"); 124 forwardDelete(state, 0); 125 state.assertEquals("|"); 126 127 state.setByString("| U+845B U+E0100 U+FE0F"); 128 forwardDelete(state, 0); 129 state.assertEquals("|"); 130 131 state.setByString("| U+845B U+E0100 U+E0100"); 132 forwardDelete(state, 0); 133 state.assertEquals("|"); 134 } 135 136 @SmallTest 137 public void testEmojiZeroWidthJoinerSequence() { 138 EditorState state = new EditorState(); 139 140 // U+200D is ZERO WIDTH JOINER. 141 state.setByString("| U+1F441 U+200D U+1F5E8"); 142 forwardDelete(state, 0); 143 state.assertEquals("|"); 144 145 state.setByString("| U+1F468 U+200D U+2764 U+FE0F U+200D U+1F48B U+200D U+1F468"); 146 forwardDelete(state, 0); 147 state.assertEquals("|"); 148 149 // End with ZERO WIDTH JOINER 150 state.setByString("| U+1F441 U+200D"); 151 forwardDelete(state, 0); 152 state.assertEquals("|"); 153 154 // Start with ZERO WIDTH JOINER 155 state.setByString("| U+200D U+1F5E8"); 156 forwardDelete(state, 0); 157 state.assertEquals("| U+1F5E8"); 158 forwardDelete(state, 0); 159 state.assertEquals("|"); 160 161 // Multiple ZERO WIDTH JOINER 162 state.setByString("| U+1F441 U+200D U+200D U+1F5E8"); 163 forwardDelete(state, 0); 164 state.assertEquals("| U+1F5E8"); 165 forwardDelete(state, 0); 166 state.assertEquals("|"); 167 168 // Isolated ZERO WIDTH JOINER 169 state.setByString("| U+200D"); 170 forwardDelete(state, 0); 171 state.assertEquals("|"); 172 173 // Isolated multiple ZERO WIDTH JOINER 174 state.setByString("| U+200D U+200D"); 175 forwardDelete(state, 0); 176 state.assertEquals("|"); 177 } 178 179 @SmallTest 180 public void testFlags() { 181 EditorState state = new EditorState(); 182 183 // Isolated regional indicator symbol 184 state.setByString("| U+1F1FA"); 185 forwardDelete(state, 0); 186 state.assertEquals("|"); 187 188 // Odd numbered regional indicator symbols 189 state.setByString("| U+1F1FA U+1F1F8 U+1F1FA"); 190 forwardDelete(state, 0); 191 state.assertEquals("| U+1F1FA"); 192 forwardDelete(state, 0); 193 state.assertEquals("|"); 194 } 195 196 @SmallTest 197 public void testEmojiModifier() { 198 EditorState state = new EditorState(); 199 200 // U+1F3FB is EMOJI MODIFIER FITZPATRICK TYPE-1-2. 201 state.setByString("| U+1F466 U+1F3FB"); 202 forwardDelete(state, 0); 203 state.assertEquals("|"); 204 205 // Isolated emoji modifier 206 state.setByString("| U+1F3FB"); 207 forwardDelete(state, 0); 208 state.assertEquals("|"); 209 210 // Isolated multiple emoji modifier 211 state.setByString("| U+1F3FB U+1F3FB"); 212 forwardDelete(state, 0); 213 state.assertEquals("| U+1F3FB"); 214 forwardDelete(state, 0); 215 state.assertEquals("|"); 216 217 // Multiple emoji modifiers 218 state.setByString("| U+1F466 U+1F3FB U+1F3FB"); 219 forwardDelete(state, 0); 220 state.assertEquals("| U+1F3FB"); 221 forwardDelete(state, 0); 222 state.assertEquals("|"); 223 } 224 225 @SmallTest 226 public void testMixedEdgeCases() { 227 EditorState state = new EditorState(); 228 229 // COMBINING ENCLOSING KEYCAP + variation selector 230 state.setByString("| '1' U+20E3 U+FE0F"); 231 forwardDelete(state, 0); 232 state.assertEquals("|"); 233 234 // Variation selector + COMBINING ENCLOSING KEYCAP 235 state.setByString("| U+2665 U+FE0F U+20E3"); 236 forwardDelete(state, 0); 237 state.assertEquals("|"); 238 239 // COMBINING ENCLOSING KEYCAP + ending with ZERO WIDTH JOINER 240 state.setByString("| '1' U+20E3 U+200D"); 241 forwardDelete(state, 0); 242 state.assertEquals("|"); 243 244 // COMBINING ENCLOSING KEYCAP + ZERO WIDTH JOINER 245 state.setByString("| '1' U+20E3 U+200D U+1F5E8"); 246 forwardDelete(state, 0); 247 state.assertEquals("| U+1F5E8 "); 248 249 // Start with ZERO WIDTH JOINER + COMBINING ENCLOSING KEYCAP 250 state.setByString("| U+200D U+20E3"); 251 forwardDelete(state, 0); 252 state.assertEquals("|"); 253 254 // ZERO WIDTH JOINER + COMBINING ENCLOSING KEYCAP 255 state.setByString("| U+1F441 U+200D U+20E3"); 256 forwardDelete(state, 0); 257 state.assertEquals("|"); 258 259 // COMBINING ENCLOSING KEYCAP + regional indicator symbol 260 state.setByString("| '1' U+20E3 U+1F1FA"); 261 forwardDelete(state, 0); 262 state.assertEquals("| U+1F1FA"); 263 forwardDelete(state, 0); 264 state.assertEquals("|"); 265 266 // Regional indicator symbol + COMBINING ENCLOSING KEYCAP 267 state.setByString("| U+1F1FA U+20E3"); 268 forwardDelete(state, 0); 269 state.assertEquals("|"); 270 271 // COMBINING ENCLOSING KEYCAP + emoji modifier 272 state.setByString("| '1' U+20E3 U+1F3FB"); 273 forwardDelete(state, 0); 274 state.assertEquals("| U+1F3FB"); 275 276 // Emoji modifier + COMBINING ENCLOSING KEYCAP 277 state.setByString("| U+1F466 U+1F3FB U+20E3"); 278 forwardDelete(state, 0); 279 state.assertEquals("|"); 280 281 // Variation selector + end with ZERO WIDTH JOINER 282 state.setByString("| U+2665 U+FE0F U+200D"); 283 forwardDelete(state, 0); 284 state.assertEquals("|"); 285 286 // Variation selector + ZERO WIDTH JOINER 287 state.setByString("| U+1F469 U+200D U+2764 U+FE0F U+200D U+1F469"); 288 forwardDelete(state, 0); 289 state.assertEquals("|"); 290 291 // Start with ZERO WIDTH JOINER + variation selector 292 state.setByString("| U+200D U+FE0F"); 293 forwardDelete(state, 0); 294 state.assertEquals("|"); 295 296 // ZERO WIDTH JOINER + variation selector 297 state.setByString("| U+1F469 U+200D U+FE0F"); 298 forwardDelete(state, 0); 299 state.assertEquals("|"); 300 301 // Variation selector + regional indicator symbol 302 state.setByString("| U+2665 U+FE0F U+1F1FA"); 303 forwardDelete(state, 0); 304 state.assertEquals("| U+1F1FA"); 305 forwardDelete(state, 0); 306 state.assertEquals("|"); 307 308 // Regional indicator symbol + variation selector 309 state.setByString("| U+1F1FA U+FE0F"); 310 forwardDelete(state, 0); 311 state.assertEquals("|"); 312 313 // Variation selector + emoji modifier 314 state.setByString("| U+2665 U+FE0F U+1F3FB"); 315 forwardDelete(state, 0); 316 state.assertEquals("| U+1F3FB"); 317 318 // Emoji modifier + variation selector 319 state.setByString("| U+1F466 U+1F3FB U+FE0F"); 320 forwardDelete(state, 0); 321 state.assertEquals("|"); 322 323 // Start with ZERO WIDTH JOINER + regional indicator symbol 324 state.setByString("| U+200D U+1F1FA"); 325 forwardDelete(state, 0); 326 state.assertEquals("| U+1F1FA"); 327 forwardDelete(state, 0); 328 state.assertEquals("|"); 329 330 // ZERO WIDTH JOINER + regional indicator symbol 331 state.setByString("| U+1F469 U+200D U+1F1FA"); 332 forwardDelete(state, 0); 333 state.assertEquals("| U+1F1FA"); 334 335 // Regional indicator symbol + end with ZERO WIDTH JOINER 336 state.setByString("| U+1F1FA U+200D"); 337 forwardDelete(state, 0); 338 state.assertEquals("|"); 339 340 // Regional indicator symbol + ZERO WIDTH JOINER 341 state.setByString("| U+1F1FA U+200D U+1F469"); 342 forwardDelete(state, 0); 343 state.assertEquals("| U+1F469"); 344 forwardDelete(state, 0); 345 state.assertEquals("|"); 346 347 // Start with ZERO WIDTH JOINER + emoji modifier 348 state.setByString("| U+200D U+1F3FB"); 349 forwardDelete(state, 0); 350 state.assertEquals("| U+1F3FB"); 351 352 // ZERO WIDTH JOINER + emoji modifier 353 state.setByString("| U+1F469 U+200D U+1F3FB"); 354 forwardDelete(state, 0); 355 state.assertEquals("| U+1F3FB"); 356 357 // Emoji modifier + end with ZERO WIDTH JOINER 358 state.setByString("| U+1F466 U+1F3FB U+200D"); 359 forwardDelete(state, 0); 360 state.assertEquals("|"); 361 362 // Emoji modifier + ZERO WIDTH JOINER 363 state.setByString("| U+1F466 U+1F3FB U+200D U+1F469"); 364 forwardDelete(state, 0); 365 state.assertEquals("| U+1F469"); 366 forwardDelete(state, 0); 367 state.assertEquals("|"); 368 369 // Regional indicator symbol + emoji modifier 370 state.setByString("| U+1F1FA U+1F3FB"); 371 forwardDelete(state, 0); 372 state.assertEquals("| U+1F3FB"); 373 forwardDelete(state, 0); 374 state.assertEquals("|"); 375 376 // Emoji modifier + regional indicator symbol 377 state.setByString("| U+1F466 U+1F3FB U+1F1FA"); 378 forwardDelete(state, 0); 379 state.assertEquals("| U+1F1FA"); 380 forwardDelete(state, 0); 381 state.assertEquals("|"); 382 } 383} 384