TextViewActivityTest.java revision c5b54bae62d5d82a576ca267202675652144185c
1/*
2 * Copyright (C) 2015 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.widget;
18
19import static android.widget.espresso.CustomViewActions.longPressAtRelativeCoordinates;
20import static android.widget.espresso.DragHandleUtils.assertNoSelectionHandles;
21import static android.widget.espresso.DragHandleUtils.onHandleView;
22import static android.widget.espresso.TextViewActions.clickOnTextAtIndex;
23import static android.widget.espresso.TextViewActions.doubleTapAndDragOnText;
24import static android.widget.espresso.TextViewActions.doubleClickOnTextAtIndex;
25import static android.widget.espresso.TextViewActions.dragHandle;
26import static android.widget.espresso.TextViewActions.Handle;
27import static android.widget.espresso.TextViewActions.longPressAndDragOnText;
28import static android.widget.espresso.TextViewActions.longPressOnTextAtIndex;
29import static android.widget.espresso.TextViewAssertions.hasInsertionPointerAtIndex;
30import static android.widget.espresso.TextViewAssertions.hasSelection;
31import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarIsDisplayed;
32import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarIsNotDisplayed;
33import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarContainsItem;
34import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarDoesNotContainItem;
35import static android.widget.espresso.FloatingToolbarEspressoUtils.clickFloatingToolbarItem;
36import static android.widget.espresso.FloatingToolbarEspressoUtils.sleepForFloatingToolbarPopup;
37import static android.support.test.espresso.Espresso.onView;
38import static android.support.test.espresso.action.ViewActions.click;
39import static android.support.test.espresso.action.ViewActions.longClick;
40import static android.support.test.espresso.action.ViewActions.pressKey;
41import static android.support.test.espresso.action.ViewActions.replaceText;
42import static android.support.test.espresso.action.ViewActions.typeTextIntoFocusedView;
43import static android.support.test.espresso.assertion.ViewAssertions.matches;
44import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
45import static android.support.test.espresso.matcher.ViewMatchers.withId;
46import static android.support.test.espresso.matcher.ViewMatchers.withText;
47import static org.hamcrest.Matchers.anyOf;
48import static org.hamcrest.Matchers.is;
49
50import android.widget.espresso.CustomViewActions.RelativeCoordinatesProvider;
51
52import android.support.test.espresso.action.EspressoKey;
53import android.test.ActivityInstrumentationTestCase2;
54import android.test.suitebuilder.annotation.MediumTest;
55import android.text.Selection;
56import android.text.Spannable;
57import android.text.InputType;
58import android.view.KeyEvent;
59
60import com.android.frameworks.coretests.R;
61
62/**
63 * Tests the TextView widget from an Activity
64 */
65@MediumTest
66public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextViewActivity>{
67
68    public TextViewActivityTest() {
69        super(TextViewActivity.class);
70    }
71
72    @Override
73    public void setUp() throws Exception {
74        super.setUp();
75        getActivity();
76    }
77
78    public void testTypedTextIsOnScreen() throws Exception {
79        final String helloWorld = "Hello world!";
80        onView(withId(R.id.textview)).perform(click());
81        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
82
83        onView(withId(R.id.textview)).check(matches(withText(helloWorld)));
84    }
85
86    public void testPositionCursorAtTextAtIndex() throws Exception {
87        final String helloWorld = "Hello world!";
88        onView(withId(R.id.textview)).perform(click());
89        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
90        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(helloWorld.indexOf("world")));
91
92        // Delete text at specified index and see if we got the right one.
93        onView(withId(R.id.textview)).perform(pressKey(KeyEvent.KEYCODE_FORWARD_DEL));
94        onView(withId(R.id.textview)).check(matches(withText("Hello orld!")));
95    }
96
97    public void testPositionCursorAtTextAtIndex_arabic() throws Exception {
98        // Arabic text. The expected cursorable boundary is
99        // | \u0623 \u064F | \u067A | \u0633 \u0652 |
100        final String text = "\u0623\u064F\u067A\u0633\u0652";
101        onView(withId(R.id.textview)).perform(click());
102        onView(withId(R.id.textview)).perform(replaceText(text));
103
104        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(0));
105        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(0));
106        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(1));
107        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(anyOf(is(0), is(2))));
108        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(2));
109        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(2));
110        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(3));
111        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(3));
112        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(4));
113        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(anyOf(is(3), is(5))));
114        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(5));
115        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(5));
116    }
117
118    public void testPositionCursorAtTextAtIndex_devanagari() throws Exception {
119        // Devanagari text. The expected cursorable boundary is | \u0915 \u093E |
120        final String text = "\u0915\u093E";
121        onView(withId(R.id.textview)).perform(click());
122        onView(withId(R.id.textview)).perform(replaceText(text));
123
124        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(0));
125        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(0));
126        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(1));
127        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(anyOf(is(0), is(2))));
128        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(2));
129        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(2));
130    }
131
132    public void testLongPressToSelect() throws Exception {
133        final String helloWorld = "Hello Kirk!";
134        onView(withId(R.id.textview)).perform(click());
135        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
136        onView(withId(R.id.textview)).perform(
137                longPressOnTextAtIndex(helloWorld.indexOf("Kirk")));
138
139        onView(withId(R.id.textview)).check(hasSelection("Kirk"));
140    }
141
142    public void testLongPressEmptySpace() throws Exception {
143        final String helloWorld = "Hello big round sun!";
144        onView(withId(R.id.textview)).perform(click());
145        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
146        // Move cursor somewhere else
147        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(helloWorld.indexOf("big")));
148        // Long-press at end of line.
149        onView(withId(R.id.textview)).perform(longPressAtRelativeCoordinates(
150                RelativeCoordinatesProvider.HorizontalReference.RIGHT, -5,
151                RelativeCoordinatesProvider.VerticalReference.CENTER, 0));
152
153        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(helloWorld.length()));
154    }
155
156    public void testLongPressAndDragToSelect() throws Exception {
157        final String helloWorld = "Hello little handsome boy!";
158        onView(withId(R.id.textview)).perform(click());
159        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
160        onView(withId(R.id.textview)).perform(
161                longPressAndDragOnText(helloWorld.indexOf("little"), helloWorld.indexOf(" boy!")));
162
163        onView(withId(R.id.textview)).check(hasSelection("little handsome"));
164    }
165
166    public void testLongPressAndDragToSelect_emoji() throws Exception {
167        final String text = "\uD83D\uDE00\uD83D\uDE01\uD83D\uDE02\uD83D\uDE03";
168        onView(withId(R.id.textview)).perform(click());
169        onView(withId(R.id.textview)).perform(replaceText(text));
170
171        onView(withId(R.id.textview)).perform(longPressAndDragOnText(4, 6));
172        onView(withId(R.id.textview)).check(hasSelection("\uD83D\uDE02"));
173
174        onView(withId(R.id.textview)).perform(click());
175
176        onView(withId(R.id.textview)).perform(longPressAndDragOnText(4, 2));
177        onView(withId(R.id.textview)).check(hasSelection("\uD83D\uDE01"));
178    }
179
180    public void testDragAndDrop() throws Exception {
181        final String text = "abc def ghi.";
182        onView(withId(R.id.textview)).perform(click());
183        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
184        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf("e")));
185
186        onView(withId(R.id.textview)).perform(
187                longPressAndDragOnText(text.indexOf("e"), text.length()));
188
189        onView(withId(R.id.textview)).check(matches(withText("abc ghi.def")));
190        onView(withId(R.id.textview)).check(hasSelection(""));
191        assertNoSelectionHandles();
192        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex("abc ghi.def".length()));
193
194        // Test undo returns to the original state.
195        onView(withId(R.id.textview)).perform(pressKey(
196                (new EspressoKey.Builder()).withCtrlPressed(true).withKeyCode(KeyEvent.KEYCODE_Z)
197                        .build()));
198        onView(withId(R.id.textview)).check(matches(withText(text)));
199    }
200
201    public void testDoubleTapToSelect() throws Exception {
202        final String helloWorld = "Hello SuetYi!";
203        onView(withId(R.id.textview)).perform(click());
204        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
205        onView(withId(R.id.textview)).perform(
206                doubleClickOnTextAtIndex(helloWorld.indexOf("SuetYi")));
207
208        onView(withId(R.id.textview)).check(hasSelection("SuetYi"));
209    }
210
211    public void testDoubleTapAndDragToSelect() throws Exception {
212        final String helloWorld = "Hello young beautiful girl!";
213        onView(withId(R.id.textview)).perform(click());
214        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
215        onView(withId(R.id.textview)).perform(
216                doubleTapAndDragOnText(helloWorld.indexOf("young"), helloWorld.indexOf(" girl!")));
217
218        onView(withId(R.id.textview)).check(hasSelection("young beautiful"));
219    }
220
221    public void testDoubleTapAndDragToSelect_multiLine() throws Exception {
222        final String helloWorld = "abcd\n" + "efg\n" + "hijklm\n" + "nop";
223        onView(withId(R.id.textview)).perform(click());
224        onView(withId(R.id.textview)).perform(replaceText(helloWorld));
225        onView(withId(R.id.textview)).perform(
226                doubleTapAndDragOnText(helloWorld.indexOf("m"), helloWorld.indexOf("a")));
227        onView(withId(R.id.textview)).check(hasSelection("abcd\nefg\nhijklm"));
228    }
229
230    public void testSelectBackwordsByTouch() throws Exception {
231        final String helloWorld = "Hello king of the Jungle!";
232        onView(withId(R.id.textview)).perform(click());
233        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
234        onView(withId(R.id.textview)).perform(
235                doubleTapAndDragOnText(helloWorld.indexOf(" Jungle!"), helloWorld.indexOf("king")));
236
237        onView(withId(R.id.textview)).check(hasSelection("king of the"));
238    }
239
240    public void testToolbarAppearsAfterSelection() throws Exception {
241        final String text = "Toolbar appears after selection.";
242        onView(withId(R.id.textview)).perform(click());
243        assertFloatingToolbarIsNotDisplayed();
244        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
245        onView(withId(R.id.textview)).perform(
246                longPressOnTextAtIndex(text.indexOf("appears")));
247
248        sleepForFloatingToolbarPopup();
249        assertFloatingToolbarIsDisplayed();
250
251        final String text2 = "Toolbar disappears after typing text.";
252        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text2));
253        assertFloatingToolbarIsNotDisplayed();
254    }
255
256    public void testToolbarAppearsAfterSelection_withFirstStringLtrAlgorithmAndRtlHint()
257            throws Exception {
258        // after the hint layout change, the floating toolbar was not visible in the case below
259        // this test tests that the floating toolbar is displayed on the screen and is visible to
260        // user.
261        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
262        textView.post(new Runnable() {
263            @Override
264            public void run() {
265                textView.setTextDirection(TextView.TEXT_DIRECTION_FIRST_STRONG_LTR);
266                textView.setInputType(InputType.TYPE_CLASS_TEXT);
267                textView.setSingleLine(true);
268                textView.setHint("الروبوت");
269            }
270        });
271        getInstrumentation().waitForIdleSync();
272
273        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView("test"));
274        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(1));
275        clickFloatingToolbarItem(
276                getActivity().getString(com.android.internal.R.string.cut));
277        onView(withId(R.id.textview)).perform(longClick());
278        sleepForFloatingToolbarPopup();
279
280        assertFloatingToolbarIsDisplayed();
281    }
282
283    public void testToolbarAndInsertionHandle() throws Exception {
284        final String text = "text";
285        onView(withId(R.id.textview)).perform(click());
286        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
287        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
288        assertFloatingToolbarIsNotDisplayed();
289
290        onHandleView(com.android.internal.R.id.insertion_handle).perform(click());
291        sleepForFloatingToolbarPopup();
292        assertFloatingToolbarIsDisplayed();
293
294        assertFloatingToolbarContainsItem(
295                getActivity().getString(com.android.internal.R.string.selectAll));
296        assertFloatingToolbarDoesNotContainItem(
297                getActivity().getString(com.android.internal.R.string.copy));
298        assertFloatingToolbarDoesNotContainItem(
299                getActivity().getString(com.android.internal.R.string.cut));
300    }
301
302    public void testToolbarAndSelectionHandle() throws Exception {
303        final String text = "abcd efg hijk";
304        onView(withId(R.id.textview)).perform(click());
305        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
306
307        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf("f")));
308        sleepForFloatingToolbarPopup();
309        assertFloatingToolbarIsDisplayed();
310
311        assertFloatingToolbarContainsItem(
312                getActivity().getString(com.android.internal.R.string.selectAll));
313        assertFloatingToolbarContainsItem(
314                getActivity().getString(com.android.internal.R.string.copy));
315        assertFloatingToolbarContainsItem(
316                getActivity().getString(com.android.internal.R.string.cut));
317
318        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
319        onHandleView(com.android.internal.R.id.selection_start_handle)
320                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('a')));
321        sleepForFloatingToolbarPopup();
322        assertFloatingToolbarIsDisplayed();
323
324        onHandleView(com.android.internal.R.id.selection_end_handle)
325                .perform(dragHandle(textView, Handle.SELECTION_END, text.length()));
326        sleepForFloatingToolbarPopup();
327        assertFloatingToolbarIsDisplayed();
328
329        assertFloatingToolbarDoesNotContainItem(
330                getActivity().getString(com.android.internal.R.string.selectAll));
331        assertFloatingToolbarContainsItem(
332                getActivity().getString(com.android.internal.R.string.copy));
333        assertFloatingToolbarContainsItem(
334                getActivity().getString(com.android.internal.R.string.cut));
335    }
336
337    public void testInsertionHandle() throws Exception {
338        final String text = "abcd efg hijk ";
339        onView(withId(R.id.textview)).perform(click());
340        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
341
342        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
343        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.length()));
344
345        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
346
347        onHandleView(com.android.internal.R.id.insertion_handle)
348                .perform(dragHandle(textView, Handle.INSERTION, text.indexOf('a')));
349        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("a")));
350
351        onHandleView(com.android.internal.R.id.insertion_handle)
352                .perform(dragHandle(textView, Handle.INSERTION, text.indexOf('f')));
353        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("f")));
354    }
355
356    public void testInsertionHandle_multiLine() throws Exception {
357        final String text = "abcd\n" + "efg\n" + "hijk\n";
358        onView(withId(R.id.textview)).perform(click());
359        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
360
361        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
362        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.length()));
363
364        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
365
366        onHandleView(com.android.internal.R.id.insertion_handle)
367                .perform(dragHandle(textView, Handle.INSERTION, text.indexOf('a')));
368        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("a")));
369
370        onHandleView(com.android.internal.R.id.insertion_handle)
371                .perform(dragHandle(textView, Handle.INSERTION, text.indexOf('f')));
372        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("f")));
373    }
374
375    public void testSelectionHandles() throws Exception {
376        final String text = "abcd efg hijk lmn";
377        onView(withId(R.id.textview)).perform(click());
378        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
379
380        assertNoSelectionHandles();
381
382        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('f')));
383
384        onHandleView(com.android.internal.R.id.selection_start_handle)
385                .check(matches(isDisplayed()));
386        onHandleView(com.android.internal.R.id.selection_end_handle)
387                .check(matches(isDisplayed()));
388
389        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
390        onHandleView(com.android.internal.R.id.selection_start_handle)
391                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('a')));
392        onView(withId(R.id.textview)).check(hasSelection("abcd efg"));
393
394        onHandleView(com.android.internal.R.id.selection_end_handle)
395                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('k') + 1));
396        onView(withId(R.id.textview)).check(hasSelection("abcd efg hijk"));
397    }
398
399    public void testSelectionHandles_bidi() throws Exception {
400        final String text = "abc \u0621\u0622\u0623 def";
401        onView(withId(R.id.textview)).perform(click());
402        onView(withId(R.id.textview)).perform(replaceText(text));
403
404        assertNoSelectionHandles();
405
406        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('\u0622')));
407
408        onHandleView(com.android.internal.R.id.selection_start_handle)
409                .check(matches(isDisplayed()));
410        onHandleView(com.android.internal.R.id.selection_end_handle)
411                .check(matches(isDisplayed()));
412
413        onView(withId(R.id.textview)).check(hasSelection("\u0621\u0622\u0623"));
414
415        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
416        onHandleView(com.android.internal.R.id.selection_start_handle)
417                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('f')));
418        onView(withId(R.id.textview)).check(hasSelection("\u0621\u0622\u0623"));
419
420        onHandleView(com.android.internal.R.id.selection_end_handle)
421                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('a')));
422        onView(withId(R.id.textview)).check(hasSelection("\u0621\u0622\u0623"));
423
424        onHandleView(com.android.internal.R.id.selection_start_handle)
425                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('\u0623') + 1,
426                        false));
427        onView(withId(R.id.textview)).check(hasSelection("\u0623"));
428
429        onHandleView(com.android.internal.R.id.selection_start_handle)
430                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('\u0621'),
431                        false));
432        onView(withId(R.id.textview)).check(hasSelection("\u0621\u0622\u0623"));
433
434        onHandleView(com.android.internal.R.id.selection_start_handle)
435                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('a')));
436        onView(withId(R.id.textview)).check(hasSelection("abc \u0621\u0622\u0623"));
437
438        onHandleView(com.android.internal.R.id.selection_end_handle)
439                .perform(dragHandle(textView, Handle.SELECTION_END, text.length()));
440        onView(withId(R.id.textview)).check(hasSelection("abc \u0621\u0622\u0623 def"));
441    }
442
443    public void testSelectionHandles_multiLine() throws Exception {
444        final String text = "abcd\n" + "efg\n" + "hijk\n" + "lmn\n" + "opqr";
445        onView(withId(R.id.textview)).perform(click());
446        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
447        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('i')));
448
449        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
450        onHandleView(com.android.internal.R.id.selection_start_handle)
451                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('e')));
452        onView(withId(R.id.textview)).check(hasSelection("efg\nhijk"));
453
454        onHandleView(com.android.internal.R.id.selection_start_handle)
455                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('a')));
456        onView(withId(R.id.textview)).check(hasSelection("abcd\nefg\nhijk"));
457
458        onHandleView(com.android.internal.R.id.selection_end_handle)
459                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('n') + 1));
460        onView(withId(R.id.textview)).check(hasSelection("abcd\nefg\nhijk\nlmn"));
461
462        onHandleView(com.android.internal.R.id.selection_end_handle)
463                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('r') + 1));
464        onView(withId(R.id.textview)).check(hasSelection("abcd\nefg\nhijk\nlmn\nopqr"));
465    }
466
467    public void testSelectionHandles_multiLine_rtl() throws Exception {
468        // Arabic text.
469        final String text = "\u062A\u062B\u062C\n" + "\u062D\u062E\u062F\n"
470                + "\u0630\u0631\u0632\n" + "\u0633\u0634\u0635\n" + "\u0636\u0637\u0638\n"
471                + "\u0639\u063A\u063B";
472        onView(withId(R.id.textview)).perform(click());
473        onView(withId(R.id.textview)).perform(replaceText(text));
474        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
475        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('\u0634')));
476
477        final TextView textView = (TextView)getActivity().findViewById(R.id.textview);
478        onHandleView(com.android.internal.R.id.selection_start_handle)
479                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('\u062E')));
480        onView(withId(R.id.textview)).check(hasSelection(
481                text.substring(text.indexOf('\u062D'), text.indexOf('\u0635') + 1)));
482
483        onHandleView(com.android.internal.R.id.selection_start_handle)
484                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('\u062A')));
485        onView(withId(R.id.textview)).check(hasSelection(
486                text.substring(text.indexOf('\u062A'), text.indexOf('\u0635') + 1)));
487
488        onHandleView(com.android.internal.R.id.selection_end_handle)
489                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('\u0638')));
490        onView(withId(R.id.textview)).check(hasSelection(
491                text.substring(text.indexOf('\u062A'), text.indexOf('\u0638') + 1)));
492
493        onHandleView(com.android.internal.R.id.selection_end_handle)
494                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('\u063B')));
495        onView(withId(R.id.textview)).check(hasSelection(text));
496    }
497
498
499    public void testSelectionHandles_doesNotPassAnotherHandle() throws Exception {
500        final String text = "abcd efg hijk lmn";
501        onView(withId(R.id.textview)).perform(click());
502        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
503        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('f')));
504
505        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
506        onHandleView(com.android.internal.R.id.selection_start_handle)
507                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('l')));
508        onView(withId(R.id.textview)).check(hasSelection("g"));
509
510        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('f')));
511        onHandleView(com.android.internal.R.id.selection_end_handle)
512                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('a')));
513        onView(withId(R.id.textview)).check(hasSelection("e"));
514    }
515
516    public void testSelectionHandles_doesNotPassAnotherHandle_multiLine() throws Exception {
517        final String text = "abcd\n" + "efg\n" + "hijk\n" + "lmn\n" + "opqr";
518        onView(withId(R.id.textview)).perform(click());
519        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
520        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('i')));
521
522        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
523        onHandleView(com.android.internal.R.id.selection_start_handle)
524                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('r') + 1));
525        onView(withId(R.id.textview)).check(hasSelection("k"));
526
527        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('i')));
528        onHandleView(com.android.internal.R.id.selection_end_handle)
529                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('a')));
530        onView(withId(R.id.textview)).check(hasSelection("h"));
531    }
532
533    public void testSelectionHandles_snapToWordBoundary() throws Exception {
534        final String text = "abcd efg hijk lmn opqr";
535        onView(withId(R.id.textview)).perform(click());
536        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
537        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('i')));
538
539        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
540
541        onHandleView(com.android.internal.R.id.selection_start_handle)
542                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('f')));
543        onView(withId(R.id.textview)).check(hasSelection("efg hijk"));
544
545        onHandleView(com.android.internal.R.id.selection_start_handle)
546                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('d') + 1));
547        onView(withId(R.id.textview)).check(hasSelection("efg hijk"));
548
549
550        onHandleView(com.android.internal.R.id.selection_start_handle)
551                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('c')));
552        onView(withId(R.id.textview)).check(hasSelection("abcd efg hijk"));
553
554        onHandleView(com.android.internal.R.id.selection_start_handle)
555                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('d')));
556        onView(withId(R.id.textview)).check(hasSelection("d efg hijk"));
557
558        onHandleView(com.android.internal.R.id.selection_start_handle)
559                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('b')));
560        onView(withId(R.id.textview)).check(hasSelection("bcd efg hijk"));
561
562        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('i')));
563
564        onHandleView(com.android.internal.R.id.selection_end_handle)
565                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('n')));
566        onView(withId(R.id.textview)).check(hasSelection("hijk lmn"));
567
568        onHandleView(com.android.internal.R.id.selection_end_handle)
569                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('o')));
570        onView(withId(R.id.textview)).check(hasSelection("hijk lmn"));
571
572        onHandleView(com.android.internal.R.id.selection_end_handle)
573                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('q')));
574        onView(withId(R.id.textview)).check(hasSelection("hijk lmn opqr"));
575
576        onHandleView(com.android.internal.R.id.selection_end_handle)
577                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('p')));
578        onView(withId(R.id.textview)).check(hasSelection("hijk lmn o"));
579
580        onHandleView(com.android.internal.R.id.selection_end_handle)
581                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('r')));
582        onView(withId(R.id.textview)).check(hasSelection("hijk lmn opq"));
583    }
584
585    public void testSelectionHandles_snapToWordBoundary_multiLine() throws Exception {
586        final String text = "abcd efg\n" + "hijk lmn\n" + "opqr stu";
587        onView(withId(R.id.textview)).perform(click());
588        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
589        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('m')));
590
591        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
592
593        onHandleView(com.android.internal.R.id.selection_start_handle)
594                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('c')));
595        onView(withId(R.id.textview)).check(hasSelection("abcd efg\nhijk lmn"));
596
597        onHandleView(com.android.internal.R.id.selection_start_handle)
598                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('g')));
599        onView(withId(R.id.textview)).check(hasSelection("g\nhijk lmn"));
600
601        onHandleView(com.android.internal.R.id.selection_start_handle)
602                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('m')));
603        onView(withId(R.id.textview)).check(hasSelection("lmn"));
604
605        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('i')));
606
607        onHandleView(com.android.internal.R.id.selection_end_handle)
608                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('u')));
609        onView(withId(R.id.textview)).check(hasSelection("hijk lmn\nopqr stu"));
610
611        onHandleView(com.android.internal.R.id.selection_end_handle)
612                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('p')));
613        onView(withId(R.id.textview)).check(hasSelection("hijk lmn\no"));
614
615        onHandleView(com.android.internal.R.id.selection_end_handle)
616                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('i')));
617        onView(withId(R.id.textview)).check(hasSelection("hijk"));
618    }
619
620    public void testSetSelectionAndActionMode() throws Exception {
621        final String text = "abc def";
622        onView(withId(R.id.textview)).perform(click());
623        onView(withId(R.id.textview)).perform(replaceText(text));
624
625        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
626        assertFloatingToolbarIsNotDisplayed();
627        textView.post(() -> Selection.setSelection((Spannable) textView.getText(), 0, 3));
628        getInstrumentation().waitForIdleSync();
629        sleepForFloatingToolbarPopup();
630        // Don't automatically start action mode.
631        assertFloatingToolbarIsNotDisplayed();
632        // Make sure that "Select All" is included in the selection action mode when the entire text
633        // is not selected.
634        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('e')));
635        sleepForFloatingToolbarPopup();
636        assertFloatingToolbarIsDisplayed();
637        // Changing the selection range by API should not interrupt the selection action mode.
638        textView.post(() -> Selection.setSelection((Spannable) textView.getText(), 0, 3));
639        getInstrumentation().waitForIdleSync();
640        sleepForFloatingToolbarPopup();
641        assertFloatingToolbarIsDisplayed();
642        assertFloatingToolbarContainsItem(
643                getActivity().getString(com.android.internal.R.string.selectAll));
644        // Make sure that "Select All" is no longer included when the entire text is selected by
645        // API.
646        textView.post(
647                () -> Selection.setSelection((Spannable) textView.getText(), 0, text.length()));
648        getInstrumentation().waitForIdleSync();
649        sleepForFloatingToolbarPopup();
650        assertFloatingToolbarIsDisplayed();
651        assertFloatingToolbarDoesNotContainItem(
652                getActivity().getString(com.android.internal.R.string.selectAll));
653        // Make sure that shrinking the selection range to cursor (an empty range) by API
654        // terminates selection action mode and does not trigger the insertion action mode.
655        textView.post(() -> Selection.setSelection((Spannable) textView.getText(), 0));
656        getInstrumentation().waitForIdleSync();
657        sleepForFloatingToolbarPopup();
658        assertFloatingToolbarIsNotDisplayed();
659        // Make sure that user click can trigger the insertion action mode.
660        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
661        onHandleView(com.android.internal.R.id.insertion_handle).perform(click());
662        sleepForFloatingToolbarPopup();
663        assertFloatingToolbarIsDisplayed();
664        // Make sure that an existing insertion action mode keeps alive after the insertion point is
665        // moved by API.
666        textView.post(() -> Selection.setSelection((Spannable) textView.getText(), 0));
667        getInstrumentation().waitForIdleSync();
668        sleepForFloatingToolbarPopup();
669        assertFloatingToolbarIsDisplayed();
670        assertFloatingToolbarDoesNotContainItem(
671                getActivity().getString(com.android.internal.R.string.copy));
672        // Make sure that selection action mode is started after selection is created by API when
673        // insertion action mode is active.
674        textView.post(
675                () -> Selection.setSelection((Spannable) textView.getText(), 1, text.length()));
676        getInstrumentation().waitForIdleSync();
677        sleepForFloatingToolbarPopup();
678        assertFloatingToolbarIsDisplayed();
679        assertFloatingToolbarContainsItem(
680                getActivity().getString(com.android.internal.R.string.copy));
681    }
682
683    public void testTransientState() throws Exception {
684        final String text = "abc def";
685        onView(withId(R.id.textview)).perform(click());
686        onView(withId(R.id.textview)).perform(replaceText(text));
687
688        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
689        assertFalse(textView.hasTransientState());
690
691        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('b')));
692        // hasTransientState should return true when user generated selection is active.
693        assertTrue(textView.hasTransientState());
694        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.indexOf('d')));
695        // hasTransientState should return false as the selection has been cleared.
696        assertFalse(textView.hasTransientState());
697        textView.post(
698                () -> Selection.setSelection((Spannable) textView.getText(), 0, text.length()));
699        getInstrumentation().waitForIdleSync();
700        // hasTransientState should return false when selection is created by API.
701        assertFalse(textView.hasTransientState());
702    }
703}
704