package com.datdo.mobilib.util;
import android.text.TextUtils;
import android.util.Patterns;
import android.widget.TextView;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* <pre>
* Recognize links (email, web-url, phone) in a {@link String} and build new HTML {@link String} which wraps links in "{@literal <}a>...{@literal <}/a>".
* This class is used together with {@link MblLinkMovementMethod}.
*
* Here is sample usage:
* <code>
* String html = MblLinkRecognizer.getLinkRecognizedHtmlText(text);
* textView.setText(Html.fromHtml(html));
* textView.setMovementMethod(new MblLinkMovementMethod(new MblLinkMovementMethodCallback() {
* {@literal @}Override
* public void onLinkClicked(final String link) {
* // ...
* }
*
* {@literal @}Override
* public void onLongClicked() {
* // ...
* }
* }));
* </code>
*
* @see MblViewUtil#displayTextWithLinks(TextView, String, MblOptions, MblLinkMovementMethod.MblLinkMovementMethodCallback)
* </pre>
*/
public class MblLinkRecognizer {
private static final String HTTP_PREFIX_PATTERN = "[Hh][Tt][Tt][Pp]://";
private static final String HTTPS_PREFIX_PATTERN = "[Hh][Tt][Tt][Pp][Ss]://";
private static final String LINK_BODY_PATTERN = "[^\\s]+";
private static final String HTTP_PATTERN = HTTP_PREFIX_PATTERN + LINK_BODY_PATTERN;
private static final String HTTPS_PATTERN = HTTPS_PREFIX_PATTERN + LINK_BODY_PATTERN;
static final Pattern pattern = Pattern.compile(Patterns.EMAIL_ADDRESS + "|" + Patterns.WEB_URL + "|" + Patterns.PHONE);
StringBuilder result = new StringBuilder();
StringBuilder source;
MblOptions options;
public static class MblOptions {
private boolean mRecognizeEmail;
private boolean mRecognizeWebUrl;
private boolean mRecognizePhone;
public MblOptions setRecognizeEmail(boolean recognizeEmail) {
mRecognizeEmail = recognizeEmail;
return this;
}
public MblOptions setRecognizeWebUrl(boolean recognizeWebUrl) {
mRecognizeWebUrl = recognizeWebUrl;
return this;
}
public MblOptions setRecognizePhone(boolean recognizePhone) {
mRecognizePhone = recognizePhone;
return this;
}
}
/**
* <pre>
* Recognize links in a String and build new HTML String which wraps links in "<a>...</a>".
* </pre>
*/
public static String getLinkRecognizedHtmlText(String text, MblOptions options) {
return new MblLinkRecognizer(text, options).getResult();
}
private MblLinkRecognizer(String s, MblOptions options) {
if (s == null) s = "";
source = new StringBuilder(s);
this.options = options != null ? options : new MblOptions();
}
private String getResult() {
while (source.length() > 0) {
Matcher matcher = pattern.matcher(source.toString());
if (!matcher.find()) matcher = null;
if (replaceRegex(matcher)) continue;
result.append(replaceChars(source.toString()));
break;
}
return result.toString();
}
private boolean replaceRegex(Matcher m) {
if (m == null) return false;
String text = m.group();
result.append(replaceChars(source.substring(0, m.start())));
if (isEmail(text)) {
if (options.mRecognizeEmail) {
result.append("<a " + "href=\"mailto:" + text + "\">" + text + "</a>");
} else {
result.append(text);
}
} if (isWebUrl(text)) {
if (options.mRecognizeWebUrl) {
result.append("<a " + "href=\"" + lowerCaseHttpxPrefix(replaceChars(text)) + "\">" + replaceChars(text) + "</a>");
} else {
result.append(text);
}
} else if (isPhone(text)) {
if (options.mRecognizePhone) {
result.append("<a " + "href=\"tel:" + text + "\">" + text + "</a>");
} else {
result.append(text);
}
}
source.delete(0, m.end());
return true;
}
private String replaceChars(String s) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
sb.append(replaceChar(s.charAt(i)));
}
return sb.toString();
}
private String replaceChar(char c) {
String r = "" + c;
switch (c) {
case '&': r = "&"; break;
case '\"': r = """; break;
case '<': r = "<"; break;
case '>': r = ">"; break;
case ' ': r = " "; break;
case '\n': r = "<br>"; break;
default: break;
}
return r;
}
static boolean isLink(String s) {
return !TextUtils.isEmpty(s) && pattern.matcher(s).matches();
}
static boolean isWebUrl(String s) {
return !TextUtils.isEmpty(s) && Patterns.WEB_URL.matcher(s).matches();
}
static boolean isEmail(String s) {
return !TextUtils.isEmpty(s) && Patterns.EMAIL_ADDRESS.matcher(s).matches();
}
static boolean isPhone(String s) {
return !TextUtils.isEmpty(s) && Patterns.PHONE.matcher(s).matches();
}
// android do not understand prefixes like "HTtP" or "hTtP"
// so we need to make all http/https prefixes lower-case
static String lowerCaseHttpxPrefix(String link) {
if (TextUtils.isEmpty(link)) return link;
String ret;
if (link.matches(HTTP_PATTERN)) {
ret = link.replaceFirst(HTTP_PREFIX_PATTERN, "http://");
} else if (link.matches(HTTPS_PATTERN)) {
ret = link.replaceFirst(HTTPS_PREFIX_PATTERN, "https://");
} else {
ret = link;
}
return ret;
}
}