Loading core/java/android/text/TextUtils.java +40 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.text; import android.annotation.FloatRange; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.PluralsRes; Loading Loading @@ -2033,6 +2034,45 @@ public class TextUtils { builder.append(end); } /** * Intent size limitations prevent sending over a megabyte of data. Limit * text length to 100K characters - 200KB. */ private static final int PARCEL_SAFE_TEXT_LENGTH = 100000; /** * Trims the text to {@link #PARCEL_SAFE_TEXT_LENGTH} length. Returns the string as it is if * the length() is smaller than {@link #PARCEL_SAFE_TEXT_LENGTH}. Used for text that is parceled * into a {@link Parcelable}. * * @hide */ @Nullable public static <T extends CharSequence> T trimToParcelableSize(@Nullable T text) { return trimToSize(text, PARCEL_SAFE_TEXT_LENGTH); } /** * Trims the text to {@code size} length. Returns the string as it is if the length() is * smaller than {@code size}. If chars at {@code size-1} and {@code size} is a surrogate * pair, returns a CharSequence of length {@code size-1}. * * @param size length of the result, should be greater than 0 * * @hide */ @Nullable public static <T extends CharSequence> T trimToSize(@Nullable T text, @IntRange(from = 1) int size) { Preconditions.checkArgument(size > 0); if (TextUtils.isEmpty(text) || text.length() <= size) return text; if (Character.isHighSurrogate(text.charAt(size - 1)) && Character.isLowSurrogate(text.charAt(size))) { size = size - 1; } return (T) text.subSequence(0, size); } private static Object sLock = new Object(); private static char[] sTemp = null; Loading core/java/android/widget/Editor.java +3 −1 Original line number Diff line number Diff line Loading @@ -6449,7 +6449,9 @@ public class Editor { private boolean fireIntent(Intent intent) { if (intent != null && Intent.ACTION_PROCESS_TEXT.equals(intent.getAction())) { intent.putExtra(Intent.EXTRA_PROCESS_TEXT, mTextView.getSelectedText()); String selectedText = mTextView.getSelectedText(); selectedText = TextUtils.trimToParcelableSize(selectedText); intent.putExtra(Intent.EXTRA_PROCESS_TEXT, selectedText); mEditor.mPreserveSelection = true; mTextView.startActivityForResult(intent, TextView.PROCESS_TEXT_REQUEST_CODE); return true; Loading core/java/android/widget/TextView.java +40 −8 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_C import static android.view.inputmethod.CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION; import android.R; import android.annotation.CheckResult; import android.annotation.ColorInt; import android.annotation.DrawableRes; import android.annotation.FloatRange; Loading Loading @@ -10329,10 +10330,22 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return isTextEditable() ? AUTOFILL_TYPE_TEXT : AUTOFILL_TYPE_NONE; } /** * Gets the {@link TextView}'s current text for AutoFill. The value is trimmed to 100K * {@code char}s if longer. * * @return current text, {@code null} if the text is not editable * * @see View#getAutofillValue() */ @Override @Nullable public AutofillValue getAutofillValue() { return isTextEditable() ? AutofillValue.forText(getText()) : null; if (isTextEditable()) { final CharSequence text = TextUtils.trimToParcelableSize(getText()); return AutofillValue.forText(text); } return null; } /** @hide */ Loading Loading @@ -10746,7 +10759,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } // Otherwise, return whatever text is being displayed. return mTransformed; return TextUtils.trimToParcelableSize(mTransformed); } void sendAccessibilityEventTypeViewTextChanged(CharSequence beforeText, Loading Loading @@ -10831,13 +10844,25 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return true; case ID_CUT: setPrimaryClip(ClipData.newPlainText(null, getTransformedText(min, max))); final ClipData cutData = ClipData.newPlainText(null, getTransformedText(min, max)); if (setPrimaryClip(cutData)) { deleteText_internal(min, max); } else { Toast.makeText(getContext(), com.android.internal.R.string.failed_to_copy_to_clipboard, Toast.LENGTH_SHORT).show(); } return true; case ID_COPY: setPrimaryClip(ClipData.newPlainText(null, getTransformedText(min, max))); final ClipData copyData = ClipData.newPlainText(null, getTransformedText(min, max)); if (setPrimaryClip(copyData)) { stopTextActionMode(); } else { Toast.makeText(getContext(), com.android.internal.R.string.failed_to_copy_to_clipboard, Toast.LENGTH_SHORT).show(); } return true; case ID_REPLACE: Loading Loading @@ -11193,17 +11218,24 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND); sharingIntent.setType("text/plain"); sharingIntent.removeExtra(android.content.Intent.EXTRA_TEXT); selectedText = TextUtils.trimToParcelableSize(selectedText); sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, selectedText); getContext().startActivity(Intent.createChooser(sharingIntent, null)); Selection.setSelection((Spannable) mText, getSelectionEnd()); } } private void setPrimaryClip(ClipData clip) { @CheckResult private boolean setPrimaryClip(ClipData clip) { ClipboardManager clipboard = (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE); try { clipboard.setPrimaryClip(clip); } catch (Throwable t) { return false; } sLastCutCopyOrTextChangedTime = SystemClock.uptimeMillis(); return true; } /** Loading core/res/res/values/strings.xml +3 −0 Original line number Diff line number Diff line Loading @@ -2626,6 +2626,9 @@ <!-- Item on EditText context menu. This action is used to cut selected the text into the clipboard. --> <string name="copy">Copy</string> <!-- Error shown by TextView/EditText when cut/copy operation fails because text is too long to copy into the clipboard. --> <string name="failed_to_copy_to_clipboard">Failed to copy to clipboard</string> <!-- Item on EditText context menu. This action is used to paste from the clipboard into the eidt field --> <string name="paste">Paste</string> Loading core/res/res/values/symbols.xml +2 −0 Original line number Diff line number Diff line Loading @@ -2540,6 +2540,8 @@ <java-symbol type="id" name="suggestionContainer" /> <java-symbol type="id" name="addToDictionaryButton" /> <java-symbol type="id" name="deleteButton" /> <!-- TextView --> <java-symbol type="string" name="failed_to_copy_to_clipboard" /> <java-symbol type="id" name="notification_material_reply_container" /> <java-symbol type="id" name="notification_material_reply_text_1" /> Loading Loading
core/java/android/text/TextUtils.java +40 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.text; import android.annotation.FloatRange; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.PluralsRes; Loading Loading @@ -2033,6 +2034,45 @@ public class TextUtils { builder.append(end); } /** * Intent size limitations prevent sending over a megabyte of data. Limit * text length to 100K characters - 200KB. */ private static final int PARCEL_SAFE_TEXT_LENGTH = 100000; /** * Trims the text to {@link #PARCEL_SAFE_TEXT_LENGTH} length. Returns the string as it is if * the length() is smaller than {@link #PARCEL_SAFE_TEXT_LENGTH}. Used for text that is parceled * into a {@link Parcelable}. * * @hide */ @Nullable public static <T extends CharSequence> T trimToParcelableSize(@Nullable T text) { return trimToSize(text, PARCEL_SAFE_TEXT_LENGTH); } /** * Trims the text to {@code size} length. Returns the string as it is if the length() is * smaller than {@code size}. If chars at {@code size-1} and {@code size} is a surrogate * pair, returns a CharSequence of length {@code size-1}. * * @param size length of the result, should be greater than 0 * * @hide */ @Nullable public static <T extends CharSequence> T trimToSize(@Nullable T text, @IntRange(from = 1) int size) { Preconditions.checkArgument(size > 0); if (TextUtils.isEmpty(text) || text.length() <= size) return text; if (Character.isHighSurrogate(text.charAt(size - 1)) && Character.isLowSurrogate(text.charAt(size))) { size = size - 1; } return (T) text.subSequence(0, size); } private static Object sLock = new Object(); private static char[] sTemp = null; Loading
core/java/android/widget/Editor.java +3 −1 Original line number Diff line number Diff line Loading @@ -6449,7 +6449,9 @@ public class Editor { private boolean fireIntent(Intent intent) { if (intent != null && Intent.ACTION_PROCESS_TEXT.equals(intent.getAction())) { intent.putExtra(Intent.EXTRA_PROCESS_TEXT, mTextView.getSelectedText()); String selectedText = mTextView.getSelectedText(); selectedText = TextUtils.trimToParcelableSize(selectedText); intent.putExtra(Intent.EXTRA_PROCESS_TEXT, selectedText); mEditor.mPreserveSelection = true; mTextView.startActivityForResult(intent, TextView.PROCESS_TEXT_REQUEST_CODE); return true; Loading
core/java/android/widget/TextView.java +40 −8 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_C import static android.view.inputmethod.CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION; import android.R; import android.annotation.CheckResult; import android.annotation.ColorInt; import android.annotation.DrawableRes; import android.annotation.FloatRange; Loading Loading @@ -10329,10 +10330,22 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return isTextEditable() ? AUTOFILL_TYPE_TEXT : AUTOFILL_TYPE_NONE; } /** * Gets the {@link TextView}'s current text for AutoFill. The value is trimmed to 100K * {@code char}s if longer. * * @return current text, {@code null} if the text is not editable * * @see View#getAutofillValue() */ @Override @Nullable public AutofillValue getAutofillValue() { return isTextEditable() ? AutofillValue.forText(getText()) : null; if (isTextEditable()) { final CharSequence text = TextUtils.trimToParcelableSize(getText()); return AutofillValue.forText(text); } return null; } /** @hide */ Loading Loading @@ -10746,7 +10759,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } // Otherwise, return whatever text is being displayed. return mTransformed; return TextUtils.trimToParcelableSize(mTransformed); } void sendAccessibilityEventTypeViewTextChanged(CharSequence beforeText, Loading Loading @@ -10831,13 +10844,25 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return true; case ID_CUT: setPrimaryClip(ClipData.newPlainText(null, getTransformedText(min, max))); final ClipData cutData = ClipData.newPlainText(null, getTransformedText(min, max)); if (setPrimaryClip(cutData)) { deleteText_internal(min, max); } else { Toast.makeText(getContext(), com.android.internal.R.string.failed_to_copy_to_clipboard, Toast.LENGTH_SHORT).show(); } return true; case ID_COPY: setPrimaryClip(ClipData.newPlainText(null, getTransformedText(min, max))); final ClipData copyData = ClipData.newPlainText(null, getTransformedText(min, max)); if (setPrimaryClip(copyData)) { stopTextActionMode(); } else { Toast.makeText(getContext(), com.android.internal.R.string.failed_to_copy_to_clipboard, Toast.LENGTH_SHORT).show(); } return true; case ID_REPLACE: Loading Loading @@ -11193,17 +11218,24 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND); sharingIntent.setType("text/plain"); sharingIntent.removeExtra(android.content.Intent.EXTRA_TEXT); selectedText = TextUtils.trimToParcelableSize(selectedText); sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, selectedText); getContext().startActivity(Intent.createChooser(sharingIntent, null)); Selection.setSelection((Spannable) mText, getSelectionEnd()); } } private void setPrimaryClip(ClipData clip) { @CheckResult private boolean setPrimaryClip(ClipData clip) { ClipboardManager clipboard = (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE); try { clipboard.setPrimaryClip(clip); } catch (Throwable t) { return false; } sLastCutCopyOrTextChangedTime = SystemClock.uptimeMillis(); return true; } /** Loading
core/res/res/values/strings.xml +3 −0 Original line number Diff line number Diff line Loading @@ -2626,6 +2626,9 @@ <!-- Item on EditText context menu. This action is used to cut selected the text into the clipboard. --> <string name="copy">Copy</string> <!-- Error shown by TextView/EditText when cut/copy operation fails because text is too long to copy into the clipboard. --> <string name="failed_to_copy_to_clipboard">Failed to copy to clipboard</string> <!-- Item on EditText context menu. This action is used to paste from the clipboard into the eidt field --> <string name="paste">Paste</string> Loading
core/res/res/values/symbols.xml +2 −0 Original line number Diff line number Diff line Loading @@ -2540,6 +2540,8 @@ <java-symbol type="id" name="suggestionContainer" /> <java-symbol type="id" name="addToDictionaryButton" /> <java-symbol type="id" name="deleteButton" /> <!-- TextView --> <java-symbol type="string" name="failed_to_copy_to_clipboard" /> <java-symbol type="id" name="notification_material_reply_container" /> <java-symbol type="id" name="notification_material_reply_text_1" /> Loading