Loading core/java/android/widget/Editor.java +130 −56 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static android.view.ContentInfo.SOURCE_DRAG_AND_DROP; import static android.widget.TextView.ACCESSIBILITY_ACTION_SMART_START_ID; import static com.android.graphics.hwui.flags.Flags.highContrastTextSmallTextRect; import static com.android.text.flags.Flags.contextMenuHideUnavailableItems; import android.R; import android.animation.ValueAnimator; Loading Loading @@ -3250,6 +3251,78 @@ public class Editor { final int menuItemOrderShare = 9; final int menuItemOrderAutofill = 10; if (contextMenuHideUnavailableItems()) { if (mTextView.canUndo()) { menu.add(CONTEXT_MENU_GROUP_UNDO_REDO, TextView.ID_UNDO, menuItemOrderUndo, com.android.internal.R.string.undo) .setAlphabeticShortcut('z') .setOnMenuItemClickListener(mOnContextMenuItemClickListener) .setIcon(a.getDrawable(0)); } if (mTextView.canRedo()) { menu.add(CONTEXT_MENU_GROUP_UNDO_REDO, TextView.ID_REDO, menuItemOrderRedo, com.android.internal.R.string.redo) .setAlphabeticShortcut('z', KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON) .setOnMenuItemClickListener(mOnContextMenuItemClickListener) .setIcon(a.getDrawable(1)); } if (mTextView.canCut()) { menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_CUT, menuItemOrderCut, com.android.internal.R.string.cut) .setAlphabeticShortcut('x') .setOnMenuItemClickListener(mOnContextMenuItemClickListener) .setIcon(a.getDrawable(2)); } if (mTextView.canCopy()) { menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_COPY, menuItemOrderCopy, com.android.internal.R.string.copy) .setAlphabeticShortcut('c') .setOnMenuItemClickListener(mOnContextMenuItemClickListener) .setIcon(a.getDrawable(3)); } if (mTextView.canPaste()) { menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_PASTE, menuItemOrderPaste, com.android.internal.R.string.paste) .setAlphabeticShortcut('v') .setIcon(a.getDrawable(4)) .setOnMenuItemClickListener(mOnContextMenuItemClickListener); } if (mTextView.canPasteAsPlainText()) { menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_PASTE_AS_PLAIN_TEXT, menuItemOrderPasteAsPlainText, com.android.internal.R.string.paste_as_plain_text) .setAlphabeticShortcut('v', KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON) .setIcon(a.getDrawable(4)) .setOnMenuItemClickListener(mOnContextMenuItemClickListener); } if (mTextView.canSelectAllText()) { menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_SELECT_ALL, menuItemOrderSelectAll, com.android.internal.R.string.selectAll) .setAlphabeticShortcut('a') .setIcon(a.getDrawable(5)) .setOnMenuItemClickListener(mOnContextMenuItemClickListener); } if (mTextView.canShare()) { menu.add(CONTEXT_MENU_GROUP_MISC, TextView.ID_SHARE, menuItemOrderShare, com.android.internal.R.string.share) .setIcon(a.getDrawable(6)) .setOnMenuItemClickListener(mOnContextMenuItemClickListener); } final String selected = mTextView.getSelectedText(); if (mTextView.canRequestAutofill() && (selected == null || selected.isEmpty())) { menu.add(CONTEXT_MENU_GROUP_MISC, TextView.ID_AUTOFILL, menuItemOrderAutofill, android.R.string.autofill) .setOnMenuItemClickListener(mOnContextMenuItemClickListener); } } else { menu.add(CONTEXT_MENU_GROUP_UNDO_REDO, TextView.ID_UNDO, menuItemOrderUndo, com.android.internal.R.string.undo) .setAlphabeticShortcut('z') Loading Loading @@ -3306,6 +3379,7 @@ public class Editor { .setEnabled(mTextView.canRequestAutofill() && (selected == null || selected.isEmpty())) .setOnMenuItemClickListener(mOnContextMenuItemClickListener); } a.recycle(); } Loading core/java/android/widget/TextView.java +24 −8 Original line number Diff line number Diff line Loading @@ -15552,15 +15552,21 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } boolean canUndo() { /** @hide */ @VisibleForTesting public boolean canUndo() { return mEditor != null && mEditor.canUndo(); } boolean canRedo() { /** @hide */ @VisibleForTesting public boolean canRedo() { return mEditor != null && mEditor.canRedo(); } boolean canCut() { /** @hide */ @VisibleForTesting public boolean canCut() { if (hasPasswordTransformationMethod()) { return false; } Loading @@ -15573,7 +15579,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return false; } boolean canCopy() { /** @hide */ @VisibleForTesting public boolean canCopy() { if (hasPasswordTransformationMethod()) { return false; } Loading @@ -15594,7 +15602,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener && isSuggestionsEnabled() && mEditor.shouldOfferToShowSuggestions(); } boolean canShare() { /** @hide */ @VisibleForTesting public boolean canShare() { if (!getContext().canStartActivityForResult() || !isDeviceProvisioned() || !getContext().getResources().getBoolean( com.android.internal.R.bool.config_textShareSupported)) { Loading @@ -15613,8 +15623,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return mDeviceProvisionedState == DEVICE_PROVISIONED_YES; } /** @hide */ @VisibleForTesting @UnsupportedAppUsage boolean canPaste() { public boolean canPaste() { return (mText instanceof Editable && mEditor != null && mEditor.mKeyListener != null && getSelectionStart() >= 0 Loading @@ -15622,7 +15634,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener && getClipboardManagerForUser().hasPrimaryClip()); } boolean canPasteAsPlainText() { /** @hide */ @VisibleForTesting public boolean canPasteAsPlainText() { if (!canPaste()) { return false; } Loading @@ -15644,7 +15658,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return canShare(); } boolean canSelectAllText() { /** @hide */ @VisibleForTesting public boolean canSelectAllText() { return canSelectText() && !hasPasswordTransformationMethod() && !(getSelectionStart() == 0 && getSelectionEnd() == mText.length()); } core/tests/coretests/src/android/widget/TextViewContextMenuTest.java +156 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; Loading @@ -40,6 +41,9 @@ import android.content.Intent; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.Icon; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.platform.test.flag.junit.SetFlagsRule; import android.view.ContextMenu; import android.view.MenuItem; import android.view.textclassifier.TextClassification; Loading @@ -47,9 +51,12 @@ import android.view.textclassifier.TextClassification; import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.verification.VerificationMode; /** * TextViewTest tests {@link TextView}. Loading Loading @@ -86,6 +93,10 @@ public class TextViewContextMenuTest { private SelectionActionModeHelper mMockHelper; @ClassRule public static final SetFlagsRule.ClassRule SET_FLAGS_CLASS_RULE = new SetFlagsRule.ClassRule(); @Rule public final SetFlagsRule mSetFlagsRule = SET_FLAGS_CLASS_RULE.createSetFlagsRule(); @Before public void setUp() { mMockHelper = mock(SelectionActionModeHelper.class); Loading Loading @@ -234,6 +245,7 @@ public class TextViewContextMenuTest { } @Test @DisableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testAutofillMenuItemEnabledWhenNoTextSelected() { ContextMenu menu = mock(ContextMenu.class); MenuItem mockMenuItem = newMockMenuItem(); Loading @@ -254,6 +266,7 @@ public class TextViewContextMenuTest { } @Test @DisableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testAutofillMenuItemNotEnabledWhenTextSelected() { ContextMenu menu = mock(ContextMenu.class); MenuItem mockMenuItem = newMockMenuItem(); Loading @@ -271,4 +284,147 @@ public class TextViewContextMenuTest { verify(menu).add(anyInt(), eq(TextView.ID_AUTOFILL), anyInt(), anyInt()); verify(mockAutofillMenuItem).setEnabled(false); } private interface EditTextSetup { void run(EditText et); } private void verifyMenuItemNotAdded(EditTextSetup setup, int id, VerificationMode times) { ContextMenu menu = mock(ContextMenu.class); MenuItem mockMenuItem = newMockMenuItem(); when(menu.add(anyInt(), anyInt(), anyInt(), anyInt())).thenReturn(mockMenuItem); EditText et = spy(new EditText(getInstrumentation().getContext())); setup.run(et); Editor editor = new Editor(et); editor.setTextContextMenuItems(menu); verify(menu, times).add(anyInt(), eq(id), anyInt(), anyInt()); } @Test @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testContextMenuUndoNotAddedWhenUnavailable() { verifyMenuItemNotAdded((spy) -> doReturn(false).when(spy).canUndo(), TextView.ID_UNDO, never()); } @Test @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testContextMenuUndoAddedWhenAvailable() { verifyMenuItemNotAdded((spy) -> doReturn(true).when(spy).canUndo(), TextView.ID_UNDO, times(1)); } @Test @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testContextMenuRedoNotAddedWhenUnavailable() { verifyMenuItemNotAdded((spy) -> doReturn(false).when(spy).canRedo(), TextView.ID_REDO, never()); } @Test @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testContextMenuRedoAddedWhenUnavailable() { verifyMenuItemNotAdded((spy) -> doReturn(true).when(spy).canRedo(), TextView.ID_REDO, times(1)); } @Test @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testContextMenuCutNotAddedWhenUnavailable() { verifyMenuItemNotAdded((spy) -> doReturn(false).when(spy).canCut(), TextView.ID_CUT, never()); } @Test @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testContextMenuCutAddedWhenAvailable() { verifyMenuItemNotAdded((spy) -> doReturn(true).when(spy).canCut(), TextView.ID_CUT, times(1)); } @Test @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testContextMenuCopyNotAddedWhenUnavailable() { verifyMenuItemNotAdded((spy) -> doReturn(false).when(spy).canCopy(), TextView.ID_COPY, never()); } @Test @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testContextMenuCopyAddedWhenAvailable() { verifyMenuItemNotAdded((spy) -> doReturn(true).when(spy).canCopy(), TextView.ID_COPY, times(1)); } @Test @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testContextMenuPasteNotAddedWhenUnavailable() { verifyMenuItemNotAdded((spy) -> doReturn(false).when(spy).canPaste(), TextView.ID_PASTE, never()); } @Test @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testContextMenuPasteAddedWhenAvailable() { verifyMenuItemNotAdded((spy) -> doReturn(true).when(spy).canPaste(), TextView.ID_PASTE, times(1)); } @Test @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testContextMenuPasteAsPlaintextNotAddedWhenUnavailable() { verifyMenuItemNotAdded((spy) -> doReturn(false).when(spy).canPasteAsPlainText(), TextView.ID_PASTE_AS_PLAIN_TEXT, never()); } @Test @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testContextMenuPasteAsPlaintextAddedWhenAvailable() { verifyMenuItemNotAdded((spy) -> doReturn(true).when(spy).canPasteAsPlainText(), TextView.ID_PASTE_AS_PLAIN_TEXT, times(1)); } @Test @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testContextMenuSelectAllNotAddedWhenUnavailable() { verifyMenuItemNotAdded((spy) -> doReturn(false).when(spy).canSelectAllText(), TextView.ID_SELECT_ALL, never()); } @Test @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testContextMenuSelectAllAddedWhenAvailable() { verifyMenuItemNotAdded((spy) -> doReturn(true).when(spy).canSelectAllText(), TextView.ID_SELECT_ALL, times(1)); } @Test @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testContextMenuShareNotAddedWhenUnavailable() { verifyMenuItemNotAdded((spy) -> doReturn(false).when(spy).canShare(), TextView.ID_SHARE, never()); } @Test @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testContextMenuShareAddedWhenAvailable() { verifyMenuItemNotAdded((spy) -> doReturn(true).when(spy).canShare(), TextView.ID_SHARE, times(1)); } @Test @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testContextMenuAutofillNotAddedWhenUnavailable() { verifyMenuItemNotAdded((spy) -> doReturn(false).when(spy).canRequestAutofill(), TextView.ID_AUTOFILL, never()); } @Test @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testContextMenuAutofillNotAddedWhenUnavailableBecauseTextSelected() { verifyMenuItemNotAdded((spy) -> { doReturn(true).when(spy).canRequestAutofill(); doReturn("test").when(spy).getSelectedText(); }, TextView.ID_AUTOFILL, never()); } } Loading
core/java/android/widget/Editor.java +130 −56 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static android.view.ContentInfo.SOURCE_DRAG_AND_DROP; import static android.widget.TextView.ACCESSIBILITY_ACTION_SMART_START_ID; import static com.android.graphics.hwui.flags.Flags.highContrastTextSmallTextRect; import static com.android.text.flags.Flags.contextMenuHideUnavailableItems; import android.R; import android.animation.ValueAnimator; Loading Loading @@ -3250,6 +3251,78 @@ public class Editor { final int menuItemOrderShare = 9; final int menuItemOrderAutofill = 10; if (contextMenuHideUnavailableItems()) { if (mTextView.canUndo()) { menu.add(CONTEXT_MENU_GROUP_UNDO_REDO, TextView.ID_UNDO, menuItemOrderUndo, com.android.internal.R.string.undo) .setAlphabeticShortcut('z') .setOnMenuItemClickListener(mOnContextMenuItemClickListener) .setIcon(a.getDrawable(0)); } if (mTextView.canRedo()) { menu.add(CONTEXT_MENU_GROUP_UNDO_REDO, TextView.ID_REDO, menuItemOrderRedo, com.android.internal.R.string.redo) .setAlphabeticShortcut('z', KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON) .setOnMenuItemClickListener(mOnContextMenuItemClickListener) .setIcon(a.getDrawable(1)); } if (mTextView.canCut()) { menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_CUT, menuItemOrderCut, com.android.internal.R.string.cut) .setAlphabeticShortcut('x') .setOnMenuItemClickListener(mOnContextMenuItemClickListener) .setIcon(a.getDrawable(2)); } if (mTextView.canCopy()) { menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_COPY, menuItemOrderCopy, com.android.internal.R.string.copy) .setAlphabeticShortcut('c') .setOnMenuItemClickListener(mOnContextMenuItemClickListener) .setIcon(a.getDrawable(3)); } if (mTextView.canPaste()) { menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_PASTE, menuItemOrderPaste, com.android.internal.R.string.paste) .setAlphabeticShortcut('v') .setIcon(a.getDrawable(4)) .setOnMenuItemClickListener(mOnContextMenuItemClickListener); } if (mTextView.canPasteAsPlainText()) { menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_PASTE_AS_PLAIN_TEXT, menuItemOrderPasteAsPlainText, com.android.internal.R.string.paste_as_plain_text) .setAlphabeticShortcut('v', KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON) .setIcon(a.getDrawable(4)) .setOnMenuItemClickListener(mOnContextMenuItemClickListener); } if (mTextView.canSelectAllText()) { menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_SELECT_ALL, menuItemOrderSelectAll, com.android.internal.R.string.selectAll) .setAlphabeticShortcut('a') .setIcon(a.getDrawable(5)) .setOnMenuItemClickListener(mOnContextMenuItemClickListener); } if (mTextView.canShare()) { menu.add(CONTEXT_MENU_GROUP_MISC, TextView.ID_SHARE, menuItemOrderShare, com.android.internal.R.string.share) .setIcon(a.getDrawable(6)) .setOnMenuItemClickListener(mOnContextMenuItemClickListener); } final String selected = mTextView.getSelectedText(); if (mTextView.canRequestAutofill() && (selected == null || selected.isEmpty())) { menu.add(CONTEXT_MENU_GROUP_MISC, TextView.ID_AUTOFILL, menuItemOrderAutofill, android.R.string.autofill) .setOnMenuItemClickListener(mOnContextMenuItemClickListener); } } else { menu.add(CONTEXT_MENU_GROUP_UNDO_REDO, TextView.ID_UNDO, menuItemOrderUndo, com.android.internal.R.string.undo) .setAlphabeticShortcut('z') Loading Loading @@ -3306,6 +3379,7 @@ public class Editor { .setEnabled(mTextView.canRequestAutofill() && (selected == null || selected.isEmpty())) .setOnMenuItemClickListener(mOnContextMenuItemClickListener); } a.recycle(); } Loading
core/java/android/widget/TextView.java +24 −8 Original line number Diff line number Diff line Loading @@ -15552,15 +15552,21 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } boolean canUndo() { /** @hide */ @VisibleForTesting public boolean canUndo() { return mEditor != null && mEditor.canUndo(); } boolean canRedo() { /** @hide */ @VisibleForTesting public boolean canRedo() { return mEditor != null && mEditor.canRedo(); } boolean canCut() { /** @hide */ @VisibleForTesting public boolean canCut() { if (hasPasswordTransformationMethod()) { return false; } Loading @@ -15573,7 +15579,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return false; } boolean canCopy() { /** @hide */ @VisibleForTesting public boolean canCopy() { if (hasPasswordTransformationMethod()) { return false; } Loading @@ -15594,7 +15602,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener && isSuggestionsEnabled() && mEditor.shouldOfferToShowSuggestions(); } boolean canShare() { /** @hide */ @VisibleForTesting public boolean canShare() { if (!getContext().canStartActivityForResult() || !isDeviceProvisioned() || !getContext().getResources().getBoolean( com.android.internal.R.bool.config_textShareSupported)) { Loading @@ -15613,8 +15623,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return mDeviceProvisionedState == DEVICE_PROVISIONED_YES; } /** @hide */ @VisibleForTesting @UnsupportedAppUsage boolean canPaste() { public boolean canPaste() { return (mText instanceof Editable && mEditor != null && mEditor.mKeyListener != null && getSelectionStart() >= 0 Loading @@ -15622,7 +15634,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener && getClipboardManagerForUser().hasPrimaryClip()); } boolean canPasteAsPlainText() { /** @hide */ @VisibleForTesting public boolean canPasteAsPlainText() { if (!canPaste()) { return false; } Loading @@ -15644,7 +15658,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return canShare(); } boolean canSelectAllText() { /** @hide */ @VisibleForTesting public boolean canSelectAllText() { return canSelectText() && !hasPasswordTransformationMethod() && !(getSelectionStart() == 0 && getSelectionEnd() == mText.length()); }
core/tests/coretests/src/android/widget/TextViewContextMenuTest.java +156 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; Loading @@ -40,6 +41,9 @@ import android.content.Intent; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.Icon; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.platform.test.flag.junit.SetFlagsRule; import android.view.ContextMenu; import android.view.MenuItem; import android.view.textclassifier.TextClassification; Loading @@ -47,9 +51,12 @@ import android.view.textclassifier.TextClassification; import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.verification.VerificationMode; /** * TextViewTest tests {@link TextView}. Loading Loading @@ -86,6 +93,10 @@ public class TextViewContextMenuTest { private SelectionActionModeHelper mMockHelper; @ClassRule public static final SetFlagsRule.ClassRule SET_FLAGS_CLASS_RULE = new SetFlagsRule.ClassRule(); @Rule public final SetFlagsRule mSetFlagsRule = SET_FLAGS_CLASS_RULE.createSetFlagsRule(); @Before public void setUp() { mMockHelper = mock(SelectionActionModeHelper.class); Loading Loading @@ -234,6 +245,7 @@ public class TextViewContextMenuTest { } @Test @DisableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testAutofillMenuItemEnabledWhenNoTextSelected() { ContextMenu menu = mock(ContextMenu.class); MenuItem mockMenuItem = newMockMenuItem(); Loading @@ -254,6 +266,7 @@ public class TextViewContextMenuTest { } @Test @DisableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testAutofillMenuItemNotEnabledWhenTextSelected() { ContextMenu menu = mock(ContextMenu.class); MenuItem mockMenuItem = newMockMenuItem(); Loading @@ -271,4 +284,147 @@ public class TextViewContextMenuTest { verify(menu).add(anyInt(), eq(TextView.ID_AUTOFILL), anyInt(), anyInt()); verify(mockAutofillMenuItem).setEnabled(false); } private interface EditTextSetup { void run(EditText et); } private void verifyMenuItemNotAdded(EditTextSetup setup, int id, VerificationMode times) { ContextMenu menu = mock(ContextMenu.class); MenuItem mockMenuItem = newMockMenuItem(); when(menu.add(anyInt(), anyInt(), anyInt(), anyInt())).thenReturn(mockMenuItem); EditText et = spy(new EditText(getInstrumentation().getContext())); setup.run(et); Editor editor = new Editor(et); editor.setTextContextMenuItems(menu); verify(menu, times).add(anyInt(), eq(id), anyInt(), anyInt()); } @Test @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testContextMenuUndoNotAddedWhenUnavailable() { verifyMenuItemNotAdded((spy) -> doReturn(false).when(spy).canUndo(), TextView.ID_UNDO, never()); } @Test @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testContextMenuUndoAddedWhenAvailable() { verifyMenuItemNotAdded((spy) -> doReturn(true).when(spy).canUndo(), TextView.ID_UNDO, times(1)); } @Test @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testContextMenuRedoNotAddedWhenUnavailable() { verifyMenuItemNotAdded((spy) -> doReturn(false).when(spy).canRedo(), TextView.ID_REDO, never()); } @Test @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testContextMenuRedoAddedWhenUnavailable() { verifyMenuItemNotAdded((spy) -> doReturn(true).when(spy).canRedo(), TextView.ID_REDO, times(1)); } @Test @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testContextMenuCutNotAddedWhenUnavailable() { verifyMenuItemNotAdded((spy) -> doReturn(false).when(spy).canCut(), TextView.ID_CUT, never()); } @Test @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testContextMenuCutAddedWhenAvailable() { verifyMenuItemNotAdded((spy) -> doReturn(true).when(spy).canCut(), TextView.ID_CUT, times(1)); } @Test @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testContextMenuCopyNotAddedWhenUnavailable() { verifyMenuItemNotAdded((spy) -> doReturn(false).when(spy).canCopy(), TextView.ID_COPY, never()); } @Test @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testContextMenuCopyAddedWhenAvailable() { verifyMenuItemNotAdded((spy) -> doReturn(true).when(spy).canCopy(), TextView.ID_COPY, times(1)); } @Test @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testContextMenuPasteNotAddedWhenUnavailable() { verifyMenuItemNotAdded((spy) -> doReturn(false).when(spy).canPaste(), TextView.ID_PASTE, never()); } @Test @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testContextMenuPasteAddedWhenAvailable() { verifyMenuItemNotAdded((spy) -> doReturn(true).when(spy).canPaste(), TextView.ID_PASTE, times(1)); } @Test @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testContextMenuPasteAsPlaintextNotAddedWhenUnavailable() { verifyMenuItemNotAdded((spy) -> doReturn(false).when(spy).canPasteAsPlainText(), TextView.ID_PASTE_AS_PLAIN_TEXT, never()); } @Test @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testContextMenuPasteAsPlaintextAddedWhenAvailable() { verifyMenuItemNotAdded((spy) -> doReturn(true).when(spy).canPasteAsPlainText(), TextView.ID_PASTE_AS_PLAIN_TEXT, times(1)); } @Test @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testContextMenuSelectAllNotAddedWhenUnavailable() { verifyMenuItemNotAdded((spy) -> doReturn(false).when(spy).canSelectAllText(), TextView.ID_SELECT_ALL, never()); } @Test @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testContextMenuSelectAllAddedWhenAvailable() { verifyMenuItemNotAdded((spy) -> doReturn(true).when(spy).canSelectAllText(), TextView.ID_SELECT_ALL, times(1)); } @Test @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testContextMenuShareNotAddedWhenUnavailable() { verifyMenuItemNotAdded((spy) -> doReturn(false).when(spy).canShare(), TextView.ID_SHARE, never()); } @Test @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testContextMenuShareAddedWhenAvailable() { verifyMenuItemNotAdded((spy) -> doReturn(true).when(spy).canShare(), TextView.ID_SHARE, times(1)); } @Test @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testContextMenuAutofillNotAddedWhenUnavailable() { verifyMenuItemNotAdded((spy) -> doReturn(false).when(spy).canRequestAutofill(), TextView.ID_AUTOFILL, never()); } @Test @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS) public void testContextMenuAutofillNotAddedWhenUnavailableBecauseTextSelected() { verifyMenuItemNotAdded((spy) -> { doReturn(true).when(spy).canRequestAutofill(); doReturn("test").when(spy).getSelectedText(); }, TextView.ID_AUTOFILL, never()); } }