1 /* 2 * Copyright (C) 2008 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 android.text.util; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertFalse; 21 import static org.junit.Assert.assertTrue; 22 23 import android.content.Context; 24 import android.content.res.Configuration; 25 import android.os.LocaleList; 26 import android.support.test.InstrumentationRegistry; 27 import android.support.test.filters.SmallTest; 28 import android.support.test.runner.AndroidJUnit4; 29 import android.text.Spannable; 30 import android.text.SpannableString; 31 import android.text.method.LinkMovementMethod; 32 import android.text.style.URLSpan; 33 import android.util.Patterns; 34 import android.view.textclassifier.SystemTextClassifier; 35 import android.view.textclassifier.TextClassificationConstants; 36 import android.view.textclassifier.TextClassifier; 37 import android.view.textclassifier.TextClassifierImpl; 38 import android.view.textclassifier.TextLinks.TextLinkSpan; 39 import android.widget.TextView; 40 41 import org.junit.After; 42 import org.junit.Before; 43 import org.junit.Test; 44 import org.junit.runner.RunWith; 45 46 import java.util.Arrays; 47 import java.util.HashSet; 48 import java.util.List; 49 import java.util.Locale; 50 import java.util.Set; 51 52 /** 53 * LinkifyTest tests {@link Linkify}. 54 */ 55 @SmallTest 56 @RunWith(AndroidJUnit4.class) 57 public class LinkifyTest { 58 59 private static final LocaleList LOCALE_LIST_US = new LocaleList(Locale.US); 60 private LocaleList mOriginalLocales; 61 private Context mContext; 62 63 @Before 64 public void setup() { 65 mContext = InstrumentationRegistry.getContext(); 66 mOriginalLocales = LocaleList.getDefault(); 67 LocaleList.setDefault(LOCALE_LIST_US); 68 } 69 70 @After 71 public void teardown() { 72 LocaleList.setDefault(mOriginalLocales); 73 } 74 75 @Test 76 public void testNothing() { 77 TextView tv; 78 79 tv = new TextView(createUsEnglishContext()); 80 tv.setText("Hey, foo (at) google.com, call 415-555-1212."); 81 82 assertFalse(tv.getMovementMethod() instanceof LinkMovementMethod); 83 assertTrue(tv.getUrls().length == 0); 84 } 85 86 @Test 87 public void testNormal() { 88 TextView tv; 89 90 tv = new TextView(createUsEnglishContext()); 91 tv.setAutoLinkMask(Linkify.ALL); 92 tv.setText("Hey, foo (at) google.com, call +1-415-555-1212."); 93 94 assertTrue(tv.getMovementMethod() instanceof LinkMovementMethod); 95 assertTrue(tv.getUrls().length == 2); 96 } 97 98 @Test 99 public void testUnclickable() { 100 TextView tv; 101 102 tv = new TextView(createUsEnglishContext()); 103 tv.setAutoLinkMask(Linkify.ALL); 104 tv.setLinksClickable(false); 105 tv.setText("Hey, foo (at) google.com, call +1-415-555-1212."); 106 107 assertFalse(tv.getMovementMethod() instanceof LinkMovementMethod); 108 assertTrue(tv.getUrls().length == 2); 109 } 110 111 private Context createUsEnglishContext() { 112 final Configuration overrideConfig = new Configuration(); 113 overrideConfig.setLocales(LOCALE_LIST_US); 114 return mContext.createConfigurationContext(overrideConfig); 115 } 116 117 @Test 118 public void testAddLinks_addsLinksWhenDefaultSchemeIsNull() { 119 Spannable spannable = new SpannableString("any https://android.com any android.com any"); 120 Linkify.addLinks(spannable, Patterns.AUTOLINK_WEB_URL, null, null, null); 121 122 URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class); 123 assertEquals("android.com and https://android.com should be linkified", 2, spans.length); 124 assertEquals("https://android.com", spans[0].getURL()); 125 assertEquals("android.com", spans[1].getURL()); 126 } 127 128 @Test 129 public void testAddLinks_addsLinksWhenSchemesArrayIsNull() { 130 Spannable spannable = new SpannableString("any https://android.com any android.com any"); 131 Linkify.addLinks(spannable, Patterns.AUTOLINK_WEB_URL, "http://", null, null); 132 133 URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class); 134 assertEquals("android.com and https://android.com should be linkified", 2, spans.length); 135 // expected behavior, passing null schemes array means: prepend defaultScheme to all links. 136 assertEquals("http://https://android.com", spans[0].getURL()); 137 assertEquals("http://android.com", spans[1].getURL()); 138 } 139 140 @Test 141 public void testAddLinks_prependsDefaultSchemeToBeginingOfLink() { 142 Spannable spannable = new SpannableString("any android.com any"); 143 Linkify.addLinks(spannable, Patterns.AUTOLINK_WEB_URL, "http://", 144 new String[] { "http://", "https://"}, null, null); 145 146 URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class); 147 assertEquals("android.com should be linkified", 1, spans.length); 148 assertEquals("http://android.com", spans[0].getURL()); 149 } 150 151 @Test 152 public void testAddLinks_doesNotPrependSchemeIfSchemeExists() { 153 Spannable spannable = new SpannableString("any https://android.com any"); 154 Linkify.addLinks(spannable, Patterns.AUTOLINK_WEB_URL, "http://", 155 new String[] { "http://", "https://"}, null, null); 156 157 URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class); 158 assertEquals("android.com should be linkified", 1, spans.length); 159 assertEquals("https://android.com", spans[0].getURL()); 160 } 161 162 @Test 163 public void testAddLinksAsync_useLegacyIfSmartDisabled_localTextClassifier() 164 throws Exception { 165 final TextClassificationConstants settings = 166 TextClassificationConstants.loadFromString("smart_linkify_enabled=false"); 167 final TextClassifier classifier = new TextClassifierImpl(mContext, settings); 168 testAddLinksAsync_useLegacyIfSmartDisabled(classifier); 169 } 170 171 @Test 172 public void testAddLinksAsync_useLegacyIfSmartDisabled_systemTextClassifier() 173 throws Exception { 174 final TextClassificationConstants settings = 175 TextClassificationConstants.loadFromString("smart_linkify_enabled=false"); 176 final TextClassifier classifier = new SystemTextClassifier(mContext, settings); 177 testAddLinksAsync_useLegacyIfSmartDisabled(classifier); 178 } 179 180 private void testAddLinksAsync_useLegacyIfSmartDisabled(TextClassifier classifier) 181 throws Exception { 182 final int linkMask = Linkify.EMAIL_ADDRESSES | Linkify.PHONE_NUMBERS | Linkify.WEB_URLS; 183 final String string = "example (at) android.com\n" 184 + "(415) 555-1212\n" 185 + "http://android.com\n" 186 + "100 Android Rd California"; 187 final Spannable expected = new SpannableString(string); 188 final Spannable actual = new SpannableString(string); 189 190 Linkify.addLinks(expected, linkMask); // legacy. 191 Linkify.addLinksAsync(actual, classifier, linkMask).get(); 192 193 final URLSpan[] expectedSpans = expected.getSpans(0, expected.length(), URLSpan.class); 194 final TextLinkSpan[] actualSpans = actual.getSpans(0, actual.length(), TextLinkSpan.class); 195 assertEquals(expectedSpans.length, actualSpans.length); 196 final Set<List> expectedLinkSpec = new HashSet<>(); 197 final Set<List> actualLinkSpec = new HashSet<>(); 198 for (int i = 0; i < expectedSpans.length; i++) { 199 final URLSpan expectedSpan = expectedSpans[i]; 200 final TextLinkSpan actualSpan = actualSpans[i]; 201 expectedLinkSpec.add(Arrays.asList( 202 expected.getSpanStart(expectedSpan), 203 expected.getSpanEnd(expectedSpan), 204 expectedSpan.getURL())); 205 actualLinkSpec.add(Arrays.asList( 206 actual.getSpanStart(actualSpan), 207 actual.getSpanEnd(actualSpan), 208 actualSpan.getUrl())); 209 } 210 assertEquals(expectedLinkSpec, actualLinkSpec); 211 } 212 } 213