Merge "FloatingToolbar: Rules for ordering menu items." into oc-dev

This commit is contained in:
Abodunrinwa Toki
2017-04-18 12:58:27 +00:00
committed by Android (Google) Code Review
4 changed files with 118 additions and 6 deletions

View File

@@ -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;
@@ -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();
@@ -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))

View File

@@ -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);
@@ -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) {

View File

@@ -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;
@@ -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;
@@ -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 {
@@ -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);
}
}

View File

@@ -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;
@@ -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.
*