• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 import java.util.Arrays;
31 import java.util.Comparator;
32 
33 /**
34  * This class is used to add {@link View.OnClickListener} for the text been wrapped by
35  * annotation.
36  */
37 public class AnnotationSpan extends URLSpan {
38 
39     private final View.OnClickListener mClickListener;
40 
AnnotationSpan(View.OnClickListener lsn)41     private AnnotationSpan(View.OnClickListener lsn) {
42         super((String) null);
43         mClickListener = lsn;
44     }
45 
46     @Override
onClick(View widget)47     public void onClick(View widget) {
48         if (mClickListener != null) {
49             mClickListener.onClick(widget);
50         }
51     }
52 
53     @Override
updateDrawState(TextPaint ds)54     public void updateDrawState(TextPaint ds) {
55         super.updateDrawState(ds);
56         ds.setUnderlineText(true);
57     }
58 
linkify(CharSequence rawText, LinkInfo... linkInfos)59     public static CharSequence linkify(CharSequence rawText, LinkInfo... linkInfos) {
60         SpannableString msg = new SpannableString(rawText);
61         Annotation[] spans = msg.getSpans(0, msg.length(), Annotation.class);
62         SpannableStringBuilder builder = new SpannableStringBuilder(msg);
63         for (Annotation annotation : spans) {
64             final String key = annotation.getValue();
65             int start = msg.getSpanStart(annotation);
66             int end = msg.getSpanEnd(annotation);
67             AnnotationSpan link = null;
68             for (LinkInfo linkInfo : linkInfos) {
69                 if (linkInfo.mAnnotation.equals(key)) {
70                     link = new AnnotationSpan(linkInfo.mListener);
71                     break;
72                 }
73             }
74             if (link != null) {
75                 builder.setSpan(link, start, end, msg.getSpanFlags(link));
76             }
77         }
78         return builder;
79     }
80 
81     /**
82      * get the text part without having text for link part
83      */
textWithoutLink(CharSequence encodedText)84     public static CharSequence textWithoutLink(CharSequence encodedText) {
85         SpannableString msg = new SpannableString(encodedText);
86         Annotation[] spans = msg.getSpans(0, msg.length(), Annotation.class);
87         if (spans == null) {
88             return encodedText;
89         }
90         Arrays.sort(spans, Comparator.comparingInt(span -> -msg.getSpanStart(span)));
91         StringBuilder msgWithoutLink = new StringBuilder(msg.toString());
92         for (Annotation span : spans) {
93             msgWithoutLink.delete(msg.getSpanStart(span), msg.getSpanEnd(span));
94         }
95         return msgWithoutLink.toString();
96     }
97 
98     /**
99      * Data class to store the annotation and the click action
100      */
101     public static class LinkInfo {
102         private static final String TAG = "AnnotationSpan.LinkInfo";
103         public static final String DEFAULT_ANNOTATION = "link";
104         private final String mAnnotation;
105         private final Boolean mActionable;
106         private final View.OnClickListener mListener;
107 
LinkInfo(String annotation, View.OnClickListener listener)108         public LinkInfo(String annotation, View.OnClickListener listener) {
109             mAnnotation = annotation;
110             mListener = listener;
111             mActionable = true; // assume actionable
112         }
113 
LinkInfo(Context context, String annotation, Intent intent)114         public LinkInfo(Context context, String annotation, Intent intent) {
115             mAnnotation = annotation;
116             if (intent != null) {
117                 mActionable = context.getPackageManager()
118                         .resolveActivity(intent, 0 /* flags */) != null;
119             } else {
120                 mActionable = false;
121             }
122             if (!mActionable) {
123                 mListener = null;
124             } else {
125                 mListener = view -> {
126                     try {
127                         view.startActivityForResult(intent, 0);
128                     } catch (ActivityNotFoundException e) {
129                         Log.w(TAG, "Activity was not found for intent, " + intent);
130                     }
131                 };
132             }
133         }
134 
isActionable()135         public boolean isActionable() {
136             return mActionable;
137         }
138     }
139 }
140