diff options
| -rw-r--r-- | api/current.txt | 7 | ||||
| -rw-r--r-- | core/java/android/text/util/Linkify.java | 138 |
2 files changed, 133 insertions, 12 deletions
diff --git a/api/current.txt b/api/current.txt index bad0e79cbc54..5e7721d0f42c 100644 --- a/api/current.txt +++ b/api/current.txt @@ -44749,6 +44749,7 @@ package android.text.util { public class Linkify { ctor public Linkify(); method public static final boolean addLinks(android.text.Spannable, int); + method public static final boolean addLinks(android.text.Spannable, int, android.text.util.Linkify.UrlSpanFactory); method public static final boolean addLinks(android.widget.TextView, int); method public static final void addLinks(android.widget.TextView, java.util.regex.Pattern, java.lang.String); method public static final void addLinks(android.widget.TextView, java.util.regex.Pattern, java.lang.String, android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter); @@ -44756,6 +44757,7 @@ package android.text.util { method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String); method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String, android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter); method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String, java.lang.String[], android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter); + method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String, java.lang.String[], android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter, android.text.util.Linkify.UrlSpanFactory); field public static final int ALL = 15; // 0xf field public static final int EMAIL_ADDRESSES = 2; // 0x2 field public static final deprecated int MAP_ADDRESSES = 8; // 0x8 @@ -44774,6 +44776,11 @@ package android.text.util { method public abstract java.lang.String transformUrl(java.util.regex.Matcher, java.lang.String); } + public static class Linkify.UrlSpanFactory { + ctor public Linkify.UrlSpanFactory(); + method public android.text.style.URLSpan create(java.lang.String); + } + public class Rfc822Token { ctor public Rfc822Token(java.lang.String, java.lang.String, java.lang.String); method public java.lang.String getAddress(); diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java index f3d39de18507..55da2ca8a3ec 100644 --- a/core/java/android/text/util/Linkify.java +++ b/core/java/android/text/util/Linkify.java @@ -35,6 +35,7 @@ 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.annotations.GuardedBy; import libcore.util.EmptyArray; @@ -63,6 +64,10 @@ import java.util.regex.Pattern; * does not have a URL scheme prefix, the supplied scheme will be prepended to * create <code>http://example.com</code> when the clickable URL link is * created. + * + * @see MatchFilter + * @see TransformFilter + * @see UrlSpanFactory */ public class Linkify { @@ -218,6 +223,44 @@ public class Linkify { } /** + * Factory class to create {@link URLSpan}s. While adding spans to a {@link Spannable}, + * {@link Linkify} will call {@link UrlSpanFactory#create(String)} function to create a + * {@link URLSpan}. + * + * @see #addLinks(Spannable, int, UrlSpanFactory) + * @see #addLinks(Spannable, Pattern, String, String[], MatchFilter, TransformFilter, + * UrlSpanFactory) + */ + public static class UrlSpanFactory { + private static final Object sInstanceLock = new Object(); + + @GuardedBy("sInstanceLock") + private static volatile UrlSpanFactory sInstance = null; + + private static synchronized UrlSpanFactory getInstance() { + if (sInstance == null) { + synchronized (sInstanceLock) { + if (sInstance == null) { + sInstance = new UrlSpanFactory(); + } + } + } + return sInstance; + } + + /** + * Factory function that will called by {@link Linkify} in order to create a + * {@link URLSpan}. + * + * @param url URL found + * @return a URLSpan instance + */ + public URLSpan create(final String url) { + return new URLSpan(url); + } + } + + /** * Scans the text of the provided Spannable and turns all occurrences * of the link types indicated in the mask into clickable links. * If the mask is nonzero, it also removes any existing URLSpans @@ -228,24 +271,57 @@ public class Linkify { * @param mask Mask to define which kinds of links will be searched. * * @return True if at least one link is found and applied. + * + * @see #addLinks(Spannable, int, UrlSpanFactory) */ public static final boolean addLinks(@NonNull Spannable text, @LinkifyMask int mask) { - return addLinks(text, mask, null); + return addLinks(text, mask, null, null); + } + + /** + * Scans the text of the provided Spannable and turns all occurrences + * of the link types indicated in the mask into clickable links. + * If the mask is nonzero, it also removes any existing URLSpans + * attached to the Spannable, to avoid problems if you call it + * repeatedly on the same text. + * + * @param text Spannable whose text is to be marked-up with links + * @param mask mask to define which kinds of links will be searched + * @param urlSpanFactory factory class used to create {@link URLSpan}s + * @return True if at least one link is found and applied. + * + * @see #addLinks(Spannable, int, UrlSpanFactory) + */ + public static final boolean addLinks(@NonNull Spannable text, @LinkifyMask int mask, + @Nullable UrlSpanFactory urlSpanFactory) { + return addLinks(text, mask, null, null); } + /** + * Scans the text of the provided Spannable and turns all occurrences of the link types + * indicated in the mask into clickable links. If the mask is nonzero, it also removes any + * existing URLSpans attached to the Spannable, to avoid problems if you call it repeatedly + * on the same text. + * + * @param text Spannable whose text is to be marked-up with links + * @param mask mask to define which kinds of links will be searched + * @param context Context to be used while identifying phone numbers + * @param urlSpanFactory factory class used to create {@link URLSpan}s + * @return true if at least one link is found and applied. + */ private static boolean addLinks(@NonNull Spannable text, @LinkifyMask int mask, - @Nullable Context context) { + @Nullable Context context, @Nullable UrlSpanFactory urlSpanFactory) { if (mask == 0) { return false; } - URLSpan[] old = text.getSpans(0, text.length(), URLSpan.class); + final URLSpan[] old = text.getSpans(0, text.length(), URLSpan.class); for (int i = old.length - 1; i >= 0; i--) { text.removeSpan(old[i]); } - ArrayList<LinkSpec> links = new ArrayList<LinkSpec>(); + final ArrayList<LinkSpec> links = new ArrayList<LinkSpec>(); if ((mask & WEB_URLS) != 0) { gatherLinks(links, text, Patterns.AUTOLINK_WEB_URL, @@ -274,7 +350,7 @@ public class Linkify { } for (LinkSpec link: links) { - applyLink(link.url, link.start, link.end, text); + applyLink(link.url, link.start, link.end, text, urlSpanFactory); } return true; @@ -290,6 +366,8 @@ public class Linkify { * @param mask Mask to define which kinds of links will be searched. * * @return True if at least one link is found and applied. + * + * @see #addLinks(Spannable, int, UrlSpanFactory) */ public static final boolean addLinks(@NonNull TextView text, @LinkifyMask int mask) { if (mask == 0) { @@ -299,7 +377,7 @@ public class Linkify { final Context context = text.getContext(); final CharSequence t = text.getText(); if (t instanceof Spannable) { - if (addLinks((Spannable) t, mask, context)) { + if (addLinks((Spannable) t, mask, context, null)) { addLinkMovementMethod(text); return true; } @@ -308,7 +386,7 @@ public class Linkify { } else { SpannableString s = SpannableString.valueOf(t); - if (addLinks(s, mask, context)) { + if (addLinks(s, mask, context, null)) { addLinkMovementMethod(text); text.setText(s); @@ -403,6 +481,8 @@ public class Linkify { * @param pattern Regex pattern to be used for finding links * @param scheme URL scheme string (eg <code>http://</code>) to be * prepended to the links that do not start with this scheme. + * @see #addLinks(Spannable, Pattern, String, String[], MatchFilter, TransformFilter, + * UrlSpanFactory) */ public static final boolean addLinks(@NonNull Spannable text, @NonNull Pattern pattern, @Nullable String scheme) { @@ -423,6 +503,8 @@ public class Linkify { * @param transformFilter Filter to allow the client code to update the link found. * * @return True if at least one link is found and applied. + * @see #addLinks(Spannable, Pattern, String, String[], MatchFilter, TransformFilter, + * UrlSpanFactory) */ public static final boolean addLinks(@NonNull Spannable spannable, @NonNull Pattern pattern, @Nullable String scheme, @Nullable MatchFilter matchFilter, @@ -446,10 +528,39 @@ public class Linkify { * @param transformFilter Filter to allow the client code to update the link found. * * @return True if at least one link is found and applied. + * + * @see #addLinks(Spannable, Pattern, String, String[], MatchFilter, TransformFilter, + * UrlSpanFactory) */ 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) { + return addLinks(spannable, pattern, defaultScheme, schemes, matchFilter, transformFilter, + null); + } + + /** + * Applies a regex to a Spannable turning the matches into links. + * + * @param spannable spannable whose text is to be marked-up with links. + * @param pattern regex pattern to be used for finding links. + * @param defaultScheme the default scheme to be prepended to links if the link does not + * start with one of the <code>schemes</code> given. + * @param schemes array of schemes (eg <code>http://</code>) to check if the link found + * contains a scheme. Passing a null or empty value means prepend + * defaultScheme + * to all links. + * @param matchFilter the filter that is used to allow the client code additional control + * over which pattern matches are to be converted into links. + * @param transformFilter filter to allow the client code to update the link found. + * @param urlSpanFactory factory class used to create {@link URLSpan}s + * + * @return True if at least one link is found and applied. + */ + public static final boolean addLinks(@NonNull Spannable spannable, @NonNull Pattern pattern, + @Nullable String defaultScheme, @Nullable String[] schemes, + @Nullable MatchFilter matchFilter, @Nullable TransformFilter transformFilter, + @Nullable UrlSpanFactory urlSpanFactory) { final String[] schemesCopy; if (defaultScheme == null) defaultScheme = ""; if (schemes == null || schemes.length < 1) { @@ -478,7 +589,7 @@ public class Linkify { if (allowed) { String url = makeUrl(m.group(0), schemesCopy, m, transformFilter); - applyLink(url, start, end, spannable); + applyLink(url, start, end, spannable, urlSpanFactory); hasMatches = true; } } @@ -486,9 +597,12 @@ public class Linkify { return hasMatches; } - private static final void applyLink(String url, int start, int end, Spannable text) { - URLSpan span = new URLSpan(url); - + private static void applyLink(String url, int start, int end, Spannable text, + @Nullable UrlSpanFactory urlSpanFactory) { + if (urlSpanFactory == null) { + urlSpanFactory = UrlSpanFactory.getInstance(); + } + final URLSpan span = urlSpanFactory.create(url); text.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } |