Loading core/java/android/text/util/Linkify.java +0 −241 Original line number Diff line number Diff line Loading @@ -19,7 +19,6 @@ package android.text.util; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UiThread; import android.content.Context; import android.telephony.PhoneNumberUtils; import android.telephony.TelephonyManager; Loading @@ -30,17 +29,12 @@ import android.text.method.LinkMovementMethod; import android.text.method.MovementMethod; import android.text.style.URLSpan; import android.util.Patterns; import android.view.textclassifier.TextClassifier; import android.view.textclassifier.TextLinks; import android.view.textclassifier.TextLinks.TextLinkSpan; import android.view.textclassifier.TextLinksParams; import android.webkit.WebView; import android.widget.TextView; import com.android.i18n.phonenumbers.PhoneNumberMatch; import com.android.i18n.phonenumbers.PhoneNumberUtil; import com.android.i18n.phonenumbers.PhoneNumberUtil.Leniency; import com.android.internal.util.Preconditions; import libcore.util.EmptyArray; Loading @@ -52,11 +46,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Locale; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.concurrent.Future; import java.util.function.Consumer; import java.util.function.Supplier; import java.util.regex.Matcher; import java.util.regex.Pattern; Loading Loading @@ -497,236 +486,6 @@ public class Linkify { return hasMatches; } /** * Scans the text of the provided TextView and turns all occurrences of the entity types * specified by {@code options} into clickable links. If links are found, this method * removes any pre-existing {@link TextLinkSpan} attached to the text (to avoid * problems if you call it repeatedly on the same text) and sets the movement method for the * TextView to LinkMovementMethod. * * <p><strong>Note:</strong> This method returns immediately but generates the links with * the specified classifier on a background thread. The generated links are applied on the * calling thread. * * @param textView TextView whose text is to be marked-up with links * @param params optional parameters to specify how to generate the links * * @return a future that may be used to interrupt or query the background task * @hide */ @UiThread public static Future<Void> addLinksAsync( @NonNull TextView textView, @Nullable TextLinksParams params) { return addLinksAsync(textView, params, null /* executor */, null /* callback */); } /** * Scans the text of the provided TextView and turns all occurrences of the entity types * specified by {@code options} into clickable links. If links are found, this method * removes any pre-existing {@link TextLinkSpan} attached to the text (to avoid * problems if you call it repeatedly on the same text) and sets the movement method for the * TextView to LinkMovementMethod. * * <p><strong>Note:</strong> This method returns immediately but generates the links with * the specified classifier on a background thread. The generated links are applied on the * calling thread. * * @param textView TextView whose text is to be marked-up with links * @param mask mask to define which kinds of links will be generated * * @return a future that may be used to interrupt or query the background task * @hide */ @UiThread public static Future<Void> addLinksAsync( @NonNull TextView textView, @LinkifyMask int mask) { return addLinksAsync(textView, TextLinksParams.fromLinkMask(mask), null /* executor */, null /* callback */); } /** * Scans the text of the provided TextView and turns all occurrences of the entity types * specified by {@code options} into clickable links. If links are found, this method * removes any pre-existing {@link TextLinkSpan} attached to the text (to avoid * problems if you call it repeatedly on the same text) and sets the movement method for the * TextView to LinkMovementMethod. * * <p><strong>Note:</strong> This method returns immediately but generates the links with * the specified classifier on a background thread. The generated links are applied on the * calling thread. * * @param textView TextView whose text is to be marked-up with links * @param params optional parameters to specify how to generate the links * @param executor Executor that runs the background task * @param callback Callback that receives the final status of the background task execution * * @return a future that may be used to interrupt or query the background task * @hide */ @UiThread public static Future<Void> addLinksAsync( @NonNull TextView textView, @Nullable TextLinksParams params, @Nullable Executor executor, @Nullable Consumer<Integer> callback) { Preconditions.checkNotNull(textView); final CharSequence text = textView.getText(); final Spannable spannable = (text instanceof Spannable) ? (Spannable) text : SpannableString.valueOf(text); final Runnable modifyTextView = () -> { addLinkMovementMethod(textView); if (spannable != text) { textView.setText(spannable); } }; return addLinksAsync(spannable, textView.getTextClassifier(), params, executor, callback, modifyTextView); } /** * Scans the text of the provided TextView and turns all occurrences of the entity types * specified by {@code options} into clickable links. If links are found, this method * removes any pre-existing {@link TextLinkSpan} attached to the text to avoid * problems if you call it repeatedly on the same text. * * <p><strong>Note:</strong> This method returns immediately but generates the links with * the specified classifier on a background thread. The generated links are applied on the * calling thread. * * <p><strong>Note:</strong> If the text is currently attached to a TextView, this method * should be called on the UI thread. * * @param text Spannable whose text is to be marked-up with links * @param classifier the TextClassifier to use to generate the links * @param params optional parameters to specify how to generate the links * * @return a future that may be used to interrupt or query the background task * @hide */ public static Future<Void> addLinksAsync( @NonNull Spannable text, @NonNull TextClassifier classifier, @Nullable TextLinksParams params) { return addLinksAsync(text, classifier, params, null /* executor */, null /* callback */); } /** * Scans the text of the provided TextView and turns all occurrences of the entity types * specified by the link {@code mask} into clickable links. If links are found, this method * removes any pre-existing {@link TextLinkSpan} attached to the text to avoid * problems if you call it repeatedly on the same text. * * <p><strong>Note:</strong> This method returns immediately but generates the links with * the specified classifier on a background thread. The generated links are applied on the * calling thread. * * <p><strong>Note:</strong> If the text is currently attached to a TextView, this method * should be called on the UI thread. * * @param text Spannable whose text is to be marked-up with links * @param classifier the TextClassifier to use to generate the links * @param mask mask to define which kinds of links will be generated * * @return a future that may be used to interrupt or query the background task * @hide */ public static Future<Void> addLinksAsync( @NonNull Spannable text, @NonNull TextClassifier classifier, @LinkifyMask int mask) { return addLinksAsync(text, classifier, TextLinksParams.fromLinkMask(mask), null /* executor */, null /* callback */); } /** * Scans the text of the provided TextView and turns all occurrences of the entity types * specified by {@code options} into clickable links. If links are found, this method * removes any pre-existing {@link TextLinkSpan} attached to the text to avoid * problems if you call it repeatedly on the same text. * * <p><strong>Note:</strong> This method returns immediately but generates the links with * the specified classifier on a background thread. The generated links are applied on the * calling thread. * * <p><strong>Note:</strong> If the text is currently attached to a TextView, this method * should be called on the UI thread. * * @param text Spannable whose text is to be marked-up with links * @param classifier the TextClassifier to use to generate the links * @param params optional parameters to specify how to generate the links * @param executor Executor that runs the background task * @param callback Callback that receives the final status of the background task execution * * @return a future that may be used to interrupt or query the background task * @hide */ public static Future<Void> addLinksAsync( @NonNull Spannable text, @NonNull TextClassifier classifier, @Nullable TextLinksParams params, @Nullable Executor executor, @Nullable Consumer<Integer> callback) { return addLinksAsync(text, classifier, params, executor, callback, null /* modifyTextView */); } private static Future<Void> addLinksAsync( @NonNull Spannable text, @NonNull TextClassifier classifier, @Nullable TextLinksParams params, @Nullable Executor executor, @Nullable Consumer<Integer> callback, @Nullable Runnable modifyTextView) { Preconditions.checkNotNull(text); Preconditions.checkNotNull(classifier); // TODO: This is a bug. We shouldnot call getMaxGenerateLinksTextLength() on the UI thread. // The input text may exceed the maximum length the text classifier can handle. In such // cases, we process the text up to the maximum length. final CharSequence truncatedText = text.subSequence( 0, Math.min(text.length(), classifier.getMaxGenerateLinksTextLength())); final TextClassifier.EntityConfig entityConfig = (params == null) ? null : params.getEntityConfig(); final TextLinks.Request request = new TextLinks.Request.Builder(truncatedText) .setLegacyFallback(true) .setEntityConfig(entityConfig) .build(); final Supplier<TextLinks> supplier = () -> classifier.generateLinks(request); final Consumer<TextLinks> consumer = links -> { if (links.getLinks().isEmpty()) { if (callback != null) { callback.accept(TextLinks.STATUS_NO_LINKS_FOUND); } return; } // Remove spans only for the part of the text we generated links for. final TextLinkSpan[] old = text.getSpans(0, truncatedText.length(), TextLinkSpan.class); for (int i = old.length - 1; i >= 0; i--) { text.removeSpan(old[i]); } final @TextLinks.Status int result = params.apply(text, links); if (result == TextLinks.STATUS_LINKS_APPLIED) { if (modifyTextView != null) { modifyTextView.run(); } } if (callback != null) { callback.accept(result); } }; if (executor == null) { return CompletableFuture.supplyAsync(supplier).thenAccept(consumer); } else { return CompletableFuture.supplyAsync(supplier, executor).thenAccept(consumer); } } private static final void applyLink(String url, int start, int end, Spannable text) { URLSpan span = new URLSpan(url); Loading Loading
core/java/android/text/util/Linkify.java +0 −241 Original line number Diff line number Diff line Loading @@ -19,7 +19,6 @@ package android.text.util; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UiThread; import android.content.Context; import android.telephony.PhoneNumberUtils; import android.telephony.TelephonyManager; Loading @@ -30,17 +29,12 @@ import android.text.method.LinkMovementMethod; import android.text.method.MovementMethod; import android.text.style.URLSpan; import android.util.Patterns; import android.view.textclassifier.TextClassifier; import android.view.textclassifier.TextLinks; import android.view.textclassifier.TextLinks.TextLinkSpan; import android.view.textclassifier.TextLinksParams; import android.webkit.WebView; import android.widget.TextView; import com.android.i18n.phonenumbers.PhoneNumberMatch; import com.android.i18n.phonenumbers.PhoneNumberUtil; import com.android.i18n.phonenumbers.PhoneNumberUtil.Leniency; import com.android.internal.util.Preconditions; import libcore.util.EmptyArray; Loading @@ -52,11 +46,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Locale; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.concurrent.Future; import java.util.function.Consumer; import java.util.function.Supplier; import java.util.regex.Matcher; import java.util.regex.Pattern; Loading Loading @@ -497,236 +486,6 @@ public class Linkify { return hasMatches; } /** * Scans the text of the provided TextView and turns all occurrences of the entity types * specified by {@code options} into clickable links. If links are found, this method * removes any pre-existing {@link TextLinkSpan} attached to the text (to avoid * problems if you call it repeatedly on the same text) and sets the movement method for the * TextView to LinkMovementMethod. * * <p><strong>Note:</strong> This method returns immediately but generates the links with * the specified classifier on a background thread. The generated links are applied on the * calling thread. * * @param textView TextView whose text is to be marked-up with links * @param params optional parameters to specify how to generate the links * * @return a future that may be used to interrupt or query the background task * @hide */ @UiThread public static Future<Void> addLinksAsync( @NonNull TextView textView, @Nullable TextLinksParams params) { return addLinksAsync(textView, params, null /* executor */, null /* callback */); } /** * Scans the text of the provided TextView and turns all occurrences of the entity types * specified by {@code options} into clickable links. If links are found, this method * removes any pre-existing {@link TextLinkSpan} attached to the text (to avoid * problems if you call it repeatedly on the same text) and sets the movement method for the * TextView to LinkMovementMethod. * * <p><strong>Note:</strong> This method returns immediately but generates the links with * the specified classifier on a background thread. The generated links are applied on the * calling thread. * * @param textView TextView whose text is to be marked-up with links * @param mask mask to define which kinds of links will be generated * * @return a future that may be used to interrupt or query the background task * @hide */ @UiThread public static Future<Void> addLinksAsync( @NonNull TextView textView, @LinkifyMask int mask) { return addLinksAsync(textView, TextLinksParams.fromLinkMask(mask), null /* executor */, null /* callback */); } /** * Scans the text of the provided TextView and turns all occurrences of the entity types * specified by {@code options} into clickable links. If links are found, this method * removes any pre-existing {@link TextLinkSpan} attached to the text (to avoid * problems if you call it repeatedly on the same text) and sets the movement method for the * TextView to LinkMovementMethod. * * <p><strong>Note:</strong> This method returns immediately but generates the links with * the specified classifier on a background thread. The generated links are applied on the * calling thread. * * @param textView TextView whose text is to be marked-up with links * @param params optional parameters to specify how to generate the links * @param executor Executor that runs the background task * @param callback Callback that receives the final status of the background task execution * * @return a future that may be used to interrupt or query the background task * @hide */ @UiThread public static Future<Void> addLinksAsync( @NonNull TextView textView, @Nullable TextLinksParams params, @Nullable Executor executor, @Nullable Consumer<Integer> callback) { Preconditions.checkNotNull(textView); final CharSequence text = textView.getText(); final Spannable spannable = (text instanceof Spannable) ? (Spannable) text : SpannableString.valueOf(text); final Runnable modifyTextView = () -> { addLinkMovementMethod(textView); if (spannable != text) { textView.setText(spannable); } }; return addLinksAsync(spannable, textView.getTextClassifier(), params, executor, callback, modifyTextView); } /** * Scans the text of the provided TextView and turns all occurrences of the entity types * specified by {@code options} into clickable links. If links are found, this method * removes any pre-existing {@link TextLinkSpan} attached to the text to avoid * problems if you call it repeatedly on the same text. * * <p><strong>Note:</strong> This method returns immediately but generates the links with * the specified classifier on a background thread. The generated links are applied on the * calling thread. * * <p><strong>Note:</strong> If the text is currently attached to a TextView, this method * should be called on the UI thread. * * @param text Spannable whose text is to be marked-up with links * @param classifier the TextClassifier to use to generate the links * @param params optional parameters to specify how to generate the links * * @return a future that may be used to interrupt or query the background task * @hide */ public static Future<Void> addLinksAsync( @NonNull Spannable text, @NonNull TextClassifier classifier, @Nullable TextLinksParams params) { return addLinksAsync(text, classifier, params, null /* executor */, null /* callback */); } /** * Scans the text of the provided TextView and turns all occurrences of the entity types * specified by the link {@code mask} into clickable links. If links are found, this method * removes any pre-existing {@link TextLinkSpan} attached to the text to avoid * problems if you call it repeatedly on the same text. * * <p><strong>Note:</strong> This method returns immediately but generates the links with * the specified classifier on a background thread. The generated links are applied on the * calling thread. * * <p><strong>Note:</strong> If the text is currently attached to a TextView, this method * should be called on the UI thread. * * @param text Spannable whose text is to be marked-up with links * @param classifier the TextClassifier to use to generate the links * @param mask mask to define which kinds of links will be generated * * @return a future that may be used to interrupt or query the background task * @hide */ public static Future<Void> addLinksAsync( @NonNull Spannable text, @NonNull TextClassifier classifier, @LinkifyMask int mask) { return addLinksAsync(text, classifier, TextLinksParams.fromLinkMask(mask), null /* executor */, null /* callback */); } /** * Scans the text of the provided TextView and turns all occurrences of the entity types * specified by {@code options} into clickable links. If links are found, this method * removes any pre-existing {@link TextLinkSpan} attached to the text to avoid * problems if you call it repeatedly on the same text. * * <p><strong>Note:</strong> This method returns immediately but generates the links with * the specified classifier on a background thread. The generated links are applied on the * calling thread. * * <p><strong>Note:</strong> If the text is currently attached to a TextView, this method * should be called on the UI thread. * * @param text Spannable whose text is to be marked-up with links * @param classifier the TextClassifier to use to generate the links * @param params optional parameters to specify how to generate the links * @param executor Executor that runs the background task * @param callback Callback that receives the final status of the background task execution * * @return a future that may be used to interrupt or query the background task * @hide */ public static Future<Void> addLinksAsync( @NonNull Spannable text, @NonNull TextClassifier classifier, @Nullable TextLinksParams params, @Nullable Executor executor, @Nullable Consumer<Integer> callback) { return addLinksAsync(text, classifier, params, executor, callback, null /* modifyTextView */); } private static Future<Void> addLinksAsync( @NonNull Spannable text, @NonNull TextClassifier classifier, @Nullable TextLinksParams params, @Nullable Executor executor, @Nullable Consumer<Integer> callback, @Nullable Runnable modifyTextView) { Preconditions.checkNotNull(text); Preconditions.checkNotNull(classifier); // TODO: This is a bug. We shouldnot call getMaxGenerateLinksTextLength() on the UI thread. // The input text may exceed the maximum length the text classifier can handle. In such // cases, we process the text up to the maximum length. final CharSequence truncatedText = text.subSequence( 0, Math.min(text.length(), classifier.getMaxGenerateLinksTextLength())); final TextClassifier.EntityConfig entityConfig = (params == null) ? null : params.getEntityConfig(); final TextLinks.Request request = new TextLinks.Request.Builder(truncatedText) .setLegacyFallback(true) .setEntityConfig(entityConfig) .build(); final Supplier<TextLinks> supplier = () -> classifier.generateLinks(request); final Consumer<TextLinks> consumer = links -> { if (links.getLinks().isEmpty()) { if (callback != null) { callback.accept(TextLinks.STATUS_NO_LINKS_FOUND); } return; } // Remove spans only for the part of the text we generated links for. final TextLinkSpan[] old = text.getSpans(0, truncatedText.length(), TextLinkSpan.class); for (int i = old.length - 1; i >= 0; i--) { text.removeSpan(old[i]); } final @TextLinks.Status int result = params.apply(text, links); if (result == TextLinks.STATUS_LINKS_APPLIED) { if (modifyTextView != null) { modifyTextView.run(); } } if (callback != null) { callback.accept(result); } }; if (executor == null) { return CompletableFuture.supplyAsync(supplier).thenAccept(consumer); } else { return CompletableFuture.supplyAsync(supplier, executor).thenAccept(consumer); } } private static final void applyLink(String url, int start, int end, Spannable text) { URLSpan span = new URLSpan(url); Loading