blob: 3e03481236180f5d9a62b841c6d31ace5370c1e7 [file] [log] [blame]
Abodunrinwa Toki223c8392015-07-24 20:55:59 -07001/*
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.support.test.espresso.Espresso.onView;
20import static android.support.test.espresso.action.ViewActions.click;
Abodunrinwa Tokic5b54ba2016-10-25 10:21:36 +010021import static android.support.test.espresso.action.ViewActions.longClick;
Abodunrinwa Toki90cdfe02015-09-15 21:15:56 +010022import static android.support.test.espresso.action.ViewActions.pressKey;
Keisuke Kuroyanagi26454142015-12-02 15:04:57 -080023import static android.support.test.espresso.action.ViewActions.replaceText;
Abodunrinwa Toki223c8392015-07-24 20:55:59 -070024import static android.support.test.espresso.assertion.ViewAssertions.matches;
Abodunrinwa Tokifc6e25e2015-11-30 19:45:32 +000025import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
Abodunrinwa Toki223c8392015-07-24 20:55:59 -070026import static android.support.test.espresso.matcher.ViewMatchers.withId;
27import static android.support.test.espresso.matcher.ViewMatchers.withText;
Siyamed Sinir21914182017-06-16 15:24:00 -070028import static android.widget.espresso.CustomViewActions.longPressAtRelativeCoordinates;
29import static android.widget.espresso.DragHandleUtils.assertNoSelectionHandles;
30import static android.widget.espresso.DragHandleUtils.onHandleView;
31import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarContainsItem;
32import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarDoesNotContainItem;
33import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarIsDisplayed;
34import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarIsNotDisplayed;
35import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarItemIndex;
36import static android.widget.espresso.FloatingToolbarEspressoUtils.clickFloatingToolbarItem;
37import static android.widget.espresso.FloatingToolbarEspressoUtils.sleepForFloatingToolbarPopup;
38import static android.widget.espresso.TextViewActions.Handle;
39import static android.widget.espresso.TextViewActions.clickOnTextAtIndex;
40import static android.widget.espresso.TextViewActions.doubleClickOnTextAtIndex;
41import static android.widget.espresso.TextViewActions.doubleTapAndDragOnText;
42import static android.widget.espresso.TextViewActions.dragHandle;
43import static android.widget.espresso.TextViewActions.longPressAndDragOnText;
44import static android.widget.espresso.TextViewActions.longPressOnTextAtIndex;
45import static android.widget.espresso.TextViewAssertions.doesNotHaveStyledText;
46import static android.widget.espresso.TextViewAssertions.hasInsertionPointerAtIndex;
47import static android.widget.espresso.TextViewAssertions.hasSelection;
48
49import static junit.framework.Assert.assertFalse;
50import static junit.framework.Assert.assertTrue;
51
Abodunrinwa Tokic5b54ba2016-10-25 10:21:36 +010052import static org.hamcrest.Matchers.anyOf;
53import static org.hamcrest.Matchers.is;
Abodunrinwa Toki223c8392015-07-24 20:55:59 -070054
Siyamed Sinir21914182017-06-16 15:24:00 -070055import android.app.Activity;
56import android.app.Instrumentation;
Abodunrinwa Tokiea6cb122017-04-28 22:14:13 +010057import android.content.ClipData;
58import android.content.ClipboardManager;
Siyamed Sinir21914182017-06-16 15:24:00 -070059import android.support.test.InstrumentationRegistry;
60import android.support.test.espresso.action.EspressoKey;
61import android.support.test.filters.MediumTest;
62import android.support.test.rule.ActivityTestRule;
63import android.support.test.runner.AndroidJUnit4;
64import android.text.InputType;
65import android.text.Selection;
66import android.text.Spannable;
Abodunrinwa Toki6eecdc92017-04-11 05:15:25 +010067import android.view.ActionMode;
Siyamed Sinir21914182017-06-16 15:24:00 -070068import android.view.KeyEvent;
Abodunrinwa Toki6eecdc92017-04-11 05:15:25 +010069import android.view.Menu;
70import android.view.MenuItem;
71import android.view.textclassifier.TextClassificationManager;
72import android.view.textclassifier.TextClassifier;
Abodunrinwa Toki9479d3e2016-03-09 19:41:41 +000073import android.widget.espresso.CustomViewActions.RelativeCoordinatesProvider;
Abodunrinwa Toki223c8392015-07-24 20:55:59 -070074
Abodunrinwa Tokic5b54ba2016-10-25 10:21:36 +010075import com.android.frameworks.coretests.R;
Keisuke Kuroyanagie27e0852016-01-08 19:05:27 +090076
Siyamed Sinir21914182017-06-16 15:24:00 -070077import org.junit.Before;
78import org.junit.Rule;
79import org.junit.Test;
80import org.junit.runner.RunWith;
81
Abodunrinwa Toki223c8392015-07-24 20:55:59 -070082/**
83 * Tests the TextView widget from an Activity
84 */
Siyamed Sinir21914182017-06-16 15:24:00 -070085@RunWith(AndroidJUnit4.class)
Abodunrinwa Tokic5b54ba2016-10-25 10:21:36 +010086@MediumTest
Siyamed Sinir21914182017-06-16 15:24:00 -070087public class TextViewActivityTest {
Abodunrinwa Toki223c8392015-07-24 20:55:59 -070088
Siyamed Sinir21914182017-06-16 15:24:00 -070089 @Rule
90 public ActivityTestRule<TextViewActivity> mActivityRule = new ActivityTestRule<>(
91 TextViewActivity.class);
Abodunrinwa Toki223c8392015-07-24 20:55:59 -070092
Siyamed Sinir21914182017-06-16 15:24:00 -070093 private Activity mActivity;
94 private Instrumentation mInstrumentation;
95
96 @Before
97 public void setUp() {
98 mActivity = mActivityRule.getActivity();
99 mInstrumentation = InstrumentationRegistry.getInstrumentation();
100 mActivity.getSystemService(TextClassificationManager.class)
Abodunrinwa Toki6eecdc92017-04-11 05:15:25 +0100101 .setTextClassifier(TextClassifier.NO_OP);
Abodunrinwa Tokic9e924e2015-10-08 12:01:35 +0100102 }
103
Siyamed Sinir21914182017-06-16 15:24:00 -0700104 @Test
105 public void testTypedTextIsOnScreen() {
Abodunrinwa Toki223c8392015-07-24 20:55:59 -0700106 final String helloWorld = "Hello world!";
Keisuke Kuroyanagi99e8623182016-11-16 20:05:14 +0900107 // We use replaceText instead of typeTextIntoFocusedView to input text to avoid
108 // unintentional interactions with software keyboard.
109 onView(withId(R.id.textview)).perform(replaceText(helloWorld));
Abodunrinwa Toki223c8392015-07-24 20:55:59 -0700110
111 onView(withId(R.id.textview)).check(matches(withText(helloWorld)));
112 }
Siyamed Sinir21914182017-06-16 15:24:00 -0700113 @Test
114 public void testPositionCursorAtTextAtIndex() {
Abodunrinwa Toki90cdfe02015-09-15 21:15:56 +0100115 final String helloWorld = "Hello world!";
Keisuke Kuroyanagi99e8623182016-11-16 20:05:14 +0900116 onView(withId(R.id.textview)).perform(replaceText(helloWorld));
Abodunrinwa Toki90cdfe02015-09-15 21:15:56 +0100117 onView(withId(R.id.textview)).perform(clickOnTextAtIndex(helloWorld.indexOf("world")));
118
119 // Delete text at specified index and see if we got the right one.
120 onView(withId(R.id.textview)).perform(pressKey(KeyEvent.KEYCODE_FORWARD_DEL));
121 onView(withId(R.id.textview)).check(matches(withText("Hello orld!")));
122 }
Abodunrinwa Tokica4aaf32015-09-22 20:31:21 +0100123
Siyamed Sinir21914182017-06-16 15:24:00 -0700124 @Test
125 public void testPositionCursorAtTextAtIndex_arabic() {
Keisuke Kuroyanagie27e0852016-01-08 19:05:27 +0900126 // Arabic text. The expected cursorable boundary is
127 // | \u0623 \u064F | \u067A | \u0633 \u0652 |
128 final String text = "\u0623\u064F\u067A\u0633\u0652";
Keisuke Kuroyanagie27e0852016-01-08 19:05:27 +0900129 onView(withId(R.id.textview)).perform(replaceText(text));
130
131 onView(withId(R.id.textview)).perform(clickOnTextAtIndex(0));
132 onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(0));
133 onView(withId(R.id.textview)).perform(clickOnTextAtIndex(1));
134 onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(anyOf(is(0), is(2))));
135 onView(withId(R.id.textview)).perform(clickOnTextAtIndex(2));
136 onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(2));
137 onView(withId(R.id.textview)).perform(clickOnTextAtIndex(3));
138 onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(3));
139 onView(withId(R.id.textview)).perform(clickOnTextAtIndex(4));
140 onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(anyOf(is(3), is(5))));
141 onView(withId(R.id.textview)).perform(clickOnTextAtIndex(5));
142 onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(5));
143 }
144
Siyamed Sinir21914182017-06-16 15:24:00 -0700145 @Test
146 public void testPositionCursorAtTextAtIndex_devanagari() {
Keisuke Kuroyanagie27e0852016-01-08 19:05:27 +0900147 // Devanagari text. The expected cursorable boundary is | \u0915 \u093E |
148 final String text = "\u0915\u093E";
Keisuke Kuroyanagie27e0852016-01-08 19:05:27 +0900149 onView(withId(R.id.textview)).perform(replaceText(text));
150
151 onView(withId(R.id.textview)).perform(clickOnTextAtIndex(0));
152 onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(0));
153 onView(withId(R.id.textview)).perform(clickOnTextAtIndex(1));
154 onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(anyOf(is(0), is(2))));
155 onView(withId(R.id.textview)).perform(clickOnTextAtIndex(2));
156 onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(2));
157 }
158
Siyamed Sinir21914182017-06-16 15:24:00 -0700159 @Test
160 public void testLongPressToSelect() {
Abodunrinwa Toki8a5e1ae2015-09-28 21:59:04 +0100161 final String helloWorld = "Hello Kirk!";
162 onView(withId(R.id.textview)).perform(click());
Keisuke Kuroyanagi99e8623182016-11-16 20:05:14 +0900163 onView(withId(R.id.textview)).perform(replaceText(helloWorld));
Abodunrinwa Toki8a5e1ae2015-09-28 21:59:04 +0100164 onView(withId(R.id.textview)).perform(
165 longPressOnTextAtIndex(helloWorld.indexOf("Kirk")));
166
167 onView(withId(R.id.textview)).check(hasSelection("Kirk"));
168 }
169
Siyamed Sinir21914182017-06-16 15:24:00 -0700170 @Test
171 public void testLongPressEmptySpace() {
Abodunrinwa Toki8a5e1ae2015-09-28 21:59:04 +0100172 final String helloWorld = "Hello big round sun!";
Keisuke Kuroyanagi99e8623182016-11-16 20:05:14 +0900173 onView(withId(R.id.textview)).perform(replaceText(helloWorld));
Abodunrinwa Toki8a5e1ae2015-09-28 21:59:04 +0100174 // Move cursor somewhere else
175 onView(withId(R.id.textview)).perform(clickOnTextAtIndex(helloWorld.indexOf("big")));
176 // Long-press at end of line.
Abodunrinwa Toki9479d3e2016-03-09 19:41:41 +0000177 onView(withId(R.id.textview)).perform(longPressAtRelativeCoordinates(
178 RelativeCoordinatesProvider.HorizontalReference.RIGHT, -5,
179 RelativeCoordinatesProvider.VerticalReference.CENTER, 0));
Abodunrinwa Toki8a5e1ae2015-09-28 21:59:04 +0100180
181 onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(helloWorld.length()));
182 }
183
Siyamed Sinir21914182017-06-16 15:24:00 -0700184 @Test
185 public void testLongPressAndDragToSelect() {
Abodunrinwa Tokica4aaf32015-09-22 20:31:21 +0100186 final String helloWorld = "Hello little handsome boy!";
Keisuke Kuroyanagi99e8623182016-11-16 20:05:14 +0900187 onView(withId(R.id.textview)).perform(replaceText(helloWorld));
Abodunrinwa Tokica4aaf32015-09-22 20:31:21 +0100188 onView(withId(R.id.textview)).perform(
189 longPressAndDragOnText(helloWorld.indexOf("little"), helloWorld.indexOf(" boy!")));
190
191 onView(withId(R.id.textview)).check(hasSelection("little handsome"));
192 }
193
Siyamed Sinir21914182017-06-16 15:24:00 -0700194 @Test
195 public void testLongPressAndDragToSelect_emoji() {
Keisuke Kuroyanagi133dfc02016-07-21 18:07:23 +0900196 final String text = "\uD83D\uDE00\uD83D\uDE01\uD83D\uDE02\uD83D\uDE03";
Keisuke Kuroyanagi133dfc02016-07-21 18:07:23 +0900197 onView(withId(R.id.textview)).perform(replaceText(text));
198
199 onView(withId(R.id.textview)).perform(longPressAndDragOnText(4, 6));
200 onView(withId(R.id.textview)).check(hasSelection("\uD83D\uDE02"));
201
202 onView(withId(R.id.textview)).perform(click());
203
204 onView(withId(R.id.textview)).perform(longPressAndDragOnText(4, 2));
205 onView(withId(R.id.textview)).check(hasSelection("\uD83D\uDE01"));
206 }
207
Siyamed Sinir21914182017-06-16 15:24:00 -0700208 @Test
209 public void testDragAndDrop() {
Keisuke Kuroyanagi4307aeb2015-12-07 11:16:39 -0800210 final String text = "abc def ghi.";
Keisuke Kuroyanagi99e8623182016-11-16 20:05:14 +0900211 onView(withId(R.id.textview)).perform(replaceText(text));
Keisuke Kuroyanagi4307aeb2015-12-07 11:16:39 -0800212 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf("e")));
213
214 onView(withId(R.id.textview)).perform(
215 longPressAndDragOnText(text.indexOf("e"), text.length()));
216
217 onView(withId(R.id.textview)).check(matches(withText("abc ghi.def")));
218 onView(withId(R.id.textview)).check(hasSelection(""));
219 assertNoSelectionHandles();
220 onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex("abc ghi.def".length()));
Keisuke Kuroyanagifae45782016-02-24 18:53:00 -0800221
222 // Test undo returns to the original state.
223 onView(withId(R.id.textview)).perform(pressKey(
224 (new EspressoKey.Builder()).withCtrlPressed(true).withKeyCode(KeyEvent.KEYCODE_Z)
225 .build()));
226 onView(withId(R.id.textview)).check(matches(withText(text)));
Keisuke Kuroyanagi4307aeb2015-12-07 11:16:39 -0800227 }
228
Siyamed Sinir21914182017-06-16 15:24:00 -0700229 @Test
230 public void testDoubleTapToSelect() {
Abodunrinwa Toki8a5e1ae2015-09-28 21:59:04 +0100231 final String helloWorld = "Hello SuetYi!";
Keisuke Kuroyanagi99e8623182016-11-16 20:05:14 +0900232 onView(withId(R.id.textview)).perform(replaceText(helloWorld));
233
Abodunrinwa Toki8a5e1ae2015-09-28 21:59:04 +0100234 onView(withId(R.id.textview)).perform(
235 doubleClickOnTextAtIndex(helloWorld.indexOf("SuetYi")));
236
237 onView(withId(R.id.textview)).check(hasSelection("SuetYi"));
238 }
239
Siyamed Sinir21914182017-06-16 15:24:00 -0700240 @Test
241 public void testDoubleTapAndDragToSelect() {
242 final String helloWorld = "Hello young beautiful person!";
Keisuke Kuroyanagi99e8623182016-11-16 20:05:14 +0900243 onView(withId(R.id.textview)).perform(replaceText(helloWorld));
Siyamed Sinir21914182017-06-16 15:24:00 -0700244 onView(withId(R.id.textview)).perform(doubleTapAndDragOnText(helloWorld.indexOf("young"),
245 helloWorld.indexOf(" person!")));
Abodunrinwa Tokica4aaf32015-09-22 20:31:21 +0100246
247 onView(withId(R.id.textview)).check(hasSelection("young beautiful"));
248 }
Abodunrinwa Toki8a5e1ae2015-09-28 21:59:04 +0100249
Siyamed Sinir21914182017-06-16 15:24:00 -0700250 @Test
251 public void testDoubleTapAndDragToSelect_multiLine() {
Sara Kato68c433d2016-08-09 14:40:45 +0900252 final String helloWorld = "abcd\n" + "efg\n" + "hijklm\n" + "nop";
Sara Kato68c433d2016-08-09 14:40:45 +0900253 onView(withId(R.id.textview)).perform(replaceText(helloWorld));
254 onView(withId(R.id.textview)).perform(
255 doubleTapAndDragOnText(helloWorld.indexOf("m"), helloWorld.indexOf("a")));
256 onView(withId(R.id.textview)).check(hasSelection("abcd\nefg\nhijklm"));
257 }
258
Siyamed Sinir21914182017-06-16 15:24:00 -0700259 @Test
260 public void testSelectBackwordsByTouch() {
Abodunrinwa Toki8a5e1ae2015-09-28 21:59:04 +0100261 final String helloWorld = "Hello king of the Jungle!";
Keisuke Kuroyanagi99e8623182016-11-16 20:05:14 +0900262 onView(withId(R.id.textview)).perform(replaceText(helloWorld));
Abodunrinwa Toki8a5e1ae2015-09-28 21:59:04 +0100263 onView(withId(R.id.textview)).perform(
264 doubleTapAndDragOnText(helloWorld.indexOf(" Jungle!"), helloWorld.indexOf("king")));
265
266 onView(withId(R.id.textview)).check(hasSelection("king of the"));
267 }
268
Siyamed Sinir21914182017-06-16 15:24:00 -0700269 @Test
270 public void testToolbarAppearsAfterSelection() {
Abodunrinwa Toki8a5e1ae2015-09-28 21:59:04 +0100271 final String text = "Toolbar appears after selection.";
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -0800272 assertFloatingToolbarIsNotDisplayed();
Keisuke Kuroyanagi99e8623182016-11-16 20:05:14 +0900273 onView(withId(R.id.textview)).perform(replaceText(text));
Abodunrinwa Toki8a5e1ae2015-09-28 21:59:04 +0100274 onView(withId(R.id.textview)).perform(
275 longPressOnTextAtIndex(text.indexOf("appears")));
276
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -0800277 sleepForFloatingToolbarPopup();
278 assertFloatingToolbarIsDisplayed();
279
280 final String text2 = "Toolbar disappears after typing text.";
Keisuke Kuroyanagi99e8623182016-11-16 20:05:14 +0900281 onView(withId(R.id.textview)).perform(replaceText(text2));
282 sleepForFloatingToolbarPopup();
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -0800283 assertFloatingToolbarIsNotDisplayed();
284 }
285
Siyamed Sinir21914182017-06-16 15:24:00 -0700286 @Test
Siyamed Sinir987ec652016-02-17 19:44:41 -0800287 public void testToolbarAppearsAfterSelection_withFirstStringLtrAlgorithmAndRtlHint()
Siyamed Sinir21914182017-06-16 15:24:00 -0700288 throws Throwable {
Siyamed Sinir987ec652016-02-17 19:44:41 -0800289 // after the hint layout change, the floating toolbar was not visible in the case below
290 // this test tests that the floating toolbar is displayed on the screen and is visible to
291 // user.
Siyamed Sinir21914182017-06-16 15:24:00 -0700292 mActivityRule.runOnUiThread(() -> {
293 final TextView textView = mActivity.findViewById(R.id.textview);
294 textView.setTextDirection(TextView.TEXT_DIRECTION_FIRST_STRONG_LTR);
295 textView.setInputType(InputType.TYPE_CLASS_TEXT);
296 textView.setSingleLine(true);
297 textView.setHint("الروبوت");
Siyamed Sinir987ec652016-02-17 19:44:41 -0800298 });
Siyamed Sinir21914182017-06-16 15:24:00 -0700299 mInstrumentation.waitForIdleSync();
Siyamed Sinir987ec652016-02-17 19:44:41 -0800300
Keisuke Kuroyanagi99e8623182016-11-16 20:05:14 +0900301 onView(withId(R.id.textview)).perform(replaceText("test"));
Siyamed Sinir987ec652016-02-17 19:44:41 -0800302 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(1));
Siyamed Sinir21914182017-06-16 15:24:00 -0700303 clickFloatingToolbarItem(mActivity.getString(com.android.internal.R.string.cut));
Siyamed Sinir987ec652016-02-17 19:44:41 -0800304 onView(withId(R.id.textview)).perform(longClick());
305 sleepForFloatingToolbarPopup();
306
307 assertFloatingToolbarIsDisplayed();
308 }
309
Siyamed Sinir21914182017-06-16 15:24:00 -0700310 @Test
311 public void testToolbarAndInsertionHandle() {
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -0800312 final String text = "text";
Abodunrinwa Toki4a056a52017-08-05 01:56:40 +0100313 assertFloatingToolbarIsNotDisplayed();
Keisuke Kuroyanagi99e8623182016-11-16 20:05:14 +0900314 onView(withId(R.id.textview)).perform(replaceText(text));
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -0800315 onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -0800316
317 onHandleView(com.android.internal.R.id.insertion_handle).perform(click());
318 sleepForFloatingToolbarPopup();
319 assertFloatingToolbarIsDisplayed();
320
321 assertFloatingToolbarContainsItem(
Siyamed Sinir21914182017-06-16 15:24:00 -0700322 mActivity.getString(com.android.internal.R.string.selectAll));
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -0800323 assertFloatingToolbarDoesNotContainItem(
Siyamed Sinir21914182017-06-16 15:24:00 -0700324 mActivity.getString(com.android.internal.R.string.copy));
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -0800325 assertFloatingToolbarDoesNotContainItem(
Siyamed Sinir21914182017-06-16 15:24:00 -0700326 mActivity.getString(com.android.internal.R.string.cut));
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -0800327 }
328
Siyamed Sinir21914182017-06-16 15:24:00 -0700329 @Test
330 public void testToolbarAndSelectionHandle() {
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -0800331 final String text = "abcd efg hijk";
Keisuke Kuroyanagi99e8623182016-11-16 20:05:14 +0900332 onView(withId(R.id.textview)).perform(replaceText(text));
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -0800333
334 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf("f")));
335 sleepForFloatingToolbarPopup();
336 assertFloatingToolbarIsDisplayed();
337
338 assertFloatingToolbarContainsItem(
Siyamed Sinir21914182017-06-16 15:24:00 -0700339 mActivity.getString(com.android.internal.R.string.selectAll));
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -0800340 assertFloatingToolbarContainsItem(
Siyamed Sinir21914182017-06-16 15:24:00 -0700341 mActivity.getString(com.android.internal.R.string.copy));
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -0800342 assertFloatingToolbarContainsItem(
Siyamed Sinir21914182017-06-16 15:24:00 -0700343 mActivity.getString(com.android.internal.R.string.cut));
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -0800344
Siyamed Sinir21914182017-06-16 15:24:00 -0700345 final TextView textView = mActivity.findViewById(R.id.textview);
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -0800346 onHandleView(com.android.internal.R.id.selection_start_handle)
347 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('a')));
348 sleepForFloatingToolbarPopup();
349 assertFloatingToolbarIsDisplayed();
350
351 onHandleView(com.android.internal.R.id.selection_end_handle)
352 .perform(dragHandle(textView, Handle.SELECTION_END, text.length()));
353 sleepForFloatingToolbarPopup();
354 assertFloatingToolbarIsDisplayed();
355
356 assertFloatingToolbarDoesNotContainItem(
Siyamed Sinir21914182017-06-16 15:24:00 -0700357 mActivity.getString(com.android.internal.R.string.selectAll));
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -0800358 assertFloatingToolbarContainsItem(
Siyamed Sinir21914182017-06-16 15:24:00 -0700359 mActivity.getString(com.android.internal.R.string.copy));
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -0800360 assertFloatingToolbarContainsItem(
Siyamed Sinir21914182017-06-16 15:24:00 -0700361 mActivity.getString(com.android.internal.R.string.cut));
Abodunrinwa Toki8a5e1ae2015-09-28 21:59:04 +0100362 }
Keisuke Kuroyanagida79ee62015-11-25 16:15:15 +0900363
Siyamed Sinir21914182017-06-16 15:24:00 -0700364 @Test
365 public void testInsertionHandle() {
Keisuke Kuroyanagie8b3dd42015-11-26 14:19:27 +0900366 final String text = "abcd efg hijk ";
Keisuke Kuroyanagi99e8623182016-11-16 20:05:14 +0900367 onView(withId(R.id.textview)).perform(replaceText(text));
Keisuke Kuroyanagie8b3dd42015-11-26 14:19:27 +0900368
369 onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
370 onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.length()));
371
Siyamed Sinir21914182017-06-16 15:24:00 -0700372 final TextView textView = mActivity.findViewById(R.id.textview);
Keisuke Kuroyanagie8b3dd42015-11-26 14:19:27 +0900373
374 onHandleView(com.android.internal.R.id.insertion_handle)
375 .perform(dragHandle(textView, Handle.INSERTION, text.indexOf('a')));
376 onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("a")));
377
378 onHandleView(com.android.internal.R.id.insertion_handle)
379 .perform(dragHandle(textView, Handle.INSERTION, text.indexOf('f')));
380 onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("f")));
381 }
382
Siyamed Sinir21914182017-06-16 15:24:00 -0700383 @Test
384 public void testInsertionHandle_multiLine() {
Keisuke Kuroyanagie8b3dd42015-11-26 14:19:27 +0900385 final String text = "abcd\n" + "efg\n" + "hijk\n";
Keisuke Kuroyanagi99e8623182016-11-16 20:05:14 +0900386 onView(withId(R.id.textview)).perform(replaceText(text));
Keisuke Kuroyanagie8b3dd42015-11-26 14:19:27 +0900387
388 onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
389 onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.length()));
390
Siyamed Sinir21914182017-06-16 15:24:00 -0700391 final TextView textView = mActivity.findViewById(R.id.textview);
Keisuke Kuroyanagie8b3dd42015-11-26 14:19:27 +0900392
393 onHandleView(com.android.internal.R.id.insertion_handle)
394 .perform(dragHandle(textView, Handle.INSERTION, text.indexOf('a')));
395 onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("a")));
396
397 onHandleView(com.android.internal.R.id.insertion_handle)
398 .perform(dragHandle(textView, Handle.INSERTION, text.indexOf('f')));
399 onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("f")));
400 }
401
Siyamed Sinir21914182017-06-16 15:24:00 -0700402 @Test
403 public void testSelectionHandles() {
Keisuke Kuroyanagida79ee62015-11-25 16:15:15 +0900404 final String text = "abcd efg hijk lmn";
Keisuke Kuroyanagi99e8623182016-11-16 20:05:14 +0900405 onView(withId(R.id.textview)).perform(replaceText(text));
Abodunrinwa Tokifc6e25e2015-11-30 19:45:32 +0000406
407 assertNoSelectionHandles();
408
Keisuke Kuroyanagi99e8623182016-11-16 20:05:14 +0900409 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('f')));
Keisuke Kuroyanagida79ee62015-11-25 16:15:15 +0900410
Abodunrinwa Tokifc6e25e2015-11-30 19:45:32 +0000411 onHandleView(com.android.internal.R.id.selection_start_handle)
412 .check(matches(isDisplayed()));
413 onHandleView(com.android.internal.R.id.selection_end_handle)
414 .check(matches(isDisplayed()));
415
Siyamed Sinir21914182017-06-16 15:24:00 -0700416 final TextView textView = mActivity.findViewById(R.id.textview);
Keisuke Kuroyanagida79ee62015-11-25 16:15:15 +0900417 onHandleView(com.android.internal.R.id.selection_start_handle)
418 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('a')));
419 onView(withId(R.id.textview)).check(hasSelection("abcd efg"));
420
421 onHandleView(com.android.internal.R.id.selection_end_handle)
422 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('k') + 1));
423 onView(withId(R.id.textview)).check(hasSelection("abcd efg hijk"));
424 }
Keisuke Kuroyanagic24c2bb2015-11-24 18:48:28 +0900425
Siyamed Sinir21914182017-06-16 15:24:00 -0700426 @Test
427 public void testSelectionHandles_bidi() {
Keisuke Kuroyanagif0bb87b72016-02-08 23:52:55 +0900428 final String text = "abc \u0621\u0622\u0623 def";
Keisuke Kuroyanagif0bb87b72016-02-08 23:52:55 +0900429 onView(withId(R.id.textview)).perform(replaceText(text));
430
431 assertNoSelectionHandles();
432
Keisuke Kuroyanagi99e8623182016-11-16 20:05:14 +0900433 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('\u0622')));
Keisuke Kuroyanagif0bb87b72016-02-08 23:52:55 +0900434
435 onHandleView(com.android.internal.R.id.selection_start_handle)
436 .check(matches(isDisplayed()));
437 onHandleView(com.android.internal.R.id.selection_end_handle)
438 .check(matches(isDisplayed()));
439
440 onView(withId(R.id.textview)).check(hasSelection("\u0621\u0622\u0623"));
441
Siyamed Sinir21914182017-06-16 15:24:00 -0700442 final TextView textView = mActivity.findViewById(R.id.textview);
Keisuke Kuroyanagif0bb87b72016-02-08 23:52:55 +0900443 onHandleView(com.android.internal.R.id.selection_start_handle)
444 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('f')));
445 onView(withId(R.id.textview)).check(hasSelection("\u0621\u0622\u0623"));
446
447 onHandleView(com.android.internal.R.id.selection_end_handle)
448 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('a')));
449 onView(withId(R.id.textview)).check(hasSelection("\u0621\u0622\u0623"));
450
451 onHandleView(com.android.internal.R.id.selection_start_handle)
Keisuke Kuroyanagi99e8623182016-11-16 20:05:14 +0900452 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('\u0623'),
Keisuke Kuroyanagif0bb87b72016-02-08 23:52:55 +0900453 false));
454 onView(withId(R.id.textview)).check(hasSelection("\u0623"));
455
456 onHandleView(com.android.internal.R.id.selection_start_handle)
457 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('\u0621'),
458 false));
459 onView(withId(R.id.textview)).check(hasSelection("\u0621\u0622\u0623"));
460
461 onHandleView(com.android.internal.R.id.selection_start_handle)
462 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('a')));
463 onView(withId(R.id.textview)).check(hasSelection("abc \u0621\u0622\u0623"));
464
465 onHandleView(com.android.internal.R.id.selection_end_handle)
466 .perform(dragHandle(textView, Handle.SELECTION_END, text.length()));
467 onView(withId(R.id.textview)).check(hasSelection("abc \u0621\u0622\u0623 def"));
468 }
469
Siyamed Sinir21914182017-06-16 15:24:00 -0700470 @Test
471 public void testSelectionHandles_multiLine() {
Keisuke Kuroyanagic24c2bb2015-11-24 18:48:28 +0900472 final String text = "abcd\n" + "efg\n" + "hijk\n" + "lmn\n" + "opqr";
Keisuke Kuroyanagi99e8623182016-11-16 20:05:14 +0900473 onView(withId(R.id.textview)).perform(replaceText(text));
474 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('i')));
Keisuke Kuroyanagic24c2bb2015-11-24 18:48:28 +0900475
Siyamed Sinir21914182017-06-16 15:24:00 -0700476 final TextView textView = mActivity.findViewById(R.id.textview);
Keisuke Kuroyanagic24c2bb2015-11-24 18:48:28 +0900477 onHandleView(com.android.internal.R.id.selection_start_handle)
478 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('e')));
479 onView(withId(R.id.textview)).check(hasSelection("efg\nhijk"));
480
481 onHandleView(com.android.internal.R.id.selection_start_handle)
482 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('a')));
483 onView(withId(R.id.textview)).check(hasSelection("abcd\nefg\nhijk"));
484
485 onHandleView(com.android.internal.R.id.selection_end_handle)
486 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('n') + 1));
487 onView(withId(R.id.textview)).check(hasSelection("abcd\nefg\nhijk\nlmn"));
488
489 onHandleView(com.android.internal.R.id.selection_end_handle)
490 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('r') + 1));
491 onView(withId(R.id.textview)).check(hasSelection("abcd\nefg\nhijk\nlmn\nopqr"));
492 }
Keisuke Kuroyanagicb6e8422015-11-24 18:51:48 +0900493
Siyamed Sinir21914182017-06-16 15:24:00 -0700494 @Test
495 public void testSelectionHandles_multiLine_rtl() {
Keisuke Kuroyanagi26454142015-12-02 15:04:57 -0800496 // Arabic text.
497 final String text = "\u062A\u062B\u062C\n" + "\u062D\u062E\u062F\n"
498 + "\u0630\u0631\u0632\n" + "\u0633\u0634\u0635\n" + "\u0636\u0637\u0638\n"
499 + "\u0639\u063A\u063B";
Keisuke Kuroyanagi26454142015-12-02 15:04:57 -0800500 onView(withId(R.id.textview)).perform(replaceText(text));
Keisuke Kuroyanagi99e8623182016-11-16 20:05:14 +0900501 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('\u0634')));
Keisuke Kuroyanagi26454142015-12-02 15:04:57 -0800502
Siyamed Sinir21914182017-06-16 15:24:00 -0700503 final TextView textView = mActivity.findViewById(R.id.textview);
Keisuke Kuroyanagi26454142015-12-02 15:04:57 -0800504 onHandleView(com.android.internal.R.id.selection_start_handle)
505 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('\u062E')));
506 onView(withId(R.id.textview)).check(hasSelection(
507 text.substring(text.indexOf('\u062D'), text.indexOf('\u0635') + 1)));
508
509 onHandleView(com.android.internal.R.id.selection_start_handle)
510 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('\u062A')));
511 onView(withId(R.id.textview)).check(hasSelection(
512 text.substring(text.indexOf('\u062A'), text.indexOf('\u0635') + 1)));
513
514 onHandleView(com.android.internal.R.id.selection_end_handle)
515 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('\u0638')));
516 onView(withId(R.id.textview)).check(hasSelection(
517 text.substring(text.indexOf('\u062A'), text.indexOf('\u0638') + 1)));
518
519 onHandleView(com.android.internal.R.id.selection_end_handle)
520 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('\u063B')));
521 onView(withId(R.id.textview)).check(hasSelection(text));
522 }
523
Siyamed Sinir21914182017-06-16 15:24:00 -0700524 @Test
525 public void testSelectionHandles_doesNotPassAnotherHandle() {
Keisuke Kuroyanagicb6e8422015-11-24 18:51:48 +0900526 final String text = "abcd efg hijk lmn";
Keisuke Kuroyanagi99e8623182016-11-16 20:05:14 +0900527 onView(withId(R.id.textview)).perform(replaceText(text));
528 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('f')));
Keisuke Kuroyanagicb6e8422015-11-24 18:51:48 +0900529
Siyamed Sinir21914182017-06-16 15:24:00 -0700530 final TextView textView = mActivity.findViewById(R.id.textview);
Keisuke Kuroyanagicb6e8422015-11-24 18:51:48 +0900531 onHandleView(com.android.internal.R.id.selection_start_handle)
532 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('l')));
533 onView(withId(R.id.textview)).check(hasSelection("g"));
534
Keisuke Kuroyanagi99e8623182016-11-16 20:05:14 +0900535 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('f')));
Keisuke Kuroyanagicb6e8422015-11-24 18:51:48 +0900536 onHandleView(com.android.internal.R.id.selection_end_handle)
537 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('a')));
538 onView(withId(R.id.textview)).check(hasSelection("e"));
539 }
540
Siyamed Sinir21914182017-06-16 15:24:00 -0700541 @Test
542 public void testSelectionHandles_doesNotPassAnotherHandle_multiLine() {
Keisuke Kuroyanagicb6e8422015-11-24 18:51:48 +0900543 final String text = "abcd\n" + "efg\n" + "hijk\n" + "lmn\n" + "opqr";
Keisuke Kuroyanagi99e8623182016-11-16 20:05:14 +0900544 onView(withId(R.id.textview)).perform(replaceText(text));
545 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('i')));
Keisuke Kuroyanagicb6e8422015-11-24 18:51:48 +0900546
Siyamed Sinir21914182017-06-16 15:24:00 -0700547 final TextView textView = mActivity.findViewById(R.id.textview);
Keisuke Kuroyanagicb6e8422015-11-24 18:51:48 +0900548 onHandleView(com.android.internal.R.id.selection_start_handle)
549 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('r') + 1));
550 onView(withId(R.id.textview)).check(hasSelection("k"));
551
Keisuke Kuroyanagi99e8623182016-11-16 20:05:14 +0900552 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('i')));
Keisuke Kuroyanagicb6e8422015-11-24 18:51:48 +0900553 onHandleView(com.android.internal.R.id.selection_end_handle)
554 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('a')));
555 onView(withId(R.id.textview)).check(hasSelection("h"));
556 }
Keisuke Kuroyanagiec913c02015-11-24 18:56:20 +0900557
Siyamed Sinir21914182017-06-16 15:24:00 -0700558 @Test
559 public void testSelectionHandles_snapToWordBoundary() {
Keisuke Kuroyanagiec913c02015-11-24 18:56:20 +0900560 final String text = "abcd efg hijk lmn opqr";
Keisuke Kuroyanagi99e8623182016-11-16 20:05:14 +0900561 onView(withId(R.id.textview)).perform(replaceText(text));
562 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('i')));
Keisuke Kuroyanagiec913c02015-11-24 18:56:20 +0900563
Siyamed Sinir21914182017-06-16 15:24:00 -0700564 final TextView textView = mActivity.findViewById(R.id.textview);
Keisuke Kuroyanagiec913c02015-11-24 18:56:20 +0900565
566 onHandleView(com.android.internal.R.id.selection_start_handle)
567 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('f')));
568 onView(withId(R.id.textview)).check(hasSelection("efg hijk"));
569
570 onHandleView(com.android.internal.R.id.selection_start_handle)
571 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('d') + 1));
572 onView(withId(R.id.textview)).check(hasSelection("efg hijk"));
573
574
575 onHandleView(com.android.internal.R.id.selection_start_handle)
576 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('c')));
577 onView(withId(R.id.textview)).check(hasSelection("abcd efg hijk"));
578
579 onHandleView(com.android.internal.R.id.selection_start_handle)
580 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('d')));
581 onView(withId(R.id.textview)).check(hasSelection("d efg hijk"));
582
583 onHandleView(com.android.internal.R.id.selection_start_handle)
584 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('b')));
585 onView(withId(R.id.textview)).check(hasSelection("bcd efg hijk"));
586
Keisuke Kuroyanagi99e8623182016-11-16 20:05:14 +0900587 onView(withId(R.id.textview)).perform(click());
588 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('i')));
Keisuke Kuroyanagiec913c02015-11-24 18:56:20 +0900589
590 onHandleView(com.android.internal.R.id.selection_end_handle)
591 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('n')));
592 onView(withId(R.id.textview)).check(hasSelection("hijk lmn"));
593
594 onHandleView(com.android.internal.R.id.selection_end_handle)
595 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('o')));
596 onView(withId(R.id.textview)).check(hasSelection("hijk lmn"));
597
598 onHandleView(com.android.internal.R.id.selection_end_handle)
599 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('q')));
600 onView(withId(R.id.textview)).check(hasSelection("hijk lmn opqr"));
601
602 onHandleView(com.android.internal.R.id.selection_end_handle)
603 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('p')));
604 onView(withId(R.id.textview)).check(hasSelection("hijk lmn o"));
605
606 onHandleView(com.android.internal.R.id.selection_end_handle)
607 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('r')));
608 onView(withId(R.id.textview)).check(hasSelection("hijk lmn opq"));
609 }
610
Siyamed Sinir21914182017-06-16 15:24:00 -0700611 @Test
612 public void testSelectionHandles_snapToWordBoundary_multiLine() {
Keisuke Kuroyanagiec913c02015-11-24 18:56:20 +0900613 final String text = "abcd efg\n" + "hijk lmn\n" + "opqr stu";
Keisuke Kuroyanagi99e8623182016-11-16 20:05:14 +0900614 onView(withId(R.id.textview)).perform(replaceText(text));
615 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('m')));
Keisuke Kuroyanagiec913c02015-11-24 18:56:20 +0900616
Siyamed Sinir21914182017-06-16 15:24:00 -0700617 final TextView textView = mActivity.findViewById(R.id.textview);
Keisuke Kuroyanagiec913c02015-11-24 18:56:20 +0900618
619 onHandleView(com.android.internal.R.id.selection_start_handle)
620 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('c')));
621 onView(withId(R.id.textview)).check(hasSelection("abcd efg\nhijk lmn"));
622
623 onHandleView(com.android.internal.R.id.selection_start_handle)
624 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('g')));
625 onView(withId(R.id.textview)).check(hasSelection("g\nhijk lmn"));
626
627 onHandleView(com.android.internal.R.id.selection_start_handle)
628 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('m')));
629 onView(withId(R.id.textview)).check(hasSelection("lmn"));
630
Keisuke Kuroyanagi99e8623182016-11-16 20:05:14 +0900631 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('i')));
Keisuke Kuroyanagiec913c02015-11-24 18:56:20 +0900632
633 onHandleView(com.android.internal.R.id.selection_end_handle)
634 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('u')));
635 onView(withId(R.id.textview)).check(hasSelection("hijk lmn\nopqr stu"));
636
637 onHandleView(com.android.internal.R.id.selection_end_handle)
638 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('p')));
639 onView(withId(R.id.textview)).check(hasSelection("hijk lmn\no"));
640
641 onHandleView(com.android.internal.R.id.selection_end_handle)
642 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('i')));
643 onView(withId(R.id.textview)).check(hasSelection("hijk"));
644 }
Keisuke Kuroyanagic477b582016-03-15 15:38:40 +0900645
Siyamed Sinir21914182017-06-16 15:24:00 -0700646 @Test
647 public void testSetSelectionAndActionMode() throws Throwable {
Keisuke Kuroyanagic477b582016-03-15 15:38:40 +0900648 final String text = "abc def";
Keisuke Kuroyanagic477b582016-03-15 15:38:40 +0900649 onView(withId(R.id.textview)).perform(replaceText(text));
650
Siyamed Sinir21914182017-06-16 15:24:00 -0700651 final TextView textView = mActivity.findViewById(R.id.textview);
Keisuke Kuroyanagic477b582016-03-15 15:38:40 +0900652 assertFloatingToolbarIsNotDisplayed();
Siyamed Sinir21914182017-06-16 15:24:00 -0700653 mActivityRule.runOnUiThread(
654 () -> Selection.setSelection((Spannable) textView.getText(), 0, 3));
655 mInstrumentation.waitForIdleSync();
Keisuke Kuroyanagic477b582016-03-15 15:38:40 +0900656 sleepForFloatingToolbarPopup();
657 // Don't automatically start action mode.
658 assertFloatingToolbarIsNotDisplayed();
659 // Make sure that "Select All" is included in the selection action mode when the entire text
660 // is not selected.
Keisuke Kuroyanagi99e8623182016-11-16 20:05:14 +0900661 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('e')));
Keisuke Kuroyanagic477b582016-03-15 15:38:40 +0900662 sleepForFloatingToolbarPopup();
663 assertFloatingToolbarIsDisplayed();
664 // Changing the selection range by API should not interrupt the selection action mode.
Siyamed Sinir21914182017-06-16 15:24:00 -0700665 mActivityRule.runOnUiThread(
666 () -> Selection.setSelection((Spannable) textView.getText(), 0, 3));
667 mInstrumentation.waitForIdleSync();
Keisuke Kuroyanagic477b582016-03-15 15:38:40 +0900668 sleepForFloatingToolbarPopup();
669 assertFloatingToolbarIsDisplayed();
670 assertFloatingToolbarContainsItem(
Siyamed Sinir21914182017-06-16 15:24:00 -0700671 mActivity.getString(com.android.internal.R.string.selectAll));
Keisuke Kuroyanagic477b582016-03-15 15:38:40 +0900672 // Make sure that "Select All" is no longer included when the entire text is selected by
673 // API.
Siyamed Sinir21914182017-06-16 15:24:00 -0700674 mActivityRule.runOnUiThread(
Keisuke Kuroyanagic477b582016-03-15 15:38:40 +0900675 () -> Selection.setSelection((Spannable) textView.getText(), 0, text.length()));
Siyamed Sinir21914182017-06-16 15:24:00 -0700676 mInstrumentation.waitForIdleSync();
677
Keisuke Kuroyanagic477b582016-03-15 15:38:40 +0900678 sleepForFloatingToolbarPopup();
679 assertFloatingToolbarIsDisplayed();
680 assertFloatingToolbarDoesNotContainItem(
Siyamed Sinir21914182017-06-16 15:24:00 -0700681 mActivity.getString(com.android.internal.R.string.selectAll));
Keisuke Kuroyanagic477b582016-03-15 15:38:40 +0900682 // Make sure that shrinking the selection range to cursor (an empty range) by API
683 // terminates selection action mode and does not trigger the insertion action mode.
Siyamed Sinir21914182017-06-16 15:24:00 -0700684 mActivityRule.runOnUiThread(
685 () -> Selection.setSelection((Spannable) textView.getText(), 0));
686 mInstrumentation.waitForIdleSync();
687
Keisuke Kuroyanagic477b582016-03-15 15:38:40 +0900688 sleepForFloatingToolbarPopup();
689 assertFloatingToolbarIsNotDisplayed();
690 // Make sure that user click can trigger the insertion action mode.
691 onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
692 onHandleView(com.android.internal.R.id.insertion_handle).perform(click());
693 sleepForFloatingToolbarPopup();
694 assertFloatingToolbarIsDisplayed();
695 // Make sure that an existing insertion action mode keeps alive after the insertion point is
696 // moved by API.
Siyamed Sinir21914182017-06-16 15:24:00 -0700697 mActivityRule.runOnUiThread(
698 () -> Selection.setSelection((Spannable) textView.getText(), 0));
699 mInstrumentation.waitForIdleSync();
700
Keisuke Kuroyanagic477b582016-03-15 15:38:40 +0900701 sleepForFloatingToolbarPopup();
702 assertFloatingToolbarIsDisplayed();
703 assertFloatingToolbarDoesNotContainItem(
Siyamed Sinir21914182017-06-16 15:24:00 -0700704 mActivity.getString(com.android.internal.R.string.copy));
Keisuke Kuroyanagic477b582016-03-15 15:38:40 +0900705 // Make sure that selection action mode is started after selection is created by API when
706 // insertion action mode is active.
Siyamed Sinir21914182017-06-16 15:24:00 -0700707 mActivityRule.runOnUiThread(
Keisuke Kuroyanagic477b582016-03-15 15:38:40 +0900708 () -> Selection.setSelection((Spannable) textView.getText(), 1, text.length()));
Siyamed Sinir21914182017-06-16 15:24:00 -0700709 mInstrumentation.waitForIdleSync();
710
Keisuke Kuroyanagic477b582016-03-15 15:38:40 +0900711 sleepForFloatingToolbarPopup();
712 assertFloatingToolbarIsDisplayed();
713 assertFloatingToolbarContainsItem(
Siyamed Sinir21914182017-06-16 15:24:00 -0700714 mActivity.getString(com.android.internal.R.string.copy));
Keisuke Kuroyanagic477b582016-03-15 15:38:40 +0900715 }
Keisuke Kuroyanagi183fd502016-04-01 15:00:53 +0900716
Siyamed Sinir21914182017-06-16 15:24:00 -0700717 @Test
718 public void testTransientState() throws Throwable {
Keisuke Kuroyanagi183fd502016-04-01 15:00:53 +0900719 final String text = "abc def";
Keisuke Kuroyanagi183fd502016-04-01 15:00:53 +0900720 onView(withId(R.id.textview)).perform(replaceText(text));
721
Siyamed Sinir21914182017-06-16 15:24:00 -0700722 final TextView textView = mActivity.findViewById(R.id.textview);
Keisuke Kuroyanagi183fd502016-04-01 15:00:53 +0900723 assertFalse(textView.hasTransientState());
724
725 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('b')));
726 // hasTransientState should return true when user generated selection is active.
727 assertTrue(textView.hasTransientState());
728 onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.indexOf('d')));
729 // hasTransientState should return false as the selection has been cleared.
730 assertFalse(textView.hasTransientState());
Siyamed Sinir21914182017-06-16 15:24:00 -0700731 mActivityRule.runOnUiThread(
Keisuke Kuroyanagi183fd502016-04-01 15:00:53 +0900732 () -> Selection.setSelection((Spannable) textView.getText(), 0, text.length()));
Siyamed Sinir21914182017-06-16 15:24:00 -0700733 mInstrumentation.waitForIdleSync();
734
Keisuke Kuroyanagi183fd502016-04-01 15:00:53 +0900735 // hasTransientState should return false when selection is created by API.
736 assertFalse(textView.hasTransientState());
737 }
Abodunrinwa Toki6eecdc92017-04-11 05:15:25 +0100738
Siyamed Sinir21914182017-06-16 15:24:00 -0700739 @Test
740 public void testResetMenuItemTitle() throws Throwable {
741 mActivity.getSystemService(TextClassificationManager.class).setTextClassifier(null);
742 final TextView textView = mActivity.findViewById(R.id.textview);
Abodunrinwa Toki7b971802017-05-23 19:01:56 +0100743 final int itemId = 1;
744 final String title1 = " AFIGBO";
745 final int index = title1.indexOf('I');
746 final String title2 = title1.substring(index);
747 final String[] title = new String[]{title1};
Siyamed Sinir21914182017-06-16 15:24:00 -0700748 mActivityRule.runOnUiThread(() -> textView.setCustomSelectionActionModeCallback(
Abodunrinwa Toki7b971802017-05-23 19:01:56 +0100749 new ActionMode.Callback() {
750 @Override
751 public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
752 return true;
753 }
754
755 @Override
756 public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
757 menu.removeItem(itemId);
758 menu.add(Menu.NONE /* group */, itemId, 0 /* order */, title[0]);
759 return true;
760 }
761
762 @Override
763 public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
764 return false;
765 }
766
767 @Override
768 public void onDestroyActionMode(ActionMode actionMode) {
769 }
770 }));
Siyamed Sinir21914182017-06-16 15:24:00 -0700771 mInstrumentation.waitForIdleSync();
772
Abodunrinwa Toki7b971802017-05-23 19:01:56 +0100773 onView(withId(R.id.textview)).perform(replaceText(title1));
774 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(index));
775 sleepForFloatingToolbarPopup();
776 assertFloatingToolbarContainsItem(title1);
777
778 // Change the menu item title.
779 title[0] = title2;
780 // Change the selection to invalidate the action mode without restarting it.
781 onHandleView(com.android.internal.R.id.selection_start_handle)
782 .perform(dragHandle(textView, Handle.SELECTION_START, index));
783 sleepForFloatingToolbarPopup();
784 assertFloatingToolbarContainsItem(title2);
785 }
786
Siyamed Sinir21914182017-06-16 15:24:00 -0700787 @Test
788 public void testAssistItemIsAtIndexZero() throws Throwable {
Abodunrinwa Toki76b51dc2017-07-13 23:37:11 +0100789 useSystemDefaultTextClassifier();
Siyamed Sinir21914182017-06-16 15:24:00 -0700790 final TextView textView = mActivity.findViewById(R.id.textview);
791 mActivityRule.runOnUiThread(() -> textView.setCustomSelectionActionModeCallback(
Abodunrinwa Toki6eecdc92017-04-11 05:15:25 +0100792 new ActionMode.Callback() {
793 @Override
794 public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
795 // Create another item at order position 0 to confirm that it will never be
796 // placed before the textAssist item.
797 menu.add(Menu.NONE, 0 /* id */, 0 /* order */, "Test");
798 return true;
799 }
800
801 @Override
802 public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
803 return true;
804 }
805
806 @Override
807 public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
808 return false;
809 }
810
811 @Override
Abodunrinwa Tokiea6cb122017-04-28 22:14:13 +0100812 public void onDestroyActionMode(ActionMode actionMode) {
813 }
Abodunrinwa Toki6eecdc92017-04-11 05:15:25 +0100814 }));
Siyamed Sinir21914182017-06-16 15:24:00 -0700815 mInstrumentation.waitForIdleSync();
Abodunrinwa Toki6eecdc92017-04-11 05:15:25 +0100816 final String text = "droid@android.com";
817
818 onView(withId(R.id.textview)).perform(replaceText(text));
819 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('@')));
820 sleepForFloatingToolbarPopup();
821 assertFloatingToolbarItemIndex(android.R.id.textAssist, 0);
822 }
Abodunrinwa Tokiea6cb122017-04-28 22:14:13 +0100823
Siyamed Sinir21914182017-06-16 15:24:00 -0700824 @Test
Abodunrinwa Toki76b51dc2017-07-13 23:37:11 +0100825 public void testNoAssistItemForPasswordField() throws Throwable {
826 useSystemDefaultTextClassifier();
827 final TextView textView = mActivity.findViewById(R.id.textview);
828 mActivityRule.runOnUiThread(() -> {
829 textView.setInputType(
830 InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
831 });
832 mInstrumentation.waitForIdleSync();
833 final String password = "afigbo@android.com";
834
835 onView(withId(R.id.textview)).perform(replaceText(password));
836 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(password.indexOf('@')));
837 sleepForFloatingToolbarPopup();
838 assertFloatingToolbarDoesNotContainItem(android.R.id.textAssist);
839 }
840
841 @Test
Siyamed Sinir21914182017-06-16 15:24:00 -0700842 public void testPastePlainText_menuAction() {
Abodunrinwa Tokiea6cb122017-04-28 22:14:13 +0100843 initializeClipboardWithText(TextStyle.STYLED);
844
845 onView(withId(R.id.textview)).perform(replaceText(""));
846 onView(withId(R.id.textview)).perform(longClick());
847 sleepForFloatingToolbarPopup();
848 clickFloatingToolbarItem(
Siyamed Sinir21914182017-06-16 15:24:00 -0700849 mActivity.getString(com.android.internal.R.string.paste_as_plain_text));
850 mInstrumentation.waitForIdleSync();
Abodunrinwa Tokiea6cb122017-04-28 22:14:13 +0100851
852 onView(withId(R.id.textview)).check(matches(withText("styledtext")));
853 onView(withId(R.id.textview)).check(doesNotHaveStyledText());
854 }
855
Siyamed Sinir21914182017-06-16 15:24:00 -0700856 @Test
Abodunrinwa Tokiea6cb122017-04-28 22:14:13 +0100857 public void testPastePlainText_noMenuItemForPlainText() {
858 initializeClipboardWithText(TextStyle.PLAIN);
859
860 onView(withId(R.id.textview)).perform(replaceText(""));
861 onView(withId(R.id.textview)).perform(longClick());
862 sleepForFloatingToolbarPopup();
863
864 assertFloatingToolbarDoesNotContainItem(
Siyamed Sinir21914182017-06-16 15:24:00 -0700865 mActivity.getString(com.android.internal.R.string.paste_as_plain_text));
Abodunrinwa Tokiea6cb122017-04-28 22:14:13 +0100866 }
867
Abodunrinwa Toki76b51dc2017-07-13 23:37:11 +0100868 private void useSystemDefaultTextClassifier() {
869 mActivity.getSystemService(TextClassificationManager.class).setTextClassifier(null);
870 }
871
Abodunrinwa Tokiea6cb122017-04-28 22:14:13 +0100872 private void initializeClipboardWithText(TextStyle textStyle) {
873 final ClipData clip;
874 switch (textStyle) {
875 case STYLED:
876 clip = ClipData.newHtmlText("html", "styledtext", "<b>styledtext</b>");
877 break;
878 case PLAIN:
879 clip = ClipData.newPlainText("plain", "plaintext");
880 break;
881 default:
882 throw new IllegalArgumentException("Invalid text style");
883 }
Siyamed Sinir21914182017-06-16 15:24:00 -0700884 mActivity.getWindow().getDecorView().post(() ->
885 mActivity.getSystemService(ClipboardManager.class).setPrimaryClip(clip));
886 mInstrumentation.waitForIdleSync();
Abodunrinwa Tokiea6cb122017-04-28 22:14:13 +0100887 }
888
889 private enum TextStyle {
890 PLAIN, STYLED
891 }
Abodunrinwa Toki223c8392015-07-24 20:55:59 -0700892}