1 /*
2  * Copyright 2017, 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 package com.android.managedprovisioning.common;
17 
18 import static android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE;
19 
20 import static com.android.internal.util.Preconditions.checkNotNull;
21 import static com.android.internal.util.Preconditions.checkStringNotEmpty;
22 
23 import android.content.Intent;
24 import android.text.Html;
25 import android.text.SpannableStringBuilder;
26 import android.text.Spanned;
27 import android.text.style.ClickableSpan;
28 import android.text.style.URLSpan;
29 
30 import com.android.managedprovisioning.preprovisioning.WebActivity;
31 
32 /**
33  * Parses HTML text using {@link Html} and sets URL links to be handled by {@link WebActivity}
34  */
35 public class HtmlToSpannedParser {
36     private static final int HTML_MODE = Html.FROM_HTML_MODE_COMPACT;
37 
38     private final ClickableSpanFactory mClickableSpanFactory;
39     private final UrlIntentFactory mUrlIntentFactory;
40 
41     /**
42      * Default constructor
43      *
44      * @param clickableSpanFactory Factory of {@link ClickableSpan} objects for urls
45      * @param urlIntentFactory Factory of {@link Intent} objects for handling urls
46      */
HtmlToSpannedParser(ClickableSpanFactory clickableSpanFactory, UrlIntentFactory urlIntentFactory)47     public HtmlToSpannedParser(ClickableSpanFactory clickableSpanFactory,
48             UrlIntentFactory urlIntentFactory) {
49         mClickableSpanFactory = checkNotNull(clickableSpanFactory);
50         mUrlIntentFactory = checkNotNull(urlIntentFactory);
51     }
52 
53     /**
54      * See {@link Html#fromHtml(String, int)} for caveats regarding limited HTML support
55      */
parseHtml(String htmlContent)56     public Spanned parseHtml(String htmlContent) {
57         Spanned spanned = Html.fromHtml(checkStringNotEmpty(htmlContent), HTML_MODE);
58         if (spanned == null) {
59             return null;
60         }
61 
62         // Make html <a> tags open WebActivity
63         SpannableStringBuilder result = new SpannableStringBuilder(spanned);
64 
65         URLSpan[] urlSpans = result.getSpans(0, result.length(), URLSpan.class);
66         for (URLSpan urlSpan : urlSpans) {
67             Intent intent = mUrlIntentFactory.create(urlSpan.getURL());
68             if (intent != null) {
69                 int spanStart = result.getSpanStart(urlSpan);
70                 int spanEnd = result.getSpanEnd(urlSpan);
71                 result.setSpan(mClickableSpanFactory.create(intent), spanStart, spanEnd,
72                         SPAN_EXCLUSIVE_EXCLUSIVE);
73                 result.removeSpan(urlSpan);
74             }
75         }
76 
77         return result;
78     }
79 
80     /**
81      * Allows to specify an intent to handle URLs
82      */
83     public interface UrlIntentFactory {
84         /**
85          * Creates an {@link Intent} based on a passed in {@link String} url
86          */
create(String url)87         Intent create(String url);
88     }
89 }