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