package cl.monsoon.s1next.widget; import android.graphics.drawable.Drawable; import android.text.Editable; import android.text.Html; import android.text.Spannable; import android.text.Spanned; import android.text.style.ImageSpan; import android.text.style.StrikethroughSpan; import android.view.View; import android.webkit.URLUtil; import org.xml.sax.XMLReader; import cl.monsoon.s1next.view.activity.GalleryActivity; /** * Adds {@link android.view.View.OnClickListener} * to {@link android.text.style.ImageSpan} and * handles {@literal <strike>} tag. */ public final class TagHandler implements Html.TagHandler { @Override public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) { if ("img".equalsIgnoreCase(tag)) { handleImg(opening, output); } else if ("strike".equalsIgnoreCase(tag)) { handleStrike(opening, output); } } /** * Replaces {@link android.view.View.OnClickListener} * with {@link cl.monsoon.s1next.widget.TagHandler.ImageClickableSpan}. * <p> * See android.text.HtmlToSpannedConverter#startImg(android.text.SpannableStringBuilder, org.xml.sax.Attributes, android.text.Html.ImageGetter) */ private void handleImg(boolean opening, Editable output) { if (!opening) { int end = output.length(); // \uFFFC: OBJECT REPLACEMENT CHARACTER int len = "\uFFFC".length(); ImageSpan imageSpan = output.getSpans(end - len, end, ImageSpan.class)[0]; String url = imageSpan.getSource(); // replace \uFFFC with ImageSpan's source // in order to support url copy when selected output.replace(end - len, end, url); // image from server doesn't have domain // skip this because we don't want to // make this image (emoticon or something // others) clickable if (URLUtil.isNetworkUrl(url)) { output.removeSpan(imageSpan); // make this ImageSpan clickable output.setSpan(new ImageClickableSpan(imageSpan.getDrawable(), url), end - len, output.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } } } /** * Adds {@link StrikethroughSpan} to {@literal <strike>} tag. * <p> * See android.text.HtmlToSpannedConverter#handleStartTag(java.lang.String, org.xml.sax.Attributes) * See android.text.HtmlToSpannedConverter#handleEndTag(java.lang.String) */ private void handleStrike(boolean opening, Editable output) { int len = output.length(); if (opening) { output.setSpan(new Strike(), len, len, Spannable.SPAN_MARK_MARK); } else { Strike strike = getLastSpan(output, Strike.class); int where = output.getSpanStart(strike); output.removeSpan(strike); if (where != len) { output.setSpan(new StrikethroughSpan(), where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } } } /** * See android.text.HtmlToSpannedConverter#getLast(android.text.Spanned, java.lang.Class) */ private static <T> T getLastSpan(Spanned text, Class<T> kind) { T[] spans = text.getSpans(0, text.length(), kind); if (spans.length == 0) { return null; } else { return spans[spans.length - 1]; } } static final class ImageClickableSpan extends ImageSpan implements View.OnClickListener { private ImageClickableSpan(Drawable d, String source) { super(d, source); } @Override public void onClick(View v) { GalleryActivity.startGalleryActivity(v.getContext(), getSource()); } } private static final class Strike {} }