1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.utils; 18 19 import android.content.ActivityNotFoundException; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.text.Annotation; 23 import android.text.SpannableString; 24 import android.text.SpannableStringBuilder; 25 import android.text.TextPaint; 26 import android.text.style.URLSpan; 27 import android.util.Log; 28 import android.view.View; 29 30 /** 31 * This class is used to add {@link View.OnClickListener} for the text been wrapped by 32 * annotation. 33 */ 34 public class AnnotationSpan extends URLSpan { 35 36 private final View.OnClickListener mClickListener; 37 AnnotationSpan(View.OnClickListener lsn)38 private AnnotationSpan(View.OnClickListener lsn) { 39 super((String) null); 40 mClickListener = lsn; 41 } 42 43 @Override onClick(View widget)44 public void onClick(View widget) { 45 if (mClickListener != null) { 46 mClickListener.onClick(widget); 47 } 48 } 49 50 @Override updateDrawState(TextPaint ds)51 public void updateDrawState(TextPaint ds) { 52 super.updateDrawState(ds); 53 ds.setUnderlineText(false); 54 } 55 linkify(CharSequence rawText, LinkInfo... linkInfos)56 public static CharSequence linkify(CharSequence rawText, LinkInfo... linkInfos) { 57 SpannableString msg = new SpannableString(rawText); 58 Annotation[] spans = msg.getSpans(0, msg.length(), Annotation.class); 59 SpannableStringBuilder builder = new SpannableStringBuilder(msg); 60 for (Annotation annotation : spans) { 61 final String key = annotation.getValue(); 62 int start = msg.getSpanStart(annotation); 63 int end = msg.getSpanEnd(annotation); 64 AnnotationSpan link = null; 65 for (LinkInfo linkInfo : linkInfos) { 66 if (linkInfo.mAnnotation.equals(key)) { 67 link = new AnnotationSpan(linkInfo.mListener); 68 break; 69 } 70 } 71 if (link != null) { 72 builder.setSpan(link, start, end, msg.getSpanFlags(link)); 73 } 74 } 75 return builder; 76 } 77 78 /** 79 * Data class to store the annotation and the click action 80 */ 81 public static class LinkInfo { 82 private static final String TAG = "AnnotationSpan.LinkInfo"; 83 public static final String DEFAULT_ANNOTATION = "link"; 84 private final String mAnnotation; 85 private final Boolean mActionable; 86 private final View.OnClickListener mListener; 87 LinkInfo(String annotation, View.OnClickListener listener)88 public LinkInfo(String annotation, View.OnClickListener listener) { 89 mAnnotation = annotation; 90 mListener = listener; 91 mActionable = true; // assume actionable 92 } 93 LinkInfo(Context context, String annotation, Intent intent)94 public LinkInfo(Context context, String annotation, Intent intent) { 95 mAnnotation = annotation; 96 if (intent != null) { 97 mActionable = context.getPackageManager() 98 .resolveActivity(intent, 0 /* flags */) != null; 99 } else { 100 mActionable = false; 101 } 102 if (!mActionable) { 103 mListener = null; 104 } else { 105 mListener = view -> { 106 try { 107 view.startActivityForResult(intent, 0); 108 } catch (ActivityNotFoundException e) { 109 Log.w(TAG, "Activity was not found for intent, " + intent); 110 } 111 }; 112 } 113 } 114 isActionable()115 public boolean isActionable() { 116 return mActionable; 117 } 118 } 119 } 120