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 import android.webkit.URLUtil; 30 31 import com.android.managedprovisioning.preprovisioning.WebActivity; 32 33 /** 34 * Parses HTML text using {@link Html} and sets URL links to be handled by {@link WebActivity} 35 */ 36 public class HtmlToSpannedParser { 37 private static final int HTML_MODE = Html.FROM_HTML_MODE_COMPACT; 38 39 private final ClickableSpanFactory mClickableSpanFactory; 40 private final UrlIntentFactory mUrlIntentFactory; 41 42 /** 43 * Default constructor 44 * 45 * @param clickableSpanFactory Factory of {@link ClickableSpan} objects for urls 46 * @param urlIntentFactory Factory of {@link Intent} objects for handling urls 47 */ HtmlToSpannedParser(ClickableSpanFactory clickableSpanFactory, UrlIntentFactory urlIntentFactory)48 public HtmlToSpannedParser(ClickableSpanFactory clickableSpanFactory, 49 UrlIntentFactory urlIntentFactory) { 50 mClickableSpanFactory = checkNotNull(clickableSpanFactory); 51 mUrlIntentFactory = checkNotNull(urlIntentFactory); 52 } 53 54 /** 55 * See {@link Html#fromHtml(String, int)} for caveats regarding limited HTML support 56 */ parseHtml(String htmlContent)57 public Spanned parseHtml(String htmlContent) { 58 Spanned spanned = Html.fromHtml(checkStringNotEmpty(htmlContent), HTML_MODE); 59 if (spanned == null) { 60 return null; 61 } 62 63 // Make html <a> tags open WebActivity 64 SpannableStringBuilder result = new SpannableStringBuilder(spanned); 65 66 URLSpan[] urlSpans = result.getSpans(0, result.length(), URLSpan.class); 67 for (URLSpan urlSpan : urlSpans) { 68 String url = urlSpan.getURL(); 69 if (!isValidURL(url)) { 70 ProvisionLogger.logw("Invalid URL provided. Only HTTP and HTTPS URLs are allowed."); 71 return null; 72 } 73 Intent intent = mUrlIntentFactory.create(url); 74 if (intent != null) { 75 int spanStart = result.getSpanStart(urlSpan); 76 int spanEnd = result.getSpanEnd(urlSpan); 77 result.setSpan(mClickableSpanFactory.create(intent), spanStart, spanEnd, 78 SPAN_EXCLUSIVE_EXCLUSIVE); 79 result.removeSpan(urlSpan); 80 } 81 } 82 83 return result; 84 } 85 isValidURL(String url)86 private boolean isValidURL(String url) { 87 return URLUtil.isHttpUrl(url) || URLUtil.isHttpsUrl(url); 88 } 89 90 /** 91 * Allows to specify an intent to handle URLs 92 */ 93 public interface UrlIntentFactory { 94 /** 95 * Creates an {@link Intent} based on a passed in {@link String} url 96 */ create(String url)97 Intent create(String url); 98 } 99 }