EditText: Disable Paste/Replace menu pop-up on Text Selection Handler click event

My goal is to have an EditText that has no fancy features, just the Text Selection Handler for moving the cursor more easily — so no context menus or pop-ups.

I’ve disabled the appearance of the text editing function actionbar (copy/Paste etc.) by consuming the ActionMode Callback event, as per this solution.

  • How to set focus to right of text in EditText for android?
  • Change layout_scrollFlags programmatically in CollapsingToolbarLayout
  • Android studio logcat not working
  • package android.support.v7.internal.view.menu does not exist: cannot find symbol class MenuBuilder
  • Get MAC Address of android device without Wifi
  • facebook login null pointer exception android
  • The middle Middle Text Select Handle (see image below) still appears when text exists in the field and a click occurs within the text. Great! I want to keep this behaviour. What I DON’T want is the “PASTE” menu to appear when the Text Select Handle itself is clicked.

    Text selection handle with paste menu

    I have also disabled long-click input for the EditText by setting android:longClickable="false" in the styles XML. Disabling the long click prevents the “Paste/Replace” menu from appearing when the mouse is clicked and held (i.e. long touch), however when the mouse is clicked (single touch) within the text, the text selection handle appears, and when the text selection handle itself is clicked, then the “paste” menu option appears (when there’s text in the clipboard). This is what I’m trying to prevent.

    From what I can see from the source, the ActionPopupWindow is what pops up with the PASTE/REPLACE options. ActionPopupWindow is a protected variable (mActionPopupWindow) in the private abstract class HandleView within public class android.widget.Editor…

    Short of disabling the clipboard service or editing the Android Source code, is there a way that I can prevent this from showing? I tried to define a new style for android:textSelectHandleWindowStyle, and set android:visibilitytogone`, but it didn’t work (app froze for a while when it would otherwise have shown).

    Related posts:

    Requesting and allowing WRITE_EXTERNAL_STORAGE permission at runtime has no effects on the current s...
    Preventing Facebook Android SDK from displaying password as plain text
    Changed order in main.xml, now I get ClassCastException
    Why are there extra pixels around my Android GridView?
    Is actionbarsherlock needed anymore?
    Android test wifi connection programatically
  • How do I include http headers with MediaPlayer setDataSource?
  • Why Facebook application id suddenly become invalid?
  • Stop Android from Layouting all my Views
  • How can I change a button style dynamically in Android?
  • No suitable HttpMessageConverter found when trying to execute restclient request
  • Cygwin for Android-NDK programming
  • 10 Solutions collect form web for “EditText: Disable Paste/Replace menu pop-up on Text Selection Handler click event”

    Solution: Override isSuggestionsEnabled and canPaste in EditText.

    For the quick solution, copy the class below – this class overrides the EditText class, and blocks all events accordingly.

    For the gritty details, keep reading.

    The solution lies in preventing PASTE/REPLACE menu from appearing in the show() method of the (non-documented) android.widget.Editor class. Before the menu appears, a check is done to if (!canPaste && !canSuggest) return;. The two methods that are used as the basis to set these variables are both in the EditText class:

    • isSuggestionsEnabled() is public, and may thus be overridden.
    • canPaste() is not, and thus must be hidden by introducing a function of the same name in the derived class.

    So incorporating these updates into a class that also has the setCustomSelectionActionModeCallback, and the disabled long-click, here is the full class to prevent all editing (but still display the text selection handler) for controlling the cursor:

    package com.cjbs.widgets;
    
    import android.content.Context;
    import android.util.AttributeSet;
    import android.view.ActionMode;
    import android.view.Menu;
    import android.view.MenuItem;
    import android.widget.EditText;
    
    
    /**
     *  This is a thin veneer over EditText, with copy/paste/spell-check removed.
     */
    public class NoMenuEditText extends EditText
    {
        private final Context context;
    
        /** This is a replacement method for the base TextView class' method of the same name. This 
         * method is used in hidden class android.widget.Editor to determine whether the PASTE/REPLACE popup
         * appears when triggered from the text insertion handle. Returning false forces this window
         * to never appear.
         * @return false
         */
        boolean canPaste()
        {
           return false;
        }
    
        /** This is a replacement method for the base TextView class' method of the same name. This method
         * is used in hidden class android.widget.Editor to determine whether the PASTE/REPLACE popup
         * appears when triggered from the text insertion handle. Returning false forces this window
         * to never appear.
         * @return false
         */
        @Override
        public boolean isSuggestionsEnabled()
        {
            return false;
        }
    
        public NoMenuEditText(Context context)
        {
            super(context);
            this.context = context;
            init();
        }
    
        public NoMenuEditText(Context context, AttributeSet attrs)
        {
            super(context, attrs);
            this.context = context;
            init();
        }
    
        public NoMenuEditText(Context context, AttributeSet attrs, int defStyle)
        {
            super(context, attrs, defStyle);
            this.context = context;
            init();
        }
    
        private void init()
        {
            this.setCustomSelectionActionModeCallback(new ActionModeCallbackInterceptor());
            this.setLongClickable(false);
        }
    
    
        /**
         * Prevents the action bar (top horizontal bar with cut, copy, paste, etc.) from appearing
         * by intercepting the callback that would cause it to be created, and returning false.
         */
        private class ActionModeCallbackInterceptor implements ActionMode.Callback
        {
            private final String TAG = NoMenuEditText.class.getSimpleName();
    
            public boolean onCreateActionMode(ActionMode mode, Menu menu) { return false; }
            public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return false; }
            public boolean onActionItemClicked(ActionMode mode, MenuItem item) { return false; }
            public void onDestroyActionMode(ActionMode mode) {}
        }
    } 
    

    I’ve tested this in Android v4.4.2 and v4.4.3.

    or simply just use

    yourEditText.setLongClickable(false);
    

    OR in XML

    android:longClickable="false"
    

    Update

    Actually the user wants to disable the text selection handle itself

    1. Create a shape (handle.xml)

     <shape xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="rectangle" >
    
     <size
        android:height="0dp"
        android:width="0dp" />
     </shape>
    

    2. In your EditText

     android:textSelectHandle="@drawable/handle"
    

    Found another solution when the blue view (insertion controller) is not appeared at all. I used reflection to set target boolean field of Editor class. Look at the android.widget.Editor and android.widget.TextView for more details.

    Add the following code into your custom EditText (with all previous code in this topic):

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            // setInsertionDisabled when user touches the view
            this.setInsertionDisabled();
        }
        return super.onTouchEvent(event);
    }
    
    /**
     * This method sets TextView#Editor#mInsertionControllerEnabled field to false
     * to return false from the Editor#hasInsertionController() method to PREVENT showing
     * of the insertionController from EditText
     * The Editor#hasInsertionController() method is called in  Editor#onTouchUpEvent(MotionEvent event) method.
     */
    
    private void setInsertionDisabled() {
        try {
            Field editorField = TextView.class.getDeclaredField("mEditor");
            editorField.setAccessible(true);
            Object editorObject = editorField.get(this);
    
            Class editorClass = Class.forName("android.widget.Editor");
            Field mInsertionControllerEnabledField = editorClass.getDeclaredField("mInsertionControllerEnabled");
            mInsertionControllerEnabledField.setAccessible(true);
            mInsertionControllerEnabledField.set(editorObject, false);
        }
        catch (Exception ignored) {
            // ignore exception here
        }
    }
    

    Also, maybe you can find the better place than onTouch() to call the target method.

    Tested on Android 5.1

    I don’t find a way to hide the menu popup , But you can disable from pasting if user tap on the menu

    Create a custom EditText and override the onTextContextMenuItem method and return false for android.R.id.paste and android.R.id.pasteAsPlainText menu id’s.

    @Override
    public boolean onTextContextMenuItem(int id) {
        switch (id){
            case android.R.id.paste:
            case android.R.id.pasteAsPlainText:
                return false;
    
        }
        return super.onTextContextMenuItem(id);
    }
    

    Here is a hack to disable “paste” popup. You have to override EditText method:

    @Override
    public int getSelectionStart() {
        for (StackTraceElement element : Thread.currentThread().getStackTrace()) {
            if (element.getMethodName().equals("canPaste")) {
                return -1;
            }
        }
        return super.getSelectionStart();
    }
    

    This solution works on newer versions of Android as well, unlike the accepted answer.

    Use this in java file
    
    if (android.os.Build.VERSION.SDK_INT < 11) {
        editText.setOnCreateContextMenuListener(new OnCreateContextMenuListener() {
    
            @Override`enter code here`
            public void onCreateContextMenu(ContextMenu menu, View v,
                    ContextMenuInfo menuInfo) {
                // TODO Auto-generated method stub
                menu.clear();
            }
        });
    } else {
        editText.setCustomSelectionActionModeCallback(new ActionMode.Callback() {
    
            public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
                // TODO Auto-generated method stub
                return false;
            }
    
            public void onDestroyActionMode(ActionMode mode) {
                // TODO Auto-generated method stub
    
            }
    
            public boolean onCreateActionMode(ActionMode mode, Menu menu) {
                // TODO Auto-generated method stub
                return false;
            }
    
            public boolean onActionItemClicked(ActionMode mode,
                    MenuItem item) {
                // TODO Auto-generated method stub
                return false;
            }`enter code here`
        });
    }
    
    
    With this code also add android:textSelectHandle="@drawable/handle"
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="rectangle" >
    
     <size
        android:height="0dp"
        android:width="0dp" />
     </shape>
    
    
    By Using these two combinations my problem is solved.
    

    None of the above solutions worked for me. I’ve managed to do my solution (explanation after), which disabled pasting anything on the EditText while maintaining all other operations valid.
    Mainly, you have to override this method on your implementation of EditText:

    @Override
    public boolean onTextContextMenuItem (int id) {
        if (id == android.R.id.paste) return false;
    
        return super.onTextContextMenuItem(id);
    }
    

    So investigating EditText code, after all checks, paste (and all ContextMenu actions on the EditText) happen at a method called onTextContextMenuItem:

    public boolean onTextContextMenuItem(int id) {
        int min = 0;
        int max = mText.length();
    
        if (isFocused()) {
            final int selStart = getSelectionStart();
            final int selEnd = getSelectionEnd();
    
            min = Math.max(0, Math.min(selStart, selEnd));
            max = Math.max(0, Math.max(selStart, selEnd));
        }
    
        switch (id) {
            case ID_SELECT_ALL:
                // This does not enter text selection mode. Text is highlighted, so that it can be
                // bulk edited, like selectAllOnFocus does. Returns true even if text is empty.
                selectAllText();
                return true;
    
            case ID_PASTE:
                paste(min, max);
                return true;
    
            case ID_CUT:
                setPrimaryClip(ClipData.newPlainText(null, getTransformedText(min, max)));
                deleteText_internal(min, max);
                stopSelectionActionMode();
                return true;
    
            case ID_COPY:
                setPrimaryClip(ClipData.newPlainText(null, getTransformedText(min, max)));
                stopSelectionActionMode();
                return true;
        }
        return false;
    }
    

    If you notice, pasting will only occur when id == ID_PASTE, so, again, looking at the EditText code:

    static final int ID_PASTE = android.R.id.paste;
    

    If you need remove the PASTE suggestion, clear the clipboard before the long click.

    //class 
    ClipboardManager clipboard;
    
    //oncreate 
    clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
    ClipData clip = ClipData.newPlainText("","");
    clipboard.setPrimaryClip(clip);
    

    I found a simple yet reliable way. The idea is the consume away the touch event, to prevent the touch event reach underlining default code.

    1. To disable copy/paste popup.
    2. To disable text selection handler.
    3. Still showing cursor at end of text.
    4. Still showing keyboard.

    maskedEditText.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            focusAndShowKeyboard(view.getContext(), maskedEditText);
            // Consume the event.
            return true;
        }
    });
    
    private static void focusAndShowKeyboard(Context context, EditText editText) {
        editText.requestFocus();
        InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY);
    }
    

    enter image description here

    Note, blinking cursor is still showing at end of text. Just that the screenshot unable to capture it.

    You can use this code:

    if (android.os.Build.VERSION.SDK_INT < 11) {
        editText.setOnCreateContextMenuListener(new OnCreateContextMenuListener() {
    
            @Override
            public void onCreateContextMenu(ContextMenu menu, View v,
                    ContextMenuInfo menuInfo) {
                // TODO Auto-generated method stub
                menu.clear();
            }
        });
    } else {
        editText.setCustomSelectionActionModeCallback(new ActionMode.Callback() {
    
            public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
                // TODO Auto-generated method stub
                return false;
            }
    
            public void onDestroyActionMode(ActionMode mode) {
                // TODO Auto-generated method stub
    
            }
    
            public boolean onCreateActionMode(ActionMode mode, Menu menu) {
                // TODO Auto-generated method stub
                return false;
            }
    
            public boolean onActionItemClicked(ActionMode mode,
                    MenuItem item) {
                // TODO Auto-generated method stub
                return false;
            }
        });
    }
    

    Returning false from onCreateActionMode will disable the cut,copy,paste options in API level greater than 11.

    Android Babe is a Google Android Fan, All about Android Phones, Android Wear, Android Dev and Android Games Apps and so on.