13483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka/* 23483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka * Copyright (C) 2018 The Android Open Source Project 33483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka * 43483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka * Licensed under the Apache License, Version 2.0 (the "License"); 53483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka * you may not use this file except in compliance with the License. 63483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka * You may obtain a copy of the License at 73483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka * 83483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka * http://www.apache.org/licenses/LICENSE-2.0 93483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka * 103483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka * Unless required by applicable law or agreed to in writing, software 113483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka * distributed under the License is distributed on an "AS IS" BASIS, 123483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka * See the License for the specific language governing permissions and 143483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka * limitations under the License. 153483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka */ 163483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka 173483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonakapackage android.text; 183483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka 193483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonakaimport static org.junit.Assert.assertEquals; 203483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonakaimport static org.junit.Assert.assertFalse; 213483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonakaimport static org.junit.Assert.assertNotNull; 223483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka 233483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonakaimport android.annotation.NonNull; 243483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonakaimport android.support.test.filters.SmallTest; 253483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonakaimport android.support.test.runner.AndroidJUnit4; 263483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonakaimport android.text.style.QuoteSpan; 273483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonakaimport android.text.style.UnderlineSpan; 283483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka 293483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonakaimport org.junit.Test; 303483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonakaimport org.junit.runner.RunWith; 313483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka 323483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka@SmallTest 333483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka@RunWith(AndroidJUnit4.class) 343483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonakapublic class SpannedStringNoCopyTest { 353483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka @Test 363483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka public void testCopyConstructor_copyNoCopySpans_SpannableStringInternalImpl() { 373483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka final SpannableString first = new SpannableString("t\nest data"); 383483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka first.setSpan(new QuoteSpan(), 0, 2, Spanned.SPAN_PARAGRAPH); 393483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka first.setSpan(new NoCopySpan.Concrete(), 2, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 403483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka first.setSpan(new UnderlineSpan(), 0, first.length(), Spanned.SPAN_PRIORITY); 413483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka 423483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka // By default, copy NoCopySpans 433483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka final SpannedString copied = new SpannedString(first); 443483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka final Object[] spans = copied.getSpans(0, copied.length(), Object.class); 453483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka assertNotNull(spans); 463483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka assertEquals(3, spans.length); 473483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka } 483483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka 493483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka @Test 503483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka public void testCopyConstructor_doesNotCopyNoCopySpans_SpannableStringInternalImpl() { 513483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka final SpannableString first = new SpannableString("t\nest data"); 523483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka first.setSpan(new QuoteSpan(), 0, 2, Spanned.SPAN_PARAGRAPH); 533483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka first.setSpan(new NoCopySpan.Concrete(), 2, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 543483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka first.setSpan(new UnderlineSpan(), 0, first.length(), Spanned.SPAN_PRIORITY); 553483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka 563483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka // Do not copy NoCopySpan if specified so. 57bd1632355ec72a7a893334a87d103d11ba4c2593Seigo Nonaka final SpannedString copied = new SpannedString(first, true /* ignoreNoCopySpan */); 583483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka final Object[] spans = copied.getSpans(0, copied.length(), Object.class); 593483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka assertNotNull(spans); 603483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka assertEquals(2, spans.length); 613483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka 623483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka for (int i = 0; i < spans.length; i++) { 633483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka assertFalse(spans[i] instanceof NoCopySpan); 643483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka } 653483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka } 663483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka 673483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka @Test 683483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka public void testCopyConstructor_copyNoCopySpans_OtherSpannedImpl() { 693483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka final SpannableString first = new SpannableString("t\nest data"); 703483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka first.setSpan(new QuoteSpan(), 0, 2, Spanned.SPAN_PARAGRAPH); 713483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka first.setSpan(new NoCopySpan.Concrete(), 2, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 723483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka first.setSpan(new UnderlineSpan(), 0, first.length(), Spanned.SPAN_PRIORITY); 733483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka 743483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka // By default, copy NoCopySpans 753483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka final SpannedString copied = new SpannedString(new CustomSpanned(first)); 763483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka final Object[] spans = copied.getSpans(0, copied.length(), Object.class); 773483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka assertNotNull(spans); 783483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka assertEquals(3, spans.length); 793483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka } 803483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka 813483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka @Test 823483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka public void testCopyConstructor_doesNotCopyNoCopySpans_OtherSpannedImpl() { 833483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka final SpannableString first = new SpannableString("t\nest data"); 843483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka first.setSpan(new QuoteSpan(), 0, 2, Spanned.SPAN_PARAGRAPH); 853483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka first.setSpan(new NoCopySpan.Concrete(), 2, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 863483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka first.setSpan(new UnderlineSpan(), 0, first.length(), Spanned.SPAN_PRIORITY); 873483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka 883483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka // Do not copy NoCopySpan if specified so. 893483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka final SpannedString copied = new SpannedString( 90bd1632355ec72a7a893334a87d103d11ba4c2593Seigo Nonaka new CustomSpanned(first), true /* ignoreNoCopySpan */); 913483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka final Object[] spans = copied.getSpans(0, copied.length(), Object.class); 923483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka assertNotNull(spans); 933483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka assertEquals(2, spans.length); 943483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka 953483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka for (int i = 0; i < spans.length; i++) { 963483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka assertFalse(spans[i] instanceof NoCopySpan); 973483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka } 983483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka } 993483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka 1003483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka // A custom implementation of Spanned 1013483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka private static class CustomSpanned implements Spanned { 1023483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka private final @NonNull Spanned mText; 1033483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka 1043483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka CustomSpanned(@NonNull Spannable text) { 1053483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka mText = text; 1063483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka } 1073483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka 1083483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka @Override 1093483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka public <T> T[] getSpans(int start, int end, Class<T> type) { 1103483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka return mText.getSpans(start, end, type); 1113483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka } 1123483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka 1133483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka @Override 1143483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka public int getSpanStart(Object tag) { 1153483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka return mText.getSpanStart(tag); 1163483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka } 1173483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka 1183483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka @Override 1193483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka public int getSpanEnd(Object tag) { 1203483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka return mText.getSpanEnd(tag); 1213483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka } 1223483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka 1233483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka @Override 1243483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka public int getSpanFlags(Object tag) { 1253483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka return mText.getSpanFlags(tag); 1263483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka } 1273483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka 1283483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka @Override 1293483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka public int nextSpanTransition(int start, int limit, Class type) { 1303483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka return mText.nextSpanTransition(start, limit, type); 1313483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka } 1323483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka 1333483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka @Override 1343483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka public int length() { 1353483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka return mText.length(); 1363483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka } 1373483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka 1383483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka @Override 1393483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka public char charAt(int index) { 1403483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka return mText.charAt(index); 1413483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka } 1423483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka 1433483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka @Override 1443483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka public CharSequence subSequence(int start, int end) { 1453483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka return mText.subSequence(start, end); 1463483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka } 1473483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka 1483483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka @Override 1493483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka public String toString() { 1503483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka return mText.toString(); 1513483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka } 1523483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka }; 1533483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka} 154