/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.settings.utils; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.text.Annotation; import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.TextPaint; import android.text.style.URLSpan; import android.util.Log; import android.view.View; import java.util.Arrays; import java.util.Comparator; /** * This class is used to add {@link View.OnClickListener} for the text been wrapped by * annotation. */ public class AnnotationSpan extends URLSpan { private final View.OnClickListener mClickListener; private AnnotationSpan(View.OnClickListener lsn) { super((String) null); mClickListener = lsn; } @Override public void onClick(View widget) { if (mClickListener != null) { mClickListener.onClick(widget); } } @Override public void updateDrawState(TextPaint ds) { super.updateDrawState(ds); ds.setUnderlineText(true); } public static CharSequence linkify(CharSequence rawText, LinkInfo... linkInfos) { SpannableString msg = new SpannableString(rawText); Annotation[] spans = msg.getSpans(0, msg.length(), Annotation.class); SpannableStringBuilder builder = new SpannableStringBuilder(msg); for (Annotation annotation : spans) { final String key = annotation.getValue(); int start = msg.getSpanStart(annotation); int end = msg.getSpanEnd(annotation); AnnotationSpan link = null; for (LinkInfo linkInfo : linkInfos) { if (linkInfo.mAnnotation.equals(key)) { link = new AnnotationSpan(linkInfo.mListener); break; } } if (link != null) { builder.setSpan(link, start, end, msg.getSpanFlags(link)); } } return builder; } /** * get the text part without having text for link part */ public static CharSequence textWithoutLink(CharSequence encodedText) { SpannableString msg = new SpannableString(encodedText); Annotation[] spans = msg.getSpans(0, msg.length(), Annotation.class); if (spans == null) { return encodedText; } Arrays.sort(spans, Comparator.comparingInt(span -> -msg.getSpanStart(span))); StringBuilder msgWithoutLink = new StringBuilder(msg.toString()); for (Annotation span : spans) { msgWithoutLink.delete(msg.getSpanStart(span), msg.getSpanEnd(span)); } return msgWithoutLink.toString(); } /** * Data class to store the annotation and the click action */ public static class LinkInfo { private static final String TAG = "AnnotationSpan.LinkInfo"; public static final String DEFAULT_ANNOTATION = "link"; private final String mAnnotation; private final Boolean mActionable; private final View.OnClickListener mListener; public LinkInfo(String annotation, View.OnClickListener listener) { mAnnotation = annotation; mListener = listener; mActionable = true; // assume actionable } public LinkInfo(Context context, String annotation, Intent intent) { mAnnotation = annotation; if (intent != null) { mActionable = context.getPackageManager() .resolveActivity(intent, 0 /* flags */) != null; } else { mActionable = false; } if (!mActionable) { mListener = null; } else { mListener = view -> { try { view.startActivityForResult(intent, 0); } catch (ActivityNotFoundException e) { Log.w(TAG, "Activity was not found for intent, " + intent); } }; } } public boolean isActionable() { return mActionable; } } }