package org.mtransit.android.util; import java.lang.ref.WeakReference; import java.util.Locale; import java.util.regex.Pattern; import org.mtransit.android.R; import org.mtransit.android.commons.MTLog; import org.mtransit.android.commons.PreferenceUtils; import org.mtransit.android.commons.StoreUtils; import org.mtransit.android.ui.MainActivity; import org.mtransit.android.ui.fragment.WebBrowserFragment; import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.text.Html; import android.text.Layout; import android.text.Spannable; import android.text.SpannableString; import android.text.Spanned; import android.text.SpannedString; import android.text.TextUtils; import android.text.method.LinkMovementMethod; import android.text.style.ClickableSpan; import android.text.style.URLSpan; import android.text.util.Linkify; import android.view.MotionEvent; import android.widget.TextView; public final class LinkUtils implements MTLog.Loggable { private static final String TAG = LinkUtils.class.getSimpleName(); @Override public String getLogTag() { return TAG; } public static CharSequence linkifyHtml(String originalText, boolean isHTML) { try { Spanned text = isHTML ? Html.fromHtml(originalText) : new SpannedString(originalText); URLSpan[] currentSpans = text.getSpans(0, text.length(), URLSpan.class); SpannableString buffer = new SpannableString(text); Linkify.addLinks(buffer, isHTML ? Linkify.EMAIL_ADDRESSES | Linkify.PHONE_NUMBERS | Linkify.MAP_ADDRESSES : Linkify.ALL); for (URLSpan span : currentSpans) { buffer.setSpan(span, text.getSpanStart(span), text.getSpanEnd(span), 0); } return buffer; } catch (Exception e) { MTLog.w(TAG, e, "Error while linkify-ing '%s'!", originalText); return originalText; } } public static boolean open(Activity activity, String url, String label, boolean www) { if (TextUtils.isEmpty(url)) { return false; } if (intercept(activity, url)) { return true; } if (www) { boolean useInternalWebBrowser = PreferenceUtils.getPrefDefault(activity, PreferenceUtils.PREFS_USE_INTERNAL_WEB_BROWSER, PreferenceUtils.PREFS_USE_INTERNAL_WEB_BROWSER_DEFAULT); if (useInternalWebBrowser) { ((MainActivity) activity).addFragmentToStack(WebBrowserFragment.newInstance(url)); return true; } } return org.mtransit.android.commons.LinkUtils.open(activity, Uri.parse(url), label); } public static boolean intercept(Activity activity, String url) { if (StoreUtils.isStoreIntent(url)) { org.mtransit.android.commons.LinkUtils.open(activity, Uri.parse(url), activity.getString(R.string.google_play)); return true; // intercepted } if (LinkUtils.isEmailIntent(url)) { org.mtransit.android.commons.LinkUtils.open(activity, Uri.parse(url), activity.getString(R.string.email)); return true; // intercepted } if (LinkUtils.isPhoneNumberIntent(url)) { org.mtransit.android.commons.LinkUtils.open(activity, Uri.parse(url), activity.getString(R.string.tel)); return true; // intercepted } if (LinkUtils.isPDFIntent(url)) { org.mtransit.android.commons.LinkUtils.open(activity, Uri.parse(url), activity.getString(R.string.file)); return true; // intercepted } if (LinkUtils.isYouTubeIntent(url)) { org.mtransit.android.commons.LinkUtils.open(activity, Uri.parse(url), activity.getString(R.string.video)); return true; // intercepted } return false; // not intercepted } public static boolean open(Activity activity, Uri uri, String label, boolean www) { return org.mtransit.android.commons.LinkUtils.open(activity, uri, label); } public static boolean open(Activity activity, Intent intent, String label, boolean www) { return org.mtransit.android.commons.LinkUtils.open(activity, intent, label); } private static final String EMAIL_SCHEME = "mailto"; public static boolean isEmailIntent(String url) { return isEmailIntent(Uri.parse(url)); } public static boolean isEmailIntent(Uri uri) { if (uri != null) { if (EMAIL_SCHEME.equals(uri.getScheme())) { return true; } } return false; } private static final String TEL_SCHEME = "tel"; public static boolean isPhoneNumberIntent(String url) { return isPhoneNumberIntent(Uri.parse(url)); } public static boolean isPhoneNumberIntent(Uri uri) { if (uri != null) { if (TEL_SCHEME.equals(uri.getScheme())) { return true; } } return false; } private static final String EXT_PDF = ".pdf"; public static boolean isPDFIntent(String url) { if (url != null) { if (url.toLowerCase(Locale.ENGLISH).endsWith(EXT_PDF)) { return true; } } return false; } public static boolean isPDFIntent(Uri uri) { return isPDFIntent(uri == null ? null : uri.toString()); } public static boolean isYouTubeIntent(String url) { return isYouTubeIntent(Uri.parse(url)); } private static final String HTTP_SCHEME = "http"; private static final String HTTPS_SCHEME = "https"; private static final Pattern YOUTUBE_WWW_AUTHORITY_REGEX = Pattern.compile("(youtube\\.com|youtu\\.be)"); public static boolean isYouTubeIntent(Uri uri) { if (uri != null) { if (HTTPS_SCHEME.equals(uri.getScheme()) || HTTP_SCHEME.equals(uri.getScheme())) { if (YOUTUBE_WWW_AUTHORITY_REGEX.matcher(uri.getAuthority()).find()) { return true; } } } return false; } public static class LinkMovementMethodInterceptop extends LinkMovementMethod implements MTLog.Loggable { private static final String TAG = LinkMovementMethodInterceptop.class.getSimpleName(); @Override public String getLogTag() { return TAG; } private static LinkMovementMethodInterceptop sInstance; public static LinkMovementMethodInterceptop getInstance(OnUrlClickListener onUrlClickListener) { if (sInstance == null) { sInstance = new LinkMovementMethodInterceptop(onUrlClickListener); } else { sInstance.setOnUrlClickListener(onUrlClickListener); } return sInstance; } private WeakReference<OnUrlClickListener> onUrlClickListenerWR; public LinkMovementMethodInterceptop(OnUrlClickListener onUrlClickListener) { setOnUrlClickListener(onUrlClickListener); } private void setOnUrlClickListener(OnUrlClickListener onUrlClickListener) { this.onUrlClickListenerWR = new WeakReference<OnUrlClickListener>(onUrlClickListener); } @Override public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) { int action = event.getAction(); if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) { int x = (int) event.getX(); int y = (int) event.getY(); x -= widget.getTotalPaddingLeft(); y -= widget.getTotalPaddingTop(); x += widget.getScrollX(); y += widget.getScrollY(); Layout layout = widget.getLayout(); int line = layout.getLineForVertical(y); int off = layout.getOffsetForHorizontal(line, x); ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); if (link.length != 0) { if (action == MotionEvent.ACTION_UP) { OnUrlClickListener listener = this.onUrlClickListenerWR == null ? null : this.onUrlClickListenerWR.get(); if (listener != null) { if (link[0] instanceof URLSpan) { String url = ((URLSpan) link[0]).getURL(); if (listener.onURLClick(url)) { return true; } } } } } } return super.onTouchEvent(widget, buffer, event); } } public interface OnUrlClickListener { boolean onURLClick(String url); } }