1223c8392f066823cf4a3a98957960deb80ab1680Abodunrinwa Toki/*
2223c8392f066823cf4a3a98957960deb80ab1680Abodunrinwa Toki * Copyright (C) 2015 The Android Open Source Project
3223c8392f066823cf4a3a98957960deb80ab1680Abodunrinwa Toki *
4223c8392f066823cf4a3a98957960deb80ab1680Abodunrinwa Toki * Licensed under the Apache License, Version 2.0 (the "License");
5223c8392f066823cf4a3a98957960deb80ab1680Abodunrinwa Toki * you may not use this file except in compliance with the License.
6223c8392f066823cf4a3a98957960deb80ab1680Abodunrinwa Toki * You may obtain a copy of the License at
7223c8392f066823cf4a3a98957960deb80ab1680Abodunrinwa Toki *
8223c8392f066823cf4a3a98957960deb80ab1680Abodunrinwa Toki *      http://www.apache.org/licenses/LICENSE-2.0
9223c8392f066823cf4a3a98957960deb80ab1680Abodunrinwa Toki *
10223c8392f066823cf4a3a98957960deb80ab1680Abodunrinwa Toki * Unless required by applicable law or agreed to in writing, software
11223c8392f066823cf4a3a98957960deb80ab1680Abodunrinwa Toki * distributed under the License is distributed on an "AS IS" BASIS,
12223c8392f066823cf4a3a98957960deb80ab1680Abodunrinwa Toki * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13223c8392f066823cf4a3a98957960deb80ab1680Abodunrinwa Toki * See the License for the specific language governing permissions and
14223c8392f066823cf4a3a98957960deb80ab1680Abodunrinwa Toki * limitations under the License
15223c8392f066823cf4a3a98957960deb80ab1680Abodunrinwa Toki */
16223c8392f066823cf4a3a98957960deb80ab1680Abodunrinwa Toki
17223c8392f066823cf4a3a98957960deb80ab1680Abodunrinwa Tokipackage android.widget;
18223c8392f066823cf4a3a98957960deb80ab1680Abodunrinwa Toki
192191418305ca42e4f219020a02f16c045c539755Siyamed Sinirimport static android.support.test.espresso.Espresso.onView;
202191418305ca42e4f219020a02f16c045c539755Siyamed Sinirimport static android.support.test.espresso.action.ViewActions.click;
212191418305ca42e4f219020a02f16c045c539755Siyamed Sinirimport static android.support.test.espresso.action.ViewActions.longClick;
222191418305ca42e4f219020a02f16c045c539755Siyamed Sinirimport static android.support.test.espresso.action.ViewActions.pressKey;
232191418305ca42e4f219020a02f16c045c539755Siyamed Sinirimport static android.support.test.espresso.action.ViewActions.replaceText;
242191418305ca42e4f219020a02f16c045c539755Siyamed Sinirimport static android.support.test.espresso.assertion.ViewAssertions.matches;
252191418305ca42e4f219020a02f16c045c539755Siyamed Sinirimport static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
262191418305ca42e4f219020a02f16c045c539755Siyamed Sinirimport static android.support.test.espresso.matcher.ViewMatchers.withId;
272191418305ca42e4f219020a02f16c045c539755Siyamed Sinirimport static android.support.test.espresso.matcher.ViewMatchers.withText;
289479d3ebe2457726d5b3624774b5540fb7d1e09cAbodunrinwa Tokiimport static android.widget.espresso.CustomViewActions.longPressAtRelativeCoordinates;
29d42cb8ffa77266abe3bcffe98212d313d223a86cKeisuke Kuroyanagiimport static android.widget.espresso.DragHandleUtils.assertNoSelectionHandles;
30d42cb8ffa77266abe3bcffe98212d313d223a86cKeisuke Kuroyanagiimport static android.widget.espresso.DragHandleUtils.onHandleView;
312191418305ca42e4f219020a02f16c045c539755Siyamed Sinirimport static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarContainsItem;
322191418305ca42e4f219020a02f16c045c539755Siyamed Sinirimport static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarDoesNotContainItem;
332191418305ca42e4f219020a02f16c045c539755Siyamed Sinirimport static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarIsDisplayed;
342191418305ca42e4f219020a02f16c045c539755Siyamed Sinirimport static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarIsNotDisplayed;
352191418305ca42e4f219020a02f16c045c539755Siyamed Sinirimport static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarItemIndex;
362191418305ca42e4f219020a02f16c045c539755Siyamed Sinirimport static android.widget.espresso.FloatingToolbarEspressoUtils.clickFloatingToolbarItem;
372191418305ca42e4f219020a02f16c045c539755Siyamed Sinirimport static android.widget.espresso.FloatingToolbarEspressoUtils.sleepForFloatingToolbarPopup;
382191418305ca42e4f219020a02f16c045c539755Siyamed Sinirimport static android.widget.espresso.TextViewActions.Handle;
3990cdfe0514154bbc008d39f1c99f7a1d2684446cAbodunrinwa Tokiimport static android.widget.espresso.TextViewActions.clickOnTextAtIndex;
408a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Tokiimport static android.widget.espresso.TextViewActions.doubleClickOnTextAtIndex;
412191418305ca42e4f219020a02f16c045c539755Siyamed Sinirimport static android.widget.espresso.TextViewActions.doubleTapAndDragOnText;
42da79ee683d74f2ad7d29147a30f3da17dd0ea6e2Keisuke Kuroyanagiimport static android.widget.espresso.TextViewActions.dragHandle;
43ca4aaf3c17fdea4e373accc212867bd9f1e2be7fAbodunrinwa Tokiimport static android.widget.espresso.TextViewActions.longPressAndDragOnText;
448a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Tokiimport static android.widget.espresso.TextViewActions.longPressOnTextAtIndex;
452191418305ca42e4f219020a02f16c045c539755Siyamed Sinirimport static android.widget.espresso.TextViewAssertions.doesNotHaveStyledText;
468a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Tokiimport static android.widget.espresso.TextViewAssertions.hasInsertionPointerAtIndex;
47ca4aaf3c17fdea4e373accc212867bd9f1e2be7fAbodunrinwa Tokiimport static android.widget.espresso.TextViewAssertions.hasSelection;
482191418305ca42e4f219020a02f16c045c539755Siyamed Sinir
492191418305ca42e4f219020a02f16c045c539755Siyamed Sinirimport static junit.framework.Assert.assertFalse;
502191418305ca42e4f219020a02f16c045c539755Siyamed Sinirimport static junit.framework.Assert.assertTrue;
512191418305ca42e4f219020a02f16c045c539755Siyamed Sinir
52c5b54bae62d5d82a576ca267202675652144185cAbodunrinwa Tokiimport static org.hamcrest.Matchers.anyOf;
53c5b54bae62d5d82a576ca267202675652144185cAbodunrinwa Tokiimport static org.hamcrest.Matchers.is;
54223c8392f066823cf4a3a98957960deb80ab1680Abodunrinwa Toki
552191418305ca42e4f219020a02f16c045c539755Siyamed Sinirimport android.app.Activity;
562191418305ca42e4f219020a02f16c045c539755Siyamed Sinirimport android.app.Instrumentation;
57ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Tokiimport android.content.ClipData;
58ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Tokiimport android.content.ClipboardManager;
592191418305ca42e4f219020a02f16c045c539755Siyamed Sinirimport android.support.test.InstrumentationRegistry;
602191418305ca42e4f219020a02f16c045c539755Siyamed Sinirimport android.support.test.espresso.action.EspressoKey;
612191418305ca42e4f219020a02f16c045c539755Siyamed Sinirimport android.support.test.filters.MediumTest;
622191418305ca42e4f219020a02f16c045c539755Siyamed Sinirimport android.support.test.rule.ActivityTestRule;
632191418305ca42e4f219020a02f16c045c539755Siyamed Sinirimport android.support.test.runner.AndroidJUnit4;
642191418305ca42e4f219020a02f16c045c539755Siyamed Sinirimport android.text.InputType;
652191418305ca42e4f219020a02f16c045c539755Siyamed Sinirimport android.text.Selection;
662191418305ca42e4f219020a02f16c045c539755Siyamed Sinirimport android.text.Spannable;
676eecdc934c6050d67a639116cde600c09e5b76bdAbodunrinwa Tokiimport android.view.ActionMode;
682191418305ca42e4f219020a02f16c045c539755Siyamed Sinirimport android.view.KeyEvent;
696eecdc934c6050d67a639116cde600c09e5b76bdAbodunrinwa Tokiimport android.view.Menu;
706eecdc934c6050d67a639116cde600c09e5b76bdAbodunrinwa Tokiimport android.view.MenuItem;
716eecdc934c6050d67a639116cde600c09e5b76bdAbodunrinwa Tokiimport android.view.textclassifier.TextClassificationManager;
726eecdc934c6050d67a639116cde600c09e5b76bdAbodunrinwa Tokiimport android.view.textclassifier.TextClassifier;
739479d3ebe2457726d5b3624774b5540fb7d1e09cAbodunrinwa Tokiimport android.widget.espresso.CustomViewActions.RelativeCoordinatesProvider;
74223c8392f066823cf4a3a98957960deb80ab1680Abodunrinwa Toki
75c5b54bae62d5d82a576ca267202675652144185cAbodunrinwa Tokiimport com.android.frameworks.coretests.R;
76e27e0850fe4acbdc911e2e4e6272be10ac2f2779Keisuke Kuroyanagi
772191418305ca42e4f219020a02f16c045c539755Siyamed Sinirimport org.junit.Before;
782191418305ca42e4f219020a02f16c045c539755Siyamed Sinirimport org.junit.Rule;
792191418305ca42e4f219020a02f16c045c539755Siyamed Sinirimport org.junit.Test;
802191418305ca42e4f219020a02f16c045c539755Siyamed Sinirimport org.junit.runner.RunWith;
812191418305ca42e4f219020a02f16c045c539755Siyamed Sinir
82223c8392f066823cf4a3a98957960deb80ab1680Abodunrinwa Toki/**
83223c8392f066823cf4a3a98957960deb80ab1680Abodunrinwa Toki * Tests the TextView widget from an Activity
84223c8392f066823cf4a3a98957960deb80ab1680Abodunrinwa Toki */
852191418305ca42e4f219020a02f16c045c539755Siyamed Sinir@RunWith(AndroidJUnit4.class)
86c5b54bae62d5d82a576ca267202675652144185cAbodunrinwa Toki@MediumTest
872191418305ca42e4f219020a02f16c045c539755Siyamed Sinirpublic class TextViewActivityTest {
88223c8392f066823cf4a3a98957960deb80ab1680Abodunrinwa Toki
892191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    @Rule
902191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    public ActivityTestRule<TextViewActivity> mActivityRule = new ActivityTestRule<>(
912191418305ca42e4f219020a02f16c045c539755Siyamed Sinir            TextViewActivity.class);
922191418305ca42e4f219020a02f16c045c539755Siyamed Sinir
932191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    private Activity mActivity;
942191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    private Instrumentation mInstrumentation;
95223c8392f066823cf4a3a98957960deb80ab1680Abodunrinwa Toki
962191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    @Before
972191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    public void setUp() {
982191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        mActivity = mActivityRule.getActivity();
992191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        mInstrumentation = InstrumentationRegistry.getInstrumentation();
1002191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        mActivity.getSystemService(TextClassificationManager.class)
1016eecdc934c6050d67a639116cde600c09e5b76bdAbodunrinwa Toki                .setTextClassifier(TextClassifier.NO_OP);
102c9e924eb5347872aeec64ed09d1793ac8483ea10Abodunrinwa Toki    }
103c9e924eb5347872aeec64ed09d1793ac8483ea10Abodunrinwa Toki
1042191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    @Test
1052191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    public void testTypedTextIsOnScreen() {
106223c8392f066823cf4a3a98957960deb80ab1680Abodunrinwa Toki        final String helloWorld = "Hello world!";
10799e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        // We use replaceText instead of typeTextIntoFocusedView to input text to avoid
10899e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        // unintentional interactions with software keyboard.
10999e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(replaceText(helloWorld));
110223c8392f066823cf4a3a98957960deb80ab1680Abodunrinwa Toki
111223c8392f066823cf4a3a98957960deb80ab1680Abodunrinwa Toki        onView(withId(R.id.textview)).check(matches(withText(helloWorld)));
112223c8392f066823cf4a3a98957960deb80ab1680Abodunrinwa Toki    }
1132191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    @Test
1142191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    public void testPositionCursorAtTextAtIndex() {
11590cdfe0514154bbc008d39f1c99f7a1d2684446cAbodunrinwa Toki        final String helloWorld = "Hello world!";
11699e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(replaceText(helloWorld));
11790cdfe0514154bbc008d39f1c99f7a1d2684446cAbodunrinwa Toki        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(helloWorld.indexOf("world")));
11890cdfe0514154bbc008d39f1c99f7a1d2684446cAbodunrinwa Toki
11990cdfe0514154bbc008d39f1c99f7a1d2684446cAbodunrinwa Toki        // Delete text at specified index and see if we got the right one.
12090cdfe0514154bbc008d39f1c99f7a1d2684446cAbodunrinwa Toki        onView(withId(R.id.textview)).perform(pressKey(KeyEvent.KEYCODE_FORWARD_DEL));
12190cdfe0514154bbc008d39f1c99f7a1d2684446cAbodunrinwa Toki        onView(withId(R.id.textview)).check(matches(withText("Hello orld!")));
12290cdfe0514154bbc008d39f1c99f7a1d2684446cAbodunrinwa Toki    }
123ca4aaf3c17fdea4e373accc212867bd9f1e2be7fAbodunrinwa Toki
1242191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    @Test
1252191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    public void testPositionCursorAtTextAtIndex_arabic() {
126e27e0850fe4acbdc911e2e4e6272be10ac2f2779Keisuke Kuroyanagi        // Arabic text. The expected cursorable boundary is
127e27e0850fe4acbdc911e2e4e6272be10ac2f2779Keisuke Kuroyanagi        // | \u0623 \u064F | \u067A | \u0633 \u0652 |
128e27e0850fe4acbdc911e2e4e6272be10ac2f2779Keisuke Kuroyanagi        final String text = "\u0623\u064F\u067A\u0633\u0652";
129e27e0850fe4acbdc911e2e4e6272be10ac2f2779Keisuke Kuroyanagi        onView(withId(R.id.textview)).perform(replaceText(text));
130e27e0850fe4acbdc911e2e4e6272be10ac2f2779Keisuke Kuroyanagi
131e27e0850fe4acbdc911e2e4e6272be10ac2f2779Keisuke Kuroyanagi        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(0));
132e27e0850fe4acbdc911e2e4e6272be10ac2f2779Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(0));
133e27e0850fe4acbdc911e2e4e6272be10ac2f2779Keisuke Kuroyanagi        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(1));
134e27e0850fe4acbdc911e2e4e6272be10ac2f2779Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(anyOf(is(0), is(2))));
135e27e0850fe4acbdc911e2e4e6272be10ac2f2779Keisuke Kuroyanagi        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(2));
136e27e0850fe4acbdc911e2e4e6272be10ac2f2779Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(2));
137e27e0850fe4acbdc911e2e4e6272be10ac2f2779Keisuke Kuroyanagi        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(3));
138e27e0850fe4acbdc911e2e4e6272be10ac2f2779Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(3));
139e27e0850fe4acbdc911e2e4e6272be10ac2f2779Keisuke Kuroyanagi        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(4));
140e27e0850fe4acbdc911e2e4e6272be10ac2f2779Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(anyOf(is(3), is(5))));
141e27e0850fe4acbdc911e2e4e6272be10ac2f2779Keisuke Kuroyanagi        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(5));
142e27e0850fe4acbdc911e2e4e6272be10ac2f2779Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(5));
143e27e0850fe4acbdc911e2e4e6272be10ac2f2779Keisuke Kuroyanagi    }
144e27e0850fe4acbdc911e2e4e6272be10ac2f2779Keisuke Kuroyanagi
1452191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    @Test
1462191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    public void testPositionCursorAtTextAtIndex_devanagari() {
147e27e0850fe4acbdc911e2e4e6272be10ac2f2779Keisuke Kuroyanagi        // Devanagari text. The expected cursorable boundary is | \u0915 \u093E |
148e27e0850fe4acbdc911e2e4e6272be10ac2f2779Keisuke Kuroyanagi        final String text = "\u0915\u093E";
149e27e0850fe4acbdc911e2e4e6272be10ac2f2779Keisuke Kuroyanagi        onView(withId(R.id.textview)).perform(replaceText(text));
150e27e0850fe4acbdc911e2e4e6272be10ac2f2779Keisuke Kuroyanagi
151e27e0850fe4acbdc911e2e4e6272be10ac2f2779Keisuke Kuroyanagi        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(0));
152e27e0850fe4acbdc911e2e4e6272be10ac2f2779Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(0));
153e27e0850fe4acbdc911e2e4e6272be10ac2f2779Keisuke Kuroyanagi        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(1));
154e27e0850fe4acbdc911e2e4e6272be10ac2f2779Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(anyOf(is(0), is(2))));
155e27e0850fe4acbdc911e2e4e6272be10ac2f2779Keisuke Kuroyanagi        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(2));
156e27e0850fe4acbdc911e2e4e6272be10ac2f2779Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(2));
157e27e0850fe4acbdc911e2e4e6272be10ac2f2779Keisuke Kuroyanagi    }
158e27e0850fe4acbdc911e2e4e6272be10ac2f2779Keisuke Kuroyanagi
1592191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    @Test
1602191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    public void testLongPressToSelect() {
1618a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki        final String helloWorld = "Hello Kirk!";
1628a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki        onView(withId(R.id.textview)).perform(click());
16399e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(replaceText(helloWorld));
1648a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki        onView(withId(R.id.textview)).perform(
1658a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki                longPressOnTextAtIndex(helloWorld.indexOf("Kirk")));
1668a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki
1678a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki        onView(withId(R.id.textview)).check(hasSelection("Kirk"));
1688a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki    }
1698a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki
1702191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    @Test
1712191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    public void testLongPressEmptySpace() {
1728a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki        final String helloWorld = "Hello big round sun!";
17399e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(replaceText(helloWorld));
1748a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki        // Move cursor somewhere else
1758a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(helloWorld.indexOf("big")));
1768a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki        // Long-press at end of line.
1779479d3ebe2457726d5b3624774b5540fb7d1e09cAbodunrinwa Toki        onView(withId(R.id.textview)).perform(longPressAtRelativeCoordinates(
1789479d3ebe2457726d5b3624774b5540fb7d1e09cAbodunrinwa Toki                RelativeCoordinatesProvider.HorizontalReference.RIGHT, -5,
1799479d3ebe2457726d5b3624774b5540fb7d1e09cAbodunrinwa Toki                RelativeCoordinatesProvider.VerticalReference.CENTER, 0));
1808a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki
1818a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(helloWorld.length()));
1828a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki    }
1838a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki
1842191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    @Test
1852191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    public void testLongPressAndDragToSelect() {
186ca4aaf3c17fdea4e373accc212867bd9f1e2be7fAbodunrinwa Toki        final String helloWorld = "Hello little handsome boy!";
18799e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(replaceText(helloWorld));
188ca4aaf3c17fdea4e373accc212867bd9f1e2be7fAbodunrinwa Toki        onView(withId(R.id.textview)).perform(
189ca4aaf3c17fdea4e373accc212867bd9f1e2be7fAbodunrinwa Toki                longPressAndDragOnText(helloWorld.indexOf("little"), helloWorld.indexOf(" boy!")));
190ca4aaf3c17fdea4e373accc212867bd9f1e2be7fAbodunrinwa Toki
191ca4aaf3c17fdea4e373accc212867bd9f1e2be7fAbodunrinwa Toki        onView(withId(R.id.textview)).check(hasSelection("little handsome"));
192ca4aaf3c17fdea4e373accc212867bd9f1e2be7fAbodunrinwa Toki    }
193ca4aaf3c17fdea4e373accc212867bd9f1e2be7fAbodunrinwa Toki
1942191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    @Test
1952191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    public void testLongPressAndDragToSelect_emoji() {
196133dfc0068d9f14eb9907a4ca77e4e87e8a705e4Keisuke Kuroyanagi        final String text = "\uD83D\uDE00\uD83D\uDE01\uD83D\uDE02\uD83D\uDE03";
197133dfc0068d9f14eb9907a4ca77e4e87e8a705e4Keisuke Kuroyanagi        onView(withId(R.id.textview)).perform(replaceText(text));
198133dfc0068d9f14eb9907a4ca77e4e87e8a705e4Keisuke Kuroyanagi
199133dfc0068d9f14eb9907a4ca77e4e87e8a705e4Keisuke Kuroyanagi        onView(withId(R.id.textview)).perform(longPressAndDragOnText(4, 6));
200133dfc0068d9f14eb9907a4ca77e4e87e8a705e4Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection("\uD83D\uDE02"));
201133dfc0068d9f14eb9907a4ca77e4e87e8a705e4Keisuke Kuroyanagi
202133dfc0068d9f14eb9907a4ca77e4e87e8a705e4Keisuke Kuroyanagi        onView(withId(R.id.textview)).perform(click());
203133dfc0068d9f14eb9907a4ca77e4e87e8a705e4Keisuke Kuroyanagi
204133dfc0068d9f14eb9907a4ca77e4e87e8a705e4Keisuke Kuroyanagi        onView(withId(R.id.textview)).perform(longPressAndDragOnText(4, 2));
205133dfc0068d9f14eb9907a4ca77e4e87e8a705e4Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection("\uD83D\uDE01"));
206133dfc0068d9f14eb9907a4ca77e4e87e8a705e4Keisuke Kuroyanagi    }
207133dfc0068d9f14eb9907a4ca77e4e87e8a705e4Keisuke Kuroyanagi
2082191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    @Test
2092191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    public void testDragAndDrop() {
2104307aeb935ab9c824f90d41bf181660c3937b1e4Keisuke Kuroyanagi        final String text = "abc def ghi.";
21199e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(replaceText(text));
2124307aeb935ab9c824f90d41bf181660c3937b1e4Keisuke Kuroyanagi        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf("e")));
2134307aeb935ab9c824f90d41bf181660c3937b1e4Keisuke Kuroyanagi
2144307aeb935ab9c824f90d41bf181660c3937b1e4Keisuke Kuroyanagi        onView(withId(R.id.textview)).perform(
2154307aeb935ab9c824f90d41bf181660c3937b1e4Keisuke Kuroyanagi                longPressAndDragOnText(text.indexOf("e"), text.length()));
2164307aeb935ab9c824f90d41bf181660c3937b1e4Keisuke Kuroyanagi
2174307aeb935ab9c824f90d41bf181660c3937b1e4Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(matches(withText("abc ghi.def")));
2184307aeb935ab9c824f90d41bf181660c3937b1e4Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection(""));
2194307aeb935ab9c824f90d41bf181660c3937b1e4Keisuke Kuroyanagi        assertNoSelectionHandles();
2204307aeb935ab9c824f90d41bf181660c3937b1e4Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex("abc ghi.def".length()));
221fae4578311970afadca8ee28a47e1e11df00eeddKeisuke Kuroyanagi
222fae4578311970afadca8ee28a47e1e11df00eeddKeisuke Kuroyanagi        // Test undo returns to the original state.
223fae4578311970afadca8ee28a47e1e11df00eeddKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(pressKey(
224fae4578311970afadca8ee28a47e1e11df00eeddKeisuke Kuroyanagi                (new EspressoKey.Builder()).withCtrlPressed(true).withKeyCode(KeyEvent.KEYCODE_Z)
225fae4578311970afadca8ee28a47e1e11df00eeddKeisuke Kuroyanagi                        .build()));
226fae4578311970afadca8ee28a47e1e11df00eeddKeisuke Kuroyanagi        onView(withId(R.id.textview)).check(matches(withText(text)));
2274307aeb935ab9c824f90d41bf181660c3937b1e4Keisuke Kuroyanagi    }
2284307aeb935ab9c824f90d41bf181660c3937b1e4Keisuke Kuroyanagi
2292191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    @Test
2302191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    public void testDoubleTapToSelect() {
2318a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki        final String helloWorld = "Hello SuetYi!";
23299e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(replaceText(helloWorld));
23399e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi
2348a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki        onView(withId(R.id.textview)).perform(
2358a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki                doubleClickOnTextAtIndex(helloWorld.indexOf("SuetYi")));
2368a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki
2378a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki        onView(withId(R.id.textview)).check(hasSelection("SuetYi"));
2388a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki    }
2398a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki
2402191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    @Test
2412191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    public void testDoubleTapAndDragToSelect() {
2422191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        final String helloWorld = "Hello young beautiful person!";
24399e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(replaceText(helloWorld));
2442191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        onView(withId(R.id.textview)).perform(doubleTapAndDragOnText(helloWorld.indexOf("young"),
2452191418305ca42e4f219020a02f16c045c539755Siyamed Sinir                        helloWorld.indexOf(" person!")));
246ca4aaf3c17fdea4e373accc212867bd9f1e2be7fAbodunrinwa Toki
247ca4aaf3c17fdea4e373accc212867bd9f1e2be7fAbodunrinwa Toki        onView(withId(R.id.textview)).check(hasSelection("young beautiful"));
248ca4aaf3c17fdea4e373accc212867bd9f1e2be7fAbodunrinwa Toki    }
2498a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki
2502191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    @Test
2512191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    public void testDoubleTapAndDragToSelect_multiLine() {
25268c433d6052b06f3c9688c740dd55c89f8b43d7fSara Kato        final String helloWorld = "abcd\n" + "efg\n" + "hijklm\n" + "nop";
25368c433d6052b06f3c9688c740dd55c89f8b43d7fSara Kato        onView(withId(R.id.textview)).perform(replaceText(helloWorld));
25468c433d6052b06f3c9688c740dd55c89f8b43d7fSara Kato        onView(withId(R.id.textview)).perform(
25568c433d6052b06f3c9688c740dd55c89f8b43d7fSara Kato                doubleTapAndDragOnText(helloWorld.indexOf("m"), helloWorld.indexOf("a")));
25668c433d6052b06f3c9688c740dd55c89f8b43d7fSara Kato        onView(withId(R.id.textview)).check(hasSelection("abcd\nefg\nhijklm"));
25768c433d6052b06f3c9688c740dd55c89f8b43d7fSara Kato    }
25868c433d6052b06f3c9688c740dd55c89f8b43d7fSara Kato
2592191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    @Test
2602191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    public void testSelectBackwordsByTouch() {
2618a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki        final String helloWorld = "Hello king of the Jungle!";
26299e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(replaceText(helloWorld));
2638a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki        onView(withId(R.id.textview)).perform(
2648a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki                doubleTapAndDragOnText(helloWorld.indexOf(" Jungle!"), helloWorld.indexOf("king")));
2658a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki
2668a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki        onView(withId(R.id.textview)).check(hasSelection("king of the"));
2678a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki    }
2688a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki
2692191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    @Test
2702191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    public void testToolbarAppearsAfterSelection() {
2718a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki        final String text = "Toolbar appears after selection.";
272b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi        assertFloatingToolbarIsNotDisplayed();
27399e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(replaceText(text));
2748a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki        onView(withId(R.id.textview)).perform(
2758a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki                longPressOnTextAtIndex(text.indexOf("appears")));
2768a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki
277b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi        sleepForFloatingToolbarPopup();
278b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi        assertFloatingToolbarIsDisplayed();
279b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi
280b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi        final String text2 = "Toolbar disappears after typing text.";
28199e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(replaceText(text2));
28299e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        sleepForFloatingToolbarPopup();
283b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi        assertFloatingToolbarIsNotDisplayed();
284b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi    }
285b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi
2862191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    @Test
287987ec6588b2279891179c9eff09fc25ec14430c4Siyamed Sinir    public void testToolbarAppearsAfterSelection_withFirstStringLtrAlgorithmAndRtlHint()
2882191418305ca42e4f219020a02f16c045c539755Siyamed Sinir            throws Throwable {
289987ec6588b2279891179c9eff09fc25ec14430c4Siyamed Sinir        // after the hint layout change, the floating toolbar was not visible in the case below
290987ec6588b2279891179c9eff09fc25ec14430c4Siyamed Sinir        // this test tests that the floating toolbar is displayed on the screen and is visible to
291987ec6588b2279891179c9eff09fc25ec14430c4Siyamed Sinir        // user.
2922191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        mActivityRule.runOnUiThread(() -> {
2932191418305ca42e4f219020a02f16c045c539755Siyamed Sinir            final TextView textView = mActivity.findViewById(R.id.textview);
2942191418305ca42e4f219020a02f16c045c539755Siyamed Sinir            textView.setTextDirection(TextView.TEXT_DIRECTION_FIRST_STRONG_LTR);
2952191418305ca42e4f219020a02f16c045c539755Siyamed Sinir            textView.setInputType(InputType.TYPE_CLASS_TEXT);
2962191418305ca42e4f219020a02f16c045c539755Siyamed Sinir            textView.setSingleLine(true);
2972191418305ca42e4f219020a02f16c045c539755Siyamed Sinir            textView.setHint("الروبوت");
298987ec6588b2279891179c9eff09fc25ec14430c4Siyamed Sinir        });
2992191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        mInstrumentation.waitForIdleSync();
300987ec6588b2279891179c9eff09fc25ec14430c4Siyamed Sinir
30199e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(replaceText("test"));
302987ec6588b2279891179c9eff09fc25ec14430c4Siyamed Sinir        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(1));
3032191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        clickFloatingToolbarItem(mActivity.getString(com.android.internal.R.string.cut));
304987ec6588b2279891179c9eff09fc25ec14430c4Siyamed Sinir        onView(withId(R.id.textview)).perform(longClick());
305987ec6588b2279891179c9eff09fc25ec14430c4Siyamed Sinir        sleepForFloatingToolbarPopup();
306987ec6588b2279891179c9eff09fc25ec14430c4Siyamed Sinir
307987ec6588b2279891179c9eff09fc25ec14430c4Siyamed Sinir        assertFloatingToolbarIsDisplayed();
308987ec6588b2279891179c9eff09fc25ec14430c4Siyamed Sinir    }
309987ec6588b2279891179c9eff09fc25ec14430c4Siyamed Sinir
3102191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    @Test
3112191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    public void testToolbarAndInsertionHandle() {
312b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi        final String text = "text";
31399e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(replaceText(text));
314b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
315b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi        assertFloatingToolbarIsNotDisplayed();
316b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi
317b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi        onHandleView(com.android.internal.R.id.insertion_handle).perform(click());
318b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi        sleepForFloatingToolbarPopup();
319b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi        assertFloatingToolbarIsDisplayed();
320b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi
321b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi        assertFloatingToolbarContainsItem(
3222191418305ca42e4f219020a02f16c045c539755Siyamed Sinir                mActivity.getString(com.android.internal.R.string.selectAll));
323b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi        assertFloatingToolbarDoesNotContainItem(
3242191418305ca42e4f219020a02f16c045c539755Siyamed Sinir                mActivity.getString(com.android.internal.R.string.copy));
325b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi        assertFloatingToolbarDoesNotContainItem(
3262191418305ca42e4f219020a02f16c045c539755Siyamed Sinir                mActivity.getString(com.android.internal.R.string.cut));
327b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi    }
328b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi
3292191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    @Test
3302191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    public void testToolbarAndSelectionHandle() {
331b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi        final String text = "abcd efg hijk";
33299e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(replaceText(text));
333b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi
334b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf("f")));
335b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi        sleepForFloatingToolbarPopup();
336b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi        assertFloatingToolbarIsDisplayed();
337b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi
338b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi        assertFloatingToolbarContainsItem(
3392191418305ca42e4f219020a02f16c045c539755Siyamed Sinir                mActivity.getString(com.android.internal.R.string.selectAll));
340b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi        assertFloatingToolbarContainsItem(
3412191418305ca42e4f219020a02f16c045c539755Siyamed Sinir                mActivity.getString(com.android.internal.R.string.copy));
342b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi        assertFloatingToolbarContainsItem(
3432191418305ca42e4f219020a02f16c045c539755Siyamed Sinir                mActivity.getString(com.android.internal.R.string.cut));
344b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi
3452191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        final TextView textView = mActivity.findViewById(R.id.textview);
346b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_start_handle)
347b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('a')));
348b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi        sleepForFloatingToolbarPopup();
349b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi        assertFloatingToolbarIsDisplayed();
350b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi
351b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_end_handle)
352b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_END, text.length()));
353b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi        sleepForFloatingToolbarPopup();
354b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi        assertFloatingToolbarIsDisplayed();
355b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi
356b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi        assertFloatingToolbarDoesNotContainItem(
3572191418305ca42e4f219020a02f16c045c539755Siyamed Sinir                mActivity.getString(com.android.internal.R.string.selectAll));
358b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi        assertFloatingToolbarContainsItem(
3592191418305ca42e4f219020a02f16c045c539755Siyamed Sinir                mActivity.getString(com.android.internal.R.string.copy));
360b0dd77c4115d333527a06cad84bc1c6ea8b4ac8eKeisuke Kuroyanagi        assertFloatingToolbarContainsItem(
3612191418305ca42e4f219020a02f16c045c539755Siyamed Sinir                mActivity.getString(com.android.internal.R.string.cut));
3628a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki    }
363da79ee683d74f2ad7d29147a30f3da17dd0ea6e2Keisuke Kuroyanagi
3642191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    @Test
3652191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    public void testInsertionHandle() {
366e8b3dd47914a52a229c1726b79fe8f02fb59bb73Keisuke Kuroyanagi        final String text = "abcd efg hijk ";
36799e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(replaceText(text));
368e8b3dd47914a52a229c1726b79fe8f02fb59bb73Keisuke Kuroyanagi
369e8b3dd47914a52a229c1726b79fe8f02fb59bb73Keisuke Kuroyanagi        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
370e8b3dd47914a52a229c1726b79fe8f02fb59bb73Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.length()));
371e8b3dd47914a52a229c1726b79fe8f02fb59bb73Keisuke Kuroyanagi
3722191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        final TextView textView = mActivity.findViewById(R.id.textview);
373e8b3dd47914a52a229c1726b79fe8f02fb59bb73Keisuke Kuroyanagi
374e8b3dd47914a52a229c1726b79fe8f02fb59bb73Keisuke Kuroyanagi        onHandleView(com.android.internal.R.id.insertion_handle)
375e8b3dd47914a52a229c1726b79fe8f02fb59bb73Keisuke Kuroyanagi                .perform(dragHandle(textView, Handle.INSERTION, text.indexOf('a')));
376e8b3dd47914a52a229c1726b79fe8f02fb59bb73Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("a")));
377e8b3dd47914a52a229c1726b79fe8f02fb59bb73Keisuke Kuroyanagi
378e8b3dd47914a52a229c1726b79fe8f02fb59bb73Keisuke Kuroyanagi        onHandleView(com.android.internal.R.id.insertion_handle)
379e8b3dd47914a52a229c1726b79fe8f02fb59bb73Keisuke Kuroyanagi                .perform(dragHandle(textView, Handle.INSERTION, text.indexOf('f')));
380e8b3dd47914a52a229c1726b79fe8f02fb59bb73Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("f")));
381e8b3dd47914a52a229c1726b79fe8f02fb59bb73Keisuke Kuroyanagi    }
382e8b3dd47914a52a229c1726b79fe8f02fb59bb73Keisuke Kuroyanagi
3832191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    @Test
3842191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    public void testInsertionHandle_multiLine() {
385e8b3dd47914a52a229c1726b79fe8f02fb59bb73Keisuke Kuroyanagi        final String text = "abcd\n" + "efg\n" + "hijk\n";
38699e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(replaceText(text));
387e8b3dd47914a52a229c1726b79fe8f02fb59bb73Keisuke Kuroyanagi
388e8b3dd47914a52a229c1726b79fe8f02fb59bb73Keisuke Kuroyanagi        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
389e8b3dd47914a52a229c1726b79fe8f02fb59bb73Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.length()));
390e8b3dd47914a52a229c1726b79fe8f02fb59bb73Keisuke Kuroyanagi
3912191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        final TextView textView = mActivity.findViewById(R.id.textview);
392e8b3dd47914a52a229c1726b79fe8f02fb59bb73Keisuke Kuroyanagi
393e8b3dd47914a52a229c1726b79fe8f02fb59bb73Keisuke Kuroyanagi        onHandleView(com.android.internal.R.id.insertion_handle)
394e8b3dd47914a52a229c1726b79fe8f02fb59bb73Keisuke Kuroyanagi                .perform(dragHandle(textView, Handle.INSERTION, text.indexOf('a')));
395e8b3dd47914a52a229c1726b79fe8f02fb59bb73Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("a")));
396e8b3dd47914a52a229c1726b79fe8f02fb59bb73Keisuke Kuroyanagi
397e8b3dd47914a52a229c1726b79fe8f02fb59bb73Keisuke Kuroyanagi        onHandleView(com.android.internal.R.id.insertion_handle)
398e8b3dd47914a52a229c1726b79fe8f02fb59bb73Keisuke Kuroyanagi                .perform(dragHandle(textView, Handle.INSERTION, text.indexOf('f')));
399e8b3dd47914a52a229c1726b79fe8f02fb59bb73Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("f")));
400e8b3dd47914a52a229c1726b79fe8f02fb59bb73Keisuke Kuroyanagi    }
401e8b3dd47914a52a229c1726b79fe8f02fb59bb73Keisuke Kuroyanagi
4022191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    @Test
4032191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    public void testSelectionHandles() {
404da79ee683d74f2ad7d29147a30f3da17dd0ea6e2Keisuke Kuroyanagi        final String text = "abcd efg hijk lmn";
40599e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(replaceText(text));
406fc6e25ef6e288cf75d70cf8185ff1c8831428936Abodunrinwa Toki
407fc6e25ef6e288cf75d70cf8185ff1c8831428936Abodunrinwa Toki        assertNoSelectionHandles();
408fc6e25ef6e288cf75d70cf8185ff1c8831428936Abodunrinwa Toki
40999e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('f')));
410da79ee683d74f2ad7d29147a30f3da17dd0ea6e2Keisuke Kuroyanagi
411fc6e25ef6e288cf75d70cf8185ff1c8831428936Abodunrinwa Toki        onHandleView(com.android.internal.R.id.selection_start_handle)
412fc6e25ef6e288cf75d70cf8185ff1c8831428936Abodunrinwa Toki                .check(matches(isDisplayed()));
413fc6e25ef6e288cf75d70cf8185ff1c8831428936Abodunrinwa Toki        onHandleView(com.android.internal.R.id.selection_end_handle)
414fc6e25ef6e288cf75d70cf8185ff1c8831428936Abodunrinwa Toki                .check(matches(isDisplayed()));
415fc6e25ef6e288cf75d70cf8185ff1c8831428936Abodunrinwa Toki
4162191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        final TextView textView = mActivity.findViewById(R.id.textview);
417da79ee683d74f2ad7d29147a30f3da17dd0ea6e2Keisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_start_handle)
418da79ee683d74f2ad7d29147a30f3da17dd0ea6e2Keisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('a')));
419da79ee683d74f2ad7d29147a30f3da17dd0ea6e2Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection("abcd efg"));
420da79ee683d74f2ad7d29147a30f3da17dd0ea6e2Keisuke Kuroyanagi
421da79ee683d74f2ad7d29147a30f3da17dd0ea6e2Keisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_end_handle)
422da79ee683d74f2ad7d29147a30f3da17dd0ea6e2Keisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('k') + 1));
423da79ee683d74f2ad7d29147a30f3da17dd0ea6e2Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection("abcd efg hijk"));
424da79ee683d74f2ad7d29147a30f3da17dd0ea6e2Keisuke Kuroyanagi    }
425c24c2bbb69634435d1d9fc97671229df245bd8d0Keisuke Kuroyanagi
4262191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    @Test
4272191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    public void testSelectionHandles_bidi() {
428f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi        final String text = "abc \u0621\u0622\u0623 def";
429f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(replaceText(text));
430f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi
431f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi        assertNoSelectionHandles();
432f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi
43399e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('\u0622')));
434f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi
435f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_start_handle)
436f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi                .check(matches(isDisplayed()));
437f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_end_handle)
438f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi                .check(matches(isDisplayed()));
439f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi
440f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection("\u0621\u0622\u0623"));
441f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi
4422191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        final TextView textView = mActivity.findViewById(R.id.textview);
443f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_start_handle)
444f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('f')));
445f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection("\u0621\u0622\u0623"));
446f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi
447f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_end_handle)
448f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('a')));
449f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection("\u0621\u0622\u0623"));
450f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi
451f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_start_handle)
45299e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('\u0623'),
453f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi                        false));
454f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection("\u0623"));
455f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi
456f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_start_handle)
457f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('\u0621'),
458f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi                        false));
459f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection("\u0621\u0622\u0623"));
460f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi
461f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_start_handle)
462f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('a')));
463f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection("abc \u0621\u0622\u0623"));
464f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi
465f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_end_handle)
466f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_END, text.length()));
467f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection("abc \u0621\u0622\u0623 def"));
468f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi    }
469f0bb87b7c40efeeaee58d4c7b767961c9800463eKeisuke Kuroyanagi
4702191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    @Test
4712191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    public void testSelectionHandles_multiLine() {
472c24c2bbb69634435d1d9fc97671229df245bd8d0Keisuke Kuroyanagi        final String text = "abcd\n" + "efg\n" + "hijk\n" + "lmn\n" + "opqr";
47399e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(replaceText(text));
47499e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('i')));
475c24c2bbb69634435d1d9fc97671229df245bd8d0Keisuke Kuroyanagi
4762191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        final TextView textView = mActivity.findViewById(R.id.textview);
477c24c2bbb69634435d1d9fc97671229df245bd8d0Keisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_start_handle)
478c24c2bbb69634435d1d9fc97671229df245bd8d0Keisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('e')));
479c24c2bbb69634435d1d9fc97671229df245bd8d0Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection("efg\nhijk"));
480c24c2bbb69634435d1d9fc97671229df245bd8d0Keisuke Kuroyanagi
481c24c2bbb69634435d1d9fc97671229df245bd8d0Keisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_start_handle)
482c24c2bbb69634435d1d9fc97671229df245bd8d0Keisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('a')));
483c24c2bbb69634435d1d9fc97671229df245bd8d0Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection("abcd\nefg\nhijk"));
484c24c2bbb69634435d1d9fc97671229df245bd8d0Keisuke Kuroyanagi
485c24c2bbb69634435d1d9fc97671229df245bd8d0Keisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_end_handle)
486c24c2bbb69634435d1d9fc97671229df245bd8d0Keisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('n') + 1));
487c24c2bbb69634435d1d9fc97671229df245bd8d0Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection("abcd\nefg\nhijk\nlmn"));
488c24c2bbb69634435d1d9fc97671229df245bd8d0Keisuke Kuroyanagi
489c24c2bbb69634435d1d9fc97671229df245bd8d0Keisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_end_handle)
490c24c2bbb69634435d1d9fc97671229df245bd8d0Keisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('r') + 1));
491c24c2bbb69634435d1d9fc97671229df245bd8d0Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection("abcd\nefg\nhijk\nlmn\nopqr"));
492c24c2bbb69634435d1d9fc97671229df245bd8d0Keisuke Kuroyanagi    }
493cb6e8420cbf8bc4000d4761e38fd6d830fc1aca0Keisuke Kuroyanagi
4942191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    @Test
4952191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    public void testSelectionHandles_multiLine_rtl() {
49626454141a8c489d84b7d486ad03869ff0f44dfdcKeisuke Kuroyanagi        // Arabic text.
49726454141a8c489d84b7d486ad03869ff0f44dfdcKeisuke Kuroyanagi        final String text = "\u062A\u062B\u062C\n" + "\u062D\u062E\u062F\n"
49826454141a8c489d84b7d486ad03869ff0f44dfdcKeisuke Kuroyanagi                + "\u0630\u0631\u0632\n" + "\u0633\u0634\u0635\n" + "\u0636\u0637\u0638\n"
49926454141a8c489d84b7d486ad03869ff0f44dfdcKeisuke Kuroyanagi                + "\u0639\u063A\u063B";
50026454141a8c489d84b7d486ad03869ff0f44dfdcKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(replaceText(text));
50199e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('\u0634')));
50226454141a8c489d84b7d486ad03869ff0f44dfdcKeisuke Kuroyanagi
5032191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        final TextView textView = mActivity.findViewById(R.id.textview);
50426454141a8c489d84b7d486ad03869ff0f44dfdcKeisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_start_handle)
50526454141a8c489d84b7d486ad03869ff0f44dfdcKeisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('\u062E')));
50626454141a8c489d84b7d486ad03869ff0f44dfdcKeisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection(
50726454141a8c489d84b7d486ad03869ff0f44dfdcKeisuke Kuroyanagi                text.substring(text.indexOf('\u062D'), text.indexOf('\u0635') + 1)));
50826454141a8c489d84b7d486ad03869ff0f44dfdcKeisuke Kuroyanagi
50926454141a8c489d84b7d486ad03869ff0f44dfdcKeisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_start_handle)
51026454141a8c489d84b7d486ad03869ff0f44dfdcKeisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('\u062A')));
51126454141a8c489d84b7d486ad03869ff0f44dfdcKeisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection(
51226454141a8c489d84b7d486ad03869ff0f44dfdcKeisuke Kuroyanagi                text.substring(text.indexOf('\u062A'), text.indexOf('\u0635') + 1)));
51326454141a8c489d84b7d486ad03869ff0f44dfdcKeisuke Kuroyanagi
51426454141a8c489d84b7d486ad03869ff0f44dfdcKeisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_end_handle)
51526454141a8c489d84b7d486ad03869ff0f44dfdcKeisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('\u0638')));
51626454141a8c489d84b7d486ad03869ff0f44dfdcKeisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection(
51726454141a8c489d84b7d486ad03869ff0f44dfdcKeisuke Kuroyanagi                text.substring(text.indexOf('\u062A'), text.indexOf('\u0638') + 1)));
51826454141a8c489d84b7d486ad03869ff0f44dfdcKeisuke Kuroyanagi
51926454141a8c489d84b7d486ad03869ff0f44dfdcKeisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_end_handle)
52026454141a8c489d84b7d486ad03869ff0f44dfdcKeisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('\u063B')));
52126454141a8c489d84b7d486ad03869ff0f44dfdcKeisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection(text));
52226454141a8c489d84b7d486ad03869ff0f44dfdcKeisuke Kuroyanagi    }
52326454141a8c489d84b7d486ad03869ff0f44dfdcKeisuke Kuroyanagi
5242191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    @Test
5252191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    public void testSelectionHandles_doesNotPassAnotherHandle() {
526cb6e8420cbf8bc4000d4761e38fd6d830fc1aca0Keisuke Kuroyanagi        final String text = "abcd efg hijk lmn";
52799e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(replaceText(text));
52899e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('f')));
529cb6e8420cbf8bc4000d4761e38fd6d830fc1aca0Keisuke Kuroyanagi
5302191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        final TextView textView = mActivity.findViewById(R.id.textview);
531cb6e8420cbf8bc4000d4761e38fd6d830fc1aca0Keisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_start_handle)
532cb6e8420cbf8bc4000d4761e38fd6d830fc1aca0Keisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('l')));
533cb6e8420cbf8bc4000d4761e38fd6d830fc1aca0Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection("g"));
534cb6e8420cbf8bc4000d4761e38fd6d830fc1aca0Keisuke Kuroyanagi
53599e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('f')));
536cb6e8420cbf8bc4000d4761e38fd6d830fc1aca0Keisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_end_handle)
537cb6e8420cbf8bc4000d4761e38fd6d830fc1aca0Keisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('a')));
538cb6e8420cbf8bc4000d4761e38fd6d830fc1aca0Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection("e"));
539cb6e8420cbf8bc4000d4761e38fd6d830fc1aca0Keisuke Kuroyanagi    }
540cb6e8420cbf8bc4000d4761e38fd6d830fc1aca0Keisuke Kuroyanagi
5412191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    @Test
5422191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    public void testSelectionHandles_doesNotPassAnotherHandle_multiLine() {
543cb6e8420cbf8bc4000d4761e38fd6d830fc1aca0Keisuke Kuroyanagi        final String text = "abcd\n" + "efg\n" + "hijk\n" + "lmn\n" + "opqr";
54499e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(replaceText(text));
54599e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('i')));
546cb6e8420cbf8bc4000d4761e38fd6d830fc1aca0Keisuke Kuroyanagi
5472191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        final TextView textView = mActivity.findViewById(R.id.textview);
548cb6e8420cbf8bc4000d4761e38fd6d830fc1aca0Keisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_start_handle)
549cb6e8420cbf8bc4000d4761e38fd6d830fc1aca0Keisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('r') + 1));
550cb6e8420cbf8bc4000d4761e38fd6d830fc1aca0Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection("k"));
551cb6e8420cbf8bc4000d4761e38fd6d830fc1aca0Keisuke Kuroyanagi
55299e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('i')));
553cb6e8420cbf8bc4000d4761e38fd6d830fc1aca0Keisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_end_handle)
554cb6e8420cbf8bc4000d4761e38fd6d830fc1aca0Keisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('a')));
555cb6e8420cbf8bc4000d4761e38fd6d830fc1aca0Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection("h"));
556cb6e8420cbf8bc4000d4761e38fd6d830fc1aca0Keisuke Kuroyanagi    }
557ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi
5582191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    @Test
5592191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    public void testSelectionHandles_snapToWordBoundary() {
560ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi        final String text = "abcd efg hijk lmn opqr";
56199e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(replaceText(text));
56299e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('i')));
563ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi
5642191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        final TextView textView = mActivity.findViewById(R.id.textview);
565ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi
566ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_start_handle)
567ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('f')));
568ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection("efg hijk"));
569ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi
570ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_start_handle)
571ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('d') + 1));
572ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection("efg hijk"));
573ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi
574ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi
575ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_start_handle)
576ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('c')));
577ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection("abcd efg hijk"));
578ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi
579ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_start_handle)
580ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('d')));
581ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection("d efg hijk"));
582ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi
583ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_start_handle)
584ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('b')));
585ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection("bcd efg hijk"));
586ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi
58799e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(click());
58899e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('i')));
589ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi
590ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_end_handle)
591ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('n')));
592ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection("hijk lmn"));
593ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi
594ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_end_handle)
595ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('o')));
596ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection("hijk lmn"));
597ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi
598ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_end_handle)
599ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('q')));
600ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection("hijk lmn opqr"));
601ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi
602ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_end_handle)
603ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('p')));
604ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection("hijk lmn o"));
605ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi
606ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_end_handle)
607ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('r')));
608ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection("hijk lmn opq"));
609ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi    }
610ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi
6112191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    @Test
6122191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    public void testSelectionHandles_snapToWordBoundary_multiLine() {
613ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi        final String text = "abcd efg\n" + "hijk lmn\n" + "opqr stu";
61499e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(replaceText(text));
61599e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('m')));
616ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi
6172191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        final TextView textView = mActivity.findViewById(R.id.textview);
618ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi
619ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_start_handle)
620ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('c')));
621ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection("abcd efg\nhijk lmn"));
622ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi
623ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_start_handle)
624ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('g')));
625ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection("g\nhijk lmn"));
626ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi
627ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_start_handle)
628ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('m')));
629ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection("lmn"));
630ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi
63199e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('i')));
632ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi
633ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_end_handle)
634ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('u')));
635ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection("hijk lmn\nopqr stu"));
636ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi
637ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_end_handle)
638ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('p')));
639ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection("hijk lmn\no"));
640ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi
641ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi        onHandleView(com.android.internal.R.id.selection_end_handle)
642ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('i')));
643ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi        onView(withId(R.id.textview)).check(hasSelection("hijk"));
644ec913c0eb6c3cb70f69653ee988d440f47e5cc55Keisuke Kuroyanagi    }
645c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi
6462191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    @Test
6472191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    public void testSetSelectionAndActionMode() throws Throwable {
648c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        final String text = "abc def";
649c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(replaceText(text));
650c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi
6512191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        final TextView textView = mActivity.findViewById(R.id.textview);
652c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        assertFloatingToolbarIsNotDisplayed();
6532191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        mActivityRule.runOnUiThread(
6542191418305ca42e4f219020a02f16c045c539755Siyamed Sinir                () -> Selection.setSelection((Spannable) textView.getText(), 0, 3));
6552191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        mInstrumentation.waitForIdleSync();
656c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        sleepForFloatingToolbarPopup();
657c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        // Don't automatically start action mode.
658c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        assertFloatingToolbarIsNotDisplayed();
659c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        // Make sure that "Select All" is included in the selection action mode when the entire text
660c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        // is not selected.
66199e86231851c23a6d198b2abeb880db097c541aeKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('e')));
662c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        sleepForFloatingToolbarPopup();
663c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        assertFloatingToolbarIsDisplayed();
664c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        // Changing the selection range by API should not interrupt the selection action mode.
6652191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        mActivityRule.runOnUiThread(
6662191418305ca42e4f219020a02f16c045c539755Siyamed Sinir                () -> Selection.setSelection((Spannable) textView.getText(), 0, 3));
6672191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        mInstrumentation.waitForIdleSync();
668c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        sleepForFloatingToolbarPopup();
669c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        assertFloatingToolbarIsDisplayed();
670c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        assertFloatingToolbarContainsItem(
6712191418305ca42e4f219020a02f16c045c539755Siyamed Sinir                mActivity.getString(com.android.internal.R.string.selectAll));
672c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        // Make sure that "Select All" is no longer included when the entire text is selected by
673c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        // API.
6742191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        mActivityRule.runOnUiThread(
675c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi                () -> Selection.setSelection((Spannable) textView.getText(), 0, text.length()));
6762191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        mInstrumentation.waitForIdleSync();
6772191418305ca42e4f219020a02f16c045c539755Siyamed Sinir
678c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        sleepForFloatingToolbarPopup();
679c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        assertFloatingToolbarIsDisplayed();
680c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        assertFloatingToolbarDoesNotContainItem(
6812191418305ca42e4f219020a02f16c045c539755Siyamed Sinir                mActivity.getString(com.android.internal.R.string.selectAll));
682c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        // Make sure that shrinking the selection range to cursor (an empty range) by API
683c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        // terminates selection action mode and does not trigger the insertion action mode.
6842191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        mActivityRule.runOnUiThread(
6852191418305ca42e4f219020a02f16c045c539755Siyamed Sinir                () -> Selection.setSelection((Spannable) textView.getText(), 0));
6862191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        mInstrumentation.waitForIdleSync();
6872191418305ca42e4f219020a02f16c045c539755Siyamed Sinir
688c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        sleepForFloatingToolbarPopup();
689c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        assertFloatingToolbarIsNotDisplayed();
690c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        // Make sure that user click can trigger the insertion action mode.
691c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
692c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        onHandleView(com.android.internal.R.id.insertion_handle).perform(click());
693c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        sleepForFloatingToolbarPopup();
694c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        assertFloatingToolbarIsDisplayed();
695c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        // Make sure that an existing insertion action mode keeps alive after the insertion point is
696c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        // moved by API.
6972191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        mActivityRule.runOnUiThread(
6982191418305ca42e4f219020a02f16c045c539755Siyamed Sinir                () -> Selection.setSelection((Spannable) textView.getText(), 0));
6992191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        mInstrumentation.waitForIdleSync();
7002191418305ca42e4f219020a02f16c045c539755Siyamed Sinir
701c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        sleepForFloatingToolbarPopup();
702c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        assertFloatingToolbarIsDisplayed();
703c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        assertFloatingToolbarDoesNotContainItem(
7042191418305ca42e4f219020a02f16c045c539755Siyamed Sinir                mActivity.getString(com.android.internal.R.string.copy));
705c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        // Make sure that selection action mode is started after selection is created by API when
706c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        // insertion action mode is active.
7072191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        mActivityRule.runOnUiThread(
708c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi                () -> Selection.setSelection((Spannable) textView.getText(), 1, text.length()));
7092191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        mInstrumentation.waitForIdleSync();
7102191418305ca42e4f219020a02f16c045c539755Siyamed Sinir
711c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        sleepForFloatingToolbarPopup();
712c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        assertFloatingToolbarIsDisplayed();
713c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi        assertFloatingToolbarContainsItem(
7142191418305ca42e4f219020a02f16c045c539755Siyamed Sinir                mActivity.getString(com.android.internal.R.string.copy));
715c477b5830af5f9e87069fae4ff87a2a6b3e275fbKeisuke Kuroyanagi    }
716183fd5071ea84aab82209c827fa0e4ff84a6b590Keisuke Kuroyanagi
7172191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    @Test
7182191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    public void testTransientState() throws Throwable {
719183fd5071ea84aab82209c827fa0e4ff84a6b590Keisuke Kuroyanagi        final String text = "abc def";
720183fd5071ea84aab82209c827fa0e4ff84a6b590Keisuke Kuroyanagi        onView(withId(R.id.textview)).perform(replaceText(text));
721183fd5071ea84aab82209c827fa0e4ff84a6b590Keisuke Kuroyanagi
7222191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        final TextView textView = mActivity.findViewById(R.id.textview);
723183fd5071ea84aab82209c827fa0e4ff84a6b590Keisuke Kuroyanagi        assertFalse(textView.hasTransientState());
724183fd5071ea84aab82209c827fa0e4ff84a6b590Keisuke Kuroyanagi
725183fd5071ea84aab82209c827fa0e4ff84a6b590Keisuke Kuroyanagi        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('b')));
726183fd5071ea84aab82209c827fa0e4ff84a6b590Keisuke Kuroyanagi        // hasTransientState should return true when user generated selection is active.
727183fd5071ea84aab82209c827fa0e4ff84a6b590Keisuke Kuroyanagi        assertTrue(textView.hasTransientState());
728183fd5071ea84aab82209c827fa0e4ff84a6b590Keisuke Kuroyanagi        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.indexOf('d')));
729183fd5071ea84aab82209c827fa0e4ff84a6b590Keisuke Kuroyanagi        // hasTransientState should return false as the selection has been cleared.
730183fd5071ea84aab82209c827fa0e4ff84a6b590Keisuke Kuroyanagi        assertFalse(textView.hasTransientState());
7312191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        mActivityRule.runOnUiThread(
732183fd5071ea84aab82209c827fa0e4ff84a6b590Keisuke Kuroyanagi                () -> Selection.setSelection((Spannable) textView.getText(), 0, text.length()));
7332191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        mInstrumentation.waitForIdleSync();
7342191418305ca42e4f219020a02f16c045c539755Siyamed Sinir
735183fd5071ea84aab82209c827fa0e4ff84a6b590Keisuke Kuroyanagi        // hasTransientState should return false when selection is created by API.
736183fd5071ea84aab82209c827fa0e4ff84a6b590Keisuke Kuroyanagi        assertFalse(textView.hasTransientState());
737183fd5071ea84aab82209c827fa0e4ff84a6b590Keisuke Kuroyanagi    }
7386eecdc934c6050d67a639116cde600c09e5b76bdAbodunrinwa Toki
7392191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    @Test
7402191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    public void testResetMenuItemTitle() throws Throwable {
7412191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        mActivity.getSystemService(TextClassificationManager.class).setTextClassifier(null);
7422191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        final TextView textView = mActivity.findViewById(R.id.textview);
7437b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki        final int itemId = 1;
7447b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki        final String title1 = " AFIGBO";
7457b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki        final int index = title1.indexOf('I');
7467b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki        final String title2 = title1.substring(index);
7477b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki        final String[] title = new String[]{title1};
7482191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        mActivityRule.runOnUiThread(() -> textView.setCustomSelectionActionModeCallback(
7497b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki                new ActionMode.Callback() {
7507b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki                    @Override
7517b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki                    public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
7527b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki                        return true;
7537b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki                    }
7547b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki
7557b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki                    @Override
7567b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki                    public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
7577b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki                        menu.removeItem(itemId);
7587b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki                        menu.add(Menu.NONE /* group */, itemId, 0 /* order */, title[0]);
7597b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki                        return true;
7607b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki                    }
7617b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki
7627b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki                    @Override
7637b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki                    public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
7647b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki                        return false;
7657b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki                    }
7667b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki
7677b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki                    @Override
7687b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki                    public void onDestroyActionMode(ActionMode actionMode) {
7697b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki                    }
7707b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki                }));
7712191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        mInstrumentation.waitForIdleSync();
7722191418305ca42e4f219020a02f16c045c539755Siyamed Sinir
7737b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki        onView(withId(R.id.textview)).perform(replaceText(title1));
7747b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(index));
7757b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki        sleepForFloatingToolbarPopup();
7767b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki        assertFloatingToolbarContainsItem(title1);
7777b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki
7787b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki        // Change the menu item title.
7797b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki        title[0] = title2;
7807b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki        // Change the selection to invalidate the action mode without restarting it.
7817b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki        onHandleView(com.android.internal.R.id.selection_start_handle)
7827b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki                .perform(dragHandle(textView, Handle.SELECTION_START, index));
7837b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki        sleepForFloatingToolbarPopup();
7847b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki        assertFloatingToolbarContainsItem(title2);
7857b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki    }
7867b97180ddfdc3dd6b595ac44b5df8dce137e80c6Abodunrinwa Toki
7872191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    @Test
7882191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    public void testAssistItemIsAtIndexZero() throws Throwable {
78976b51dc450255bd1774f0309745ceb404b4cc5cfAbodunrinwa Toki        useSystemDefaultTextClassifier();
7902191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        final TextView textView = mActivity.findViewById(R.id.textview);
7912191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        mActivityRule.runOnUiThread(() -> textView.setCustomSelectionActionModeCallback(
7926eecdc934c6050d67a639116cde600c09e5b76bdAbodunrinwa Toki                new ActionMode.Callback() {
7936eecdc934c6050d67a639116cde600c09e5b76bdAbodunrinwa Toki                    @Override
7946eecdc934c6050d67a639116cde600c09e5b76bdAbodunrinwa Toki                    public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
7956eecdc934c6050d67a639116cde600c09e5b76bdAbodunrinwa Toki                        // Create another item at order position 0 to confirm that it will never be
7966eecdc934c6050d67a639116cde600c09e5b76bdAbodunrinwa Toki                        // placed before the textAssist item.
7976eecdc934c6050d67a639116cde600c09e5b76bdAbodunrinwa Toki                        menu.add(Menu.NONE, 0 /* id */, 0 /* order */, "Test");
7986eecdc934c6050d67a639116cde600c09e5b76bdAbodunrinwa Toki                        return true;
7996eecdc934c6050d67a639116cde600c09e5b76bdAbodunrinwa Toki                    }
8006eecdc934c6050d67a639116cde600c09e5b76bdAbodunrinwa Toki
8016eecdc934c6050d67a639116cde600c09e5b76bdAbodunrinwa Toki                    @Override
8026eecdc934c6050d67a639116cde600c09e5b76bdAbodunrinwa Toki                    public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
8036eecdc934c6050d67a639116cde600c09e5b76bdAbodunrinwa Toki                        return true;
8046eecdc934c6050d67a639116cde600c09e5b76bdAbodunrinwa Toki                    }
8056eecdc934c6050d67a639116cde600c09e5b76bdAbodunrinwa Toki
8066eecdc934c6050d67a639116cde600c09e5b76bdAbodunrinwa Toki                    @Override
8076eecdc934c6050d67a639116cde600c09e5b76bdAbodunrinwa Toki                    public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
8086eecdc934c6050d67a639116cde600c09e5b76bdAbodunrinwa Toki                        return false;
8096eecdc934c6050d67a639116cde600c09e5b76bdAbodunrinwa Toki                    }
8106eecdc934c6050d67a639116cde600c09e5b76bdAbodunrinwa Toki
8116eecdc934c6050d67a639116cde600c09e5b76bdAbodunrinwa Toki                    @Override
812ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki                    public void onDestroyActionMode(ActionMode actionMode) {
813ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki                    }
8146eecdc934c6050d67a639116cde600c09e5b76bdAbodunrinwa Toki                }));
8152191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        mInstrumentation.waitForIdleSync();
8166eecdc934c6050d67a639116cde600c09e5b76bdAbodunrinwa Toki        final String text = "droid@android.com";
8176eecdc934c6050d67a639116cde600c09e5b76bdAbodunrinwa Toki
8186eecdc934c6050d67a639116cde600c09e5b76bdAbodunrinwa Toki        onView(withId(R.id.textview)).perform(replaceText(text));
8196eecdc934c6050d67a639116cde600c09e5b76bdAbodunrinwa Toki        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('@')));
8206eecdc934c6050d67a639116cde600c09e5b76bdAbodunrinwa Toki        sleepForFloatingToolbarPopup();
8216eecdc934c6050d67a639116cde600c09e5b76bdAbodunrinwa Toki        assertFloatingToolbarItemIndex(android.R.id.textAssist, 0);
8226eecdc934c6050d67a639116cde600c09e5b76bdAbodunrinwa Toki    }
823ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki
8242191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    @Test
82576b51dc450255bd1774f0309745ceb404b4cc5cfAbodunrinwa Toki    public void testNoAssistItemForPasswordField() throws Throwable {
82676b51dc450255bd1774f0309745ceb404b4cc5cfAbodunrinwa Toki        useSystemDefaultTextClassifier();
82776b51dc450255bd1774f0309745ceb404b4cc5cfAbodunrinwa Toki        final TextView textView = mActivity.findViewById(R.id.textview);
82876b51dc450255bd1774f0309745ceb404b4cc5cfAbodunrinwa Toki        mActivityRule.runOnUiThread(() -> {
82976b51dc450255bd1774f0309745ceb404b4cc5cfAbodunrinwa Toki            textView.setInputType(
83076b51dc450255bd1774f0309745ceb404b4cc5cfAbodunrinwa Toki                    InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
83176b51dc450255bd1774f0309745ceb404b4cc5cfAbodunrinwa Toki        });
83276b51dc450255bd1774f0309745ceb404b4cc5cfAbodunrinwa Toki        mInstrumentation.waitForIdleSync();
83376b51dc450255bd1774f0309745ceb404b4cc5cfAbodunrinwa Toki        final String password = "afigbo@android.com";
83476b51dc450255bd1774f0309745ceb404b4cc5cfAbodunrinwa Toki
83576b51dc450255bd1774f0309745ceb404b4cc5cfAbodunrinwa Toki        onView(withId(R.id.textview)).perform(replaceText(password));
83676b51dc450255bd1774f0309745ceb404b4cc5cfAbodunrinwa Toki        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(password.indexOf('@')));
83776b51dc450255bd1774f0309745ceb404b4cc5cfAbodunrinwa Toki        sleepForFloatingToolbarPopup();
83876b51dc450255bd1774f0309745ceb404b4cc5cfAbodunrinwa Toki        assertFloatingToolbarDoesNotContainItem(android.R.id.textAssist);
83976b51dc450255bd1774f0309745ceb404b4cc5cfAbodunrinwa Toki    }
84076b51dc450255bd1774f0309745ceb404b4cc5cfAbodunrinwa Toki
84176b51dc450255bd1774f0309745ceb404b4cc5cfAbodunrinwa Toki    @Test
8422191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    public void testPastePlainText_menuAction() {
843ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki        initializeClipboardWithText(TextStyle.STYLED);
844ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki
845ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki        onView(withId(R.id.textview)).perform(replaceText(""));
846ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki        onView(withId(R.id.textview)).perform(longClick());
847ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki        sleepForFloatingToolbarPopup();
848ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki        clickFloatingToolbarItem(
8492191418305ca42e4f219020a02f16c045c539755Siyamed Sinir                mActivity.getString(com.android.internal.R.string.paste_as_plain_text));
8502191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        mInstrumentation.waitForIdleSync();
851ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki
852ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki        onView(withId(R.id.textview)).check(matches(withText("styledtext")));
853ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki        onView(withId(R.id.textview)).check(doesNotHaveStyledText());
854ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki    }
855ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki
8562191418305ca42e4f219020a02f16c045c539755Siyamed Sinir    @Test
857ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki    public void testPastePlainText_noMenuItemForPlainText() {
858ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki        initializeClipboardWithText(TextStyle.PLAIN);
859ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki
860ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki        onView(withId(R.id.textview)).perform(replaceText(""));
861ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki        onView(withId(R.id.textview)).perform(longClick());
862ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki        sleepForFloatingToolbarPopup();
863ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki
864ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki        assertFloatingToolbarDoesNotContainItem(
8652191418305ca42e4f219020a02f16c045c539755Siyamed Sinir                mActivity.getString(com.android.internal.R.string.paste_as_plain_text));
866ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki    }
867ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki
86876b51dc450255bd1774f0309745ceb404b4cc5cfAbodunrinwa Toki    private void useSystemDefaultTextClassifier() {
86976b51dc450255bd1774f0309745ceb404b4cc5cfAbodunrinwa Toki        mActivity.getSystemService(TextClassificationManager.class).setTextClassifier(null);
87076b51dc450255bd1774f0309745ceb404b4cc5cfAbodunrinwa Toki    }
87176b51dc450255bd1774f0309745ceb404b4cc5cfAbodunrinwa Toki
872ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki    private void initializeClipboardWithText(TextStyle textStyle) {
873ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki        final ClipData clip;
874ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki        switch (textStyle) {
875ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki            case STYLED:
876ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki                clip = ClipData.newHtmlText("html", "styledtext", "<b>styledtext</b>");
877ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki                break;
878ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki            case PLAIN:
879ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki                clip = ClipData.newPlainText("plain", "plaintext");
880ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki                break;
881ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki            default:
882ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki                throw new IllegalArgumentException("Invalid text style");
883ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki        }
8842191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        mActivity.getWindow().getDecorView().post(() ->
8852191418305ca42e4f219020a02f16c045c539755Siyamed Sinir                mActivity.getSystemService(ClipboardManager.class).setPrimaryClip(clip));
8862191418305ca42e4f219020a02f16c045c539755Siyamed Sinir        mInstrumentation.waitForIdleSync();
887ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki    }
888ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki
889ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki    private enum TextStyle {
890ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki        PLAIN, STYLED
891ea6cb1215e97232bf96da02e35b6b8e938572eaaAbodunrinwa Toki    }
892223c8392f066823cf4a3a98957960deb80ab1680Abodunrinwa Toki}
893