Loading core/java/android/text/method/LinkMovementMethod.java +10 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.text.method; import android.os.Build; import android.text.Layout; import android.text.NoCopySpan; import android.text.Selection; Loading @@ -35,6 +36,8 @@ public class LinkMovementMethod extends ScrollingMovementMethod { private static final int UP = 2; private static final int DOWN = 3; private static final int HIDE_FLOATING_TOOLBAR_DELAY_MS = 200; @Override public boolean canSelectArbitrarily() { return true; Loading Loading @@ -215,6 +218,12 @@ public class LinkMovementMethod extends ScrollingMovementMethod { if (action == MotionEvent.ACTION_UP) { links[0].onClick(widget); } else if (action == MotionEvent.ACTION_DOWN) { if (widget.getContext().getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.O_MR1) { // Selection change will reposition the toolbar. Hide it for a few ms for a // smoother transition. widget.hideFloatingToolbar(HIDE_FLOATING_TOOLBAR_DELAY_MS); } Selection.setSelection(buffer, buffer.getSpanStart(links[0]), buffer.getSpanEnd(links[0])); Loading core/java/android/widget/Editor.java +21 −11 Original line number Diff line number Diff line Loading @@ -289,6 +289,7 @@ public class Editor { boolean mShowSoftInputOnFocus = true; private boolean mPreserveSelection; private boolean mRestartActionModeOnNextRefresh; private boolean mRequestingLinkActionMode; private SelectionActionModeHelper mSelectionActionModeHelper; Loading Loading @@ -2127,6 +2128,7 @@ public class Editor { return; } stopTextActionMode(); mRequestingLinkActionMode = true; getSelectionActionModeHelper().startLinkActionModeAsync(start, end); } Loading Loading @@ -2212,7 +2214,9 @@ public class Editor { mTextActionMode = mTextView.startActionMode(actionModeCallback, ActionMode.TYPE_FLOATING); final boolean selectionStarted = mTextActionMode != null; if (selectionStarted && !mTextView.isTextSelectable() && mShowSoftInputOnFocus) { if (selectionStarted && mTextView.isTextEditable() && !mTextView.isTextSelectable() && mShowSoftInputOnFocus) { // Show the IME to be able to replace text, except when selecting non editable text. final InputMethodManager imm = InputMethodManager.peekInstance(); if (imm != null) { Loading Loading @@ -2322,11 +2326,15 @@ public class Editor { if (!selectAllGotFocus && text.length() > 0) { // Move cursor final int offset = mTextView.getOffsetForPosition(event.getX(), event.getY()); final boolean shouldInsertCursor = !mRequestingLinkActionMode; if (shouldInsertCursor) { Selection.setSelection((Spannable) text, offset); if (mSpellChecker != null) { // When the cursor moves, the word that was typed may need spell check mSpellChecker.onSelectionChanged(); } } if (!extractedTextModeWillBeStarted()) { if (isCursorInsideEasyCorrectionSpan()) { Loading @@ -2335,16 +2343,17 @@ public class Editor { mTextView.removeCallbacks(mInsertionActionModeRunnable); } mShowSuggestionRunnable = new Runnable() { public void run() { replace(); } }; mShowSuggestionRunnable = this::replace; // removeCallbacks is performed on every touch mTextView.postDelayed(mShowSuggestionRunnable, ViewConfiguration.getDoubleTapTimeout()); } else if (hasInsertionController()) { if (shouldInsertCursor) { getInsertionController().show(); } else { getInsertionController().hide(); } } } } Loading Loading @@ -4170,6 +4179,7 @@ public class Editor { } mAssistClickHandlers.clear(); mRequestingLinkActionMode = false; } @Override Loading core/java/android/widget/SelectionActionModeHelper.java +20 −9 Original line number Diff line number Diff line Loading @@ -71,7 +71,7 @@ public final class SelectionActionModeHelper { private final TextClassificationHelper mTextClassificationHelper; private final TextClassificationConstants mTextClassificationSettings; private TextClassification mTextClassification; @Nullable private TextClassification mTextClassification; private AsyncTask mTextClassificationAsyncTask; private final SelectionTracker mSelectionTracker; Loading Loading @@ -124,7 +124,8 @@ public final class SelectionActionModeHelper { : mTextClassificationHelper::classifyText, mSmartSelectSprite != null ? this::startSelectionActionModeWithSmartSelectAnimation : this::startSelectionActionMode) : this::startSelectionActionMode, mTextClassificationHelper::getOriginalSelection) .execute(); } } Loading @@ -143,7 +144,8 @@ public final class SelectionActionModeHelper { mTextView, mTextClassificationHelper.getTimeoutDuration(), mTextClassificationHelper::classifyText, this::startLinkActionMode) this::startLinkActionMode, mTextClassificationHelper::getOriginalSelection) .execute(); } } Loading @@ -158,7 +160,8 @@ public final class SelectionActionModeHelper { mTextView, mTextClassificationHelper.getTimeoutDuration(), mTextClassificationHelper::classifyText, this::invalidateActionMode) this::invalidateActionMode, mTextClassificationHelper::getOriginalSelection) .execute(); } } Loading Loading @@ -822,6 +825,7 @@ public final class SelectionActionModeHelper { private final int mTimeOutDuration; private final Supplier<SelectionResult> mSelectionResultSupplier; private final Consumer<SelectionResult> mSelectionResultCallback; private final Supplier<SelectionResult> mTimeOutResultSupplier; private final TextView mTextView; private final String mOriginalText; Loading @@ -830,16 +834,19 @@ public final class SelectionActionModeHelper { * @param timeOut time in milliseconds to timeout the query if it has not completed * @param selectionResultSupplier fetches the selection results. Runs on a background thread * @param selectionResultCallback receives the selection results. Runs on the UiThread * @param timeOutResultSupplier default result if the task times out */ TextClassificationAsyncTask( @NonNull TextView textView, int timeOut, @NonNull Supplier<SelectionResult> selectionResultSupplier, @NonNull Consumer<SelectionResult> selectionResultCallback) { @NonNull Consumer<SelectionResult> selectionResultCallback, @NonNull Supplier<SelectionResult> timeOutResultSupplier) { super(textView != null ? textView.getHandler() : null); mTextView = Preconditions.checkNotNull(textView); mTimeOutDuration = timeOut; mSelectionResultSupplier = Preconditions.checkNotNull(selectionResultSupplier); mSelectionResultCallback = Preconditions.checkNotNull(selectionResultCallback); mTimeOutResultSupplier = Preconditions.checkNotNull(timeOutResultSupplier); // Make a copy of the original text. mOriginalText = getText(mTextView).toString(); } Loading @@ -863,7 +870,7 @@ public final class SelectionActionModeHelper { private void onTimeOut() { if (getStatus() == Status.RUNNING) { onPostExecute(null); onPostExecute(mTimeOutResultSupplier.get()); } cancel(true); } Loading Loading @@ -963,6 +970,10 @@ public final class SelectionActionModeHelper { return performClassification(selection); } public SelectionResult getOriginalSelection() { return new SelectionResult(mSelectionStart, mSelectionEnd, null, null); } /** * Maximum time (in milliseconds) to wait for a textclassifier result before timing out. */ Loading Loading @@ -1025,14 +1036,14 @@ public final class SelectionActionModeHelper { private static final class SelectionResult { private final int mStart; private final int mEnd; private final TextClassification mClassification; @Nullable private final TextClassification mClassification; @Nullable private final TextSelection mSelection; SelectionResult(int start, int end, TextClassification classification, @Nullable TextSelection selection) { @Nullable TextClassification classification, @Nullable TextSelection selection) { mStart = start; mEnd = end; mClassification = Preconditions.checkNotNull(classification); mClassification = classification; mSelection = selection; } } Loading core/java/android/widget/TextView.java +8 −1 Original line number Diff line number Diff line Loading @@ -11593,6 +11593,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } /** @hide */ public void hideFloatingToolbar(int durationMs) { if (mEditor != null) { mEditor.hideFloatingToolbar(durationMs); } } boolean canUndo() { return mEditor != null && mEditor.canUndo(); } Loading Loading @@ -11687,7 +11694,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener boolean selectAllText() { if (mEditor != null) { // Hide the toolbar before changing the selection to avoid flickering. mEditor.hideFloatingToolbar(FLOATING_TOOLBAR_SELECT_ALL_REFRESH_DELAY); hideFloatingToolbar(FLOATING_TOOLBAR_SELECT_ALL_REFRESH_DELAY); } final int length = mText.length(); Selection.setSelection((Spannable) mText, 0, length); Loading Loading
core/java/android/text/method/LinkMovementMethod.java +10 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.text.method; import android.os.Build; import android.text.Layout; import android.text.NoCopySpan; import android.text.Selection; Loading @@ -35,6 +36,8 @@ public class LinkMovementMethod extends ScrollingMovementMethod { private static final int UP = 2; private static final int DOWN = 3; private static final int HIDE_FLOATING_TOOLBAR_DELAY_MS = 200; @Override public boolean canSelectArbitrarily() { return true; Loading Loading @@ -215,6 +218,12 @@ public class LinkMovementMethod extends ScrollingMovementMethod { if (action == MotionEvent.ACTION_UP) { links[0].onClick(widget); } else if (action == MotionEvent.ACTION_DOWN) { if (widget.getContext().getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.O_MR1) { // Selection change will reposition the toolbar. Hide it for a few ms for a // smoother transition. widget.hideFloatingToolbar(HIDE_FLOATING_TOOLBAR_DELAY_MS); } Selection.setSelection(buffer, buffer.getSpanStart(links[0]), buffer.getSpanEnd(links[0])); Loading
core/java/android/widget/Editor.java +21 −11 Original line number Diff line number Diff line Loading @@ -289,6 +289,7 @@ public class Editor { boolean mShowSoftInputOnFocus = true; private boolean mPreserveSelection; private boolean mRestartActionModeOnNextRefresh; private boolean mRequestingLinkActionMode; private SelectionActionModeHelper mSelectionActionModeHelper; Loading Loading @@ -2127,6 +2128,7 @@ public class Editor { return; } stopTextActionMode(); mRequestingLinkActionMode = true; getSelectionActionModeHelper().startLinkActionModeAsync(start, end); } Loading Loading @@ -2212,7 +2214,9 @@ public class Editor { mTextActionMode = mTextView.startActionMode(actionModeCallback, ActionMode.TYPE_FLOATING); final boolean selectionStarted = mTextActionMode != null; if (selectionStarted && !mTextView.isTextSelectable() && mShowSoftInputOnFocus) { if (selectionStarted && mTextView.isTextEditable() && !mTextView.isTextSelectable() && mShowSoftInputOnFocus) { // Show the IME to be able to replace text, except when selecting non editable text. final InputMethodManager imm = InputMethodManager.peekInstance(); if (imm != null) { Loading Loading @@ -2322,11 +2326,15 @@ public class Editor { if (!selectAllGotFocus && text.length() > 0) { // Move cursor final int offset = mTextView.getOffsetForPosition(event.getX(), event.getY()); final boolean shouldInsertCursor = !mRequestingLinkActionMode; if (shouldInsertCursor) { Selection.setSelection((Spannable) text, offset); if (mSpellChecker != null) { // When the cursor moves, the word that was typed may need spell check mSpellChecker.onSelectionChanged(); } } if (!extractedTextModeWillBeStarted()) { if (isCursorInsideEasyCorrectionSpan()) { Loading @@ -2335,16 +2343,17 @@ public class Editor { mTextView.removeCallbacks(mInsertionActionModeRunnable); } mShowSuggestionRunnable = new Runnable() { public void run() { replace(); } }; mShowSuggestionRunnable = this::replace; // removeCallbacks is performed on every touch mTextView.postDelayed(mShowSuggestionRunnable, ViewConfiguration.getDoubleTapTimeout()); } else if (hasInsertionController()) { if (shouldInsertCursor) { getInsertionController().show(); } else { getInsertionController().hide(); } } } } Loading Loading @@ -4170,6 +4179,7 @@ public class Editor { } mAssistClickHandlers.clear(); mRequestingLinkActionMode = false; } @Override Loading
core/java/android/widget/SelectionActionModeHelper.java +20 −9 Original line number Diff line number Diff line Loading @@ -71,7 +71,7 @@ public final class SelectionActionModeHelper { private final TextClassificationHelper mTextClassificationHelper; private final TextClassificationConstants mTextClassificationSettings; private TextClassification mTextClassification; @Nullable private TextClassification mTextClassification; private AsyncTask mTextClassificationAsyncTask; private final SelectionTracker mSelectionTracker; Loading Loading @@ -124,7 +124,8 @@ public final class SelectionActionModeHelper { : mTextClassificationHelper::classifyText, mSmartSelectSprite != null ? this::startSelectionActionModeWithSmartSelectAnimation : this::startSelectionActionMode) : this::startSelectionActionMode, mTextClassificationHelper::getOriginalSelection) .execute(); } } Loading @@ -143,7 +144,8 @@ public final class SelectionActionModeHelper { mTextView, mTextClassificationHelper.getTimeoutDuration(), mTextClassificationHelper::classifyText, this::startLinkActionMode) this::startLinkActionMode, mTextClassificationHelper::getOriginalSelection) .execute(); } } Loading @@ -158,7 +160,8 @@ public final class SelectionActionModeHelper { mTextView, mTextClassificationHelper.getTimeoutDuration(), mTextClassificationHelper::classifyText, this::invalidateActionMode) this::invalidateActionMode, mTextClassificationHelper::getOriginalSelection) .execute(); } } Loading Loading @@ -822,6 +825,7 @@ public final class SelectionActionModeHelper { private final int mTimeOutDuration; private final Supplier<SelectionResult> mSelectionResultSupplier; private final Consumer<SelectionResult> mSelectionResultCallback; private final Supplier<SelectionResult> mTimeOutResultSupplier; private final TextView mTextView; private final String mOriginalText; Loading @@ -830,16 +834,19 @@ public final class SelectionActionModeHelper { * @param timeOut time in milliseconds to timeout the query if it has not completed * @param selectionResultSupplier fetches the selection results. Runs on a background thread * @param selectionResultCallback receives the selection results. Runs on the UiThread * @param timeOutResultSupplier default result if the task times out */ TextClassificationAsyncTask( @NonNull TextView textView, int timeOut, @NonNull Supplier<SelectionResult> selectionResultSupplier, @NonNull Consumer<SelectionResult> selectionResultCallback) { @NonNull Consumer<SelectionResult> selectionResultCallback, @NonNull Supplier<SelectionResult> timeOutResultSupplier) { super(textView != null ? textView.getHandler() : null); mTextView = Preconditions.checkNotNull(textView); mTimeOutDuration = timeOut; mSelectionResultSupplier = Preconditions.checkNotNull(selectionResultSupplier); mSelectionResultCallback = Preconditions.checkNotNull(selectionResultCallback); mTimeOutResultSupplier = Preconditions.checkNotNull(timeOutResultSupplier); // Make a copy of the original text. mOriginalText = getText(mTextView).toString(); } Loading @@ -863,7 +870,7 @@ public final class SelectionActionModeHelper { private void onTimeOut() { if (getStatus() == Status.RUNNING) { onPostExecute(null); onPostExecute(mTimeOutResultSupplier.get()); } cancel(true); } Loading Loading @@ -963,6 +970,10 @@ public final class SelectionActionModeHelper { return performClassification(selection); } public SelectionResult getOriginalSelection() { return new SelectionResult(mSelectionStart, mSelectionEnd, null, null); } /** * Maximum time (in milliseconds) to wait for a textclassifier result before timing out. */ Loading Loading @@ -1025,14 +1036,14 @@ public final class SelectionActionModeHelper { private static final class SelectionResult { private final int mStart; private final int mEnd; private final TextClassification mClassification; @Nullable private final TextClassification mClassification; @Nullable private final TextSelection mSelection; SelectionResult(int start, int end, TextClassification classification, @Nullable TextSelection selection) { @Nullable TextClassification classification, @Nullable TextSelection selection) { mStart = start; mEnd = end; mClassification = Preconditions.checkNotNull(classification); mClassification = classification; mSelection = selection; } } Loading
core/java/android/widget/TextView.java +8 −1 Original line number Diff line number Diff line Loading @@ -11593,6 +11593,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } /** @hide */ public void hideFloatingToolbar(int durationMs) { if (mEditor != null) { mEditor.hideFloatingToolbar(durationMs); } } boolean canUndo() { return mEditor != null && mEditor.canUndo(); } Loading Loading @@ -11687,7 +11694,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener boolean selectAllText() { if (mEditor != null) { // Hide the toolbar before changing the selection to avoid flickering. mEditor.hideFloatingToolbar(FLOATING_TOOLBAR_SELECT_ALL_REFRESH_DELAY); hideFloatingToolbar(FLOATING_TOOLBAR_SELECT_ALL_REFRESH_DELAY); } final int length = mText.length(); Selection.setSelection((Spannable) mText, 0, length); Loading