Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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