1 /* 2 * Copyright (C) 2014 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.inputmethod.compat; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertNotNull; 21 import static org.junit.Assert.assertTrue; 22 23 import android.graphics.Typeface; 24 import android.os.Build; 25 import android.text.SpannableString; 26 import android.text.Spanned; 27 import android.text.style.StyleSpan; 28 29 import androidx.test.filters.SmallTest; 30 import androidx.test.runner.AndroidJUnit4; 31 32 import org.junit.Test; 33 import org.junit.runner.RunWith; 34 35 import java.util.Locale; 36 37 @SmallTest 38 @RunWith(AndroidJUnit4.class) 39 public class LocaleSpanCompatUtilsTests { 40 @Test testInstantiatable()41 public void testInstantiatable() { 42 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { 43 // LocaleSpan isn't yet available. 44 return; 45 } 46 assertTrue(LocaleSpanCompatUtils.isLocaleSpanAvailable()); 47 final Object japaneseLocaleSpan = LocaleSpanCompatUtils.newLocaleSpan(Locale.JAPANESE); 48 assertNotNull(japaneseLocaleSpan); 49 assertEquals(Locale.JAPANESE, 50 LocaleSpanCompatUtils.getLocaleFromLocaleSpan(japaneseLocaleSpan)); 51 } 52 assertLocaleSpan(final Spanned spanned, final int index, final int expectedStart, final int expectedEnd, final Locale expectedLocale, final int expectedSpanFlags)53 private static void assertLocaleSpan(final Spanned spanned, final int index, 54 final int expectedStart, final int expectedEnd, 55 final Locale expectedLocale, final int expectedSpanFlags) { 56 final Object span = spanned.getSpans(0, spanned.length(), Object.class)[index]; 57 assertEquals(expectedLocale, LocaleSpanCompatUtils.getLocaleFromLocaleSpan(span)); 58 assertEquals(expectedStart, spanned.getSpanStart(span)); 59 assertEquals(expectedEnd, spanned.getSpanEnd(span)); 60 assertEquals(expectedSpanFlags, spanned.getSpanFlags(span)); 61 } 62 assertSpanEquals(final Object expectedSpan, final Spanned spanned, final int index)63 private static void assertSpanEquals(final Object expectedSpan, final Spanned spanned, 64 final int index) { 65 final Object[] spans = spanned.getSpans(0, spanned.length(), Object.class); 66 assertEquals(expectedSpan, spans[index]); 67 } 68 assertSpanCount(final int expectedCount, final Spanned spanned)69 private static void assertSpanCount(final int expectedCount, final Spanned spanned) { 70 final Object[] spans = spanned.getSpans(0, spanned.length(), Object.class); 71 assertEquals(expectedCount, spans.length); 72 } 73 74 @Test testUpdateLocaleSpan()75 public void testUpdateLocaleSpan() { 76 if (!LocaleSpanCompatUtils.isLocaleSpanAvailable()) { 77 return; 78 } 79 80 // Test if the simplest case works. 81 { 82 final SpannableString text = new SpannableString("0123456789"); 83 LocaleSpanCompatUtils.updateLocaleSpan(text, 1, 5, Locale.JAPANESE); 84 assertSpanCount(1, text); 85 assertLocaleSpan(text, 0, 1, 5, Locale.JAPANESE, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 86 } 87 88 // Test if only LocaleSpans are updated. 89 { 90 final SpannableString text = new SpannableString("0123456789"); 91 final StyleSpan styleSpan = new StyleSpan(Typeface.BOLD); 92 text.setSpan(styleSpan, 0, 7, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 93 LocaleSpanCompatUtils.updateLocaleSpan(text, 1, 5, Locale.JAPANESE); 94 assertSpanCount(2, text); 95 assertSpanEquals(styleSpan, text, 0); 96 assertLocaleSpan(text, 1, 1, 5, Locale.JAPANESE, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 97 } 98 99 // Test if two jointed spans are merged into one span. 100 { 101 final SpannableString text = new SpannableString("0123456789"); 102 text.setSpan(LocaleSpanCompatUtils.newLocaleSpan(Locale.JAPANESE), 1, 3, 103 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 104 LocaleSpanCompatUtils.updateLocaleSpan(text, 3, 5, Locale.JAPANESE); 105 assertSpanCount(1, text); 106 assertLocaleSpan(text, 0, 1, 5, Locale.JAPANESE, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 107 } 108 109 // Test if two overlapped spans are merged into one span. 110 { 111 final SpannableString text = new SpannableString("0123456789"); 112 text.setSpan(LocaleSpanCompatUtils.newLocaleSpan(Locale.JAPANESE), 1, 4, 113 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 114 LocaleSpanCompatUtils.updateLocaleSpan(text, 3, 5, Locale.JAPANESE); 115 assertSpanCount(1, text); 116 assertLocaleSpan(text, 0, 1, 5, Locale.JAPANESE, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 117 } 118 119 // Test if three overlapped spans are merged into one span. 120 { 121 final SpannableString text = new SpannableString("0123456789"); 122 text.setSpan(LocaleSpanCompatUtils.newLocaleSpan(Locale.JAPANESE), 1, 4, 123 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 124 text.setSpan(LocaleSpanCompatUtils.newLocaleSpan(Locale.JAPANESE), 5, 6, 125 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 126 LocaleSpanCompatUtils.updateLocaleSpan(text, 2, 8, Locale.JAPANESE); 127 assertSpanCount(1, text); 128 assertLocaleSpan(text, 0, 1, 8, Locale.JAPANESE, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 129 } 130 131 // Test if disjoint spans remain disjoint. 132 { 133 final SpannableString text = new SpannableString("0123456789"); 134 text.setSpan(LocaleSpanCompatUtils.newLocaleSpan(Locale.JAPANESE), 1, 3, 135 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 136 text.setSpan(LocaleSpanCompatUtils.newLocaleSpan(Locale.JAPANESE), 5, 6, 137 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 138 LocaleSpanCompatUtils.updateLocaleSpan(text, 8, 9, Locale.JAPANESE); 139 assertSpanCount(3, text); 140 assertLocaleSpan(text, 0, 1, 3, Locale.JAPANESE, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 141 assertLocaleSpan(text, 1, 5, 6, Locale.JAPANESE, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 142 assertLocaleSpan(text, 2, 8, 9, Locale.JAPANESE, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 143 } 144 145 // Test if existing span flags are preserved during merge. 146 { 147 final SpannableString text = new SpannableString("0123456789"); 148 text.setSpan(LocaleSpanCompatUtils.newLocaleSpan(Locale.JAPANESE), 1, 5, 149 Spanned.SPAN_INCLUSIVE_INCLUSIVE | Spanned.SPAN_INTERMEDIATE); 150 LocaleSpanCompatUtils.updateLocaleSpan(text, 3, 4, Locale.JAPANESE); 151 assertSpanCount(1, text); 152 assertLocaleSpan(text, 0, 1, 5, Locale.JAPANESE, 153 Spanned.SPAN_INCLUSIVE_INCLUSIVE | Spanned.SPAN_INTERMEDIATE); 154 } 155 156 // Test if existing span flags are preserved even when partially overlapped (leading edge). 157 { 158 final SpannableString text = new SpannableString("0123456789"); 159 text.setSpan(LocaleSpanCompatUtils.newLocaleSpan(Locale.JAPANESE), 1, 5, 160 Spanned.SPAN_INCLUSIVE_INCLUSIVE | Spanned.SPAN_INTERMEDIATE); 161 LocaleSpanCompatUtils.updateLocaleSpan(text, 3, 7, Locale.JAPANESE); 162 assertSpanCount(1, text); 163 assertLocaleSpan(text, 0, 1, 7, Locale.JAPANESE, 164 Spanned.SPAN_INCLUSIVE_EXCLUSIVE | Spanned.SPAN_INTERMEDIATE); 165 } 166 167 // Test if existing span flags are preserved even when partially overlapped (trailing edge). 168 { 169 final SpannableString text = new SpannableString("0123456789"); 170 text.setSpan(LocaleSpanCompatUtils.newLocaleSpan(Locale.JAPANESE), 3, 7, 171 Spanned.SPAN_INCLUSIVE_INCLUSIVE | Spanned.SPAN_INTERMEDIATE); 172 LocaleSpanCompatUtils.updateLocaleSpan(text, 1, 5, Locale.JAPANESE); 173 assertSpanCount(1, text); 174 assertLocaleSpan(text, 0, 1, 7, Locale.JAPANESE, 175 Spanned.SPAN_EXCLUSIVE_INCLUSIVE | Spanned.SPAN_INTERMEDIATE); 176 } 177 178 // Test if existing locale span will be removed when the locale doesn't match. 179 { 180 final SpannableString text = new SpannableString("0123456789"); 181 text.setSpan(LocaleSpanCompatUtils.newLocaleSpan(Locale.ENGLISH), 3, 5, 182 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 183 LocaleSpanCompatUtils.updateLocaleSpan(text, 1, 7, Locale.JAPANESE); 184 assertSpanCount(1, text); 185 assertLocaleSpan(text, 0, 1, 7, Locale.JAPANESE, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 186 } 187 188 // Test if existing locale span will be removed when the locale doesn't match. (case 2) 189 { 190 final SpannableString text = new SpannableString("0123456789"); 191 text.setSpan(LocaleSpanCompatUtils.newLocaleSpan(Locale.ENGLISH), 3, 7, 192 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 193 LocaleSpanCompatUtils.updateLocaleSpan(text, 5, 6, Locale.JAPANESE); 194 assertSpanCount(3, text); 195 assertLocaleSpan(text, 0, 3, 5, Locale.ENGLISH, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 196 assertLocaleSpan(text, 1, 6, 7, Locale.ENGLISH, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 197 assertLocaleSpan(text, 2, 5, 6, Locale.JAPANESE, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 198 } 199 200 // Test if existing locale span will be removed when the locale doesn't match. (case 3) 201 { 202 final SpannableString text = new SpannableString("0123456789"); 203 text.setSpan(LocaleSpanCompatUtils.newLocaleSpan(Locale.ENGLISH), 3, 7, 204 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 205 LocaleSpanCompatUtils.updateLocaleSpan(text, 2, 5, Locale.JAPANESE); 206 assertSpanCount(2, text); 207 assertLocaleSpan(text, 0, 5, 7, Locale.ENGLISH, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 208 assertLocaleSpan(text, 1, 2, 5, Locale.JAPANESE, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 209 } 210 211 // Test if existing locale span will be removed when the locale doesn't match. (case 3) 212 { 213 final SpannableString text = new SpannableString("0123456789"); 214 text.setSpan(LocaleSpanCompatUtils.newLocaleSpan(Locale.ENGLISH), 3, 7, 215 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 216 LocaleSpanCompatUtils.updateLocaleSpan(text, 5, 8, Locale.JAPANESE); 217 assertSpanCount(2, text); 218 assertLocaleSpan(text, 0, 3, 5, Locale.ENGLISH, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 219 assertLocaleSpan(text, 1, 5, 8, Locale.JAPANESE, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 220 } 221 } 222 } 223