private void notifyCommitComposition() { // Gecko already committed its composition, and // we should remove the composition on our side as well. boolean wasComposing = false; final Object[] spans = mText.getSpans(0, mText.length(), Object.class); for (Object span : spans) { if ((mText.getSpanFlags(span) & Spanned.SPAN_COMPOSING) != 0) { mText.removeSpan(span); wasComposing = true; } } if (!wasComposing) { return; } // Generate a text change notification if we actually cleared the composition. final CharSequence text = TextUtils.stringOrSpannedString(mText); geckoPostToIc( new Runnable() { @Override public void run() { mListener.onTextChange(text, 0, text.length(), text.length()); } }); }
private void geckoActionReply() { if (DEBUG) { // GeckoEditableListener methods should all be called from the Gecko thread ThreadUtils.assertOnGeckoThread(); } final Action action = mActionQueue.peek(); if (action == null) { throw new IllegalStateException("empty actions queue"); } if (DEBUG) { Log.d(LOGTAG, "reply: Action(" + getConstantName(Action.class, "TYPE_", action.mType) + ")"); } switch (action.mType) { case Action.TYPE_SET_SELECTION: final int len = mText.length(); final int curStart = Selection.getSelectionStart(mText); final int curEnd = Selection.getSelectionEnd(mText); // start == -1 when the start offset should remain the same // end == -1 when the end offset should remain the same final int selStart = Math.min(action.mStart < 0 ? curStart : action.mStart, len); final int selEnd = Math.min(action.mEnd < 0 ? curEnd : action.mEnd, len); if (selStart < action.mStart || selEnd < action.mEnd) { Log.w(LOGTAG, "IME sync error: selection out of bounds"); } Selection.setSelection(mText, selStart, selEnd); geckoPostToIc( new Runnable() { @Override public void run() { mActionQueue.syncWithGecko(); final int start = Selection.getSelectionStart(mText); final int end = Selection.getSelectionEnd(mText); if (selStart == start && selEnd == end) { // There has not been another new selection in the mean time that // made this notification out-of-date mListener.onSelectionChange(start, end); } } }); break; case Action.TYPE_SET_SPAN: mText.setSpan(action.mSpanObject, action.mStart, action.mEnd, action.mSpanFlags); break; case Action.TYPE_REMOVE_SPAN: mText.removeSpan(action.mSpanObject); break; case Action.TYPE_SET_HANDLER: geckoSetIcHandler(action.mHandler); break; } if (action.mShouldUpdate) { geckoUpdateGecko(false); } }
private void clearCachedMark(SpannableStringBuilder ssb) { Cached[] cs = ssb.getSpans(0, ssb.length(), Cached.class); if (cs != null && cs.length > 0) { for (Cached c : cs) { ssb.removeSpan(c); } } }
private void resetLinkSpan(SpannableStringBuilder ssb, RichTextConfig config, URLSpan urlSpan) { int start = ssb.getSpanStart(urlSpan); int end = ssb.getSpanEnd(urlSpan); ssb.removeSpan(urlSpan); LinkHolder linkHolder = new LinkHolder(urlSpan.getURL()); if (config.linkFixCallback != null) { config.linkFixCallback.fix(linkHolder); } LongClickableURLSpan longClickableURLSpan = new LongClickableURLSpan( linkHolder, config.onUrlClickListener, config.onUrlLongClickListener); ssb.setSpan(longClickableURLSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); }
protected void makeLinkClickable( SpannableStringBuilder strBuilder, final URLSpan span, final Activity c) { int start = strBuilder.getSpanStart(span); int end = strBuilder.getSpanEnd(span); int flags = strBuilder.getSpanFlags(span); final ClickableSpan clickable = new ClickableSpan() { public void onClick(View view) { // TODO make clickable ContentOpen.openingText(url, true, c); } }; strBuilder.setSpan(clickable, start, end, flags); strBuilder.removeSpan(span); }
public static void setTextWithIcon(Context context, TextView textView, String text) { Spanned html = Html.fromHtml(text); SpannableStringBuilder builder = new SpannableStringBuilder(html); ImageSpan[] images = builder.getSpans(0, builder.length(), ImageSpan.class); if (images != null && images.length > 0) { ImageSpan imagePlaceholder = images[0]; int start = builder.getSpanStart(imagePlaceholder); int end = builder.getSpanEnd(imagePlaceholder); int flags = builder.getSpanFlags(imagePlaceholder); ImageSpan imageSpan = new ImageSpan(context, R.drawable.lock_icon, ImageSpan.ALIGN_BASELINE); builder.setSpan(imageSpan, start, end, flags); builder.removeSpan(imagePlaceholder); } textView.setText(builder); }
private void handleClick(SpannableStringBuilder ssb, RichTextConfig config, boolean cached) { if (cached) { LongClickableURLSpan[] lcus = ssb.getSpans(0, ssb.length(), LongClickableURLSpan.class); if (lcus != null && lcus.length > 0) { for (LongClickableURLSpan lcu : lcus) { resetLinkSpan(ssb, config, lcu); } } } else { if (config.clickable >= 0) { // 处理超链接点击事件 URLSpan[] urlSpans = ssb.getSpans(0, ssb.length(), URLSpan.class); for (int i = 0, size = urlSpans == null ? 0 : urlSpans.length; i < size; i++) { resetLinkSpan(ssb, config, urlSpans[i]); } } else { // 移除URLSpan URLSpan[] urlSpans = ssb.getSpans(0, ssb.length(), URLSpan.class); for (int i = 0, size = urlSpans == null ? 0 : urlSpans.length; i < size; i++) { ssb.removeSpan(urlSpans[i]); } } } }
private int handleImage( SpannableStringBuilder ssb, ImageGetterWrapper imageGetterWrapper, RichTextConfig config, boolean cached) { if (cached) { ClickableImageSpan[] cis = ssb.getSpans(0, ssb.length(), ClickableImageSpan.class); if (cis != null && cis.length > 0) { for (ClickableImageSpan ci : cis) { int start = ssb.getSpanStart(ci); int end = ssb.getSpanEnd(ci); ssb.removeSpan(ci); OnImageClickListener onImageClickListener = null; OnImageLongClickListener onImageLongClickListener = null; if (config.clickable > 0) { onImageClickListener = config.onImageClickListener; onImageLongClickListener = config.onImageLongClickListener; } Drawable drawable = imageGetterWrapper.getDrawable(ci.getSource()); if (drawable == null) { drawable = new ColorDrawable(Color.TRANSPARENT); } ClickableImageSpan nci = new ClickableImageSpan(drawable, ci, onImageClickListener, onImageLongClickListener); ssb.setSpan(nci, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } return cis.length; } } else if (!config.noImage) { ImageSpan[] iss = ssb.getSpans(0, ssb.length(), ImageSpan.class); if (iss != null && iss.length > 0) { ArrayList<String> imageUrls = new ArrayList<>(iss.length); for (int i = 0; i < iss.length; i++) { ImageSpan imageSpan = iss[i]; String imageUrl = imageSpan.getSource(); imageUrls.add(imageUrl); int start = ssb.getSpanStart(imageSpan); int end = ssb.getSpanEnd(imageSpan); ClickableSpan[] clickableSpans = ssb.getSpans(start, end, ClickableSpan.class); if (clickableSpans != null && clickableSpans.length != 0) { for (ClickableSpan cs : clickableSpans) { ssb.removeSpan(cs); } } OnImageClickListener onImageClickListener = null; OnImageLongClickListener onImageLongClickListener = null; if (config.clickable > 0) { onImageClickListener = config.onImageClickListener; onImageLongClickListener = config.onImageLongClickListener; } Drawable drawable = imageGetterWrapper.getDrawable(imageUrl); if (drawable == null) { drawable = new ColorDrawable(Color.TRANSPARENT); } ClickableImageSpan cacheImageSpan = new ClickableImageSpan( drawable, imageUrls, i, onImageClickListener, onImageLongClickListener); ssb.removeSpan(imageSpan); ssb.setSpan(cacheImageSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } return iss.length; } } return 0; }