Ensure that TextViewActivityTest still pass for the new system toolbar.
The tests pass for both the old (local) and system toolbars. Bug: 190031097 Test: atest android.widget.TextViewActivityTes Change-Id: I1542d966d363c4a8bd2ac9465c982b82019472d7
This commit is contained in:
@@ -1318,6 +1318,7 @@ final class RemoteSelectionToolbar {
|
||||
contentContainer.setLayoutParams(new ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
contentContainer.setTag(FloatingToolbar.FLOATING_TOOLBAR_TAG);
|
||||
contentContainer.setContentDescription(FloatingToolbar.FLOATING_TOOLBAR_TAG);
|
||||
contentContainer.setClipToOutline(true);
|
||||
return contentContainer;
|
||||
}
|
||||
|
||||
@@ -1475,6 +1475,7 @@ public final class LocalFloatingToolbarPopup implements FloatingToolbarPopup {
|
||||
contentContainer.setLayoutParams(new ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
contentContainer.setTag(FloatingToolbar.FLOATING_TOOLBAR_TAG);
|
||||
contentContainer.setContentDescription(FloatingToolbar.FLOATING_TOOLBAR_TAG);
|
||||
contentContainer.setClipToOutline(true);
|
||||
return contentContainer;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.widget;
|
||||
|
||||
import static com.android.internal.widget.floatingtoolbar.FloatingToolbar.FLOATING_TOOLBAR_TAG;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.support.test.uiautomator.By;
|
||||
import android.support.test.uiautomator.UiDevice;
|
||||
import android.support.test.uiautomator.Until;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
|
||||
import com.android.internal.R;
|
||||
|
||||
final class FloatingToolbarUtils {
|
||||
|
||||
private final UiDevice mDevice;
|
||||
|
||||
FloatingToolbarUtils() {
|
||||
mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
|
||||
}
|
||||
|
||||
void waitForFloatingToolbarPopup() {
|
||||
mDevice.wait(Until.findObject(By.desc(FLOATING_TOOLBAR_TAG)), 500);
|
||||
}
|
||||
|
||||
void assertFloatingToolbarIsDisplayed() {
|
||||
waitForFloatingToolbarPopup();
|
||||
assertThat(mDevice.hasObject(By.desc(FLOATING_TOOLBAR_TAG))).isTrue();
|
||||
}
|
||||
|
||||
void assertFloatingToolbarContainsItem(String itemLabel) {
|
||||
waitForFloatingToolbarPopup();
|
||||
assertWithMessage("Expected to find item labelled [" + itemLabel + "]")
|
||||
.that(mDevice.hasObject(
|
||||
By.desc(FLOATING_TOOLBAR_TAG).hasDescendant(By.text(itemLabel))))
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
void assertFloatingToolbarDoesNotContainItem(String itemLabel) {
|
||||
waitForFloatingToolbarPopup();
|
||||
assertWithMessage("Expected to not find item labelled [" + itemLabel + "]")
|
||||
.that(mDevice.hasObject(
|
||||
By.desc(FLOATING_TOOLBAR_TAG).hasDescendant(By.text(itemLabel))))
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
void assertFloatingToolbarContainsItemAtIndex(String itemLabel, int index) {
|
||||
waitForFloatingToolbarPopup();
|
||||
assertWithMessage("Expected to find item labelled [" + itemLabel + "] at index " + index)
|
||||
.that(mDevice.findObject(By.desc(FLOATING_TOOLBAR_TAG))
|
||||
.findObjects(By.clickable(true))
|
||||
.get(index)
|
||||
.getChildren()
|
||||
.get(1)
|
||||
.getText())
|
||||
.isEqualTo(itemLabel);
|
||||
}
|
||||
|
||||
void clickFloatingToolbarItem(String label) {
|
||||
waitForFloatingToolbarPopup();
|
||||
mDevice.findObject(By.desc(FLOATING_TOOLBAR_TAG))
|
||||
.findObject(By.text(label))
|
||||
.click();
|
||||
}
|
||||
|
||||
void clickFloatingToolbarOverflowItem(String label) {
|
||||
// TODO: There might be a benefit to combining this with "clickFloatingToolbarItem" method.
|
||||
waitForFloatingToolbarPopup();
|
||||
mDevice.findObject(By.desc(FLOATING_TOOLBAR_TAG))
|
||||
.findObject(By.desc(str(R.string.floating_toolbar_open_overflow_description)))
|
||||
.click();
|
||||
mDevice.wait(
|
||||
Until.findObject(By.desc(FLOATING_TOOLBAR_TAG).hasDescendant(By.text(label))),
|
||||
1000);
|
||||
mDevice.findObject(By.desc(FLOATING_TOOLBAR_TAG))
|
||||
.findObject(By.text(label))
|
||||
.click();
|
||||
}
|
||||
|
||||
private static String str(int id) {
|
||||
return Resources.getSystem().getString(id);
|
||||
}
|
||||
}
|
||||
@@ -17,9 +17,6 @@
|
||||
package android.widget;
|
||||
|
||||
import static android.widget.espresso.DragHandleUtils.onHandleView;
|
||||
import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarContainsItem;
|
||||
import static android.widget.espresso.FloatingToolbarEspressoUtils.clickFloatingToolbarItem;
|
||||
import static android.widget.espresso.FloatingToolbarEspressoUtils.sleepForFloatingToolbarPopup;
|
||||
import static android.widget.espresso.SuggestionsPopupwindowUtils.assertSuggestionsPopupContainsItem;
|
||||
import static android.widget.espresso.SuggestionsPopupwindowUtils.assertSuggestionsPopupIsDisplayed;
|
||||
import static android.widget.espresso.SuggestionsPopupwindowUtils.assertSuggestionsPopupIsNotDisplayed;
|
||||
@@ -72,6 +69,7 @@ public class SuggestionsPopupWindowTest {
|
||||
@Rule
|
||||
public final ActivityTestRule<TextViewActivity> mActivityRule =
|
||||
new ActivityTestRule<>(TextViewActivity.class);
|
||||
private final FloatingToolbarUtils mToolbar = new FloatingToolbarUtils();
|
||||
|
||||
private TextViewActivity getActivity() {
|
||||
return mActivityRule.getActivity();
|
||||
@@ -118,22 +116,19 @@ public class SuggestionsPopupWindowTest {
|
||||
setSuggestionSpan(suggestionSpan, text.indexOf('d'), text.indexOf('f') + 1);
|
||||
|
||||
onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('e')));
|
||||
sleepForFloatingToolbarPopup();
|
||||
assertFloatingToolbarContainsItem(
|
||||
getActivity().getString(com.android.internal.R.string.replace));
|
||||
sleepForFloatingToolbarPopup();
|
||||
clickFloatingToolbarItem(
|
||||
mToolbar.clickFloatingToolbarOverflowItem(
|
||||
getActivity().getString(com.android.internal.R.string.replace));
|
||||
|
||||
assertSuggestionsPopupIsDisplayed();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsertionActionMode() {
|
||||
public void testInsertionActionMode() throws Throwable {
|
||||
final String text = "abc def ghi";
|
||||
|
||||
onView(withId(R.id.textview)).perform(click());
|
||||
onView(withId(R.id.textview)).perform(replaceText(text));
|
||||
Thread.sleep(500);
|
||||
|
||||
final SuggestionSpan suggestionSpan = new SuggestionSpan(getActivity(),
|
||||
new String[]{"DEF", "Def"}, SuggestionSpan.FLAG_AUTO_CORRECTION);
|
||||
@@ -141,10 +136,7 @@ public class SuggestionsPopupWindowTest {
|
||||
|
||||
onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.indexOf('e')));
|
||||
onHandleView(com.android.internal.R.id.insertion_handle).perform(click());
|
||||
sleepForFloatingToolbarPopup();
|
||||
assertFloatingToolbarContainsItem(
|
||||
getActivity().getString(com.android.internal.R.string.replace));
|
||||
clickFloatingToolbarItem(
|
||||
mToolbar.clickFloatingToolbarItem(
|
||||
getActivity().getString(com.android.internal.R.string.replace));
|
||||
|
||||
assertSuggestionsPopupIsDisplayed();
|
||||
|
||||
@@ -16,14 +16,9 @@
|
||||
|
||||
package android.widget;
|
||||
|
||||
import static android.app.PendingIntent.FLAG_IMMUTABLE;
|
||||
import static android.widget.espresso.CustomViewActions.longPressAtRelativeCoordinates;
|
||||
import static android.widget.espresso.DragHandleUtils.onHandleView;
|
||||
import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarContainsItem;
|
||||
import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarDoesNotContainItem;
|
||||
import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarIsDisplayed;
|
||||
import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarItemIndex;
|
||||
import static android.widget.espresso.FloatingToolbarEspressoUtils.clickFloatingToolbarItem;
|
||||
import static android.widget.espresso.FloatingToolbarEspressoUtils.sleepForFloatingToolbarPopup;
|
||||
import static android.widget.espresso.TextViewActions.Handle;
|
||||
import static android.widget.espresso.TextViewActions.clickOnTextAtIndex;
|
||||
import static android.widget.espresso.TextViewActions.doubleClickOnTextAtIndex;
|
||||
@@ -63,10 +58,17 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Instrumentation;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.RemoteAction;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.os.Bundle;
|
||||
import android.support.test.uiautomator.By;
|
||||
import android.support.test.uiautomator.UiDevice;
|
||||
import android.support.test.uiautomator.Until;
|
||||
import android.text.InputType;
|
||||
import android.text.Selection;
|
||||
import android.text.Spannable;
|
||||
@@ -78,6 +80,7 @@ import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.view.textclassifier.SelectionEvent;
|
||||
import android.view.textclassifier.TextClassification;
|
||||
import android.view.textclassifier.TextClassificationManager;
|
||||
import android.view.textclassifier.TextClassifier;
|
||||
import android.view.textclassifier.TextLinks;
|
||||
@@ -101,6 +104,7 @@ import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Tests the TextView widget from an Activity
|
||||
@@ -115,11 +119,16 @@ public class TextViewActivityTest {
|
||||
|
||||
private Activity mActivity;
|
||||
private Instrumentation mInstrumentation;
|
||||
private UiDevice mDevice;
|
||||
private FloatingToolbarUtils mToolbar;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
public void setUp() throws Exception {
|
||||
mActivity = mActivityRule.getActivity();
|
||||
mInstrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
mDevice = UiDevice.getInstance(mInstrumentation);
|
||||
mDevice.wakeUp();
|
||||
mToolbar = new FloatingToolbarUtils();
|
||||
TextClassificationManager tcm = mActivity.getSystemService(
|
||||
TextClassificationManager.class);
|
||||
tcm.setTextClassifier(TextClassifier.NO_OP);
|
||||
@@ -131,14 +140,14 @@ public class TextViewActivityTest {
|
||||
final String helloWorld = "Hello world!";
|
||||
// We use replaceText instead of typeTextIntoFocusedView to input text to avoid
|
||||
// unintentional interactions with software keyboard.
|
||||
onView(withId(R.id.textview)).perform(replaceText(helloWorld));
|
||||
setText(helloWorld);
|
||||
|
||||
onView(withId(R.id.textview)).check(matches(withText(helloWorld)));
|
||||
}
|
||||
@Test
|
||||
public void testPositionCursorAtTextAtIndex() {
|
||||
final String helloWorld = "Hello world!";
|
||||
onView(withId(R.id.textview)).perform(replaceText(helloWorld));
|
||||
setText(helloWorld);
|
||||
onView(withId(R.id.textview)).perform(clickOnTextAtIndex(helloWorld.indexOf("world")));
|
||||
|
||||
// Delete text at specified index and see if we got the right one.
|
||||
@@ -151,7 +160,7 @@ public class TextViewActivityTest {
|
||||
// Arabic text. The expected cursorable boundary is
|
||||
// | \u0623 \u064F | \u067A | \u0633 \u0652 |
|
||||
final String text = "\u0623\u064F\u067A\u0633\u0652";
|
||||
onView(withId(R.id.textview)).perform(replaceText(text));
|
||||
setText(text);
|
||||
|
||||
onView(withId(R.id.textview)).perform(clickOnTextAtIndex(0));
|
||||
onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(0));
|
||||
@@ -171,7 +180,7 @@ public class TextViewActivityTest {
|
||||
public void testPositionCursorAtTextAtIndex_devanagari() {
|
||||
// Devanagari text. The expected cursorable boundary is | \u0915 \u093E |
|
||||
final String text = "\u0915\u093E";
|
||||
onView(withId(R.id.textview)).perform(replaceText(text));
|
||||
setText(text);
|
||||
|
||||
onView(withId(R.id.textview)).perform(clickOnTextAtIndex(0));
|
||||
onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(0));
|
||||
@@ -185,7 +194,7 @@ public class TextViewActivityTest {
|
||||
public void testLongPressToSelect() {
|
||||
final String helloWorld = "Hello Kirk!";
|
||||
onView(withId(R.id.textview)).perform(click());
|
||||
onView(withId(R.id.textview)).perform(replaceText(helloWorld));
|
||||
setText(helloWorld);
|
||||
onView(withId(R.id.textview)).perform(
|
||||
longPressOnTextAtIndex(helloWorld.indexOf("Kirk")));
|
||||
|
||||
@@ -195,7 +204,7 @@ public class TextViewActivityTest {
|
||||
@Test
|
||||
public void testLongPressEmptySpace() {
|
||||
final String helloWorld = "Hello big round sun!";
|
||||
onView(withId(R.id.textview)).perform(replaceText(helloWorld));
|
||||
setText(helloWorld);
|
||||
// Move cursor somewhere else
|
||||
onView(withId(R.id.textview)).perform(clickOnTextAtIndex(helloWorld.indexOf("big")));
|
||||
// Long-press at end of line.
|
||||
@@ -209,7 +218,7 @@ public class TextViewActivityTest {
|
||||
@Test
|
||||
public void testLongPressAndDragToSelect() {
|
||||
final String helloWorld = "Hello little handsome boy!";
|
||||
onView(withId(R.id.textview)).perform(replaceText(helloWorld));
|
||||
setText(helloWorld);
|
||||
onView(withId(R.id.textview)).perform(
|
||||
longPressAndDragOnText(helloWorld.indexOf("little"), helloWorld.indexOf(" boy!")));
|
||||
|
||||
@@ -219,7 +228,7 @@ public class TextViewActivityTest {
|
||||
@Test
|
||||
public void testLongPressAndDragToSelect_emoji() {
|
||||
final String text = "\uD83D\uDE00\uD83D\uDE01\uD83D\uDE02\uD83D\uDE03";
|
||||
onView(withId(R.id.textview)).perform(replaceText(text));
|
||||
setText(text);
|
||||
|
||||
onView(withId(R.id.textview)).perform(longPressAndDragOnText(4, 6));
|
||||
onView(withId(R.id.textview)).check(hasSelection("\uD83D\uDE02"));
|
||||
@@ -233,7 +242,7 @@ public class TextViewActivityTest {
|
||||
@Test
|
||||
public void testDragAndDrop() {
|
||||
final String text = "abc def ghi.";
|
||||
onView(withId(R.id.textview)).perform(replaceText(text));
|
||||
setText(text);
|
||||
onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf("e")));
|
||||
|
||||
onView(withId(R.id.textview)).perform(
|
||||
@@ -253,7 +262,7 @@ public class TextViewActivityTest {
|
||||
@Test
|
||||
public void testDoubleTapToSelect() {
|
||||
final String helloWorld = "Hello SuetYi!";
|
||||
onView(withId(R.id.textview)).perform(replaceText(helloWorld));
|
||||
setText(helloWorld);
|
||||
|
||||
onView(withId(R.id.textview)).perform(
|
||||
doubleClickOnTextAtIndex(helloWorld.indexOf("SuetYi")));
|
||||
@@ -264,7 +273,7 @@ public class TextViewActivityTest {
|
||||
@Test
|
||||
public void testDoubleTapAndDragToSelect() {
|
||||
final String helloWorld = "Hello young beautiful person!";
|
||||
onView(withId(R.id.textview)).perform(replaceText(helloWorld));
|
||||
setText(helloWorld);
|
||||
onView(withId(R.id.textview)).perform(doubleTapAndDragOnText(helloWorld.indexOf("young"),
|
||||
helloWorld.indexOf(" person!")));
|
||||
|
||||
@@ -274,7 +283,7 @@ public class TextViewActivityTest {
|
||||
@Test
|
||||
public void testDoubleTapAndDragToSelect_multiLine() {
|
||||
final String helloWorld = "abcd\n" + "efg\n" + "hijklm\n" + "nop";
|
||||
onView(withId(R.id.textview)).perform(replaceText(helloWorld));
|
||||
setText(helloWorld);
|
||||
onView(withId(R.id.textview)).perform(
|
||||
doubleTapAndDragOnText(helloWorld.indexOf("m"), helloWorld.indexOf("a")));
|
||||
onView(withId(R.id.textview)).check(hasSelection("abcd\nefg\nhijklm"));
|
||||
@@ -283,7 +292,7 @@ public class TextViewActivityTest {
|
||||
@Test
|
||||
public void testSelectBackwordsByTouch() {
|
||||
final String helloWorld = "Hello king of the Jungle!";
|
||||
onView(withId(R.id.textview)).perform(replaceText(helloWorld));
|
||||
setText(helloWorld);
|
||||
onView(withId(R.id.textview)).perform(
|
||||
doubleTapAndDragOnText(helloWorld.indexOf(" Jungle!"), helloWorld.indexOf("king")));
|
||||
|
||||
@@ -293,12 +302,11 @@ public class TextViewActivityTest {
|
||||
@Test
|
||||
public void testToolbarAppearsAfterSelection() {
|
||||
final String text = "Toolbar appears after selection.";
|
||||
onView(withId(R.id.textview)).perform(replaceText(text));
|
||||
setText(text);
|
||||
onView(withId(R.id.textview)).perform(
|
||||
longPressOnTextAtIndex(text.indexOf("appears")));
|
||||
|
||||
sleepForFloatingToolbarPopup();
|
||||
assertFloatingToolbarIsDisplayed();
|
||||
mToolbar.assertFloatingToolbarIsDisplayed();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -316,13 +324,12 @@ public class TextViewActivityTest {
|
||||
});
|
||||
mInstrumentation.waitForIdleSync();
|
||||
|
||||
onView(withId(R.id.textview)).perform(replaceText("test"));
|
||||
setText("test");
|
||||
onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(1));
|
||||
clickFloatingToolbarItem(mActivity.getString(com.android.internal.R.string.cut));
|
||||
mToolbar.clickFloatingToolbarItem(mActivity.getString(com.android.internal.R.string.cut));
|
||||
onView(withId(R.id.textview)).perform(longClick());
|
||||
sleepForFloatingToolbarPopup();
|
||||
|
||||
assertFloatingToolbarIsDisplayed();
|
||||
mToolbar.assertFloatingToolbarIsDisplayed();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -330,8 +337,7 @@ public class TextViewActivityTest {
|
||||
TextLinks.TextLink textLink = addLinkifiedTextToTextView(R.id.textview);
|
||||
int position = (textLink.getStart() + textLink.getEnd()) / 2;
|
||||
onView(withId(R.id.textview)).perform(clickOnTextAtIndex(position));
|
||||
sleepForFloatingToolbarPopup();
|
||||
assertFloatingToolbarIsDisplayed();
|
||||
mToolbar.assertFloatingToolbarIsDisplayed();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -341,23 +347,20 @@ public class TextViewActivityTest {
|
||||
final int position = (textLink.getStart() + textLink.getEnd()) / 2;
|
||||
|
||||
onView(withId(R.id.nonselectable_textview)).perform(clickOnTextAtIndex(position));
|
||||
sleepForFloatingToolbarPopup();
|
||||
assertFloatingToolbarIsDisplayed();
|
||||
mToolbar.assertFloatingToolbarIsDisplayed();
|
||||
assertTrue(textView.hasSelection());
|
||||
|
||||
// toggle
|
||||
onView(withId(R.id.nonselectable_textview)).perform(clickOnTextAtIndex(position));
|
||||
sleepForFloatingToolbarPopup();
|
||||
mToolbar.waitForFloatingToolbarPopup();
|
||||
assertFalse(textView.hasSelection());
|
||||
|
||||
onView(withId(R.id.nonselectable_textview)).perform(clickOnTextAtIndex(position));
|
||||
sleepForFloatingToolbarPopup();
|
||||
assertFloatingToolbarIsDisplayed();
|
||||
mToolbar.assertFloatingToolbarIsDisplayed();
|
||||
assertTrue(textView.hasSelection());
|
||||
|
||||
// click outside
|
||||
onView(withId(R.id.nonselectable_textview)).perform(clickOnTextAtIndex(0));
|
||||
sleepForFloatingToolbarPopup();
|
||||
assertFalse(textView.hasSelection());
|
||||
}
|
||||
|
||||
@@ -371,8 +374,7 @@ public class TextViewActivityTest {
|
||||
});
|
||||
mInstrumentation.waitForIdleSync();
|
||||
|
||||
sleepForFloatingToolbarPopup();
|
||||
assertFloatingToolbarIsDisplayed();
|
||||
mToolbar.assertFloatingToolbarIsDisplayed();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -384,7 +386,7 @@ public class TextViewActivityTest {
|
||||
final TextView textView = mActivity.findViewById(R.id.textview);
|
||||
textView.setText(text);
|
||||
textView.setCustomSelectionActionModeCallback(
|
||||
new ActionMode.Callback() {
|
||||
new ActionModeCallbackAdapter() {
|
||||
@Override
|
||||
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
|
||||
menu.clear();
|
||||
@@ -397,29 +399,19 @@ public class TextViewActivityTest {
|
||||
clickedItem[0] = item;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyActionMode(ActionMode mode) {}
|
||||
});
|
||||
});
|
||||
mInstrumentation.waitForIdleSync();
|
||||
|
||||
onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf("f")));
|
||||
sleepForFloatingToolbarPopup();
|
||||
|
||||
// Change the selection so that the menu items are refreshed.
|
||||
final TextView textView = mActivity.findViewById(R.id.textview);
|
||||
onHandleView(com.android.internal.R.id.selection_start_handle)
|
||||
.perform(dragHandle(textView, Handle.SELECTION_START, 0));
|
||||
sleepForFloatingToolbarPopup();
|
||||
assertFloatingToolbarIsDisplayed();
|
||||
mToolbar.assertFloatingToolbarIsDisplayed();
|
||||
|
||||
clickFloatingToolbarItem("Item");
|
||||
mToolbar.clickFloatingToolbarItem("Item");
|
||||
mInstrumentation.waitForIdleSync();
|
||||
|
||||
assertEquals(latestItem[0], clickedItem[0]);
|
||||
@@ -433,13 +425,11 @@ public class TextViewActivityTest {
|
||||
mActivityRule.runOnUiThread(() -> textView.setFocusableInTouchMode(true));
|
||||
|
||||
onView(withId(R.id.nonselectable_textview)).perform(clickOnTextAtIndex(position));
|
||||
sleepForFloatingToolbarPopup();
|
||||
assertFloatingToolbarIsDisplayed();
|
||||
mToolbar.assertFloatingToolbarIsDisplayed();
|
||||
assertTrue(textView.hasSelection());
|
||||
|
||||
mActivityRule.runOnUiThread(() -> textView.clearFocus());
|
||||
mInstrumentation.waitForIdleSync();
|
||||
sleepForFloatingToolbarPopup();
|
||||
|
||||
assertFalse(textView.hasSelection());
|
||||
}
|
||||
@@ -452,14 +442,12 @@ public class TextViewActivityTest {
|
||||
|
||||
onView(withId(R.id.nonselectable_textview))
|
||||
.perform(clickOnTextAtIndex(nonselectablePosition));
|
||||
sleepForFloatingToolbarPopup();
|
||||
assertFloatingToolbarIsDisplayed();
|
||||
mToolbar.assertFloatingToolbarIsDisplayed();
|
||||
assertTrue(nonselectableTextView.hasSelection());
|
||||
|
||||
UiDevice device = UiDevice.getInstance(mInstrumentation);
|
||||
device.openNotification();
|
||||
mDevice.openNotification();
|
||||
Thread.sleep(2000);
|
||||
device.pressBack();
|
||||
mDevice.pressBack();
|
||||
Thread.sleep(2000);
|
||||
|
||||
assertFalse(nonselectableTextView.hasSelection());
|
||||
@@ -492,62 +480,58 @@ public class TextViewActivityTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToolbarAndInsertionHandle() {
|
||||
public void testToolbarAndInsertionHandle() throws Throwable {
|
||||
final String text = "text";
|
||||
onView(withId(R.id.textview)).perform(replaceText(text));
|
||||
setText(text);
|
||||
Thread.sleep(500);
|
||||
onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
|
||||
|
||||
onHandleView(com.android.internal.R.id.insertion_handle).perform(click());
|
||||
sleepForFloatingToolbarPopup();
|
||||
assertFloatingToolbarIsDisplayed();
|
||||
|
||||
assertFloatingToolbarContainsItem(
|
||||
mToolbar.assertFloatingToolbarContainsItem(
|
||||
mActivity.getString(com.android.internal.R.string.selectAll));
|
||||
assertFloatingToolbarDoesNotContainItem(
|
||||
mToolbar.assertFloatingToolbarDoesNotContainItem(
|
||||
mActivity.getString(com.android.internal.R.string.copy));
|
||||
assertFloatingToolbarDoesNotContainItem(
|
||||
mToolbar.assertFloatingToolbarDoesNotContainItem(
|
||||
mActivity.getString(com.android.internal.R.string.cut));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToolbarAndSelectionHandle() {
|
||||
final String text = "abcd efg hijk";
|
||||
onView(withId(R.id.textview)).perform(replaceText(text));
|
||||
setText(text);
|
||||
|
||||
onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf("f")));
|
||||
sleepForFloatingToolbarPopup();
|
||||
assertFloatingToolbarIsDisplayed();
|
||||
mToolbar.assertFloatingToolbarIsDisplayed();
|
||||
|
||||
assertFloatingToolbarContainsItem(
|
||||
mToolbar.assertFloatingToolbarContainsItem(
|
||||
mActivity.getString(com.android.internal.R.string.selectAll));
|
||||
assertFloatingToolbarContainsItem(
|
||||
mToolbar.assertFloatingToolbarContainsItem(
|
||||
mActivity.getString(com.android.internal.R.string.copy));
|
||||
assertFloatingToolbarContainsItem(
|
||||
mToolbar.assertFloatingToolbarContainsItem(
|
||||
mActivity.getString(com.android.internal.R.string.cut));
|
||||
|
||||
final TextView textView = mActivity.findViewById(R.id.textview);
|
||||
onHandleView(com.android.internal.R.id.selection_start_handle)
|
||||
.perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('a')));
|
||||
sleepForFloatingToolbarPopup();
|
||||
assertFloatingToolbarIsDisplayed();
|
||||
mToolbar.assertFloatingToolbarIsDisplayed();
|
||||
|
||||
onHandleView(com.android.internal.R.id.selection_end_handle)
|
||||
.perform(dragHandle(textView, Handle.SELECTION_END, text.length()));
|
||||
sleepForFloatingToolbarPopup();
|
||||
assertFloatingToolbarIsDisplayed();
|
||||
mToolbar.assertFloatingToolbarIsDisplayed();
|
||||
|
||||
assertFloatingToolbarDoesNotContainItem(
|
||||
mToolbar.assertFloatingToolbarDoesNotContainItem(
|
||||
mActivity.getString(com.android.internal.R.string.selectAll));
|
||||
assertFloatingToolbarContainsItem(
|
||||
mToolbar.assertFloatingToolbarContainsItem(
|
||||
mActivity.getString(com.android.internal.R.string.copy));
|
||||
assertFloatingToolbarContainsItem(
|
||||
mToolbar.assertFloatingToolbarContainsItem(
|
||||
mActivity.getString(com.android.internal.R.string.cut));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsertionHandle() {
|
||||
final String text = "abcd efg hijk ";
|
||||
onView(withId(R.id.textview)).perform(replaceText(text));
|
||||
setText(text);
|
||||
|
||||
onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
|
||||
onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.length()));
|
||||
@@ -566,7 +550,7 @@ public class TextViewActivityTest {
|
||||
@Test
|
||||
public void testInsertionHandle_multiLine() {
|
||||
final String text = "abcd\n" + "efg\n" + "hijk\n" + "lmn\n";
|
||||
onView(withId(R.id.textview)).perform(replaceText(text));
|
||||
setText(text);
|
||||
|
||||
onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
|
||||
onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.length()));
|
||||
@@ -604,7 +588,7 @@ public class TextViewActivityTest {
|
||||
final TextView textView = mActivity.findViewById(R.id.textview);
|
||||
|
||||
final String text = "hello the world";
|
||||
onView(withId(R.id.textview)).perform(replaceText(text));
|
||||
setText(text);
|
||||
|
||||
onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
|
||||
onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.length()));
|
||||
@@ -618,7 +602,7 @@ public class TextViewActivityTest {
|
||||
enableFlagsForInsertionHandleGestures();
|
||||
final TextView textView = mActivity.findViewById(R.id.textview);
|
||||
final String text = "hello the world";
|
||||
onView(withId(R.id.textview)).perform(replaceText(text));
|
||||
setText(text);
|
||||
|
||||
onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
|
||||
onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.length()));
|
||||
@@ -634,7 +618,7 @@ public class TextViewActivityTest {
|
||||
final TextView textView = mActivity.findViewById(R.id.textview);
|
||||
|
||||
final String text = "hello the world";
|
||||
onView(withId(R.id.textview)).perform(replaceText(text));
|
||||
setText(text);
|
||||
|
||||
onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
|
||||
onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.length()));
|
||||
@@ -649,7 +633,7 @@ public class TextViewActivityTest {
|
||||
final TextView textView = mActivity.findViewById(R.id.textview);
|
||||
|
||||
final String text = "hello the world";
|
||||
onView(withId(R.id.textview)).perform(replaceText(text));
|
||||
setText(text);
|
||||
|
||||
onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
|
||||
onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.length()));
|
||||
@@ -662,7 +646,7 @@ public class TextViewActivityTest {
|
||||
@Test
|
||||
public void testSelectionHandles() {
|
||||
final String text = "abcd efg hijk lmn";
|
||||
onView(withId(R.id.textview)).perform(replaceText(text));
|
||||
setText(text);
|
||||
|
||||
onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('f')));
|
||||
|
||||
@@ -684,7 +668,7 @@ public class TextViewActivityTest {
|
||||
@Test
|
||||
public void testSelectionHandles_bidi() {
|
||||
final String text = "abc \u0621\u0622\u0623 def";
|
||||
onView(withId(R.id.textview)).perform(replaceText(text));
|
||||
setText(text);
|
||||
|
||||
onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('\u0622')));
|
||||
|
||||
@@ -726,7 +710,7 @@ public class TextViewActivityTest {
|
||||
@Test
|
||||
public void testSelectionHandles_multiLine() {
|
||||
final String text = "abcd\n" + "efg\n" + "hijk\n" + "lmn\n" + "opqr";
|
||||
onView(withId(R.id.textview)).perform(replaceText(text));
|
||||
setText(text);
|
||||
onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('i')));
|
||||
|
||||
final TextView textView = mActivity.findViewById(R.id.textview);
|
||||
@@ -754,7 +738,7 @@ public class TextViewActivityTest {
|
||||
final String text = "\u062A\u062B\u062C\n" + "\u062D\u062E\u062F\n"
|
||||
+ "\u0630\u0631\u0632\n" + "\u0633\u0634\u0635\n" + "\u0636\u0637\u0638\n"
|
||||
+ "\u0639\u063A\u063B";
|
||||
onView(withId(R.id.textview)).perform(replaceText(text));
|
||||
setText(text);
|
||||
onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('\u0634')));
|
||||
|
||||
final TextView textView = mActivity.findViewById(R.id.textview);
|
||||
@@ -781,7 +765,7 @@ public class TextViewActivityTest {
|
||||
@Test
|
||||
public void testSelectionHandles_doesNotPassAnotherHandle() {
|
||||
final String text = "abcd efg hijk lmn";
|
||||
onView(withId(R.id.textview)).perform(replaceText(text));
|
||||
setText(text);
|
||||
onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('f')));
|
||||
|
||||
final TextView textView = mActivity.findViewById(R.id.textview);
|
||||
@@ -798,7 +782,7 @@ public class TextViewActivityTest {
|
||||
@Test
|
||||
public void testSelectionHandles_doesNotPassAnotherHandle_multiLine() {
|
||||
final String text = "abcd\n" + "efg\n" + "hijk\n" + "lmn\n" + "opqr";
|
||||
onView(withId(R.id.textview)).perform(replaceText(text));
|
||||
setText(text);
|
||||
onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('i')));
|
||||
|
||||
final TextView textView = mActivity.findViewById(R.id.textview);
|
||||
@@ -815,7 +799,7 @@ public class TextViewActivityTest {
|
||||
@Test
|
||||
public void testSelectionHandles_snapToWordBoundary() {
|
||||
final String text = "abcd efg hijk lmn opqr";
|
||||
onView(withId(R.id.textview)).perform(replaceText(text));
|
||||
setText(text);
|
||||
onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('i')));
|
||||
|
||||
final TextView textView = mActivity.findViewById(R.id.textview);
|
||||
@@ -868,7 +852,7 @@ public class TextViewActivityTest {
|
||||
@Test
|
||||
public void testSelectionHandles_snapToWordBoundary_multiLine() {
|
||||
final String text = "abcd efg\n" + "hijk lmn\n" + "opqr stu";
|
||||
onView(withId(R.id.textview)).perform(replaceText(text));
|
||||
setText(text);
|
||||
onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('m')));
|
||||
|
||||
final TextView textView = mActivity.findViewById(R.id.textview);
|
||||
@@ -903,7 +887,7 @@ public class TextViewActivityTest {
|
||||
@Test
|
||||
public void testSelectionHandles_visibleEvenWithEmptyMenu() {
|
||||
((TextView) mActivity.findViewById(R.id.textview)).setCustomSelectionActionModeCallback(
|
||||
new ActionMode.Callback() {
|
||||
new ActionModeCallbackAdapter() {
|
||||
@Override
|
||||
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
|
||||
menu.clear();
|
||||
@@ -915,17 +899,9 @@ public class TextViewActivityTest {
|
||||
menu.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyActionMode(ActionMode mode) {}
|
||||
});
|
||||
final String text = "abcd efg hijk lmn";
|
||||
onView(withId(R.id.textview)).perform(replaceText(text));
|
||||
setText(text);
|
||||
|
||||
onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('f')));
|
||||
|
||||
@@ -946,7 +922,7 @@ public class TextViewActivityTest {
|
||||
textView.setCustomSelectionActionModeCallback(amCallback);
|
||||
|
||||
final String text = "abc def";
|
||||
onView(withId(R.id.textview)).perform(replaceText(text));
|
||||
setText(text);
|
||||
mActivityRule.runOnUiThread(
|
||||
() -> Selection.setSelection((Spannable) textView.getText(), 0, 3));
|
||||
mInstrumentation.waitForIdleSync();
|
||||
@@ -955,15 +931,13 @@ public class TextViewActivityTest {
|
||||
// Make sure that "Select All" is included in the selection action mode when the entire text
|
||||
// is not selected.
|
||||
onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('e')));
|
||||
sleepForFloatingToolbarPopup();
|
||||
assertFloatingToolbarIsDisplayed();
|
||||
mToolbar.assertFloatingToolbarIsDisplayed();
|
||||
// Changing the selection range by API should not interrupt the selection action mode.
|
||||
mActivityRule.runOnUiThread(
|
||||
() -> Selection.setSelection((Spannable) textView.getText(), 0, 3));
|
||||
mInstrumentation.waitForIdleSync();
|
||||
sleepForFloatingToolbarPopup();
|
||||
assertFloatingToolbarIsDisplayed();
|
||||
assertFloatingToolbarContainsItem(
|
||||
mToolbar.assertFloatingToolbarIsDisplayed();
|
||||
mToolbar.assertFloatingToolbarContainsItem(
|
||||
mActivity.getString(com.android.internal.R.string.selectAll));
|
||||
// Make sure that "Select All" is no longer included when the entire text is selected by
|
||||
// API.
|
||||
@@ -971,9 +945,8 @@ public class TextViewActivityTest {
|
||||
() -> Selection.setSelection((Spannable) textView.getText(), 0, text.length()));
|
||||
mInstrumentation.waitForIdleSync();
|
||||
|
||||
sleepForFloatingToolbarPopup();
|
||||
assertFloatingToolbarIsDisplayed();
|
||||
assertFloatingToolbarDoesNotContainItem(
|
||||
mToolbar.assertFloatingToolbarIsDisplayed();
|
||||
mToolbar.assertFloatingToolbarDoesNotContainItem(
|
||||
mActivity.getString(com.android.internal.R.string.selectAll));
|
||||
// Make sure that shrinking the selection range to cursor (an empty range) by API
|
||||
// terminates selection action mode and does not trigger the insertion action mode.
|
||||
@@ -984,17 +957,15 @@ public class TextViewActivityTest {
|
||||
// Make sure that user click can trigger the insertion action mode.
|
||||
onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
|
||||
onHandleView(com.android.internal.R.id.insertion_handle).perform(click());
|
||||
sleepForFloatingToolbarPopup();
|
||||
assertFloatingToolbarIsDisplayed();
|
||||
mToolbar.assertFloatingToolbarIsDisplayed();
|
||||
// Make sure that an existing insertion action mode keeps alive after the insertion point is
|
||||
// moved by API.
|
||||
mActivityRule.runOnUiThread(
|
||||
() -> Selection.setSelection((Spannable) textView.getText(), 0));
|
||||
mInstrumentation.waitForIdleSync();
|
||||
|
||||
sleepForFloatingToolbarPopup();
|
||||
assertFloatingToolbarIsDisplayed();
|
||||
assertFloatingToolbarDoesNotContainItem(
|
||||
mToolbar.assertFloatingToolbarIsDisplayed();
|
||||
mToolbar.assertFloatingToolbarDoesNotContainItem(
|
||||
mActivity.getString(com.android.internal.R.string.copy));
|
||||
// Make sure that selection action mode is started after selection is created by API when
|
||||
// insertion action mode is active.
|
||||
@@ -1002,16 +973,15 @@ public class TextViewActivityTest {
|
||||
() -> Selection.setSelection((Spannable) textView.getText(), 1, text.length()));
|
||||
mInstrumentation.waitForIdleSync();
|
||||
|
||||
sleepForFloatingToolbarPopup();
|
||||
assertFloatingToolbarIsDisplayed();
|
||||
assertFloatingToolbarContainsItem(
|
||||
mToolbar.assertFloatingToolbarIsDisplayed();
|
||||
mToolbar.assertFloatingToolbarContainsItem(
|
||||
mActivity.getString(com.android.internal.R.string.copy));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransientState() throws Throwable {
|
||||
final String text = "abc def";
|
||||
onView(withId(R.id.textview)).perform(replaceText(text));
|
||||
setText(text);
|
||||
|
||||
final TextView textView = mActivity.findViewById(R.id.textview);
|
||||
assertFalse(textView.hasTransientState());
|
||||
@@ -1032,58 +1002,43 @@ public class TextViewActivityTest {
|
||||
|
||||
@Test
|
||||
public void testResetMenuItemTitle() throws Throwable {
|
||||
mActivity.getSystemService(TextClassificationManager.class).setTextClassifier(null);
|
||||
mActivity.getSystemService(TextClassificationManager.class)
|
||||
.setTextClassifier(TextClassifier.NO_OP);
|
||||
final TextView textView = mActivity.findViewById(R.id.textview);
|
||||
final int itemId = 1;
|
||||
final String title1 = " AFIGBO";
|
||||
final int index = title1.indexOf('I');
|
||||
final String title2 = title1.substring(index);
|
||||
final String title1 = "@AFIGBO";
|
||||
final int index = 3;
|
||||
final String title2 = "IGBO";
|
||||
final String[] title = new String[]{title1};
|
||||
mActivityRule.runOnUiThread(() -> textView.setCustomSelectionActionModeCallback(
|
||||
new ActionMode.Callback() {
|
||||
@Override
|
||||
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
|
||||
return true;
|
||||
}
|
||||
|
||||
new ActionModeCallbackAdapter() {
|
||||
@Override
|
||||
public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
|
||||
menu.removeItem(itemId);
|
||||
menu.clear();
|
||||
menu.add(Menu.NONE /* group */, itemId, 0 /* order */, title[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyActionMode(ActionMode actionMode) {
|
||||
}
|
||||
}));
|
||||
mInstrumentation.waitForIdleSync();
|
||||
|
||||
onView(withId(R.id.textview)).perform(replaceText(title1));
|
||||
setText(title1);
|
||||
onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(index));
|
||||
sleepForFloatingToolbarPopup();
|
||||
assertFloatingToolbarContainsItem(title1);
|
||||
mToolbar.assertFloatingToolbarContainsItem(title1);
|
||||
|
||||
// Change the menu item title.
|
||||
title[0] = title2;
|
||||
// Change the selection to invalidate the action mode without restarting it.
|
||||
onHandleView(com.android.internal.R.id.selection_start_handle)
|
||||
.perform(dragHandle(textView, Handle.SELECTION_START, index));
|
||||
sleepForFloatingToolbarPopup();
|
||||
assertFloatingToolbarContainsItem(title2);
|
||||
mToolbar.assertFloatingToolbarContainsItem(title2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAssistItemIsAtIndexZero() throws Throwable {
|
||||
useSystemDefaultTextClassifier();
|
||||
final SingleActionTextClassifier tc = useSingleActionTextClassifier();
|
||||
final TextView textView = mActivity.findViewById(R.id.textview);
|
||||
mActivityRule.runOnUiThread(() -> textView.setCustomSelectionActionModeCallback(
|
||||
new ActionMode.Callback() {
|
||||
new ActionModeCallbackAdapter() {
|
||||
@Override
|
||||
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
|
||||
// Create another item at order position 0 to confirm that it will never be
|
||||
@@ -1091,33 +1046,19 @@ public class TextViewActivityTest {
|
||||
menu.add(Menu.NONE, 0 /* id */, 0 /* order */, "Test");
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyActionMode(ActionMode actionMode) {
|
||||
}
|
||||
}));
|
||||
mInstrumentation.waitForIdleSync();
|
||||
final String text = "droid@android.com";
|
||||
|
||||
onView(withId(R.id.textview)).perform(replaceText(text));
|
||||
setText(text);
|
||||
onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('@')));
|
||||
sleepForFloatingToolbarPopup();
|
||||
assertFloatingToolbarItemIndex(android.R.id.textAssist, 0);
|
||||
mToolbar.assertFloatingToolbarContainsItemAtIndex(tc.getActionLabel(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoAssistItemForPasswordField() throws Throwable {
|
||||
useSystemDefaultTextClassifier();
|
||||
final SingleActionTextClassifier tc = useSingleActionTextClassifier();
|
||||
|
||||
final TextView textView = mActivity.findViewById(R.id.textview);
|
||||
mActivityRule.runOnUiThread(() -> {
|
||||
textView.setInputType(
|
||||
@@ -1126,23 +1067,22 @@ public class TextViewActivityTest {
|
||||
mInstrumentation.waitForIdleSync();
|
||||
final String password = "afigbo@android.com";
|
||||
|
||||
onView(withId(R.id.textview)).perform(replaceText(password));
|
||||
setText(password);
|
||||
onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(password.indexOf('@')));
|
||||
sleepForFloatingToolbarPopup();
|
||||
assertFloatingToolbarDoesNotContainItem(android.R.id.textAssist);
|
||||
mToolbar.assertFloatingToolbarDoesNotContainItem(tc.getActionLabel());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoAssistItemForTextFieldWithUnsupportedCharacters() throws Throwable {
|
||||
useSystemDefaultTextClassifier();
|
||||
// NOTE: This test addresses a security bug.
|
||||
final SingleActionTextClassifier tc = useSingleActionTextClassifier();
|
||||
final String text = "\u202Emoc.diordna.com";
|
||||
final TextView textView = mActivity.findViewById(R.id.textview);
|
||||
mActivityRule.runOnUiThread(() -> textView.setText(text));
|
||||
mInstrumentation.waitForIdleSync();
|
||||
|
||||
onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('.')));
|
||||
sleepForFloatingToolbarPopup();
|
||||
assertFloatingToolbarDoesNotContainItem(android.R.id.textAssist);
|
||||
mToolbar.assertFloatingToolbarDoesNotContainItem(tc.getActionLabel());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1159,10 +1099,9 @@ public class TextViewActivityTest {
|
||||
mInstrumentation.waitForIdleSync();
|
||||
final String text = "andyroid@android.com";
|
||||
|
||||
onView(withId(R.id.textview)).perform(replaceText(text));
|
||||
setText(text);
|
||||
onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('@')));
|
||||
sleepForFloatingToolbarPopup();
|
||||
clickFloatingToolbarItem(mActivity.getString(com.android.internal.R.string.copy));
|
||||
mToolbar.clickFloatingToolbarItem(mActivity.getString(com.android.internal.R.string.copy));
|
||||
mInstrumentation.waitForIdleSync();
|
||||
|
||||
final SelectionEvent lastEvent = selectionEvents.get(selectionEvents.size() - 1);
|
||||
@@ -1178,9 +1117,8 @@ public class TextViewActivityTest {
|
||||
|
||||
final String text = "My number is 987654321";
|
||||
|
||||
onView(withId(R.id.textview)).perform(replaceText(text));
|
||||
setText(text);
|
||||
onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('9')));
|
||||
sleepForFloatingToolbarPopup();
|
||||
onView(withId(R.id.textview)).perform(clickOnTextAtIndex(0));
|
||||
mInstrumentation.waitForIdleSync();
|
||||
|
||||
@@ -1211,9 +1149,8 @@ public class TextViewActivityTest {
|
||||
final String text = "My number is 987654321";
|
||||
|
||||
// Long press to trigger selection
|
||||
onView(withId(R.id.textview)).perform(replaceText(text));
|
||||
setText(text);
|
||||
onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('9')));
|
||||
sleepForFloatingToolbarPopup();
|
||||
|
||||
// Type over the selection
|
||||
onView(withId(R.id.textview)).perform(pressKey(KeyEvent.KEYCODE_A));
|
||||
@@ -1255,16 +1192,14 @@ public class TextViewActivityTest {
|
||||
});
|
||||
|
||||
// Long press to trigger selection
|
||||
onView(withId(R.id.textview)).perform(replaceText("android.com"));
|
||||
setText("android.com");
|
||||
onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(0));
|
||||
sleepForFloatingToolbarPopup();
|
||||
// Click "Copy" to dismiss the selection.
|
||||
clickFloatingToolbarItem(mActivity.getString(com.android.internal.R.string.copy));
|
||||
mToolbar.clickFloatingToolbarItem(mActivity.getString(com.android.internal.R.string.copy));
|
||||
|
||||
// Long press to trigger another selection
|
||||
onView(withId(R.id.textview)).perform(replaceText("android@android.com"));
|
||||
setText("android@android.com");
|
||||
onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(0));
|
||||
sleepForFloatingToolbarPopup();
|
||||
|
||||
// suggestSelection should be called in two different TextClassifier sessions.
|
||||
assertEquals(2, testableTextClassifiers.size());
|
||||
@@ -1276,10 +1211,9 @@ public class TextViewActivityTest {
|
||||
public void testPastePlainText_menuAction() {
|
||||
initializeClipboardWithText(TextStyle.STYLED);
|
||||
|
||||
onView(withId(R.id.textview)).perform(replaceText(""));
|
||||
setText("");
|
||||
onView(withId(R.id.textview)).perform(longClick());
|
||||
sleepForFloatingToolbarPopup();
|
||||
clickFloatingToolbarItem(
|
||||
mToolbar.clickFloatingToolbarItem(
|
||||
mActivity.getString(com.android.internal.R.string.paste_as_plain_text));
|
||||
mInstrumentation.waitForIdleSync();
|
||||
|
||||
@@ -1291,18 +1225,33 @@ public class TextViewActivityTest {
|
||||
public void testPastePlainText_noMenuItemForPlainText() {
|
||||
initializeClipboardWithText(TextStyle.PLAIN);
|
||||
|
||||
onView(withId(R.id.textview)).perform(replaceText(""));
|
||||
setText("");
|
||||
onView(withId(R.id.textview)).perform(longClick());
|
||||
sleepForFloatingToolbarPopup();
|
||||
|
||||
assertFloatingToolbarDoesNotContainItem(
|
||||
mToolbar.assertFloatingToolbarDoesNotContainItem(
|
||||
mActivity.getString(com.android.internal.R.string.paste_as_plain_text));
|
||||
}
|
||||
|
||||
private void setText(String text) {
|
||||
onView(withId(R.id.textview)).perform(replaceText(text));
|
||||
mDevice.wait(Until.findObject(By.text(text)), 1000);
|
||||
mInstrumentation.waitForIdleSync();
|
||||
}
|
||||
|
||||
private void useSystemDefaultTextClassifier() {
|
||||
mActivity.getSystemService(TextClassificationManager.class).setTextClassifier(null);
|
||||
}
|
||||
|
||||
private SingleActionTextClassifier useSingleActionTextClassifier() {
|
||||
useSystemDefaultTextClassifier();
|
||||
final TextClassificationManager tcm =
|
||||
mActivity.getSystemService(TextClassificationManager.class);
|
||||
final SingleActionTextClassifier oneActionTC =
|
||||
new SingleActionTextClassifier(mActivity, tcm.getTextClassifier());
|
||||
tcm.setTextClassifier(oneActionTC);
|
||||
return oneActionTC;
|
||||
}
|
||||
|
||||
private void initializeClipboardWithText(TextStyle textStyle) {
|
||||
final ClipData clip;
|
||||
switch (textStyle) {
|
||||
@@ -1324,7 +1273,7 @@ public class TextViewActivityTest {
|
||||
PLAIN, STYLED
|
||||
}
|
||||
|
||||
private final class TestableTextClassifier implements TextClassifier {
|
||||
private static final class TestableTextClassifier implements TextClassifier {
|
||||
final List<SelectionEvent> mSelectionEvents = new ArrayList<>();
|
||||
final List<TextSelection.Request> mTextSelectionRequests = new ArrayList<>();
|
||||
|
||||
@@ -1349,4 +1298,54 @@ public class TextViewActivityTest {
|
||||
return mTextSelectionRequests;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class SingleActionTextClassifier implements TextClassifier {
|
||||
|
||||
private final RemoteAction mAction;
|
||||
private final TextClassifier mOriginal;
|
||||
private final TextClassification mClassificationResult;
|
||||
|
||||
SingleActionTextClassifier(Context context, TextClassifier original) {
|
||||
mAction = new RemoteAction(
|
||||
Icon.createWithResource(context, android.R.drawable.btn_star),
|
||||
"assist",
|
||||
"assist",
|
||||
PendingIntent.getActivity(context, 0, new Intent(), FLAG_IMMUTABLE));
|
||||
mClassificationResult = new TextClassification.Builder().addAction(mAction).build();
|
||||
mOriginal = Objects.requireNonNull(original);
|
||||
}
|
||||
|
||||
public String getActionLabel() {
|
||||
return mAction.getTitle().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextSelection suggestSelection(TextSelection.Request request) {
|
||||
final TextSelection sel = mOriginal.suggestSelection(request);
|
||||
return new TextSelection.Builder(
|
||||
sel.getSelectionStartIndex(), sel.getSelectionEndIndex())
|
||||
.setTextClassification(mClassificationResult)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
private static class ActionModeCallbackAdapter implements ActionMode.Callback {
|
||||
@Override
|
||||
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyActionMode(ActionMode actionMode) {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,263 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License
|
||||
*/
|
||||
|
||||
package android.widget.espresso;
|
||||
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.action.ViewActions.click;
|
||||
import static androidx.test.espresso.assertion.ViewAssertions.matches;
|
||||
import static androidx.test.espresso.matcher.RootMatchers.isPlatformPopup;
|
||||
import static androidx.test.espresso.matcher.RootMatchers.withDecorView;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withTagValue;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
||||
|
||||
import static com.android.internal.widget.floatingtoolbar.LocalFloatingToolbarPopup.MenuItemRepr;
|
||||
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.test.espresso.NoMatchingRootException;
|
||||
import androidx.test.espresso.NoMatchingViewException;
|
||||
import androidx.test.espresso.UiController;
|
||||
import androidx.test.espresso.ViewAction;
|
||||
import androidx.test.espresso.ViewInteraction;
|
||||
|
||||
import com.android.internal.widget.floatingtoolbar.FloatingToolbar;
|
||||
|
||||
import org.hamcrest.Description;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.hamcrest.TypeSafeMatcher;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Espresso utility methods for the floating toolbar.
|
||||
*/
|
||||
public class FloatingToolbarEspressoUtils {
|
||||
private final static Object TAG = FloatingToolbar.FLOATING_TOOLBAR_TAG;
|
||||
|
||||
private FloatingToolbarEspressoUtils() {}
|
||||
|
||||
private static ViewInteraction onFloatingToolBar() {
|
||||
return onView(withTagValue(is(TAG)))
|
||||
.inRoot(allOf(
|
||||
isPlatformPopup(),
|
||||
withDecorView(hasDescendant(withTagValue(is(TAG))))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link ViewInteraction} for the floating bar menu item with the given matcher.
|
||||
*
|
||||
* @param matcher The matcher for the menu item.
|
||||
*/
|
||||
public static ViewInteraction onFloatingToolBarItem(Matcher<View> matcher) {
|
||||
return onView(matcher)
|
||||
.inRoot(withDecorView(hasDescendant(withTagValue(is(TAG)))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the floating toolbar is displayed on screen.
|
||||
*
|
||||
* @throws AssertionError if the assertion fails
|
||||
*/
|
||||
public static void assertFloatingToolbarIsDisplayed() {
|
||||
onFloatingToolBar().check(matches(isDisplayed()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the floating toolbar is not displayed on screen.
|
||||
*
|
||||
* @throws AssertionError if the assertion fails
|
||||
* @deprecated Negative assertions are taking too long to timeout in Espresso.
|
||||
*/
|
||||
@Deprecated
|
||||
public static void assertFloatingToolbarIsNotDisplayed() {
|
||||
try {
|
||||
onFloatingToolBar().check(matches(isDisplayed()));
|
||||
} catch (NoMatchingRootException | NoMatchingViewException | AssertionError e) {
|
||||
return;
|
||||
}
|
||||
throw new AssertionError("Floating toolbar is displayed");
|
||||
}
|
||||
|
||||
private static void toggleOverflow() {
|
||||
final int id = com.android.internal.R.id.overflow;
|
||||
onView(allOf(withId(id), isDisplayed()))
|
||||
.inRoot(withDecorView(hasDescendant(withId(id))))
|
||||
.perform(click());
|
||||
onView(isRoot()).perform(SLEEP);
|
||||
}
|
||||
|
||||
public static void sleepForFloatingToolbarPopup() {
|
||||
onView(isRoot()).perform(SLEEP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the floating toolbar contains the specified item.
|
||||
*
|
||||
* @param itemLabel label of the item.
|
||||
* @throws AssertionError if the assertion fails
|
||||
*/
|
||||
public static void assertFloatingToolbarContainsItem(String itemLabel) {
|
||||
try{
|
||||
onFloatingToolBar().check(matches(hasDescendant(withText(itemLabel))));
|
||||
} catch (AssertionError e) {
|
||||
try{
|
||||
toggleOverflow();
|
||||
} catch (NoMatchingViewException | NoMatchingRootException e2) {
|
||||
// No overflow items.
|
||||
throw e;
|
||||
}
|
||||
try{
|
||||
onFloatingToolBar().check(matches(hasDescendant(withText(itemLabel))));
|
||||
} finally {
|
||||
toggleOverflow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the floating toolbar contains a specified item at a specified index.
|
||||
*
|
||||
* @param menuItemId id of the menu item
|
||||
* @param index expected index of the menu item in the floating toolbar
|
||||
* @throws AssertionError if the assertion fails
|
||||
*/
|
||||
public static void assertFloatingToolbarItemIndex(final int menuItemId, final int index) {
|
||||
onFloatingToolBar().check(matches(new TypeSafeMatcher<View>() {
|
||||
private List<Integer> menuItemIds = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public boolean matchesSafely(View view) {
|
||||
collectMenuItemIds(view);
|
||||
return menuItemIds.size() > index && menuItemIds.get(index) == menuItemId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {}
|
||||
|
||||
private void collectMenuItemIds(View view) {
|
||||
if (view.getTag() instanceof MenuItemRepr) {
|
||||
menuItemIds.add(((MenuItemRepr) view.getTag()).itemId);
|
||||
} else if (view instanceof ViewGroup) {
|
||||
ViewGroup viewGroup = (ViewGroup) view;
|
||||
for (int i = 0; i < viewGroup.getChildCount(); i++) {
|
||||
collectMenuItemIds(viewGroup.getChildAt(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the floating toolbar doesn't contain the specified item.
|
||||
*
|
||||
* @param itemLabel label of the item.
|
||||
* @throws AssertionError if the assertion fails
|
||||
*/
|
||||
public static void assertFloatingToolbarDoesNotContainItem(String itemLabel) {
|
||||
final Predicate<View> hasMenuItemLabel = view ->
|
||||
view.getTag() instanceof MenuItemRepr
|
||||
&& itemLabel.equals(((MenuItemRepr) view.getTag()).title);
|
||||
assertFloatingToolbarMenuItem(hasMenuItemLabel, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the floating toolbar does not contain a menu item with the specified id.
|
||||
*
|
||||
* @param menuItemId id of the menu item
|
||||
* @throws AssertionError if the assertion fails
|
||||
*/
|
||||
public static void assertFloatingToolbarDoesNotContainItem(final int menuItemId) {
|
||||
final Predicate<View> hasMenuItemId = view ->
|
||||
view.getTag() instanceof MenuItemRepr
|
||||
&& ((MenuItemRepr) view.getTag()).itemId == menuItemId;
|
||||
assertFloatingToolbarMenuItem(hasMenuItemId, false);
|
||||
}
|
||||
|
||||
private static void assertFloatingToolbarMenuItem(
|
||||
final Predicate<View> predicate, final boolean positiveAssertion) {
|
||||
onFloatingToolBar().check(matches(new TypeSafeMatcher<View>() {
|
||||
@Override
|
||||
public boolean matchesSafely(View view) {
|
||||
return positiveAssertion == containsItem(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {}
|
||||
|
||||
private boolean containsItem(View view) {
|
||||
if (predicate.test(view)) {
|
||||
return true;
|
||||
} else if (view instanceof ViewGroup) {
|
||||
ViewGroup viewGroup = (ViewGroup) view;
|
||||
for (int i = 0; i < viewGroup.getChildCount(); i++) {
|
||||
if (containsItem(viewGroup.getChildAt(i))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Click specified item on the floating tool bar.
|
||||
*
|
||||
* @param itemLabel label of the item.
|
||||
*/
|
||||
public static void clickFloatingToolbarItem(String itemLabel) {
|
||||
try{
|
||||
onFloatingToolBarItem(withText(itemLabel)).check(matches(isDisplayed()));
|
||||
} catch (AssertionError e) {
|
||||
// Try to find the item in the overflow menu.
|
||||
toggleOverflow();
|
||||
}
|
||||
onFloatingToolBarItem(withText(itemLabel)).perform(click());
|
||||
}
|
||||
|
||||
/**
|
||||
* ViewAction to sleep to wait floating toolbar's animation.
|
||||
*/
|
||||
private static final ViewAction SLEEP = new ViewAction() {
|
||||
private static final long SLEEP_DURATION = 400;
|
||||
|
||||
@Override
|
||||
public Matcher<View> getConstraints() {
|
||||
return isDisplayed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Sleep " + SLEEP_DURATION + " ms.";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void perform(UiController uiController, View view) {
|
||||
uiController.loopMainThreadForAtLeast(SLEEP_DURATION);
|
||||
}
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user