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