Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove option to paste rich text from Android EditText context menu #38189

Closed
wants to merge 14 commits into from
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import static com.facebook.react.uimanager.UIManagerHelper.getReactContext;
import static com.facebook.react.views.text.TextAttributeProps.UNSET;

import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Paint;
Expand All @@ -28,8 +30,11 @@
import android.text.method.KeyListener;
import android.text.method.QwertyKeyListener;
import android.util.TypedValue;
import android.view.ActionMode;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityNodeInfo;
Expand Down Expand Up @@ -181,6 +186,35 @@ public boolean performAccessibilityAction(View host, int action, Bundle args) {
}
};
ViewCompat.setAccessibilityDelegate(this, editTextAccessibilityDelegate);
ActionMode.Callback customActionModeCallback =
new ActionMode.Callback() {
/*
* Editor onCreateActionMode adds the cut, copy, paste, share, autofill,
* and paste as plain text items to the context menu.
*/
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
menu.removeItem(android.R.id.pasteAsPlainText);
return true;
}

@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return true;
}

@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
return false;
}

@Override
public void onDestroyActionMode(ActionMode mode) {}
};
setCustomSelectionActionModeCallback(customActionModeCallback);
if (Build.VERSION.SDK_INT >= 23) {
setCustomInsertionActionModeCallback(customActionModeCallback);
}
}

@Override
Expand Down Expand Up @@ -269,6 +303,37 @@ public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
return inputConnection;
}

/*
* Called when a context menu option for the text view is selected.
* React Native replaces copy (as rich text) with copy as plain text.
*/
@Override
public boolean onTextContextMenuItem(int id) {
if (id == android.R.id.paste) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
id = android.R.id.pasteAsPlainText;
} else {
ClipboardManager clipboard =
(ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
ClipData previousClipData = clipboard.getPrimaryClip();
if (previousClipData != null) {
for (int i = 0; i < previousClipData.getItemCount(); i++) {
final CharSequence text = previousClipData.getItemAt(i).coerceToText(getContext());
final CharSequence paste = (text instanceof Spanned) ? text.toString() : text;
if (paste != null) {
ClipData clipData = ClipData.newPlainText(null, text);
clipboard.setPrimaryClip(clipData);
}
}
boolean actionPerformed = super.onTextContextMenuItem(id);
clipboard.setPrimaryClip(previousClipData);
return actionPerformed;
}
}
}
return super.onTextContextMenuItem(id);
}

@Override
public void clearFocus() {
setFocusableInTouchMode(false);
Expand Down