Java Code Examples for android.text.Spannable#getSpans()

The following examples show how to use android.text.Spannable#getSpans() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: LinkTouchMovementMethod.java    From BigApp_Discuz_Android with Apache License 2.0 6 votes vote down vote up
TouchableSpan getPressedSpan(TextView textView, Spannable spannable, MotionEvent event) {

        int x = (int) event.getX();
        int y = (int) event.getY();

        x -= textView.getTotalPaddingLeft();
        y -= textView.getTotalPaddingTop();

        x += textView.getScrollX();
        y += textView.getScrollY();

        Layout layout = textView.getLayout();
        int line = layout.getLineForVertical(y);
        int off = layout.getOffsetForHorizontal(line, x);

        TouchableSpan[] link = spannable.getSpans(off, off, TouchableSpan.class);
        TouchableSpan touchedSpan = null;
        if (link.length > 0) {
            touchedSpan = link[0];
        }
        return touchedSpan;
    }
 
Example 2
Source File: RTEditorMovementMethod.java    From memoir with Apache License 2.0 6 votes vote down vote up
@Override
public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
    int action = event.getAction();

    if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) {

        int index = getCharIndexAt(widget, event);
        if (index != -1) {
            ClickableSpan[] link = buffer.getSpans(index, index, ClickableSpan.class);
            if (link.length != 0) {
                if (action == MotionEvent.ACTION_UP) {
                    link[0].onClick(widget);
                } else if (action == MotionEvent.ACTION_DOWN) {
                    Selection.setSelection(buffer, buffer.getSpanStart(link[0]), buffer.getSpanEnd(link[0]));
                }
                return true;
            }
        }
        /*else {
            Selection.removeSelection(buffer);
        }*/

    }

    return super.onTouchEvent(widget, buffer, event);
}
 
Example 3
Source File: CustomLinkMovementMethod.java    From SimplifySpan with MIT License 6 votes vote down vote up
private CustomClickableSpan getPressedSpan(TextView textView, Spannable spannable, MotionEvent event) {
    int x = (int) event.getX();
    int y = (int) event.getY();

    x -= textView.getTotalPaddingLeft();
    y -= textView.getTotalPaddingTop();

    x += textView.getScrollX();
    y += textView.getScrollY();

    Layout layout = textView.getLayout();
    int line = layout.getLineForVertical(y);
    int off = layout.getOffsetForHorizontal(line, x);

    CustomClickableSpan[] link = spannable.getSpans(off, off, CustomClickableSpan.class);
    CustomClickableSpan touchedSpan = null;
    if (link.length > 0) {
        touchedSpan = link[0];
    }
    return touchedSpan;
}
 
Example 4
Source File: SelectableLinkMovementMethod.java    From mimi-reader with Apache License 2.0 5 votes vote down vote up
@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) {
                link[0].onClick(widget);
            } else if (action == MotionEvent.ACTION_DOWN) {
                Selection.setSelection(buffer, buffer.getSpanStart(link[0]), buffer.getSpanEnd(link[0]));
            }

            return true;
        }
        /*else {
            that's the line we need to remove
            Selection.removeSelection(buffer);
        }*/
    }

    return super.onTouchEvent(widget, buffer, event);
}
 
Example 5
Source File: LinkMovementMethod.java    From ForPDA with GNU General Public License v3.0 5 votes vote down vote up
@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) {
                String url = ((URLSpan) link[0]).getURL();
                if (!IntentHandler.handle(url))
                    link[0].onClick(widget);
            } else {
                Selection.setSelection(buffer,
                        buffer.getSpanStart(link[0]),
                        buffer.getSpanEnd(link[0]));
            }
            return true;
        } else {
            Selection.removeSelection(buffer);
        }
    }
    return super.onTouchEvent(widget, buffer, event);
}
 
Example 6
Source File: DisplaySpans.java    From brailleback with Apache License 2.0 5 votes vote down vote up
/**
 * Recycles objects owned by the spannable.  In particular, any
 * accessibility nodes that have been associated with {@code spannable}
 * are recycled and removed.
 */
public static void recycleSpans(CharSequence chars) {
    if (!(chars instanceof Spannable)) {
        return;
    }
    Spannable spannable = (Spannable) chars;
    AccessibilityNodeInfoCompat[] nodes = spannable.getSpans(
        0, spannable.length(), AccessibilityNodeInfoCompat.class);
    for (AccessibilityNodeInfoCompat node : nodes) {
        node.recycle();
        spannable.removeSpan(node);
    }
}
 
Example 7
Source File: Touch.java    From JotaTextEditor with Apache License 2.0 5 votes vote down vote up
public static void cancelFling(TextView widget, Spannable buffer)
{
    DragState[] ds;

    ds = buffer.getSpans(0, buffer.length(), DragState.class);

    if ( ds.length > 0 ){
        if ( ds[0].mFlingRunnable != null ){
            ds[0].mFlingRunnable.endFling();
            widget.cancelLongPress();
        }
    }

}
 
Example 8
Source File: AlignToPointSpan.java    From revolution-irc with GNU General Public License v3.0 5 votes vote down vote up
public static CharSequence apply(TextView textView, CharSequence text) {
    if (text == null || !(text instanceof Spannable))
        return text;
    Spannable s = (Spannable) text;
    for (AlignToPointSpan span : s.getSpans(0, text.length(),
            AlignToPointSpan.class)) {
        span.mMargin = (int) Layout.getDesiredWidth(text, 0, s.getSpanStart(span.mAnchor),
                textView.getPaint());
    }
    return text;
}
 
Example 9
Source File: LinkMovementClickMethod.java    From imsdk-android with MIT License 5 votes vote down vote up
@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) {
                if(System.currentTimeMillis() - lastClickTime < CLICK_DELAY){
                    link[0].onClick(widget);
                }
            } else if (action == MotionEvent.ACTION_DOWN) {
                Selection.setSelection(buffer,
                        buffer.getSpanStart(link[0]),
                        buffer.getSpanEnd(link[0]));
                lastClickTime = System.currentTimeMillis();
            }

            return true;
        } else {
            Selection.removeSelection(buffer);
        }
    }
    return super.onTouchEvent(widget, buffer, event);
}
 
Example 10
Source File: WeiboTextView.java    From BigApp_Discuz_Android with Apache License 2.0 4 votes vote down vote up
@Override
        public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
            int action = event.getAction();

//            LogUtils.printLog(WeiboTextView.class, "MotionEvent:" + action);

//            if (action == MotionEvent.ACTION_MOVE) {
//                isPressed = false;
//            }
            switch (action) {
                case MotionEvent.ACTION_DOWN:
                    break;
                case MotionEvent.ACTION_UP:
                    break;

                case MotionEvent.ACTION_CANCEL:
                    buffer.setSpan(new BackgroundColorSpan(0x00000000), 0, weiboTextView.length(),
                            Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                    Selection.setSelection(buffer, 0, weiboTextView.length());
                    break;
            }


            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) {

                    int start = buffer.getSpanStart(link[0]);
                    int end = buffer.getSpanEnd(link[0]);

//                    LogUtils.printLog(WebViewUtils.class, "start:" + start + " end:" + end);

                    if (action == MotionEvent.ACTION_UP) {
                        link[0].onClick(widget);
                        buffer.setSpan(new BackgroundColorSpan(0x00000000), start, end,
                                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                        Selection.setSelection(buffer, start, end);
                    } else if (action == MotionEvent.ACTION_DOWN) {
                        buffer.setSpan(new BackgroundColorSpan(weiboTextView.clickBgClolr), start, end,
                                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                        Selection.setSelection(buffer, start, end);
                    }

                    if (widget instanceof WeiboTextView) {
                        ((WeiboTextView) widget).linkHit = true;
                    }
                    return true;
                } else {
                    Selection.removeSelection(buffer);
                    Touch.onTouchEvent(widget, buffer, event);
                    return false;
                }
            }


            return Touch.onTouchEvent(widget, buffer, event);
        }
 
Example 11
Source File: SpanCollector.java    From memoir with Apache License 2.0 4 votes vote down vote up
/**
 * Return an array of the markup objects attached to the specified slice of a Spannable and whose
 * type is the specified type or a subclass of it (see Spanned.getSpans(int, int, Class<T>)).
 */
protected final RTSpan<V>[] getSpansAndroid(Spannable str, int selStart, int selEnd) {
    RTSpan<V>[] spans = str.getSpans(selStart, selEnd, mSpanClazz);
    return spans == null ? (RTSpan<V>[]) Array.newInstance(mSpanClazz) : spans;
}
 
Example 12
Source File: SocialViewHelper.java    From socialview with Apache License 2.0 4 votes vote down vote up
private void recolorize() {
    final CharSequence text = view.getText();
    if (!(text instanceof Spannable)) {
        throw new IllegalStateException("Attached text is not a Spannable," +
            "add TextView.BufferType.SPANNABLE when setting text to this TextView.");
    }
    final Spannable spannable = (Spannable) text;
    for (final Object span : spannable.getSpans(0, text.length(), CharacterStyle.class)) {
        spannable.removeSpan(span);
    }
    if (isHashtagEnabled()) {
        spanAll(spannable, getHashtagPattern(), new Supplier<CharacterStyle>() {
                @Override
                public CharacterStyle get() {
                    return hashtagClickListener != null
                        ? new SocialClickableSpan(hashtagClickListener, hashtagColors, false)
                        : new ForegroundColorSpan(hashtagColors.getDefaultColor());
                }
            }
        );
    }
    if (isMentionEnabled()) {
        spanAll(spannable, getMentionPattern(), new Supplier<CharacterStyle>() {
                @Override
                public CharacterStyle get() {
                    return mentionClickListener != null
                        ? new SocialClickableSpan(mentionClickListener, mentionColors, false)
                        : new ForegroundColorSpan(mentionColors.getDefaultColor());
                }
            }
        );
    }
    if (isHyperlinkEnabled()) {
        spanAll(spannable, getHyperlinkPattern(), new Supplier<CharacterStyle>() {
                @Override
                public CharacterStyle get() {
                    return hyperlinkClickListener != null
                        ? new SocialClickableSpan(hyperlinkClickListener, hyperlinkColors, true)
                        : new SocialURLSpan(text, hyperlinkColors);
                }
            }
        );
    }
}
 
Example 13
Source File: IRCColorUtils.java    From revolution-irc with GNU General Public License v3.0 4 votes vote down vote up
public static String convertSpannableToIRCString(Context context, Spannable spannable) {
    int n;
    int pFg = 99;
    int pBg = 99;
    boolean pBold = false;
    boolean pItalic = false;
    boolean pUnderline = false;
    StringBuilder ret = new StringBuilder(spannable.length());
    for (int i = 0; i < spannable.length(); i = n) {
        n = spannable.nextSpanTransition(i, spannable.length(), Object.class);
        int fg = 99;
        int bg = 99;
        boolean bold = false;
        boolean italic = false;
        boolean underline = false;
        for (Object span : spannable.getSpans(i, n, Object.class)) {
            int flags = spannable.getSpanFlags(span);
            if ((flags & Spannable.SPAN_COMPOSING) != 0)
                continue;
            if (span instanceof ForegroundColorSpan) {
                fg = findNearestIRCColor(context, ((ForegroundColorSpan) span).getForegroundColor());
            } else if (span instanceof BackgroundColorSpan) {
                bg = findNearestIRCColor(context, ((BackgroundColorSpan) span).getBackgroundColor());
            } else if (span instanceof StyleSpan) {
                int style = ((StyleSpan) span).getStyle();
                if (style == Typeface.BOLD || style == Typeface.BOLD_ITALIC)
                    bold = true;
                if (style == Typeface.ITALIC || style == Typeface.BOLD_ITALIC)
                    italic = true;
            } else if (span instanceof UnderlineSpan) {
                underline = true;
            }
        }
        if ((!bold && pBold) || (!italic && pItalic) || (!underline && pUnderline)) {
            ret.append((char) 0x0F);
            pFg = -1;
            pBg = -1;
            pBold = false;
            pItalic = false;
            pUnderline = false;
        }
        if (bold && !pBold)
            ret.append((char) 0x02);
        if (italic && !pItalic)
            ret.append((char) 0x1D);
        if (underline && !pUnderline)
            ret.append((char) 0x1F);
        if (fg != pFg || bg != pBg) {
            ret.append((char) 0x03);
            ret.append(fg);
            ret.append(',');
            ret.append(bg);
        }

        pFg = fg;
        pBg = bg;
        pBold = bold;
        pItalic = italic;
        pUnderline = underline;
        ret.append(spannable, i, n);
    }
    return ret.toString();
}
 
Example 14
Source File: LinkifiedTextView.java    From RedReader with GNU General Public License v3.0 4 votes vote down vote up
@Override
public boolean onTouchEvent(final MotionEvent event) {
	final CharSequence text = getText();

	if(!(text instanceof Spannable)) {
		return false;
	}

	if(!PrefsUtility.pref_appearance_link_text_clickable(
			mActivity,
			PreferenceManager.getDefaultSharedPreferences(mActivity))) {

		return false;
	}

	final Spannable buffer = (Spannable)text;

	int action = event.getAction();

	if (action == MotionEvent.ACTION_UP ||
			action == MotionEvent.ACTION_DOWN) {
		int x = (int) event.getX();
		int y = (int) event.getY();

		x -= getTotalPaddingLeft();
		y -= getTotalPaddingTop();

		x += getScrollX();
		y += getScrollY();

		final Layout layout = getLayout();
		final int line = layout.getLineForVertical(y);
		final int off = layout.getOffsetForHorizontal(line, x);

		final ClickableSpan[] links = buffer.getSpans(off, off, ClickableSpan.class);

		if (links.length != 0) {
			if (action == MotionEvent.ACTION_UP) {
				links[0].onClick(this);
			} else if (action == MotionEvent.ACTION_DOWN) {
				Selection.setSelection(
						buffer,
						buffer.getSpanStart(links[0]),
						buffer.getSpanEnd(links[0]));
			}

			return true;

		} else {
			Selection.removeSelection(buffer);
		}
	}

	return false;
}
 
Example 15
Source File: LongClickableLinkMovementMethod.java    From iBeebo with GNU General Public License v3.0 4 votes vote down vote up
private boolean action(int what, TextView widget, Spannable buffer) {
    Layout layout = widget.getLayout();

    int padding = widget.getTotalPaddingTop() + widget.getTotalPaddingBottom();
    int areatop = widget.getScrollY();
    int areabot = areatop + widget.getHeight() - padding;

    int linetop = layout.getLineForVertical(areatop);
    int linebot = layout.getLineForVertical(areabot);

    int first = layout.getLineStart(linetop);
    int last = layout.getLineEnd(linebot);

    MyURLSpan[] candidates = buffer.getSpans(first, last, MyURLSpan.class);

    int a = Selection.getSelectionStart(buffer);
    int b = Selection.getSelectionEnd(buffer);

    int selStart = Math.min(a, b);
    int selEnd = Math.max(a, b);

    if (selStart < 0) {
        if (buffer.getSpanStart(FROM_BELOW) >= 0) {
            selStart = selEnd = buffer.length();
        }
    }

    if (selStart > last) {
        selStart = selEnd = Integer.MAX_VALUE;
    }
    if (selEnd < first) {
        selStart = selEnd = -1;
    }

    switch (what) {
        case CLICK:
            if (selStart == selEnd) {
                return false;
            }

            MyURLSpan[] link = buffer.getSpans(selStart, selEnd, MyURLSpan.class);

            if (link.length != 1) {
                return false;
            }

            link[0].onClick(widget);
            break;

        case UP:
            int best_start = -1;
            int best_end = -1;

            for (MyURLSpan candidate1 : candidates) {
                int end = buffer.getSpanEnd(candidate1);

                if (end < selEnd || selStart == selEnd) {
                    if (end > best_end) {
                        best_start = buffer.getSpanStart(candidate1);
                        best_end = end;
                    }
                }
            }

            if (best_start >= 0) {
                Selection.setSelection(buffer, best_end, best_start);
                return true;
            }

            break;

        case DOWN:
            best_start = Integer.MAX_VALUE;
            best_end = Integer.MAX_VALUE;

            for (MyURLSpan candidate : candidates) {
                int start = buffer.getSpanStart(candidate);

                if (start > selStart || selStart == selEnd) {
                    if (start < best_start) {
                        best_start = start;
                        best_end = buffer.getSpanEnd(candidate);
                    }
                }
            }

            if (best_end < Integer.MAX_VALUE) {
                Selection.setSelection(buffer, best_start, best_end);
                return true;
            }

            break;
    }

    return false;
}
 
Example 16
Source File: Touch.java    From JotaTextEditor with Apache License 2.0 4 votes vote down vote up
public static int getInitialScrollY(TextView widget, Spannable buffer) {
    DragState[] ds = buffer.getSpans(0, buffer.length(), DragState.class);
    return ds.length > 0 ? ds[0].mScrollY : -1;
}
 
Example 17
Source File: ConversationFragment.java    From KlyphMessenger with MIT License 4 votes vote down vote up
@Override
public void onListItemClick(ListView l, View v, int position, long id)
{
	super.onListItemClick(l, v, position, id);

	final Message message = (Message) getAdapter().getItem(position);

	List<String> list = new ArrayList<String>();

	int copyText = -1;
	int downloadImage = -1;

	String body = message.getBody();

	if (body.length() > 0)
	{
		list.add(getString(R.string.copy_text));
		copyText = list.size() - 1;

		Spannable spannable = new SpannableString(body);
		Linkify.addLinks(spannable, Linkify.WEB_URLS);

		URLSpan[] urls = spannable.getSpans(0, spannable.length(), URLSpan.class);
		if (urls.length > 0)
		{
			for (URLSpan urlSpan : urls)
			{
				list.add(urlSpan.getURL());
			}
		}
	}

	/*
	 * if (message.getAttachment() != null)
	 * {
	 * list.add(getString(R.string.download_image));
	 * downloadImage = list.size() - 1;
	 * }
	 */

	final int fcopyText = copyText;
	final int fdownloadImage = downloadImage;

	final String[] items = list.toArray(new String[0]);

	// For Api 8 to 10
	AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
	builder.setItems(items, new DialogInterface.OnClickListener() {
		public void onClick(DialogInterface dialog, int which)
		{
			if (which == fcopyText)
			{
				handleCopyTextAction(message);
			}
			else if (which == fdownloadImage)
			{
				handleDownloadAction(message);
			}
			else
			{
				handleUrlAction(items[which]);
			}
		}
	});
	builder.create().show();
}
 
Example 18
Source File: ClickableLinksTextView.java    From Overchan-Android with GNU General Public License v3.0 4 votes vote down vote up
private boolean checkLinksOnTouch(MotionEvent event) {
    this.copyBaseEditorIfNecessary();

    int action = event.getAction() & 0xff; // getActionMasked()
    boolean discardNextActionUp = this.getDiscardNextActionUp();

    // call the base method anyway
    final boolean superResult = super.onTouchEvent(event);

    // the same check as in the super.onTouchEvent(event)
    if (discardNextActionUp && action == MotionEvent.ACTION_UP) {
        return superResult;
    }

    final boolean touchIsFinished = (action == MotionEvent.ACTION_UP) && !this.getIgnoreActionUpEvent() && this.isFocused();

    // Copied from the LinkMovementMethod class
    if (touchIsFinished) {
        Spannable spannable = (Spannable) this.getText();
        int x = (int) event.getX();
        int y = (int) event.getY();

        x -= this.getTotalPaddingLeft();
        y -= this.getTotalPaddingTop();

        x += this.getScrollX();
        y += this.getScrollY();

        Layout layout = this.getLayout();
        int line = layout.getLineForVertical(y);
        int off = layout.getOffsetForHorizontal(line, x);

        ClickableSpan[] link = spannable.getSpans(off, off, ClickableSpan.class);

        if (link.length != 0) {
            link[0].onClick(this);
            return true;
        }
    }

    return superResult;
}
 
Example 19
Source File: LocaleSpanCompatUtils.java    From Indic-Keyboard with Apache License 2.0 4 votes vote down vote up
/**
 * Ensures that the specified range is covered with only one {@link LocaleSpan} with the given
 * locale. If the region is already covered by one or more {@link LocaleSpan}, their ranges are
 * updated so that each character has only one locale.
 * @param spannable the spannable object to be updated.
 * @param start the start index from which {@link LocaleSpan} is attached (inclusive).
 * @param end the end index to which {@link LocaleSpan} is attached (exclusive).
 * @param locale the locale to be attached to the specified range.
 */
@UsedForTesting
public static void updateLocaleSpan(final Spannable spannable, final int start,
        final int end, final Locale locale) {
    if (end < start) {
        Log.e(TAG, "Invalid range: start=" + start + " end=" + end);
        return;
    }
    if (!isLocaleSpanAvailable()) {
        return;
    }
    // A brief summary of our strategy;
    //   1. Enumerate all LocaleSpans between [start - 1, end + 1].
    //   2. For each LocaleSpan S:
    //      - Update the range of S so as not to cover [start, end] if S doesn't have the
    //        expected locale.
    //      - Mark S as "to be merged" if S has the expected locale.
    //   3. Merge all the LocaleSpans that are marked as "to be merged" into one LocaleSpan.
    //      If no appropriate span is found, create a new one with newLocaleSpan method.
    final int searchStart = Math.max(start - 1, 0);
    final int searchEnd = Math.min(end + 1, spannable.length());
    // LocaleSpans found in the target range. See the step 1 in the above comment.
    final Object[] existingLocaleSpans = spannable.getSpans(searchStart, searchEnd,
            LOCALE_SPAN_TYPE);
    // LocaleSpans that are marked as "to be merged". See the step 2 in the above comment.
    final ArrayList<Object> existingLocaleSpansToBeMerged = new ArrayList<>();
    boolean isStartExclusive = true;
    boolean isEndExclusive = true;
    int newStart = start;
    int newEnd = end;
    for (final Object existingLocaleSpan : existingLocaleSpans) {
        final Locale attachedLocale = getLocaleFromLocaleSpan(existingLocaleSpan);
        if (!locale.equals(attachedLocale)) {
            // This LocaleSpan does not have the expected locale. Update its range if it has
            // an intersection with the range [start, end] (the first case of the step 2 in the
            // above comment).
            removeLocaleSpanFromRange(existingLocaleSpan, spannable, start, end);
            continue;
        }
        final int spanStart = spannable.getSpanStart(existingLocaleSpan);
        final int spanEnd = spannable.getSpanEnd(existingLocaleSpan);
        if (spanEnd < spanStart) {
            Log.e(TAG, "Invalid span: spanStart=" + spanStart + " spanEnd=" + spanEnd);
            continue;
        }
        if (spanEnd < start || end < spanStart) {
            // No intersection found.
            continue;
        }

        // Here existingLocaleSpan has the expected locale and an intersection with the
        // range [start, end] (the second case of the the step 2 in the above comment).
        final int spanFlag = spannable.getSpanFlags(existingLocaleSpan);
        if (spanStart < newStart) {
            newStart = spanStart;
            isStartExclusive = ((spanFlag & Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) ==
                    Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        }
        if (newEnd < spanEnd) {
            newEnd = spanEnd;
            isEndExclusive = ((spanFlag & Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) ==
                    Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        }
        existingLocaleSpansToBeMerged.add(existingLocaleSpan);
    }

    int originalLocaleSpanFlag = 0;
    Object localeSpan = null;
    if (existingLocaleSpansToBeMerged.isEmpty()) {
        // If there is no LocaleSpan that is marked as to be merged, create a new one.
        localeSpan = newLocaleSpan(locale);
    } else {
        // Reuse the first LocaleSpan to avoid unnecessary object instantiation.
        localeSpan = existingLocaleSpansToBeMerged.get(0);
        originalLocaleSpanFlag = spannable.getSpanFlags(localeSpan);
        // No need to keep other instances.
        for (int i = 1; i < existingLocaleSpansToBeMerged.size(); ++i) {
            spannable.removeSpan(existingLocaleSpansToBeMerged.get(i));
        }
    }
    final int localeSpanFlag = getSpanFlag(originalLocaleSpanFlag, isStartExclusive,
            isEndExclusive);
    spannable.setSpan(localeSpan, newStart, newEnd, localeSpanFlag);
}
 
Example 20
Source File: LongClickLinkMovementMethod.java    From mimi-reader with Apache License 2.0 4 votes vote down vote up
@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();
            lastRawX = (int) event.getRawX();
            lastRawY = (int) event.getRawY();

            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);

            LongClickableSpan[] link = buffer.getSpans(off, off, LongClickableSpan.class);
//            SpoilerSpan[] check = buffer.getSpans(off, off, SpoilerSpan.class);

            if (link.length != 0) {
                // If the user is pressing down and there is no thread, make one and start it
                if (event.getAction() == MotionEvent.ACTION_DOWN && longClickSensor == null) {
                    thisLink = link[0];
                    lastWidget = widget;
                    longClickSensor = new java.lang.Thread(new MyDelayedAction());
                    longClickSensor.start();
                }
                // If the user has let go and there was a thread, stop it and forget about the thread
                if (event.getAction() == MotionEvent.ACTION_UP && longClickSensor != null) {
                    longClickSensor.interrupt();
                    longClickSensor = null;
                }
            }

            if (link.length != 0) {
                if (action == MotionEvent.ACTION_UP) {
                    if (System.currentTimeMillis() - lastClickTime < 800) {
                        link[0].onClick(widget);
                    }
                } else if (action == MotionEvent.ACTION_DOWN) {
                    // Selection.setSelection(buffer, buffer.getSpanStart(link[0]), buffer.getSpanEnd(link[0]));
                    lastClickTime = System.currentTimeMillis();
                }
                return true;
            }
        } else {
            int deltaX = Math.abs((int) event.getRawX() - lastRawX);
            int deltaY = Math.abs((int) event.getRawY() - lastRawY);
            // must hold finger still
            if ((longClickSensor != null) && ((deltaX > 10) || (deltaY > 10))) {
                longClickSensor.interrupt();
                longClickSensor = null;
            }
        }

        return super.onTouchEvent(widget, buffer, event);
    }