Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2008 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.assertEquals;
     20 import static org.junit.Assert.assertFalse;
     21 import static org.junit.Assert.assertTrue;
     22 
     23 import android.os.SystemClock;
     24 import android.support.test.filters.MediumTest;
     25 import android.support.test.runner.AndroidJUnit4;
     26 import android.text.Editable;
     27 import android.text.InputType;
     28 import android.text.Selection;
     29 import android.text.Spannable;
     30 import android.text.SpannableStringBuilder;
     31 import android.text.method.BaseKeyListener;
     32 import android.view.KeyCharacterMap;
     33 import android.view.KeyEvent;
     34 import android.widget.TextView.BufferType;
     35 
     36 import com.android.compatibility.common.util.CtsKeyEventUtil;
     37 
     38 import org.junit.Test;
     39 import org.junit.runner.RunWith;
     40 
     41 /**
     42  * Test {@link android.text.method.BaseKeyListener}.
     43  */
     44 @MediumTest
     45 @RunWith(AndroidJUnit4.class)
     46 public class BaseKeyListenerTest extends KeyListenerTestCase {
     47     private static final CharSequence TEST_STRING = "123456";
     48 
     49     @Test
     50     public void testBackspace() throws Throwable {
     51         verifyBackspace(0);
     52     }
     53 
     54     private void verifyBackspace(int modifiers) throws Throwable {
     55         final BaseKeyListener mockBaseKeyListener = new MockBaseKeyListener();
     56         final KeyEvent event = getKey(KeyEvent.KEYCODE_DEL, modifiers);
     57         Editable content = Editable.Factory.getInstance().newEditable(TEST_STRING);
     58 
     59         // Nothing to delete when the cursor is at the beginning.
     60         prepTextViewSync(content, mockBaseKeyListener, false, 0, 0);
     61         mockBaseKeyListener.backspace(mTextView, content, event.getKeyCode(), event);
     62         assertEquals("123456", content.toString());
     63 
     64         // Delete the first three letters using a selection.
     65         prepTextViewSync(content, mockBaseKeyListener, false, 0, 3);
     66         mockBaseKeyListener.backspace(mTextView, content, event.getKeyCode(), event);
     67         assertEquals("456", content.toString());
     68 
     69         // Delete the character prior to the cursor when there's no selection
     70         prepTextViewSync(content, mockBaseKeyListener, false, 2, 2);
     71         mockBaseKeyListener.backspace(mTextView, content, event.getKeyCode(), event);
     72         assertEquals("46", content.toString());
     73         mockBaseKeyListener.backspace(mTextView, content, event.getKeyCode(), event);
     74         assertEquals("6", content.toString());
     75 
     76         // The deletion works on a Logical direction basis in RTL text..
     77         String testText = "\u05E9\u05DC\u05D5\u05DD\u002E";
     78         content = Editable.Factory.getInstance().newEditable(testText);
     79 
     80         prepTextViewSync(content, mockBaseKeyListener, false, 0, 0);
     81         mockBaseKeyListener.backspace(mTextView, content, event.getKeyCode(), event);
     82         assertEquals(testText, content.toString());
     83 
     84         int end = testText.length();
     85         prepTextViewSync(content, mockBaseKeyListener, false, end, end);
     86         mockBaseKeyListener.backspace(mTextView, content, event.getKeyCode(), event);
     87         assertEquals("\u05E9\u05DC\u05D5\u05DD", content.toString());
     88 
     89         int middle = testText.length() / 2;
     90         prepTextViewSync(content, mockBaseKeyListener, false, middle, middle);
     91         mockBaseKeyListener.backspace(mTextView, content, event.getKeyCode(), event);
     92         assertEquals("\u05E9\u05D5\u05DD", content.toString());
     93 
     94         // And in BiDi text
     95         testText = "\u05D6\u05D4\u0020Android\u0020\u05E2\u05D5\u05D1\u05D3";
     96         content = Editable.Factory.getInstance().newEditable(testText);
     97 
     98         prepTextViewSync(content, mockBaseKeyListener, false, 0, 0);
     99         mockBaseKeyListener.backspace(mTextView, content, event.getKeyCode(), event);
    100         assertEquals(content.toString(), content.toString());
    101 
    102         end = testText.length();
    103         prepTextViewSync(content, mockBaseKeyListener, false, end, end);
    104         mockBaseKeyListener.backspace(mTextView, content, event.getKeyCode(), event);
    105         assertEquals("\u05D6\u05D4\u0020Android\u0020\u05E2\u05D5\u05D1", content.toString());
    106 
    107         prepTextViewSync(content, mockBaseKeyListener, false, 6, 6);
    108         mockBaseKeyListener.backspace(mTextView, content, event.getKeyCode(), event);
    109         assertEquals("\u05D6\u05D4\u0020Anroid\u0020\u05E2\u05D5\u05D1", content.toString());
    110     }
    111 
    112     @Test
    113     public void testBackspace_withShift() throws Throwable {
    114         verifyBackspace(KeyEvent.META_SHIFT_ON | KeyEvent.META_SHIFT_LEFT_ON);
    115     }
    116 
    117     @Test
    118     public void testBackspace_withAlt() throws Throwable {
    119         final BaseKeyListener mockBaseKeyListener = new MockBaseKeyListener();
    120         Editable content = Editable.Factory.getInstance().newEditable(TEST_STRING);
    121 
    122         // Delete the entire line with ALT + DEL, even if we're at the head...
    123         prepTextViewSync(content, mockBaseKeyListener, false, 0, 0);
    124         executeAltBackspace(content, mockBaseKeyListener);
    125         assertEquals("", content.toString());
    126 
    127         // ...or the tail...
    128         content = Editable.Factory.getInstance().newEditable(TEST_STRING);
    129         final int end = TEST_STRING.length();
    130         prepTextViewSync(content, mockBaseKeyListener, false, end, end);
    131         executeAltBackspace(content, mockBaseKeyListener);
    132         assertEquals("", content.toString());
    133 
    134         // ...or somewhere in the middle.
    135         content = Editable.Factory.getInstance().newEditable(TEST_STRING);
    136         final int middle = end / 2;
    137         prepTextViewSync(content, mockBaseKeyListener, false, middle, middle);
    138         executeAltBackspace(content, mockBaseKeyListener);
    139         assertEquals("", content.toString());
    140     }
    141 
    142     @Test
    143     public void testBackspace_withSendKeys() throws Throwable {
    144         final BaseKeyListener mockBaseKeyListener = new MockBaseKeyListener();
    145 
    146         // Delete the first character '1'
    147         prepTextViewSync(TEST_STRING, mockBaseKeyListener, true, 1, 1);
    148         CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_DEL);
    149         assertEquals("23456", mTextView.getText().toString());
    150 
    151         // Delete character '2' and '3'
    152         prepTextViewSync(TEST_STRING, mockBaseKeyListener, true, 1, 3);
    153         CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_DEL);
    154         assertEquals("1456", mTextView.getText().toString());
    155 
    156         // Delete everything on the line the cursor is on.
    157         prepTextViewSync(TEST_STRING, mockBaseKeyListener, true, 0, 0);
    158         CtsKeyEventUtil.sendKeyWhileHoldingModifier(
    159                 mInstrumentation, mTextView, KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_ALT_LEFT);
    160         assertEquals("", mTextView.getText().toString());
    161 
    162         // ALT+DEL deletes the selection only.
    163         prepTextViewSync(TEST_STRING, mockBaseKeyListener, true, 2, 4);
    164         CtsKeyEventUtil.sendKeyWhileHoldingModifier(
    165                 mInstrumentation, mTextView, KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_ALT_LEFT);
    166         assertEquals("1256", mTextView.getText().toString());
    167 
    168         // DEL key does not take effect when TextView does not have BaseKeyListener.
    169         prepTextViewSync(TEST_STRING, null, true, 1, 1);
    170         CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_DEL);
    171         assertEquals(TEST_STRING, mTextView.getText().toString());
    172     }
    173 
    174     private void verifyCursorPosition(Editable content, int offset) {
    175         assertEquals(offset, Selection.getSelectionStart(content));
    176         assertEquals(offset, Selection.getSelectionEnd(content));
    177     }
    178 
    179     @Test
    180     public void testBackspace_withCtrl() throws Throwable {
    181         final BaseKeyListener mockBaseKeyListener = new MockBaseKeyListener();
    182 
    183         // If the contents only having symbolic characters, delete all characters.
    184         String testText = "!#$%&'()`{*}_?+";
    185         Editable content = Editable.Factory.getInstance().newEditable(testText);
    186         prepTextViewSync(content, mockBaseKeyListener, false, testText.length(), testText.length());
    187         executeCtrlBackspace(content, mockBaseKeyListener);
    188         assertEquals("", content.toString());
    189         verifyCursorPosition(content, 0);
    190 
    191         // Latin ASCII text
    192         testText = "Hello, World. This is Android.";
    193         content = Editable.Factory.getInstance().newEditable(testText);
    194 
    195         // If the cursor is head of the text, should do nothing.
    196         prepTextViewSync(content, mockBaseKeyListener, false, 0, 0);
    197         executeCtrlBackspace(content, mockBaseKeyListener);
    198         assertEquals("Hello, World. This is Android.", content.toString());
    199         verifyCursorPosition(content, 0);
    200 
    201         prepTextViewSync(content, mockBaseKeyListener, false, testText.length(), testText.length());
    202         executeCtrlBackspace(content, mockBaseKeyListener);
    203         assertEquals("Hello, World. This is ", content.toString());
    204         verifyCursorPosition(content, content.toString().length());
    205 
    206         executeCtrlBackspace(content, mockBaseKeyListener);
    207         assertEquals("Hello, World. This ", content.toString());
    208         verifyCursorPosition(content, content.toString().length());
    209 
    210         executeCtrlBackspace(content, mockBaseKeyListener);
    211         assertEquals("Hello, World. ", content.toString());
    212         verifyCursorPosition(content, content.toString().length());
    213 
    214         executeCtrlBackspace(content, mockBaseKeyListener);
    215         assertEquals("Hello, ", content.toString());
    216         verifyCursorPosition(content, content.toString().length());
    217 
    218         executeCtrlBackspace(content, mockBaseKeyListener);
    219         assertEquals("", content.toString());
    220         verifyCursorPosition(content, 0);
    221 
    222         executeCtrlBackspace(content, mockBaseKeyListener);
    223         assertEquals("", content.toString());
    224         verifyCursorPosition(content, 0);
    225 
    226         // Latin ASCII, cursor is middle of the text.
    227         testText = "Hello, World. This is Android.";
    228         content = Editable.Factory.getInstance().newEditable(testText);
    229         int charsFromTail = 12;  // Cursor location is 12 chars from the tail.(before "is").
    230         prepTextViewSync(content, mockBaseKeyListener, false,
    231                          testText.length() - charsFromTail, testText.length() - charsFromTail);
    232 
    233         executeCtrlBackspace(content, mockBaseKeyListener);
    234         assertEquals("Hello, World.  is Android.", content.toString());
    235         verifyCursorPosition(content, content.toString().length() - charsFromTail);
    236 
    237         executeCtrlBackspace(content, mockBaseKeyListener);
    238         assertEquals("Hello,  is Android.", content.toString());
    239         verifyCursorPosition(content, content.toString().length() - charsFromTail);
    240 
    241         executeCtrlBackspace(content, mockBaseKeyListener);
    242         assertEquals(" is Android.", content.toString());
    243         verifyCursorPosition(content, 0);
    244 
    245         executeCtrlBackspace(content, mockBaseKeyListener);
    246         assertEquals(" is Android.", content.toString());
    247         verifyCursorPosition(content, 0);
    248 
    249         // Latin ASCII, cursor is inside word.
    250         testText = "Hello, World. This is Android.";
    251         content = Editable.Factory.getInstance().newEditable(testText);
    252         charsFromTail = 14;  // Cursor location is 12 chars from the tail. (inside "This")
    253         prepTextViewSync(content, mockBaseKeyListener, false,
    254                          testText.length() - charsFromTail, testText.length() - charsFromTail);
    255 
    256 
    257         executeCtrlBackspace(content, mockBaseKeyListener);
    258         assertEquals("Hello, World. is is Android.", content.toString());
    259         verifyCursorPosition(content, content.toString().length() - charsFromTail);
    260 
    261         executeCtrlBackspace(content, mockBaseKeyListener);
    262         assertEquals("Hello, is is Android.", content.toString());
    263         verifyCursorPosition(content, content.toString().length() - charsFromTail);
    264 
    265         executeCtrlBackspace(content, mockBaseKeyListener);
    266         assertEquals("is is Android.", content.toString());
    267         verifyCursorPosition(content, 0);
    268 
    269         executeCtrlBackspace(content, mockBaseKeyListener);
    270         assertEquals("is is Android.", content.toString());
    271         verifyCursorPosition(content, 0);
    272 
    273         // Hebrew Text
    274         // The deletion works on a Logical direction basis.
    275         testText = "\u05E9\u05DC\u05D5\u05DD\u0020\u05D4\u05E2\u05D5\u05DC\u05DD\u002E\u0020" +
    276                    "\u05D6\u05D4\u0020\u05D0\u05E0\u05D3\u05E8\u05D5\u05D0\u05D9\u05D3\u002E";
    277         content = Editable.Factory.getInstance().newEditable(testText);
    278         prepTextViewSync(content, mockBaseKeyListener, false, testText.length(), testText.length());
    279 
    280         executeCtrlBackspace(content, mockBaseKeyListener);
    281         assertEquals("\u05E9\u05DC\u05D5\u05DD\u0020\u05D4\u05E2\u05D5\u05DC\u05DD\u002E\u0020" +
    282                      "\u05D6\u05D4\u0020", content.toString());
    283         verifyCursorPosition(content, content.toString().length());
    284 
    285         executeCtrlBackspace(content, mockBaseKeyListener);
    286         assertEquals("\u05E9\u05DC\u05D5\u05DD\u0020\u05D4\u05E2\u05D5\u05DC\u05DD\u002E\u0020",
    287                      content.toString());
    288         verifyCursorPosition(content, content.toString().length());
    289 
    290         executeCtrlBackspace(content, mockBaseKeyListener);
    291         assertEquals("\u05E9\u05DC\u05D5\u05DD\u0020", content.toString());
    292         verifyCursorPosition(content, content.toString().length());
    293 
    294         executeCtrlBackspace(content, mockBaseKeyListener);
    295         assertEquals("", content.toString());
    296         verifyCursorPosition(content, 0);
    297 
    298         executeCtrlBackspace(content, mockBaseKeyListener);
    299         assertEquals("", content.toString());
    300         verifyCursorPosition(content, 0);
    301 
    302         // BiDi Text
    303         // The deletion works on a Logical direction basis.
    304         testText = "\u05D6\u05D4\u0020\u05DC\u002D\u0020\u0041Android\u0020\u05E2\u05D5\u05D1" +
    305                    "\u05D3\u0020\u05D4\u05D9\u05D8\u05D1\u002E";
    306         content = Editable.Factory.getInstance().newEditable(testText);
    307         prepTextViewSync(content, mockBaseKeyListener, false, testText.length(), testText.length());
    308 
    309         executeCtrlBackspace(content, mockBaseKeyListener);
    310         assertEquals("\u05D6\u05D4\u0020\u05DC\u002D\u0020\u0041Android\u0020\u05E2\u05D5\u05D1" +
    311                      "\u05D3\u0020", content.toString());
    312         verifyCursorPosition(content, content.toString().length());
    313 
    314         executeCtrlBackspace(content, mockBaseKeyListener);
    315         assertEquals("\u05D6\u05D4\u0020\u05DC\u002D\u0020\u0041Android\u0020", content.toString());
    316         verifyCursorPosition(content, content.toString().length());
    317 
    318         executeCtrlBackspace(content, mockBaseKeyListener);
    319         assertEquals("\u05D6\u05D4\u0020\u05DC\u002D\u0020", content.toString());
    320         verifyCursorPosition(content, content.toString().length());
    321 
    322         executeCtrlBackspace(content, mockBaseKeyListener);
    323         assertEquals("\u05D6\u05D4\u0020", content.toString());
    324         verifyCursorPosition(content, content.toString().length());
    325 
    326         executeCtrlBackspace(content, mockBaseKeyListener);
    327         assertEquals("", content.toString());
    328         verifyCursorPosition(content, 0);
    329 
    330         executeCtrlBackspace(content, mockBaseKeyListener);
    331         assertEquals("", content.toString());
    332         verifyCursorPosition(content, 0);
    333     }
    334 
    335     @Test
    336     public void testForwardDelete_withCtrl() throws Throwable {
    337         final BaseKeyListener mockBaseKeyListener = new MockBaseKeyListener();
    338 
    339         // If the contents only having symbolic characters, delete all characters.
    340         String testText = "!#$%&'()`{*}_?+";
    341         Editable content = Editable.Factory.getInstance().newEditable(testText);
    342         prepTextViewSync(content, mockBaseKeyListener, false, 0, 0);
    343         executeCtrlForwardDelete(content, mockBaseKeyListener);
    344         assertEquals("", content.toString());
    345         verifyCursorPosition(content, 0);
    346 
    347         // Latin ASCII text
    348         testText = "Hello, World. This is Android.";
    349         content = Editable.Factory.getInstance().newEditable(testText);
    350 
    351         // If the cursor is tail of the text, should do nothing.
    352         prepTextViewSync(content, mockBaseKeyListener, false, testText.length(), testText.length());
    353         executeCtrlForwardDelete(content, mockBaseKeyListener);
    354         assertEquals("Hello, World. This is Android.", content.toString());
    355         verifyCursorPosition(content, testText.length());
    356 
    357         prepTextViewSync(content, mockBaseKeyListener, false, 0, 0);
    358         executeCtrlForwardDelete(content, mockBaseKeyListener);
    359         assertEquals(", World. This is Android.", content.toString());
    360         verifyCursorPosition(content, 0);
    361 
    362         executeCtrlForwardDelete(content, mockBaseKeyListener);
    363         assertEquals(". This is Android.", content.toString());
    364         verifyCursorPosition(content, 0);
    365 
    366         executeCtrlForwardDelete(content, mockBaseKeyListener);
    367         assertEquals(" is Android.", content.toString());
    368         verifyCursorPosition(content, 0);
    369 
    370         executeCtrlForwardDelete(content, mockBaseKeyListener);
    371         assertEquals(" Android.", content.toString());
    372         verifyCursorPosition(content, 0);
    373 
    374         executeCtrlForwardDelete(content, mockBaseKeyListener);
    375         assertEquals(".", content.toString());
    376         verifyCursorPosition(content, 0);
    377 
    378         executeCtrlForwardDelete(content, mockBaseKeyListener);
    379         assertEquals("", content.toString());
    380         verifyCursorPosition(content, 0);
    381 
    382         executeCtrlForwardDelete(content, mockBaseKeyListener);
    383         assertEquals("", content.toString());
    384         verifyCursorPosition(content, 0);
    385 
    386         // Latin ASCII, cursor is middle of the text.
    387         testText = "Hello, World. This is Android.";
    388         content = Editable.Factory.getInstance().newEditable(testText);
    389         int charsFromHead = 14;  // Cursor location is 14 chars from the head.(before "This").
    390         prepTextViewSync(content, mockBaseKeyListener, false, charsFromHead, charsFromHead);
    391 
    392         executeCtrlForwardDelete(content, mockBaseKeyListener);
    393         assertEquals("Hello, World.  is Android.", content.toString());
    394         verifyCursorPosition(content, charsFromHead);
    395 
    396         executeCtrlForwardDelete(content, mockBaseKeyListener);
    397         assertEquals("Hello, World.  Android.", content.toString());
    398         verifyCursorPosition(content, charsFromHead);
    399 
    400         executeCtrlForwardDelete(content, mockBaseKeyListener);
    401         assertEquals("Hello, World. .", content.toString());
    402         verifyCursorPosition(content, charsFromHead);
    403 
    404         executeCtrlForwardDelete(content, mockBaseKeyListener);
    405         assertEquals("Hello, World. ", content.toString());
    406         verifyCursorPosition(content, charsFromHead);
    407 
    408         executeCtrlForwardDelete(content, mockBaseKeyListener);
    409         assertEquals("Hello, World. ", content.toString());
    410         verifyCursorPosition(content, charsFromHead);
    411 
    412         // Latin ASCII, cursor is inside word.
    413         testText = "Hello, World. This is Android.";
    414         content = Editable.Factory.getInstance().newEditable(testText);
    415         charsFromHead = 16;  // Cursor location is 16 chars from the head. (inside "This")
    416         prepTextViewSync(content, mockBaseKeyListener, false, charsFromHead, charsFromHead);
    417 
    418         executeCtrlForwardDelete(content, mockBaseKeyListener);
    419         assertEquals("Hello, World. Th is Android.", content.toString());
    420         verifyCursorPosition(content, charsFromHead);
    421 
    422         executeCtrlForwardDelete(content, mockBaseKeyListener);
    423         assertEquals("Hello, World. Th Android.", content.toString());
    424         verifyCursorPosition(content, charsFromHead);
    425 
    426         executeCtrlForwardDelete(content, mockBaseKeyListener);
    427         assertEquals("Hello, World. Th.", content.toString());
    428         verifyCursorPosition(content, charsFromHead);
    429 
    430         executeCtrlForwardDelete(content, mockBaseKeyListener);
    431         assertEquals("Hello, World. Th", content.toString());
    432         verifyCursorPosition(content, charsFromHead);
    433 
    434         executeCtrlForwardDelete(content, mockBaseKeyListener);
    435         assertEquals("Hello, World. Th", content.toString());
    436         verifyCursorPosition(content, charsFromHead);
    437 
    438         // Hebrew Text
    439         // The deletion works on a Logical direction basis.
    440         testText = "\u05E9\u05DC\u05D5\u05DD\u0020\u05D4\u05E2\u05D5\u05DC\u05DD\u002E\u0020" +
    441                    "\u05D6\u05D4\u0020\u05D0\u05E0\u05D3\u05E8\u05D5\u05D0\u05D9\u05D3\u002E";
    442         content = Editable.Factory.getInstance().newEditable(testText);
    443         prepTextViewSync(content, mockBaseKeyListener, false, 0, 0);
    444 
    445         executeCtrlForwardDelete(content, mockBaseKeyListener);
    446         assertEquals("\u0020\u05D4\u05E2\u05D5\u05DC\u05DD\u002E\u0020\u05D6\u05D4\u0020\u05D0" +
    447                      "\u05E0\u05D3\u05E8\u05D5\u05D0\u05D9\u05D3\u002E", content.toString());
    448         verifyCursorPosition(content, 0);
    449 
    450         executeCtrlForwardDelete(content, mockBaseKeyListener);
    451         assertEquals("\u002E\u0020\u05D6\u05D4\u0020\u05D0\u05E0\u05D3\u05E8\u05D5\u05D0\u05D9" +
    452                 "\u05D3\u002E", content.toString());
    453         verifyCursorPosition(content, 0);
    454 
    455         executeCtrlForwardDelete(content, mockBaseKeyListener);
    456         assertEquals("\u0020\u05D0\u05E0\u05D3\u05E8\u05D5\u05D0\u05D9\u05D3\u002E",
    457                      content.toString());
    458         verifyCursorPosition(content, 0);
    459 
    460         executeCtrlForwardDelete(content, mockBaseKeyListener);
    461         assertEquals("\u002E", content.toString());
    462         verifyCursorPosition(content, 0);
    463 
    464         executeCtrlForwardDelete(content, mockBaseKeyListener);
    465         assertEquals("", content.toString());
    466         verifyCursorPosition(content, 0);
    467 
    468         executeCtrlForwardDelete(content, mockBaseKeyListener);
    469         assertEquals("", content.toString());
    470         verifyCursorPosition(content, 0);
    471 
    472         // BiDi Text
    473         // The deletion works on a Logical direction basis.
    474         testText = "\u05D6\u05D4\u0020\u05DC\u002D\u0020\u0041Android\u0020\u05E2\u05D5\u05D1" +
    475                    "\u05D3\u0020\u05D4\u05D9\u05D8\u05D1\u002E";
    476         content = Editable.Factory.getInstance().newEditable(testText);
    477         prepTextViewSync(content, mockBaseKeyListener, false, 0, 0);
    478 
    479         executeCtrlForwardDelete(content, mockBaseKeyListener);
    480         assertEquals("\u0020\u05DC\u002D\u0020\u0041Android\u0020\u05E2\u05D5\u05D1\u05D3\u0020" +
    481                      "\u05D4\u05D9\u05D8\u05D1\u002E", content.toString());
    482         verifyCursorPosition(content, 0);
    483 
    484         executeCtrlForwardDelete(content, mockBaseKeyListener);
    485         assertEquals("\u002D\u0020\u0041Android\u0020\u05E2\u05D5\u05D1\u05D3\u0020\u05D4\u05D9" +
    486                      "\u05D8\u05D1\u002E", content.toString());
    487         verifyCursorPosition(content, 0);
    488 
    489         executeCtrlForwardDelete(content, mockBaseKeyListener);
    490         assertEquals("\u0020\u05E2\u05D5\u05D1\u05D3\u0020\u05D4\u05D9\u05D8\u05D1\u002E",
    491                      content.toString());
    492         verifyCursorPosition(content, 0);
    493 
    494         executeCtrlForwardDelete(content, mockBaseKeyListener);
    495         assertEquals("\u0020\u05D4\u05D9\u05D8\u05D1\u002E", content.toString());
    496         verifyCursorPosition(content, 0);
    497 
    498         executeCtrlForwardDelete(content, mockBaseKeyListener);
    499         assertEquals("\u002E", content.toString());
    500         verifyCursorPosition(content, 0);
    501 
    502         executeCtrlForwardDelete(content, mockBaseKeyListener);
    503         assertEquals("", content.toString());
    504         verifyCursorPosition(content, 0);
    505 
    506         executeCtrlForwardDelete(content, mockBaseKeyListener);
    507         assertEquals("", content.toString());
    508         verifyCursorPosition(content, 0);
    509     }
    510 
    511     /*
    512      * Check point:
    513      * 1. Press 0 key, the content of TextView does not changed.
    514      * 2. Set a selection and press DEL key, the selection is deleted.
    515      * 3. ACTION_MULTIPLE KEYCODE_UNKNOWN by inserting the event's text into the content.
    516      */
    517     @Test
    518     public void testPressKey() throws Throwable {
    519         final BaseKeyListener mockBaseKeyListener = new MockBaseKeyListener();
    520 
    521         // press '0' key.
    522         prepTextViewSync(TEST_STRING, mockBaseKeyListener, true, 0, 0);
    523         CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_0);
    524         assertEquals("123456", mTextView.getText().toString());
    525 
    526         // delete character '2'
    527         prepTextViewSync(mTextView.getText(), mockBaseKeyListener, true, 1, 2);
    528         CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_DEL);
    529         assertEquals("13456", mTextView.getText().toString());
    530 
    531         // test ACTION_MULTIPLE KEYCODE_UNKNOWN key event.
    532         KeyEvent event = new KeyEvent(SystemClock.uptimeMillis(), "abcd",
    533                 KeyCharacterMap.BUILT_IN_KEYBOARD, 0);
    534         prepTextViewSync(mTextView.getText(), mockBaseKeyListener, true, 2, 2);
    535         CtsKeyEventUtil.sendKey(mInstrumentation, mTextView, event);
    536         mInstrumentation.waitForIdleSync();
    537         // the text of TextView is never changed, onKeyOther never works.
    538 //        assertEquals("13abcd456", mTextView.getText().toString());
    539     }
    540 
    541     @Test
    542     public void testOnKeyOther() {
    543         final BaseKeyListener mockBaseKeyListener = new MockBaseKeyListener();
    544         final String string = "abc";
    545         final SpannableStringBuilder content = new SpannableStringBuilder(string);
    546 
    547         KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_UNKNOWN);
    548         assertFalse(mockBaseKeyListener.onKeyOther(mTextView, content, event));
    549         assertEquals(string, content.toString());
    550 
    551         event = new KeyEvent(KeyEvent.ACTION_MULTIPLE, KeyEvent.KEYCODE_0);
    552         assertFalse(mockBaseKeyListener.onKeyOther(mTextView, content, event));
    553         assertEquals(string, content.toString());
    554 
    555         Selection.setSelection(content, 1, 0);
    556         event = new KeyEvent(KeyEvent.ACTION_MULTIPLE, KeyEvent.KEYCODE_UNKNOWN);
    557         assertFalse(mockBaseKeyListener.onKeyOther(mTextView, content, event));
    558         assertEquals(string, content.toString());
    559 
    560         event = new KeyEvent(SystemClock.uptimeMillis(), "b", 0, 0);
    561         assertTrue(mockBaseKeyListener.onKeyOther(mTextView, content, event));
    562         assertEquals("bbc", content.toString());
    563     }
    564 
    565     private void executeAltBackspace(Editable content, BaseKeyListener listener) {
    566         final KeyEvent delKeyEvent = getKey(KeyEvent.KEYCODE_DEL,
    567                 KeyEvent.META_ALT_ON | KeyEvent.META_ALT_LEFT_ON);
    568         listener.backspace(mTextView, content, KeyEvent.KEYCODE_DEL, delKeyEvent);
    569     }
    570 
    571     private void executeCtrlBackspace(Editable content, BaseKeyListener listener) {
    572         final KeyEvent delKeyEvent = getKey(KeyEvent.KEYCODE_DEL,
    573                 KeyEvent.META_CTRL_ON | KeyEvent.META_CTRL_LEFT_ON);
    574         listener.backspace(mTextView, content, KeyEvent.KEYCODE_DEL, delKeyEvent);
    575     }
    576 
    577     private void executeCtrlForwardDelete(Editable content, BaseKeyListener listener) {
    578         final KeyEvent delKeyEvent = getKey(KeyEvent.KEYCODE_FORWARD_DEL,
    579                 KeyEvent.META_CTRL_ON | KeyEvent.META_CTRL_LEFT_ON);
    580         listener.forwardDelete(mTextView, content, KeyEvent.KEYCODE_FORWARD_DEL, delKeyEvent);
    581     }
    582 
    583     /**
    584      * Prepares mTextView state for tests by synchronously setting the content and key listener, on
    585      * the UI thread.
    586      */
    587     private void prepTextViewSync(final CharSequence content, final BaseKeyListener keyListener,
    588             final boolean selectInTextView, final int selectionStart, final int selectionEnd)
    589                     throws Throwable {
    590         mActivityRule.runOnUiThread(() -> {
    591             mTextView.setText(content, BufferType.EDITABLE);
    592             mTextView.setKeyListener(keyListener);
    593             Selection.setSelection(
    594                     selectInTextView ? mTextView.getText() : (Spannable) content,
    595                     selectionStart, selectionEnd);
    596         });
    597         mInstrumentation.waitForIdleSync();
    598         assertTrue(mTextView.hasWindowFocus());
    599     }
    600 
    601     /**
    602      * A mocked {@link android.text.method.BaseKeyListener} for testing purposes.
    603      */
    604     private class MockBaseKeyListener extends BaseKeyListener {
    605         public int getInputType() {
    606             return InputType.TYPE_CLASS_DATETIME
    607                     | InputType.TYPE_DATETIME_VARIATION_DATE;
    608         }
    609     }
    610 }
    611