diff options
author | Abodunrinwa Toki <toki@google.com> | 2018-11-29 13:51:56 +0000 |
---|---|---|
committer | Abodunrinwa Toki <toki@google.com> | 2019-01-03 14:20:30 +0000 |
commit | a69950ce18f85ea8514083a5e175450e17e93565 (patch) | |
tree | bd05831f4fec7fca444ae1369671089b48a2f562 | |
parent | 002c637337db17b86cb5a22fb25af1273a37b946 (diff) | |
download | base-a69950ce18f85ea8514083a5e175450e17e93565.tar.gz |
RESTRICT AUTOMERGE Do not linkify text with RLO/LRO characters.
Also don't show smart actions for selections in text with unsupported
characters.
Bug: 116321860
Test: atest android.view.textclassifier.TextClassificationManagerTest \
android.text.util.cts.LinkifyTest \
android.text.util.LinkifyTest \
android.widget.TextViewActivityTest
Change-Id: I01b5e936aa4dfc937a98f50e9fc8171666861a61
6 files changed, 77 insertions, 2 deletions
diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java index c905f49569d7..dc68da0310b6 100644 --- a/core/java/android/text/util/Linkify.java +++ b/core/java/android/text/util/Linkify.java @@ -29,6 +29,7 @@ import android.text.Spanned; import android.text.method.LinkMovementMethod; import android.text.method.MovementMethod; import android.text.style.URLSpan; +import android.util.Log; import android.util.Patterns; import android.view.textclassifier.TextClassifier; import android.view.textclassifier.TextLinks; @@ -77,6 +78,9 @@ import java.util.regex.Pattern; */ public class Linkify { + + private static final String LOG_TAG = "Linkify"; + /** * Bit field indicating that web URLs should be matched in methods that * take an options mask @@ -246,6 +250,11 @@ public class Linkify { private static boolean addLinks(@NonNull Spannable text, @LinkifyMask int mask, @Nullable Context context) { + if (text != null && containsUnsupportedCharacters(text.toString())) { + android.util.EventLog.writeEvent(0x534e4554, "116321860", -1, ""); + return false; + } + if (mask == 0) { return false; } @@ -292,6 +301,29 @@ public class Linkify { } /** + * Returns true if the specified text contains at least one unsupported character for applying + * links. Also logs the error. + * + * @param text the text to apply links to + * @hide + */ + public static boolean containsUnsupportedCharacters(String text) { + if (text.contains("\u202C")) { + Log.e(LOG_TAG, "Unsupported character for applying links: u202C"); + return true; + } + if (text.contains("\u202D")) { + Log.e(LOG_TAG, "Unsupported character for applying links: u202D"); + return true; + } + if (text.contains("\u202E")) { + Log.e(LOG_TAG, "Unsupported character for applying links: u202E"); + return true; + } + return false; + } + + /** * Scans the text of the provided TextView and turns all occurrences of * the link types indicated in the mask into clickable links. If matches * are found the movement method for the TextView is set to @@ -461,6 +493,11 @@ public class Linkify { public static final boolean addLinks(@NonNull Spannable spannable, @NonNull Pattern pattern, @Nullable String defaultScheme, @Nullable String[] schemes, @Nullable MatchFilter matchFilter, @Nullable TransformFilter transformFilter) { + if (spannable != null && containsUnsupportedCharacters(spannable.toString())) { + android.util.EventLog.writeEvent(0x534e4554, "116321860", -1, ""); + return false; + } + final String[] schemesCopy; if (defaultScheme == null) defaultScheme = ""; if (schemes == null || schemes.length < 1) { diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java index 9511a9efb3d5..49ca969fa7af 100644 --- a/core/java/android/view/textclassifier/TextClassification.java +++ b/core/java/android/view/textclassifier/TextClassification.java @@ -104,7 +104,7 @@ public final class TextClassification implements Parcelable { /** * @hide */ - static final TextClassification EMPTY = new TextClassification.Builder().build(); + public static final TextClassification EMPTY = new TextClassification.Builder().build(); private static final String LOG_TAG = "TextClassification"; // TODO(toki): investigate a way to derive this based on device properties. diff --git a/core/java/android/view/textclassifier/TextLinksParams.java b/core/java/android/view/textclassifier/TextLinksParams.java index be4c3bcdff67..c21206ca0258 100644 --- a/core/java/android/view/textclassifier/TextLinksParams.java +++ b/core/java/android/view/textclassifier/TextLinksParams.java @@ -107,6 +107,13 @@ public final class TextLinksParams { Preconditions.checkNotNull(textLinks); final String textString = text.toString(); + + if (Linkify.containsUnsupportedCharacters(textString)) { + // Do not apply links to text containing unsupported characters. + android.util.EventLog.writeEvent(0x534e4554, "116321860", -1, ""); + return TextLinks.STATUS_NO_LINKS_APPLIED; + } + if (!textString.startsWith(textLinks.getText())) { return TextLinks.STATUS_DIFFERENT_TEXT; } diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java index 6cb0eaa7f47d..0d88e6986f11 100644 --- a/core/java/android/widget/SelectionActionModeHelper.java +++ b/core/java/android/widget/SelectionActionModeHelper.java @@ -31,6 +31,7 @@ import android.text.Layout; import android.text.Selection; import android.text.Spannable; import android.text.TextUtils; +import android.text.util.Linkify; import android.util.Log; import android.view.ActionMode; import android.view.textclassifier.SelectionEvent; @@ -1045,7 +1046,12 @@ public final class SelectionActionModeHelper { trimText(); final TextClassification classification; - if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.P) { + if (Linkify.containsUnsupportedCharacters(mText)) { + // Do not show smart actions for text containing unsupported characters. + android.util.EventLog.writeEvent(0x534e4554, "116321860", -1, ""); + classification = TextClassification.EMPTY; + } else if (mContext.getApplicationInfo().targetSdkVersion + >= Build.VERSION_CODES.P) { final TextClassification.Request request = new TextClassification.Request.Builder( mTrimmedText, mRelativeStart, mRelativeEnd) diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java index c8a53cc86347..9015e92a4f08 100644 --- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java +++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java @@ -39,6 +39,8 @@ import android.service.textclassifier.TextClassifierService; import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; +import android.text.Spannable; +import android.text.SpannableString; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; @@ -307,6 +309,16 @@ public class TextClassificationManagerTest { } @Test + public void testApplyLinks_unsupportedCharacter() { + if (isTextClassifierDisabled()) return; + Spannable url = new SpannableString("\u202Emoc.diordna.com"); + TextLinks.Request request = new TextLinks.Request.Builder(url).build(); + assertEquals( + TextLinks.STATUS_NO_LINKS_APPLIED, + mClassifier.generateLinks(request).apply(url, 0, null)); + } + + @Test public void testSetTextClassifier() { TextClassifier classifier = mock(TextClassifier.class); mTcm.setTextClassifier(classifier); diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java index 70dc6189c6c2..90758ba7c418 100644 --- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java +++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java @@ -983,6 +983,19 @@ public class TextViewActivityTest { } @Test + public void testNoAssistItemForTextFieldWithUnsupportedCharacters() throws Throwable { + useSystemDefaultTextClassifier(); + final String text = "\u202Emoc.diordna.com"; + final TextView textView = mActivity.findViewById(R.id.textview); + mActivityRule.runOnUiThread(() -> textView.setText(text)); + mInstrumentation.waitForIdleSync(); + + onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('.'))); + sleepForFloatingToolbarPopup(); + assertFloatingToolbarDoesNotContainItem(android.R.id.textAssist); + } + + @Test public void testSelectionMetricsLogger_noAbandonAfterCopy() throws Throwable { final List<SelectionEvent> selectionEvents = new ArrayList<>(); final TextClassifier classifier = new TextClassifier() { |