Android intercept paste\copy\cut on editText

23,700

Solution 1

Seems there isn't much you can do by using the API: android paste event

Source reading to the rescue!

I dug into the Android Source of the TextView (EditText is a TextView with some different configuration) and found out that the menu used to offer the cut/copy/paste options is just a modified ContextMenu (source).

As for a normal context-menu, the View must create the menu (source) and then handle the interaction in a callback-method (source).

Because the handling method is public, we can simply hook into it by extending EditText and overwriting the method to react on the different actions. Here is an example-implementation:

import android.content.Context;
import android.util.AttributeSet;
import android.widget.EditText;
import android.widget.Toast;

/**
 * An EditText, which notifies when something was cut/copied/pasted inside it.
 * @author Lukas Knuth
 * @version 1.0
 */
public class MonitoringEditText extends EditText {

    private final Context context;

    /*
        Just the constructors to create a new EditText...
     */
    public MonitoringEditText(Context context) {
        super(context);
        this.context = context;
    }

    public MonitoringEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
    }

    public MonitoringEditText(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.context = context;
    }

    /**
     * <p>This is where the "magic" happens.</p>
     * <p>The menu used to cut/copy/paste is a normal ContextMenu, which allows us to
     *  overwrite the consuming method and react on the different events.</p>
     * @see <a href="http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.3_r1/android/widget/TextView.java#TextView.onTextContextMenuItem%28int%29">Original Implementation</a>
     */
    @Override
    public boolean onTextContextMenuItem(int id) {
        // Do your thing:
        boolean consumed = super.onTextContextMenuItem(id);
        // React:
        switch (id){
            case android.R.id.cut:
                onTextCut();
                break;
            case android.R.id.paste:
                onTextPaste();
                break;
            case android.R.id.copy:
                onTextCopy();
        }
        return consumed;
    }

    /**
     * Text was cut from this EditText.
     */
    public void onTextCut(){
        Toast.makeText(context, "Cut!", Toast.LENGTH_SHORT).show();
    }

    /**
     * Text was copied from this EditText.
     */
    public void onTextCopy(){
        Toast.makeText(context, "Copy!", Toast.LENGTH_SHORT).show();
    }

    /**
     * Text was pasted into the EditText.
     */
    public void onTextPaste(){
        Toast.makeText(context, "Paste!", Toast.LENGTH_SHORT).show();
    }
}

Now, when the user uses cut/copy/paste, a Toast is shown (of course you could do other things, too).

The neat thing is that this works down to Android 1.5 and you don't need to re-create the context-menu (like suggested in the above linked question), which will keep the constant look of the platform (for example with HTC Sense).

Solution 2

There is a much simpler way, although not 100% reliable.

Add TextChangedListener to your editbox:

EditText et = (EditText) mView.findViewById(R.id.yourEditText);
et.addTextChangedListener(new TextWatcher() {

  @Override
  public void onTextChanged(CharSequence s, int start, int before, int count) {
     if (count > 2) toast("text was pasted");
  }

  @Override
  public void beforeTextChanged(CharSequence s, int start, int count, int after) {

  }

  public void afterTextChanged(Editable s) {
               
  }
});

If the text changes for more than 2 characters, you can assume it was pasted (some smileys take up two characters).

Of course it will not detect pasting when the user pastes 1 or 2 characters, and it will falsely report pasting if the change in text was triggered by something else.

But for most purposes, it gets the job done 👍

Share:
23,700
and_dev
Author by

and_dev

Updated on July 09, 2022

Comments

  • and_dev
    and_dev almost 2 years

    How can I intercept this kind of events ?

    I need to add some logic when the user trying to paste some text into my EditText i know i can use TextWatcher but this entrypoint not good for me becuase i only need to intercept in case of paste and not every time the user press my EditText,

  • Nirav Mehta
    Nirav Mehta almost 10 years
    i got can't instantiate class no empty constructor error what solution of it ???
  • Lukas Knuth
    Lukas Knuth almost 10 years
    well, the class has no empty constructor. you have to pass it an instance of Context (if your code is in an Activity, you can pass it this).
  • GuillermoMP
    GuillermoMP over 8 years
    Expanded your solution with a listener so it can be used as a plug&play component. The gist gist.github.com/guillermomuntaner/82491cbf0c88dec560a5
  • Zxcv
    Zxcv over 7 years
    How to get the inserted Spanned String from the paste ?
  • Lukas Knuth
    Lukas Knuth over 7 years
    @Pierre you could add a TextWatcher and record the changes. If a change occurs and you get a fitting cut/paste/copy action, you can figure out which part of the content changed.
  • Zxcv
    Zxcv over 7 years
    Finally found out a better solution. I do not want a TextWatcher triggered each time a letter is pressed. So, I used the ClipBoardManager to override the pasted content. Thanks to: stackoverflow.com/questions/6651184/… and developer.android.com/guide/topics/text/copy-paste.html
  • tiagocarvalho92
    tiagocarvalho92 almost 5 years
    This doesn't work if your edittext is limited to 1 char only and you want to copy to multiple edittexts ( like a code with 1 et for each digit)
  • lenooh
    lenooh almost 5 years
    tiagocarvalho92: yes, that is written in the description.
  • milosmns
    milosmns about 4 years
    This seems ok. For I'd look into integrating with the system and maybe use auto-fill or that OTP provider thing that automatically reads the messages. It's a much better user experience. Also having a 'paste' button would do the trick. There's really no reason to be constrained to EditText in that scenario.