Linkifypublic class Linkify extends Object 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
useful for matching things like email addresses, web urls, etc. and making
them actionable.
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
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
the scheme http:// . If the pattern matches example.com, which
does not have a url scheme prefix, the supplied scheme will be prepended to
create http://example.com when the clickable url link is
created. |
Fields Summary |
---|
public static final int | WEB_URLSBit field indicating that web URLs should be matched in methods that
take an options mask | public static final int | EMAIL_ADDRESSESBit field indicating that email addresses should be matched in methods
that take an options mask | public static final int | PHONE_NUMBERSBit field indicating that phone numbers should be matched in methods that
take an options mask | public static final int | MAP_ADDRESSESBit field indicating that street addresses should be matched in methods that
take an options mask | public static final int | ALLBit mask indicating that all available patterns should be matched in
methods that take an options mask | private static final int | PHONE_NUMBER_MINIMUM_DIGITSDon't treat anything with fewer than this many digits as a
phone number. | public static final MatchFilter | sUrlMatchFilterFilters 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. | public static final MatchFilter | sPhoneNumberMatchFilterFilters out URL matches that don't have enough digits to be a
phone number. | public static final TransformFilter | sPhoneNumberTransformFilterTransforms matched phone number text into something suitable
to be used in a tel: URL. It does this by removing everything
but the digits and plus signs. For instance:
'+1 (919) 555-1212'
becomes '+19195551212' |
Methods Summary |
---|
private static final void | addLinkMovementMethod(android.widget.TextView t)
MovementMethod m = t.getMovementMethod();
if ((m == null) || !(m instanceof LinkMovementMethod)) {
if (t.getLinksClickable()) {
t.setMovementMethod(LinkMovementMethod.getInstance());
}
}
| public static final boolean | addLinks(android.text.Spannable text, int mask)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.
if (mask == 0) {
return false;
}
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>();
if ((mask & WEB_URLS) != 0) {
gatherLinks(links, text, Patterns.WEB_URL,
new String[] { "http://", "https://", "rtsp://" },
sUrlMatchFilter, null);
}
if ((mask & EMAIL_ADDRESSES) != 0) {
gatherLinks(links, text, Patterns.EMAIL_ADDRESS,
new String[] { "mailto:" },
null, null);
}
if ((mask & PHONE_NUMBERS) != 0) {
gatherTelLinks(links, text);
}
if ((mask & MAP_ADDRESSES) != 0) {
gatherMapLinks(links, text);
}
pruneOverlaps(links);
if (links.size() == 0) {
return false;
}
for (LinkSpec link: links) {
applyLink(link.url, link.start, link.end, text);
}
return true;
| public static final boolean | addLinks(android.widget.TextView text, int mask)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
LinkMovementMethod.
if (mask == 0) {
return false;
}
CharSequence t = text.getText();
if (t instanceof Spannable) {
if (addLinks((Spannable) t, mask)) {
addLinkMovementMethod(text);
return true;
}
return false;
} else {
SpannableString s = SpannableString.valueOf(t);
if (addLinks(s, mask)) {
addLinkMovementMethod(text);
text.setText(s);
return true;
}
return false;
}
| public static final void | addLinks(android.widget.TextView text, java.util.regex.Pattern pattern, java.lang.String scheme)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.
addLinks(text, pattern, scheme, null, null);
| public static final void | addLinks(android.widget.TextView text, java.util.regex.Pattern p, java.lang.String scheme, android.text.util.Linkify$MatchFilter matchFilter, android.text.util.Linkify$TransformFilter transformFilter)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.
SpannableString s = SpannableString.valueOf(text.getText());
if (addLinks(s, p, scheme, matchFilter, transformFilter)) {
text.setText(s);
addLinkMovementMethod(text);
}
| public static final boolean | addLinks(android.text.Spannable text, java.util.regex.Pattern pattern, java.lang.String scheme)Applies a regex to a Spannable turning the matches into
links.
return addLinks(text, pattern, scheme, null, null);
| public static final boolean | addLinks(android.text.Spannable s, java.util.regex.Pattern p, java.lang.String scheme, android.text.util.Linkify$MatchFilter matchFilter, android.text.util.Linkify$TransformFilter transformFilter)Applies a regex to a Spannable turning the matches into
links.
boolean hasMatches = false;
String prefix = (scheme == null) ? "" : scheme.toLowerCase(Locale.ROOT);
Matcher m = p.matcher(s);
while (m.find()) {
int start = m.start();
int end = m.end();
boolean allowed = true;
if (matchFilter != null) {
allowed = matchFilter.acceptMatch(s, start, end);
}
if (allowed) {
String url = makeUrl(m.group(0), new String[] { prefix },
m, transformFilter);
applyLink(url, start, end, s);
hasMatches = true;
}
}
return hasMatches;
| private static final void | applyLink(java.lang.String url, int start, int end, android.text.Spannable text)
URLSpan span = new URLSpan(url);
text.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
| private static final void | gatherLinks(java.util.ArrayList links, android.text.Spannable s, java.util.regex.Pattern pattern, java.lang.String[] schemes, android.text.util.Linkify$MatchFilter matchFilter, android.text.util.Linkify$TransformFilter transformFilter)
Matcher m = pattern.matcher(s);
while (m.find()) {
int start = m.start();
int end = m.end();
if (matchFilter == null || matchFilter.acceptMatch(s, start, end)) {
LinkSpec spec = new LinkSpec();
String url = makeUrl(m.group(0), schemes, m, transformFilter);
spec.url = url;
spec.start = start;
spec.end = end;
links.add(spec);
}
}
| private static final void | gatherMapLinks(java.util.ArrayList links, android.text.Spannable s)
String string = s.toString();
String address;
int base = 0;
try {
while ((address = WebView.findAddress(string)) != null) {
int start = string.indexOf(address);
if (start < 0) {
break;
}
LinkSpec spec = new LinkSpec();
int length = address.length();
int end = start + length;
spec.start = base + start;
spec.end = base + end;
string = string.substring(end);
base += end;
String encodedAddress = null;
try {
encodedAddress = URLEncoder.encode(address,"UTF-8");
} catch (UnsupportedEncodingException e) {
continue;
}
spec.url = "geo:0,0?q=" + encodedAddress;
links.add(spec);
}
} catch (UnsupportedOperationException e) {
// findAddress may fail with an unsupported exception on platforms without a WebView.
// In this case, we will not append anything to the links variable: it would have died
// in WebView.findAddress.
return;
}
| private static final void | gatherTelLinks(java.util.ArrayList links, android.text.Spannable s)
PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
Iterable<PhoneNumberMatch> matches = phoneUtil.findNumbers(s.toString(),
Locale.getDefault().getCountry(), Leniency.POSSIBLE, Long.MAX_VALUE);
for (PhoneNumberMatch match : matches) {
LinkSpec spec = new LinkSpec();
spec.url = "tel:" + PhoneNumberUtils.normalizeNumber(match.rawString());
spec.start = match.start();
spec.end = match.end();
links.add(spec);
}
| private static final java.lang.String | makeUrl(java.lang.String url, java.lang.String[] prefixes, java.util.regex.Matcher m, android.text.util.Linkify$TransformFilter filter)
if (filter != null) {
url = filter.transformUrl(m, url);
}
boolean hasPrefix = false;
for (int i = 0; i < prefixes.length; i++) {
if (url.regionMatches(true, 0, prefixes[i], 0,
prefixes[i].length())) {
hasPrefix = true;
// Fix capitalization if necessary
if (!url.regionMatches(false, 0, prefixes[i], 0,
prefixes[i].length())) {
url = prefixes[i] + url.substring(prefixes[i].length());
}
break;
}
}
if (!hasPrefix) {
url = prefixes[0] + url;
}
return url;
| private static final void | pruneOverlaps(java.util.ArrayList links)
Comparator<LinkSpec> c = new Comparator<LinkSpec>() {
public final int compare(LinkSpec a, LinkSpec b) {
if (a.start < b.start) {
return -1;
}
if (a.start > b.start) {
return 1;
}
if (a.end < b.end) {
return 1;
}
if (a.end > b.end) {
return -1;
}
return 0;
}
public final boolean equals(Object o) {
return false;
}
};
Collections.sort(links, c);
int len = links.size();
int i = 0;
while (i < len - 1) {
LinkSpec a = links.get(i);
LinkSpec b = links.get(i + 1);
int remove = -1;
if ((a.start <= b.start) && (a.end > b.start)) {
if (b.end <= a.end) {
remove = i + 1;
} else if ((a.end - a.start) > (b.end - b.start)) {
remove = i + 1;
} else if ((a.end - a.start) < (b.end - b.start)) {
remove = i;
}
if (remove != -1) {
links.remove(remove);
len--;
continue;
}
}
i++;
}
|
|