diff options
Diffstat (limited to 'library/gingerbread/src/com/android/setupwizardlib/view/RichTextView.java')
-rw-r--r-- | library/gingerbread/src/com/android/setupwizardlib/view/RichTextView.java | 318 |
1 files changed, 158 insertions, 160 deletions
diff --git a/library/gingerbread/src/com/android/setupwizardlib/view/RichTextView.java b/library/gingerbread/src/com/android/setupwizardlib/view/RichTextView.java index 1ee3219..5e50e7a 100644 --- a/library/gingerbread/src/com/android/setupwizardlib/view/RichTextView.java +++ b/library/gingerbread/src/com/android/setupwizardlib/view/RichTextView.java @@ -20,6 +20,8 @@ import android.content.Context; import android.graphics.drawable.Drawable; import android.os.Build.VERSION; import android.os.Build.VERSION_CODES; +import androidx.core.view.ViewCompat; +import androidx.appcompat.widget.AppCompatTextView; import android.text.Annotation; import android.text.SpannableString; import android.text.Spanned; @@ -29,10 +31,6 @@ import android.text.style.TextAppearanceSpan; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; - -import androidx.appcompat.widget.AppCompatTextView; -import androidx.core.view.ViewCompat; - import com.android.setupwizardlib.span.LinkSpan; import com.android.setupwizardlib.span.LinkSpan.OnLinkClickListener; import com.android.setupwizardlib.span.SpanHelper; @@ -40,178 +38,178 @@ import com.android.setupwizardlib.util.LinkAccessibilityHelper; import com.android.setupwizardlib.view.TouchableMovementMethod.TouchableLinkMovementMethod; /** - * An extension of TextView that automatically replaces the annotation tags as specified in - * {@link SpanHelper#replaceSpan(android.text.Spannable, Object, Object)} + * An extension of TextView that automatically replaces the annotation tags as specified in {@link + * SpanHelper#replaceSpan(android.text.Spannable, Object, Object)} */ public class RichTextView extends AppCompatTextView implements OnLinkClickListener { - /* static section */ - - private static final String TAG = "RichTextView"; - - private static final String ANNOTATION_LINK = "link"; - private static final String ANNOTATION_TEXT_APPEARANCE = "textAppearance"; - - /** - * Replace <annotation> tags in strings to become their respective types. Currently 2 - * types are supported: - * <ol> - * <li><annotation link="foobar"> will create a - * {@link com.android.setupwizardlib.span.LinkSpan} that broadcasts with the key - * "foobar"</li> - * <li><annotation textAppearance="TextAppearance.FooBar"> will create a - * {@link android.text.style.TextAppearanceSpan} with @style/TextAppearance.FooBar</li> - * </ol> - */ - public static CharSequence getRichText(Context context, CharSequence text) { - if (text instanceof Spanned) { - final SpannableString spannable = new SpannableString(text); - final Annotation[] spans = spannable.getSpans(0, spannable.length(), Annotation.class); - for (Annotation span : spans) { - final String key = span.getKey(); - if (ANNOTATION_TEXT_APPEARANCE.equals(key)) { - String textAppearance = span.getValue(); - final int style = context.getResources() - .getIdentifier(textAppearance, "style", context.getPackageName()); - if (style == 0) { - Log.w(TAG, "Cannot find resource: " + style); - } - final TextAppearanceSpan textAppearanceSpan = - new TextAppearanceSpan(context, style); - SpanHelper.replaceSpan(spannable, span, textAppearanceSpan); - } else if (ANNOTATION_LINK.equals(key)) { - LinkSpan link = new LinkSpan(span.getValue()); - SpanHelper.replaceSpan(spannable, span, link); - } - } - return spannable; + /* static section */ + + private static final String TAG = "RichTextView"; + + private static final String ANNOTATION_LINK = "link"; + private static final String ANNOTATION_TEXT_APPEARANCE = "textAppearance"; + + /** + * Replace <annotation> tags in strings to become their respective types. Currently 2 types + * are supported: + * + * <ol> + * <li><annotation link="foobar"> will create a {@link + * com.android.setupwizardlib.span.LinkSpan} that broadcasts with the key "foobar" + * <li><annotation textAppearance="TextAppearance.FooBar"> will create a {@link + * android.text.style.TextAppearanceSpan} with @style/TextAppearance.FooBar + * </ol> + */ + public static CharSequence getRichText(Context context, CharSequence text) { + if (text instanceof Spanned) { + final SpannableString spannable = new SpannableString(text); + final Annotation[] spans = spannable.getSpans(0, spannable.length(), Annotation.class); + for (Annotation span : spans) { + final String key = span.getKey(); + if (ANNOTATION_TEXT_APPEARANCE.equals(key)) { + String textAppearance = span.getValue(); + final int style = + context + .getResources() + .getIdentifier(textAppearance, "style", context.getPackageName()); + if (style == 0) { + Log.w(TAG, "Cannot find resource: " + style); + } + final TextAppearanceSpan textAppearanceSpan = new TextAppearanceSpan(context, style); + SpanHelper.replaceSpan(spannable, span, textAppearanceSpan); + } else if (ANNOTATION_LINK.equals(key)) { + LinkSpan link = new LinkSpan(span.getValue()); + SpanHelper.replaceSpan(spannable, span, link); } - return text; - } - - /* non-static section */ - - private LinkAccessibilityHelper mAccessibilityHelper; - private OnLinkClickListener mOnLinkClickListener; - - public RichTextView(Context context) { - super(context); - init(); - } - - public RichTextView(Context context, AttributeSet attrs) { - super(context, attrs); - init(); + } + return spannable; } - - private void init() { - mAccessibilityHelper = new LinkAccessibilityHelper(this); - ViewCompat.setAccessibilityDelegate(this, mAccessibilityHelper); + return text; + } + + /* non-static section */ + + private LinkAccessibilityHelper accessibilityHelper; + private OnLinkClickListener onLinkClickListener; + + public RichTextView(Context context) { + super(context); + init(); + } + + public RichTextView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + private void init() { + accessibilityHelper = new LinkAccessibilityHelper(this); + ViewCompat.setAccessibilityDelegate(this, accessibilityHelper); + } + + @Override + public void setText(CharSequence text, BufferType type) { + text = getRichText(getContext(), text); + // Set text first before doing anything else because setMovementMethod internally calls + // setText. This in turn ends up calling this method with mText as the first parameter + super.setText(text, type); + boolean hasLinks = hasLinks(text); + + if (hasLinks) { + // When a TextView has a movement method, it will set the view to clickable. This makes + // View.onTouchEvent always return true and consumes the touch event, essentially + // nullifying any return values of MovementMethod.onTouchEvent. + // To still allow propagating touch events to the parent when this view doesn't have + // links, we only set the movement method here if the text contains links. + setMovementMethod(TouchableLinkMovementMethod.getInstance()); + } else { + setMovementMethod(null); } - - @Override - public void setText(CharSequence text, BufferType type) { - text = getRichText(getContext(), text); - // Set text first before doing anything else because setMovementMethod internally calls - // setText. This in turn ends up calling this method with mText as the first parameter - super.setText(text, type); - boolean hasLinks = hasLinks(text); - - if (hasLinks) { - // When a TextView has a movement method, it will set the view to clickable. This makes - // View.onTouchEvent always return true and consumes the touch event, essentially - // nullifying any return values of MovementMethod.onTouchEvent. - // To still allow propagating touch events to the parent when this view doesn't have - // links, we only set the movement method here if the text contains links. - setMovementMethod(TouchableLinkMovementMethod.getInstance()); - } else { - setMovementMethod(null); - } - // ExploreByTouchHelper automatically enables focus for RichTextView - // even though it may not have any links. Causes problems during talkback - // as individual TextViews consume touch events and thereby reducing the focus window - // shown by Talkback. Disable focus if there are no links - setFocusable(hasLinks); - // Do not "reveal" (i.e. scroll to) this view when this view is focused. Since this view is - // focusable in touch mode, we may be focused when the screen is first shown, and starting - // a screen halfway scrolled down is confusing to the user. - if (VERSION.SDK_INT >= VERSION_CODES.N_MR1) { - setRevealOnFocusHint(false); - // setRevealOnFocusHint is a new API added in SDK 25. For lower SDK versions, do not - // call setFocusableInTouchMode. We won't get touch effect on those earlier versions, - // but the link will still work, and will prevent the scroll view from starting halfway - // down the page. - setFocusableInTouchMode(hasLinks); - } + // ExploreByTouchHelper automatically enables focus for RichTextView + // even though it may not have any links. Causes problems during talkback + // as individual TextViews consume touch events and thereby reducing the focus window + // shown by Talkback. Disable focus if there are no links + setFocusable(hasLinks); + // Do not "reveal" (i.e. scroll to) this view when this view is focused. Since this view is + // focusable in touch mode, we may be focused when the screen is first shown, and starting + // a screen halfway scrolled down is confusing to the user. + if (VERSION.SDK_INT >= VERSION_CODES.N_MR1) { + setRevealOnFocusHint(false); + // setRevealOnFocusHint is a new API added in SDK 25. For lower SDK versions, do not + // call setFocusableInTouchMode. We won't get touch effect on those earlier versions, + // but the link will still work, and will prevent the scroll view from starting halfway + // down the page. + setFocusableInTouchMode(hasLinks); } + } - private boolean hasLinks(CharSequence text) { - if (text instanceof Spanned) { - final ClickableSpan[] spans = - ((Spanned) text).getSpans(0, text.length(), ClickableSpan.class); - return spans.length > 0; - } - return false; + private boolean hasLinks(CharSequence text) { + if (text instanceof Spanned) { + final ClickableSpan[] spans = + ((Spanned) text).getSpans(0, text.length(), ClickableSpan.class); + return spans.length > 0; } - - @Override - @SuppressWarnings("ClickableViewAccessibility") // super.onTouchEvent is called - public boolean onTouchEvent(MotionEvent event) { - // Since View#onTouchEvent always return true if the view is clickable (which is the case - // when a TextView has a movement method), override the implementation to allow the movement - // method, if it implements TouchableMovementMethod, to say that the touch is not handled, - // allowing the event to bubble up to the parent view. - boolean superResult = super.onTouchEvent(event); - MovementMethod movementMethod = getMovementMethod(); - if (movementMethod instanceof TouchableMovementMethod) { - TouchableMovementMethod touchableMovementMethod = - (TouchableMovementMethod) movementMethod; - if (touchableMovementMethod.getLastTouchEvent() == event) { - return touchableMovementMethod.isLastTouchEventHandled(); - } - } - return superResult; + return false; + } + + @Override + @SuppressWarnings("ClickableViewAccessibility") // super.onTouchEvent is called + public boolean onTouchEvent(MotionEvent event) { + // Since View#onTouchEvent always return true if the view is clickable (which is the case + // when a TextView has a movement method), override the implementation to allow the movement + // method, if it implements TouchableMovementMethod, to say that the touch is not handled, + // allowing the event to bubble up to the parent view. + boolean superResult = super.onTouchEvent(event); + MovementMethod movementMethod = getMovementMethod(); + if (movementMethod instanceof TouchableMovementMethod) { + TouchableMovementMethod touchableMovementMethod = (TouchableMovementMethod) movementMethod; + if (touchableMovementMethod.getLastTouchEvent() == event) { + return touchableMovementMethod.isLastTouchEventHandled(); + } } + return superResult; + } - @Override - protected boolean dispatchHoverEvent(MotionEvent event) { - if (mAccessibilityHelper != null && mAccessibilityHelper.dispatchHoverEvent(event)) { - return true; - } - return super.dispatchHoverEvent(event); + @Override + protected boolean dispatchHoverEvent(MotionEvent event) { + if (accessibilityHelper != null && accessibilityHelper.dispatchHoverEvent(event)) { + return true; } - - @Override - protected void drawableStateChanged() { - super.drawableStateChanged(); - - if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) { - // b/26765507 causes drawableStart and drawableEnd to not get the right state on M. As a - // workaround, set the state on those drawables directly. - final int[] state = getDrawableState(); - for (Drawable drawable : getCompoundDrawablesRelative()) { - if (drawable != null) { - if (drawable.setState(state)) { - invalidateDrawable(drawable); - } - } - } + return super.dispatchHoverEvent(event); + } + + @Override + protected void drawableStateChanged() { + super.drawableStateChanged(); + + if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) { + // b/26765507 causes drawableStart and drawableEnd to not get the right state on M. As a + // workaround, set the state on those drawables directly. + final int[] state = getDrawableState(); + for (Drawable drawable : getCompoundDrawablesRelative()) { + if (drawable != null) { + if (drawable.setState(state)) { + invalidateDrawable(drawable); + } } + } } + } - public void setOnLinkClickListener(OnLinkClickListener listener) { - mOnLinkClickListener = listener; - } + public void setOnLinkClickListener(OnLinkClickListener listener) { + onLinkClickListener = listener; + } - public OnLinkClickListener getOnLinkClickListener() { - return mOnLinkClickListener; - } + public OnLinkClickListener getOnLinkClickListener() { + return onLinkClickListener; + } - @Override - public boolean onLinkClick(LinkSpan span) { - if (mOnLinkClickListener != null) { - return mOnLinkClickListener.onLinkClick(span); - } - return false; + @Override + public boolean onLinkClick(LinkSpan span) { + if (onLinkClickListener != null) { + return onLinkClickListener.onLinkClick(span); } + return false; + } } |