Loading core/java/android/widget/Editor.java +6 −5 Original line number Diff line number Diff line Loading @@ -146,7 +146,7 @@ public class Editor { private static final String UNDO_OWNER_TAG = "Editor"; // Ordering constants used to place the Action Mode or context menu items in their menu. private static final int MENU_ITEM_ORDER_ASSIST = 1; private static final int MENU_ITEM_ORDER_ASSIST = 0; private static final int MENU_ITEM_ORDER_UNDO = 2; private static final int MENU_ITEM_ORDER_REDO = 3; private static final int MENU_ITEM_ORDER_CUT = 4; Loading @@ -156,8 +156,8 @@ public class Editor { private static final int MENU_ITEM_ORDER_PASTE_AS_PLAIN_TEXT = 8; private static final int MENU_ITEM_ORDER_SELECT_ALL = 9; private static final int MENU_ITEM_ORDER_REPLACE = 10; private static final int MENU_ITEM_ORDER_PROCESS_TEXT_INTENT_ACTIONS_START = 11; private static final int MENU_ITEM_ORDER_AUTOFILL = 12; private static final int MENU_ITEM_ORDER_AUTOFILL = 11; private static final int MENU_ITEM_ORDER_PROCESS_TEXT_INTENT_ACTIONS_START = 100; // Each Editor manages its own undo stack. private final UndoManager mUndoManager = new UndoManager(); Loading Loading @@ -6322,9 +6322,10 @@ public class Editor { * Adds "PROCESS_TEXT" menu items to the specified menu. */ public void onInitializeMenu(Menu menu) { int i = 0; final int size = mSupportedActivities.size(); loadSupportedActivities(); for (ResolveInfo resolveInfo : mSupportedActivities) { for (int i = 0; i < size; i++) { final ResolveInfo resolveInfo = mSupportedActivities.get(i); menu.add(Menu.NONE, Menu.NONE, Editor.MENU_ITEM_ORDER_PROCESS_TEXT_INTENT_ACTIONS_START + i++, getLabel(resolveInfo)) Loading core/java/com/android/internal/widget/FloatingToolbar.java +31 −0 Original line number Diff line number Diff line Loading @@ -233,6 +233,7 @@ public final class FloatingToolbar { private void doShow() { List<MenuItem> menuItems = getVisibleAndEnabledMenuItems(mMenu); tidy(menuItems); if (!isCurrentlyShowing(menuItems) || mWidthChanged) { mPopup.dismiss(); mPopup.layoutMenuItems(menuItems, mMenuItemClickListener, mSuggestedWidth); Loading Loading @@ -274,6 +275,36 @@ public final class FloatingToolbar { return menuItems; } /** * Update the list of menu items to conform to certain requirements. */ private void tidy(List<MenuItem> menuItems) { int assistItemIndex = -1; Drawable assistItemDrawable = null; final int size = menuItems.size(); for (int i = 0; i < size; i++) { final MenuItem menuItem = menuItems.get(i); if (menuItem.getItemId() == android.R.id.textAssist) { assistItemIndex = i; assistItemDrawable = menuItem.getIcon(); } // Remove icons for all menu items with text. if (!TextUtils.isEmpty(menuItem.getTitle())) { menuItem.setIcon(null); } } if (assistItemIndex > -1) { final MenuItem assistMenuItem = menuItems.remove(assistItemIndex); // Ensure the assist menu item preserves its icon. assistMenuItem.setIcon(assistItemDrawable); // Ensure the assist menu item is always the first item. menuItems.add(0, assistMenuItem); } } private List<Object> getShowingMenuItemsReferences(List<MenuItem> menuItems) { List<Object> references = new ArrayList<Object>(); for (MenuItem menuItem : menuItems) { Loading core/tests/coretests/src/android/widget/TextViewActivityTest.java +42 −1 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import static android.widget.espresso.TextViewActions.longPressAndDragOnText; import static android.widget.espresso.TextViewActions.longPressOnTextAtIndex; import static android.widget.espresso.TextViewAssertions.hasInsertionPointerAtIndex; import static android.widget.espresso.TextViewAssertions.hasSelection; import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarItemIndex; import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarIsDisplayed; import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarIsNotDisplayed; import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarContainsItem; Loading @@ -46,6 +47,11 @@ import static android.support.test.espresso.matcher.ViewMatchers.withText; import static org.hamcrest.Matchers.anyOf; import static org.hamcrest.Matchers.is; import android.view.ActionMode; import android.view.Menu; import android.view.MenuItem; import android.view.textclassifier.TextClassificationManager; import android.view.textclassifier.TextClassifier; import android.widget.espresso.CustomViewActions.RelativeCoordinatesProvider; import android.support.test.espresso.action.EspressoKey; Loading @@ -71,7 +77,8 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV @Override public void setUp() throws Exception { super.setUp(); getActivity(); getActivity().getSystemService(TextClassificationManager.class) .setTextClassifier(TextClassifier.NO_OP); } public void testTypedTextIsOnScreen() throws Exception { Loading Loading @@ -676,4 +683,38 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV // hasTransientState should return false when selection is created by API. assertFalse(textView.hasTransientState()); } public void testAssistItemIsAtIndexZero() throws Exception { getActivity().getSystemService(TextClassificationManager.class).setTextClassifier(null); final TextView textView = (TextView) getActivity().findViewById(R.id.textview); textView.post(() -> textView.setCustomSelectionActionModeCallback( new ActionMode.Callback() { @Override public boolean onCreateActionMode(ActionMode actionMode, Menu menu) { // Create another item at order position 0 to confirm that it will never be // placed before the textAssist item. 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) {} })); final String text = "droid@android.com"; onView(withId(R.id.textview)).perform(replaceText(text)); onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('@'))); sleepForFloatingToolbarPopup(); assertFloatingToolbarItemIndex(android.R.id.textAssist, 0); } } core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java +39 −0 Original line number Diff line number Diff line Loading @@ -29,7 +29,13 @@ import static android.support.test.espresso.matcher.ViewMatchers.withText; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.is; import android.view.MenuItem; import android.view.ViewGroup; import java.util.ArrayList; import java.util.List; import org.hamcrest.Description; import org.hamcrest.Matcher; import org.hamcrest.TypeSafeMatcher; import android.support.test.espresso.NoMatchingRootException; import android.support.test.espresso.NoMatchingViewException; Loading Loading @@ -122,6 +128,39 @@ public class FloatingToolbarEspressoUtils { } } /** * 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 MenuItem) { menuItemIds.add(((MenuItem) view.getTag()).getItemId()); } 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. * Loading Loading
core/java/android/widget/Editor.java +6 −5 Original line number Diff line number Diff line Loading @@ -146,7 +146,7 @@ public class Editor { private static final String UNDO_OWNER_TAG = "Editor"; // Ordering constants used to place the Action Mode or context menu items in their menu. private static final int MENU_ITEM_ORDER_ASSIST = 1; private static final int MENU_ITEM_ORDER_ASSIST = 0; private static final int MENU_ITEM_ORDER_UNDO = 2; private static final int MENU_ITEM_ORDER_REDO = 3; private static final int MENU_ITEM_ORDER_CUT = 4; Loading @@ -156,8 +156,8 @@ public class Editor { private static final int MENU_ITEM_ORDER_PASTE_AS_PLAIN_TEXT = 8; private static final int MENU_ITEM_ORDER_SELECT_ALL = 9; private static final int MENU_ITEM_ORDER_REPLACE = 10; private static final int MENU_ITEM_ORDER_PROCESS_TEXT_INTENT_ACTIONS_START = 11; private static final int MENU_ITEM_ORDER_AUTOFILL = 12; private static final int MENU_ITEM_ORDER_AUTOFILL = 11; private static final int MENU_ITEM_ORDER_PROCESS_TEXT_INTENT_ACTIONS_START = 100; // Each Editor manages its own undo stack. private final UndoManager mUndoManager = new UndoManager(); Loading Loading @@ -6322,9 +6322,10 @@ public class Editor { * Adds "PROCESS_TEXT" menu items to the specified menu. */ public void onInitializeMenu(Menu menu) { int i = 0; final int size = mSupportedActivities.size(); loadSupportedActivities(); for (ResolveInfo resolveInfo : mSupportedActivities) { for (int i = 0; i < size; i++) { final ResolveInfo resolveInfo = mSupportedActivities.get(i); menu.add(Menu.NONE, Menu.NONE, Editor.MENU_ITEM_ORDER_PROCESS_TEXT_INTENT_ACTIONS_START + i++, getLabel(resolveInfo)) Loading
core/java/com/android/internal/widget/FloatingToolbar.java +31 −0 Original line number Diff line number Diff line Loading @@ -233,6 +233,7 @@ public final class FloatingToolbar { private void doShow() { List<MenuItem> menuItems = getVisibleAndEnabledMenuItems(mMenu); tidy(menuItems); if (!isCurrentlyShowing(menuItems) || mWidthChanged) { mPopup.dismiss(); mPopup.layoutMenuItems(menuItems, mMenuItemClickListener, mSuggestedWidth); Loading Loading @@ -274,6 +275,36 @@ public final class FloatingToolbar { return menuItems; } /** * Update the list of menu items to conform to certain requirements. */ private void tidy(List<MenuItem> menuItems) { int assistItemIndex = -1; Drawable assistItemDrawable = null; final int size = menuItems.size(); for (int i = 0; i < size; i++) { final MenuItem menuItem = menuItems.get(i); if (menuItem.getItemId() == android.R.id.textAssist) { assistItemIndex = i; assistItemDrawable = menuItem.getIcon(); } // Remove icons for all menu items with text. if (!TextUtils.isEmpty(menuItem.getTitle())) { menuItem.setIcon(null); } } if (assistItemIndex > -1) { final MenuItem assistMenuItem = menuItems.remove(assistItemIndex); // Ensure the assist menu item preserves its icon. assistMenuItem.setIcon(assistItemDrawable); // Ensure the assist menu item is always the first item. menuItems.add(0, assistMenuItem); } } private List<Object> getShowingMenuItemsReferences(List<MenuItem> menuItems) { List<Object> references = new ArrayList<Object>(); for (MenuItem menuItem : menuItems) { Loading
core/tests/coretests/src/android/widget/TextViewActivityTest.java +42 −1 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import static android.widget.espresso.TextViewActions.longPressAndDragOnText; import static android.widget.espresso.TextViewActions.longPressOnTextAtIndex; import static android.widget.espresso.TextViewAssertions.hasInsertionPointerAtIndex; import static android.widget.espresso.TextViewAssertions.hasSelection; import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarItemIndex; import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarIsDisplayed; import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarIsNotDisplayed; import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarContainsItem; Loading @@ -46,6 +47,11 @@ import static android.support.test.espresso.matcher.ViewMatchers.withText; import static org.hamcrest.Matchers.anyOf; import static org.hamcrest.Matchers.is; import android.view.ActionMode; import android.view.Menu; import android.view.MenuItem; import android.view.textclassifier.TextClassificationManager; import android.view.textclassifier.TextClassifier; import android.widget.espresso.CustomViewActions.RelativeCoordinatesProvider; import android.support.test.espresso.action.EspressoKey; Loading @@ -71,7 +77,8 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV @Override public void setUp() throws Exception { super.setUp(); getActivity(); getActivity().getSystemService(TextClassificationManager.class) .setTextClassifier(TextClassifier.NO_OP); } public void testTypedTextIsOnScreen() throws Exception { Loading Loading @@ -676,4 +683,38 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV // hasTransientState should return false when selection is created by API. assertFalse(textView.hasTransientState()); } public void testAssistItemIsAtIndexZero() throws Exception { getActivity().getSystemService(TextClassificationManager.class).setTextClassifier(null); final TextView textView = (TextView) getActivity().findViewById(R.id.textview); textView.post(() -> textView.setCustomSelectionActionModeCallback( new ActionMode.Callback() { @Override public boolean onCreateActionMode(ActionMode actionMode, Menu menu) { // Create another item at order position 0 to confirm that it will never be // placed before the textAssist item. 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) {} })); final String text = "droid@android.com"; onView(withId(R.id.textview)).perform(replaceText(text)); onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('@'))); sleepForFloatingToolbarPopup(); assertFloatingToolbarItemIndex(android.R.id.textAssist, 0); } }
core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java +39 −0 Original line number Diff line number Diff line Loading @@ -29,7 +29,13 @@ import static android.support.test.espresso.matcher.ViewMatchers.withText; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.is; import android.view.MenuItem; import android.view.ViewGroup; import java.util.ArrayList; import java.util.List; import org.hamcrest.Description; import org.hamcrest.Matcher; import org.hamcrest.TypeSafeMatcher; import android.support.test.espresso.NoMatchingRootException; import android.support.test.espresso.NoMatchingViewException; Loading Loading @@ -122,6 +128,39 @@ public class FloatingToolbarEspressoUtils { } } /** * 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 MenuItem) { menuItemIds.add(((MenuItem) view.getTag()).getItemId()); } 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. * Loading