RESTRICT AUTOMERGE Do not linkify text with RLO/LRO characters.
am: a69950ce18
Change-Id: I0830e1c1a1cea2fd93f0b1ed8a1a792260201bb2
This commit is contained in:
@@ -30,6 +30,7 @@ import android.text.Spanned;
|
|||||||
import android.text.method.LinkMovementMethod;
|
import android.text.method.LinkMovementMethod;
|
||||||
import android.text.method.MovementMethod;
|
import android.text.method.MovementMethod;
|
||||||
import android.text.style.URLSpan;
|
import android.text.style.URLSpan;
|
||||||
|
import android.util.Log;
|
||||||
import android.util.Patterns;
|
import android.util.Patterns;
|
||||||
import android.view.textclassifier.TextClassifier;
|
import android.view.textclassifier.TextClassifier;
|
||||||
import android.view.textclassifier.TextLinks;
|
import android.view.textclassifier.TextLinks;
|
||||||
@@ -78,6 +79,9 @@ import java.util.regex.Pattern;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
public class Linkify {
|
public class Linkify {
|
||||||
|
|
||||||
|
private static final String LOG_TAG = "Linkify";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bit field indicating that web URLs should be matched in methods that
|
* Bit field indicating that web URLs should be matched in methods that
|
||||||
* take an options mask
|
* take an options mask
|
||||||
@@ -247,6 +251,11 @@ public class Linkify {
|
|||||||
|
|
||||||
private static boolean addLinks(@NonNull Spannable text, @LinkifyMask int mask,
|
private static boolean addLinks(@NonNull Spannable text, @LinkifyMask int mask,
|
||||||
@Nullable Context context) {
|
@Nullable Context context) {
|
||||||
|
if (text != null && containsUnsupportedCharacters(text.toString())) {
|
||||||
|
android.util.EventLog.writeEvent(0x534e4554, "116321860", -1, "");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (mask == 0) {
|
if (mask == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -292,6 +301,29 @@ public class Linkify {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
* Scans the text of the provided TextView and turns all occurrences of
|
||||||
* the link types indicated in the mask into clickable links. If matches
|
* the link types indicated in the mask into clickable links. If matches
|
||||||
@@ -462,6 +494,11 @@ public class Linkify {
|
|||||||
public static final boolean addLinks(@NonNull Spannable spannable, @NonNull Pattern pattern,
|
public static final boolean addLinks(@NonNull Spannable spannable, @NonNull Pattern pattern,
|
||||||
@Nullable String defaultScheme, @Nullable String[] schemes,
|
@Nullable String defaultScheme, @Nullable String[] schemes,
|
||||||
@Nullable MatchFilter matchFilter, @Nullable TransformFilter transformFilter) {
|
@Nullable MatchFilter matchFilter, @Nullable TransformFilter transformFilter) {
|
||||||
|
if (spannable != null && containsUnsupportedCharacters(spannable.toString())) {
|
||||||
|
android.util.EventLog.writeEvent(0x534e4554, "116321860", -1, "");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
final String[] schemesCopy;
|
final String[] schemesCopy;
|
||||||
if (defaultScheme == null) defaultScheme = "";
|
if (defaultScheme == null) defaultScheme = "";
|
||||||
if (schemes == null || schemes.length < 1) {
|
if (schemes == null || schemes.length < 1) {
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ public final class TextClassification implements Parcelable {
|
|||||||
/**
|
/**
|
||||||
* @hide
|
* @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";
|
private static final String LOG_TAG = "TextClassification";
|
||||||
// TODO(toki): investigate a way to derive this based on device properties.
|
// TODO(toki): investigate a way to derive this based on device properties.
|
||||||
|
|||||||
@@ -107,6 +107,13 @@ public final class TextLinksParams {
|
|||||||
Preconditions.checkNotNull(textLinks);
|
Preconditions.checkNotNull(textLinks);
|
||||||
|
|
||||||
final String textString = text.toString();
|
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())) {
|
if (!textString.startsWith(textLinks.getText())) {
|
||||||
return TextLinks.STATUS_DIFFERENT_TEXT;
|
return TextLinks.STATUS_DIFFERENT_TEXT;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import android.text.Layout;
|
|||||||
import android.text.Selection;
|
import android.text.Selection;
|
||||||
import android.text.Spannable;
|
import android.text.Spannable;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.text.util.Linkify;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.ActionMode;
|
import android.view.ActionMode;
|
||||||
import android.view.textclassifier.SelectionEvent;
|
import android.view.textclassifier.SelectionEvent;
|
||||||
@@ -1045,7 +1046,12 @@ public final class SelectionActionModeHelper {
|
|||||||
|
|
||||||
trimText();
|
trimText();
|
||||||
final TextClassification classification;
|
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 =
|
final TextClassification.Request request =
|
||||||
new TextClassification.Request.Builder(
|
new TextClassification.Request.Builder(
|
||||||
mTrimmedText, mRelativeStart, mRelativeEnd)
|
mTrimmedText, mRelativeStart, mRelativeEnd)
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ import android.service.textclassifier.TextClassifierService;
|
|||||||
import android.support.test.InstrumentationRegistry;
|
import android.support.test.InstrumentationRegistry;
|
||||||
import android.support.test.filters.SmallTest;
|
import android.support.test.filters.SmallTest;
|
||||||
import android.support.test.runner.AndroidJUnit4;
|
import android.support.test.runner.AndroidJUnit4;
|
||||||
|
import android.text.Spannable;
|
||||||
|
import android.text.SpannableString;
|
||||||
|
|
||||||
import org.hamcrest.BaseMatcher;
|
import org.hamcrest.BaseMatcher;
|
||||||
import org.hamcrest.Description;
|
import org.hamcrest.Description;
|
||||||
@@ -306,6 +308,16 @@ public class TextClassificationManagerTest {
|
|||||||
mClassifier.generateLinks(request);
|
mClassifier.generateLinks(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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
|
@Test
|
||||||
public void testSetTextClassifier() {
|
public void testSetTextClassifier() {
|
||||||
TextClassifier classifier = mock(TextClassifier.class);
|
TextClassifier classifier = mock(TextClassifier.class);
|
||||||
|
|||||||
@@ -982,6 +982,19 @@ public class TextViewActivityTest {
|
|||||||
assertFloatingToolbarDoesNotContainItem(android.R.id.textAssist);
|
assertFloatingToolbarDoesNotContainItem(android.R.id.textAssist);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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
|
@Test
|
||||||
public void testSelectionMetricsLogger_noAbandonAfterCopy() throws Throwable {
|
public void testSelectionMetricsLogger_noAbandonAfterCopy() throws Throwable {
|
||||||
final List<SelectionEvent> selectionEvents = new ArrayList<>();
|
final List<SelectionEvent> selectionEvents = new ArrayList<>();
|
||||||
|
|||||||
Reference in New Issue
Block a user