New Linkify.addLinks function with set of known schemes

am: 6eccafd

* commit '6eccafd3394f977d44c329dc75eb12739a818f4b':
  New Linkify.addLinks function with set of known schemes
This commit is contained in:
Siyamed Sinir
2016-03-21 17:35:40 +00:00
committed by android-build-merger
4 changed files with 147 additions and 62 deletions

View File

@@ -39775,8 +39775,10 @@ package android.text.util {
method public static final boolean addLinks(android.widget.TextView, int); 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);
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); 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);
method public static final void addLinks(android.widget.TextView, 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); 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, 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);
field public static final int ALL = 15; // 0xf field public static final int ALL = 15; // 0xf
field public static final int EMAIL_ADDRESSES = 2; // 0x2 field public static final int EMAIL_ADDRESSES = 2; // 0x2
field public static final int MAP_ADDRESSES = 8; // 0x8 field public static final int MAP_ADDRESSES = 8; // 0x8

View File

@@ -42500,8 +42500,10 @@ package android.text.util {
method public static final boolean addLinks(android.widget.TextView, int); 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);
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); 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);
method public static final void addLinks(android.widget.TextView, 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); 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, 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);
field public static final int ALL = 15; // 0xf field public static final int ALL = 15; // 0xf
field public static final int EMAIL_ADDRESSES = 2; // 0x2 field public static final int EMAIL_ADDRESSES = 2; // 0x2
field public static final int MAP_ADDRESSES = 8; // 0x8 field public static final int MAP_ADDRESSES = 8; // 0x8

View File

@@ -39839,8 +39839,10 @@ package android.text.util {
method public static final boolean addLinks(android.widget.TextView, int); 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);
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); 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);
method public static final void addLinks(android.widget.TextView, 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); 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, 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);
field public static final int ALL = 15; // 0xf field public static final int ALL = 15; // 0xf
field public static final int EMAIL_ADDRESSES = 2; // 0x2 field public static final int EMAIL_ADDRESSES = 2; // 0x2
field public static final int MAP_ADDRESSES = 8; // 0x8 field public static final int MAP_ADDRESSES = 8; // 0x8

View File

@@ -16,6 +16,9 @@
package android.text.util; package android.text.util;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.telephony.PhoneNumberUtils; import android.telephony.PhoneNumberUtils;
import android.text.method.LinkMovementMethod; import android.text.method.LinkMovementMethod;
import android.text.method.MovementMethod; import android.text.method.MovementMethod;
@@ -29,6 +32,8 @@ import android.widget.TextView;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@@ -41,19 +46,21 @@ import com.android.i18n.phonenumbers.PhoneNumberMatch;
import com.android.i18n.phonenumbers.PhoneNumberUtil; import com.android.i18n.phonenumbers.PhoneNumberUtil;
import com.android.i18n.phonenumbers.PhoneNumberUtil.Leniency; import com.android.i18n.phonenumbers.PhoneNumberUtil.Leniency;
import libcore.util.EmptyArray;
/** /**
* Linkify take a piece of text and a regular expression and turns all of the * Linkify take a piece of text and a regular expression and turns all of the
* regex matches in the text into clickable links. This is particularly * regex matches in the text into clickable links. This is particularly
* useful for matching things like email addresses, web urls, etc. and making * useful for matching things like email addresses, web URLs, etc. and making
* them actionable. * them actionable.
* *
* Alone with the pattern that is to be matched, a url scheme prefix is also * Alone with the pattern that is to be matched, a URL scheme prefix is also
* required. Any pattern match that does not begin with the supplied scheme * required. Any pattern match that does not begin with the supplied scheme
* will have the scheme prepended to the matched text when the clickable url * will have the scheme prepended to the matched text when the clickable URL
* is created. For instance, if you are matching web urls you would supply * is created. For instance, if you are matching web URLs you would supply
* the scheme <code>http://</code>. If the pattern matches example.com, which * the scheme <code>http://</code>. If the pattern matches example.com, which
* does not have a url scheme prefix, the supplied scheme will be prepended to * 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 * create <code>http://example.com</code> when the clickable URL link is
* created. * created.
*/ */
@@ -97,6 +104,11 @@ public class Linkify {
*/ */
private static final int PHONE_NUMBER_MINIMUM_DIGITS = 5; private static final int PHONE_NUMBER_MINIMUM_DIGITS = 5;
/** @hide */
@IntDef(flag = true, value = { WEB_URLS, EMAIL_ADDRESSES, PHONE_NUMBERS, MAP_ADDRESSES, ALL })
@Retention(RetentionPolicy.SOURCE)
public @interface LinkifyMask {}
/** /**
* Filters out web URL matches that occur after an at-sign (@). This is * Filters out web URL matches that occur after an at-sign (@). This is
* to prevent turning the domain name in an email address into a web link. * to prevent turning the domain name in an email address into a web link.
@@ -152,10 +164,10 @@ public class Linkify {
* MatchFilter enables client code to have more control over * MatchFilter enables client code to have more control over
* what is allowed to match and become a link, and what is not. * what is allowed to match and become a link, and what is not.
* *
* For example: when matching web urls you would like things like * For example: when matching web URLs you would like things like
* http://www.example.com to match, as well as just example.com itelf. * http://www.example.com to match, as well as just example.com itelf.
* However, you would not want to match against the domain in * However, you would not want to match against the domain in
* support@example.com. So, when matching against a web url pattern you * support@example.com. So, when matching against a web URL pattern you
* might also include a MatchFilter that disallows the match if it is * might also include a MatchFilter that disallows the match if it is
* immediately preceded by an at-sign (@). * immediately preceded by an at-sign (@).
*/ */
@@ -203,8 +215,13 @@ public class Linkify {
* If the mask is nonzero, it also removes any existing URLSpans * If the mask is nonzero, it also removes any existing URLSpans
* attached to the Spannable, to avoid problems if you call it * attached to the Spannable, to avoid problems if you call it
* repeatedly on the same text. * 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.
*
* @return True if at least one link is found and applied.
*/ */
public static final boolean addLinks(Spannable text, int mask) { public static final boolean addLinks(@NonNull Spannable text, @LinkifyMask int mask) {
if (mask == 0) { if (mask == 0) {
return false; return false;
} }
@@ -255,8 +272,13 @@ public class Linkify {
* the link types indicated in the mask into clickable links. If matches * the link types indicated in the mask into clickable links. If matches
* are found the movement method for the TextView is set to * are found the movement method for the TextView is set to
* LinkMovementMethod. * LinkMovementMethod.
*
* @param text TextView whose text is to be marked-up with links
* @param mask Mask to define which kinds of links will be searched.
*
* @return True if at least one link is found and applied.
*/ */
public static final boolean addLinks(TextView text, int mask) { public static final boolean addLinks(@NonNull TextView text, @LinkifyMask int mask) {
if (mask == 0) { if (mask == 0) {
return false; return false;
} }
@@ -284,7 +306,7 @@ public class Linkify {
} }
} }
private static final void addLinkMovementMethod(TextView t) { private static final void addLinkMovementMethod(@NonNull TextView t) {
MovementMethod m = t.getMovementMethod(); MovementMethod m = t.getMovementMethod();
if ((m == null) || !(m instanceof LinkMovementMethod)) { if ((m == null) || !(m instanceof LinkMovementMethod)) {
@@ -302,12 +324,12 @@ public class Linkify {
* *
* @param text TextView whose text is to be marked-up with links * @param text TextView whose text is to be marked-up with links
* @param pattern Regex pattern to be used for finding links * @param pattern Regex pattern to be used for finding links
* @param scheme Url scheme string (eg <code>http://</code> to be * @param scheme URL scheme string (eg <code>http://</code>) to be
* prepended to the url of links that do not have * prepended to the links that do not start with this scheme.
* a scheme specified in the link text
*/ */
public static final void addLinks(TextView text, Pattern pattern, String scheme) { public static final void addLinks(@NonNull TextView text, @NonNull Pattern pattern,
addLinks(text, pattern, scheme, null, null); @Nullable String scheme) {
addLinks(text, pattern, scheme, null, null, null);
} }
/** /**
@@ -317,20 +339,45 @@ public class Linkify {
* to LinkMovementMethod. * to LinkMovementMethod.
* *
* @param text TextView whose text is to be marked-up with links * @param text TextView whose text is to be marked-up with links
* @param p Regex pattern to be used for finding links * @param pattern Regex pattern to be used for finding links
* @param scheme Url scheme string (eg <code>http://</code> to be * @param scheme URL scheme string (eg <code>http://</code>) to be
* prepended to the url of links that do not have * prepended to the links that do not start with this scheme.
* a scheme specified in the link text
* @param matchFilter The filter that is used to allow the client code * @param matchFilter The filter that is used to allow the client code
* additional control over which pattern matches are * additional control over which pattern matches are
* to be converted into links. * to be converted into links.
*/ */
public static final void addLinks(TextView text, Pattern p, String scheme, public static final void addLinks(@NonNull TextView text, @NonNull Pattern pattern,
MatchFilter matchFilter, TransformFilter transformFilter) { @Nullable String scheme, @Nullable MatchFilter matchFilter,
SpannableString s = SpannableString.valueOf(text.getText()); @Nullable TransformFilter transformFilter) {
addLinks(text, pattern, scheme, null, matchFilter, transformFilter);
}
if (addLinks(s, p, scheme, matchFilter, transformFilter)) { /**
text.setText(s); * Applies a regex to the text of a TextView turning the matches into
* links. If links are found then UrlSpans are applied to the link
* text match areas, and the movement method for the text is changed
* to LinkMovementMethod.
*
* @param text TextView 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.
*/
public static final void addLinks(@NonNull TextView text, @NonNull Pattern pattern,
@Nullable String defaultScheme, @Nullable String[] schemes,
@Nullable MatchFilter matchFilter, @Nullable TransformFilter transformFilter) {
SpannableString spannable = SpannableString.valueOf(text.getText());
boolean linksAdded = addLinks(spannable, pattern, defaultScheme, schemes, matchFilter,
transformFilter);
if (linksAdded) {
text.setText(spannable);
addLinkMovementMethod(text); addLinkMovementMethod(text);
} }
} }
@@ -339,37 +386,72 @@ public class Linkify {
* Applies a regex to a Spannable turning the matches into * Applies a regex to a Spannable turning the matches into
* links. * links.
* *
* @param text Spannable whose text is to be marked-up with * @param text Spannable whose text is to be marked-up with links
* links
* @param pattern Regex pattern to be used for finding links * @param pattern Regex pattern to be used for finding links
* @param scheme Url scheme string (eg <code>http://</code> to be * @param scheme URL scheme string (eg <code>http://</code>) to be
* prepended to the url of links that do not have * prepended to the links that do not start with this scheme.
* a scheme specified in the link text
*/ */
public static final boolean addLinks(Spannable text, Pattern pattern, String scheme) { public static final boolean addLinks(@NonNull Spannable text, @NonNull Pattern pattern,
return addLinks(text, pattern, scheme, null, null); @Nullable String scheme) {
return addLinks(text, pattern, scheme, null, null, null);
} }
/** /**
* Applies a regex to a Spannable turning the matches into * Applies a regex to a Spannable turning the matches into
* links. * links.
* *
* @param s Spannable whose text is to be marked-up with * @param spannable Spannable whose text is to be marked-up with links
* links * @param pattern Regex pattern to be used for finding links
* @param p Regex pattern to be used for finding links * @param scheme URL scheme string (eg <code>http://</code>) to be
* @param scheme Url scheme string (eg <code>http://</code> to be * prepended to the links that do not start with this scheme.
* prepended to the url of links that do not have * @param matchFilter The filter that is used to allow the client code
* a scheme specified in the link text * additional control over which pattern matches are
* @param matchFilter The filter that is used to allow the client code * to be converted into links.
* additional control over which pattern matches are * @param transformFilter Filter to allow the client code to update the link found.
* to be converted into links. *
* @return True if at least one link is found and applied.
*/ */
public static final boolean addLinks(Spannable s, Pattern p, public static final boolean addLinks(@NonNull Spannable spannable, @NonNull Pattern pattern,
String scheme, MatchFilter matchFilter, @Nullable String scheme, @Nullable MatchFilter matchFilter,
TransformFilter transformFilter) { @Nullable TransformFilter transformFilter) {
return addLinks(spannable, pattern, scheme, null, matchFilter,
transformFilter);
}
/**
* 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.
*
* @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) {
final String[] schemesCopy;
if (defaultScheme == null) defaultScheme = "";
if (schemes == null || schemes.length < 1) {
schemes = EmptyArray.STRING;
}
schemesCopy = new String[schemes.length + 1];
schemesCopy[0] = defaultScheme.toLowerCase(Locale.ROOT);
for (int index = 0; index < schemes.length; index++) {
String scheme = schemes[index];
schemesCopy[index + 1] = (scheme == null) ? "" : scheme.toLowerCase(Locale.ROOT);
}
boolean hasMatches = false; boolean hasMatches = false;
String prefix = (scheme == null) ? "" : scheme.toLowerCase(Locale.ROOT); Matcher m = pattern.matcher(spannable);
Matcher m = p.matcher(s);
while (m.find()) { while (m.find()) {
int start = m.start(); int start = m.start();
@@ -377,14 +459,13 @@ public class Linkify {
boolean allowed = true; boolean allowed = true;
if (matchFilter != null) { if (matchFilter != null) {
allowed = matchFilter.acceptMatch(s, start, end); allowed = matchFilter.acceptMatch(spannable, start, end);
} }
if (allowed) { if (allowed) {
String url = makeUrl(m.group(0), new String[] { prefix }, String url = makeUrl(m.group(0), schemesCopy, m, transformFilter);
m, transformFilter);
applyLink(url, start, end, s); applyLink(url, start, end, spannable);
hasMatches = true; hasMatches = true;
} }
} }
@@ -398,22 +479,20 @@ public class Linkify {
text.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); text.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
} }
private static final String makeUrl(String url, String[] prefixes, private static final String makeUrl(@NonNull String url, @NonNull String[] prefixes,
Matcher m, TransformFilter filter) { Matcher matcher, @Nullable TransformFilter filter) {
if (filter != null) { if (filter != null) {
url = filter.transformUrl(m, url); url = filter.transformUrl(matcher, url);
} }
boolean hasPrefix = false; boolean hasPrefix = false;
for (int i = 0; i < prefixes.length; i++) { for (int i = 0; i < prefixes.length; i++) {
if (url.regionMatches(true, 0, prefixes[i], 0, if (url.regionMatches(true, 0, prefixes[i], 0, prefixes[i].length())) {
prefixes[i].length())) {
hasPrefix = true; hasPrefix = true;
// Fix capitalization if necessary // Fix capitalization if necessary
if (!url.regionMatches(false, 0, prefixes[i], 0, if (!url.regionMatches(false, 0, prefixes[i], 0, prefixes[i].length())) {
prefixes[i].length())) {
url = prefixes[i] + url.substring(prefixes[i].length()); url = prefixes[i] + url.substring(prefixes[i].length());
} }
@@ -421,7 +500,7 @@ public class Linkify {
} }
} }
if (!hasPrefix) { if (!hasPrefix && prefixes.length > 0) {
url = prefixes[0] + url; url = prefixes[0] + url;
} }