mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Remove option to paste rich text from Android EditText context menu (#38189)
Summary: Text is copy pasted as rich text on Android TextInput instead of Plain Text. ### What is the root cause of that problem? Android EditText and iOS UITextField/UITextView have different copy/paste behavior. - Android TextInput copies/pastes rich text - iOS UITextField copies/pastes plain text. | iOS (react-native) | Android (react-native) | | ----------- | ----------- | | <video src="https://user-images.githubusercontent.com/24992535/249170968-8fde35f0-a53c-4c5c-bd89-ee822c08eadf.mp4" width="350" /> | <video src="https://user-images.githubusercontent.com/24992535/249171968-bf0915a0-4060-4586-b267-7c2b463d76f6.mov" width="350" /> | ### What changes do you think we should make in order to solve the problem? The issue is a bug in react-native https://github.com/facebook/react-native/issues/31442: 1) The JavaScript TextInput and ReactEditText Android state are not in sync 2) The TextInput Android Native state over-rides the JavaScript state. 3) onChangeText passes a plain text string to JavaScript, not rich text (text with spans and styles). More info at https://github.com/Expensify/App/issues/21411#issuecomment-1611591137 The solution consists of: 1) **Over-riding onTextContextMenuItem in ReactEditText to copy/paste plain text instead of rich-text** (https://stackoverflow.com/a/45319485/7295772). 2) **Removing the `Paste as plaintext` option from the insert and selection context menu** fixes https://github.com/facebook/react-native/issues/31442 ## Changelog: [ANDROID] [FIXED] - Remove option to paste rich text from Android EditText context menu Pull Request resolved: https://github.com/facebook/react-native/pull/38189 Test Plan: #### Reproducing the issue on Android https://user-images.githubusercontent.com/24992535/249185416-76f8a687-1aca-4dc9-9abe-3d73d6e2893c.mp4 #### Fixing the issue on Android Sourcecode https://github.com/fabriziobertoglio1987/text-input-cursor-flickering-android/blob/fix-copy-paste/app/src/main/java/com/example/myapplication/CustomEditText.java https://user-images.githubusercontent.com/24992535/249486339-95449bb9-71b6-430c-8207-f5672f034fa9.mp4 #### Testing the solution on React Native https://github.com/Expensify/App/assets/24992535/b302237b-99e5-44a2-996d-8bc50bbbc95c Reviewed By: mdvacca Differential Revision: D47824730 Pulled By: NickGerleman fbshipit-source-id: 35525e7d52e664b0f78649d23941262ee45a00cd
This commit is contained in:
committed by
Luna Wei
parent
a601b22d14
commit
5b45e973f4
+65
@@ -10,6 +10,8 @@ package com.facebook.react.views.textinput;
|
||||
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;
|
||||
@@ -28,8 +30,11 @@ import android.text.TextWatcher;
|
||||
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;
|
||||
@@ -180,6 +185,35 @@ public class ReactEditText extends AppCompatEditText
|
||||
}
|
||||
};
|
||||
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 >= Build.VERSION_CODES.M) {
|
||||
setCustomInsertionActionModeCallback(customActionModeCallback);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -268,6 +302,37 @@ public class ReactEditText extends AppCompatEditText
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user