Merge "Fix app crash if the selection is from reverse direction." am: 769acc45e4
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1355582 Change-Id: Ic96a92523730356672a6146d3e4566dba5ce4302
This commit is contained in:
@@ -104,17 +104,44 @@ public final class SelectionActionModeHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Swap the selection index if the start index is greater than end index.
|
||||||
|
*
|
||||||
|
* @return the swap result, index 0 is the start index and index 1 is the end index.
|
||||||
|
*/
|
||||||
|
private static int[] sortSelctionIndices(int selectionStart, int selectionEnd) {
|
||||||
|
if (selectionStart < selectionEnd) {
|
||||||
|
return new int[]{selectionStart, selectionEnd};
|
||||||
|
}
|
||||||
|
return new int[]{selectionEnd, selectionStart};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link TextView} selection start and end index may not be sorted, this method will swap
|
||||||
|
* the {@link TextView} selection index if the start index is greater than end index.
|
||||||
|
*
|
||||||
|
* @param textView the selected TextView.
|
||||||
|
* @return the swap result, index 0 is the start index and index 1 is the end index.
|
||||||
|
*/
|
||||||
|
private static int[] sortSelctionIndicesFromTextView(TextView textView) {
|
||||||
|
int selectionStart = textView.getSelectionStart();
|
||||||
|
int selectionEnd = textView.getSelectionEnd();
|
||||||
|
|
||||||
|
return sortSelctionIndices(selectionStart, selectionEnd);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts Selection ActionMode.
|
* Starts Selection ActionMode.
|
||||||
*/
|
*/
|
||||||
public void startSelectionActionModeAsync(boolean adjustSelection) {
|
public void startSelectionActionModeAsync(boolean adjustSelection) {
|
||||||
// Check if the smart selection should run for editable text.
|
// Check if the smart selection should run for editable text.
|
||||||
adjustSelection &= getTextClassificationSettings().isSmartSelectionEnabled();
|
adjustSelection &= getTextClassificationSettings().isSmartSelectionEnabled();
|
||||||
|
int[] sortedSelectionIndices = sortSelctionIndicesFromTextView(mTextView);
|
||||||
|
|
||||||
mSelectionTracker.onOriginalSelection(
|
mSelectionTracker.onOriginalSelection(
|
||||||
getText(mTextView),
|
getText(mTextView),
|
||||||
mTextView.getSelectionStart(),
|
sortedSelectionIndices[0],
|
||||||
mTextView.getSelectionEnd(),
|
sortedSelectionIndices[1],
|
||||||
false /*isLink*/);
|
false /*isLink*/);
|
||||||
cancelAsyncTask();
|
cancelAsyncTask();
|
||||||
if (skipTextClassification()) {
|
if (skipTextClassification()) {
|
||||||
@@ -139,12 +166,14 @@ public final class SelectionActionModeHelper {
|
|||||||
* Starts Link ActionMode.
|
* Starts Link ActionMode.
|
||||||
*/
|
*/
|
||||||
public void startLinkActionModeAsync(int start, int end) {
|
public void startLinkActionModeAsync(int start, int end) {
|
||||||
mSelectionTracker.onOriginalSelection(getText(mTextView), start, end, true /*isLink*/);
|
int[] indexResult = sortSelctionIndices(start, end);
|
||||||
|
mSelectionTracker.onOriginalSelection(getText(mTextView), indexResult[0], indexResult[1],
|
||||||
|
true /*isLink*/);
|
||||||
cancelAsyncTask();
|
cancelAsyncTask();
|
||||||
if (skipTextClassification()) {
|
if (skipTextClassification()) {
|
||||||
startLinkActionMode(null);
|
startLinkActionMode(null);
|
||||||
} else {
|
} else {
|
||||||
resetTextClassificationHelper(start, end);
|
resetTextClassificationHelper(indexResult[0], indexResult[1]);
|
||||||
mTextClassificationAsyncTask = new TextClassificationAsyncTask(
|
mTextClassificationAsyncTask = new TextClassificationAsyncTask(
|
||||||
mTextView,
|
mTextView,
|
||||||
mTextClassificationHelper.getTimeoutDuration(),
|
mTextClassificationHelper.getTimeoutDuration(),
|
||||||
@@ -173,19 +202,23 @@ public final class SelectionActionModeHelper {
|
|||||||
|
|
||||||
/** Reports a selection action event. */
|
/** Reports a selection action event. */
|
||||||
public void onSelectionAction(int menuItemId, @Nullable String actionLabel) {
|
public void onSelectionAction(int menuItemId, @Nullable String actionLabel) {
|
||||||
|
int[] sortedSelectionIndices = sortSelctionIndicesFromTextView(mTextView);
|
||||||
mSelectionTracker.onSelectionAction(
|
mSelectionTracker.onSelectionAction(
|
||||||
mTextView.getSelectionStart(), mTextView.getSelectionEnd(),
|
sortedSelectionIndices[0], sortedSelectionIndices[1],
|
||||||
getActionType(menuItemId), actionLabel, mTextClassification);
|
getActionType(menuItemId), actionLabel, mTextClassification);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onSelectionDrag() {
|
public void onSelectionDrag() {
|
||||||
|
int[] sortedSelectionIndices = sortSelctionIndicesFromTextView(mTextView);
|
||||||
mSelectionTracker.onSelectionAction(
|
mSelectionTracker.onSelectionAction(
|
||||||
mTextView.getSelectionStart(), mTextView.getSelectionEnd(),
|
sortedSelectionIndices[0], sortedSelectionIndices[1],
|
||||||
SelectionEvent.ACTION_DRAG, /* actionLabel= */ null, mTextClassification);
|
SelectionEvent.ACTION_DRAG, /* actionLabel= */ null, mTextClassification);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onTextChanged(int start, int end) {
|
public void onTextChanged(int start, int end) {
|
||||||
mSelectionTracker.onTextChanged(start, end, mTextClassification);
|
int[] sortedSelectionIndices = sortSelctionIndices(start, end);
|
||||||
|
mSelectionTracker.onTextChanged(sortedSelectionIndices[0], sortedSelectionIndices[1],
|
||||||
|
mTextClassification);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean resetSelection(int textIndex) {
|
public boolean resetSelection(int textIndex) {
|
||||||
@@ -302,9 +335,10 @@ public final class SelectionActionModeHelper {
|
|||||||
startSelectionActionMode(startSelectionResult);
|
startSelectionActionMode(startSelectionResult);
|
||||||
};
|
};
|
||||||
// TODO do not trigger the animation if the change included only non-printable characters
|
// TODO do not trigger the animation if the change included only non-printable characters
|
||||||
|
int[] sortedSelectionIndices = sortSelctionIndicesFromTextView(mTextView);
|
||||||
final boolean didSelectionChange =
|
final boolean didSelectionChange =
|
||||||
result != null && (mTextView.getSelectionStart() != result.mStart
|
result != null && (sortedSelectionIndices[0] != result.mStart
|
||||||
|| mTextView.getSelectionEnd() != result.mEnd);
|
|| sortedSelectionIndices[1] != result.mEnd);
|
||||||
|
|
||||||
if (!didSelectionChange) {
|
if (!didSelectionChange) {
|
||||||
onAnimationEndCallback.run();
|
onAnimationEndCallback.run();
|
||||||
@@ -454,16 +488,18 @@ public final class SelectionActionModeHelper {
|
|||||||
if (actionMode != null) {
|
if (actionMode != null) {
|
||||||
actionMode.invalidate();
|
actionMode.invalidate();
|
||||||
}
|
}
|
||||||
|
final int[] sortedSelectionIndices = sortSelctionIndicesFromTextView(mTextView);
|
||||||
mSelectionTracker.onSelectionUpdated(
|
mSelectionTracker.onSelectionUpdated(
|
||||||
mTextView.getSelectionStart(), mTextView.getSelectionEnd(), mTextClassification);
|
sortedSelectionIndices[0], sortedSelectionIndices[1], mTextClassification);
|
||||||
mTextClassificationAsyncTask = null;
|
mTextClassificationAsyncTask = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void resetTextClassificationHelper(int selectionStart, int selectionEnd) {
|
private void resetTextClassificationHelper(int selectionStart, int selectionEnd) {
|
||||||
if (selectionStart < 0 || selectionEnd < 0) {
|
if (selectionStart < 0 || selectionEnd < 0) {
|
||||||
// Use selection indices
|
// Use selection indices
|
||||||
selectionStart = mTextView.getSelectionStart();
|
int[] sortedSelectionIndices = sortSelctionIndicesFromTextView(mTextView);
|
||||||
selectionEnd = mTextView.getSelectionEnd();
|
selectionStart = sortedSelectionIndices[0];
|
||||||
|
selectionEnd = sortedSelectionIndices[1];
|
||||||
}
|
}
|
||||||
mTextClassificationHelper.init(
|
mTextClassificationHelper.init(
|
||||||
mTextView::getTextClassifier,
|
mTextView::getTextClassifier,
|
||||||
@@ -603,10 +639,11 @@ public final class SelectionActionModeHelper {
|
|||||||
mAllowReset = false;
|
mAllowReset = false;
|
||||||
boolean selected = editor.selectCurrentWord();
|
boolean selected = editor.selectCurrentWord();
|
||||||
if (selected) {
|
if (selected) {
|
||||||
mSelectionStart = editor.getTextView().getSelectionStart();
|
final int[] sortedSelectionIndices = sortSelctionIndicesFromTextView(textView);
|
||||||
mSelectionEnd = editor.getTextView().getSelectionEnd();
|
mSelectionStart = sortedSelectionIndices[0];
|
||||||
|
mSelectionEnd = sortedSelectionIndices[1];
|
||||||
mLogger.logSelectionAction(
|
mLogger.logSelectionAction(
|
||||||
textView.getSelectionStart(), textView.getSelectionEnd(),
|
sortedSelectionIndices[0], sortedSelectionIndices[1],
|
||||||
SelectionEvent.ACTION_RESET,
|
SelectionEvent.ACTION_RESET,
|
||||||
/* actionLabel= */ null, /* classification= */ null);
|
/* actionLabel= */ null, /* classification= */ null);
|
||||||
}
|
}
|
||||||
@@ -1179,8 +1216,9 @@ public final class SelectionActionModeHelper {
|
|||||||
|
|
||||||
SelectionResult(int start, int end,
|
SelectionResult(int start, int end,
|
||||||
@Nullable TextClassification classification, @Nullable TextSelection selection) {
|
@Nullable TextClassification classification, @Nullable TextSelection selection) {
|
||||||
mStart = start;
|
int[] sortedIndices = sortSelctionIndices(start, end);
|
||||||
mEnd = end;
|
mStart = sortedIndices[0];
|
||||||
|
mEnd = sortedIndices[1];
|
||||||
mClassification = classification;
|
mClassification = classification;
|
||||||
mSelection = selection;
|
mSelection = selection;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user