Home | History | Annotate | Download | only in compat
      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.annotation.TargetApi;
     20 import android.os.Build;
     21 import android.test.AndroidTestCase;
     22 import android.test.suitebuilder.annotation.SmallTest;
     23 import android.text.Spanned;
     24 import android.text.TextUtils;
     25 import android.text.style.SuggestionSpan;
     26 
     27 import com.android.inputmethod.latin.SuggestedWords;
     28 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
     29 
     30 import java.util.ArrayList;
     31 import java.util.Arrays;
     32 import java.util.Locale;
     33 
     34 import javax.annotation.Nullable;
     35 
     36 @SmallTest
     37 public class SuggestionSpanUtilsTest extends AndroidTestCase {
     38 
     39     /**
     40      * Helper method to create a dummy {@link SuggestedWordInfo}.
     41      *
     42      * @param kindAndFlags the kind and flags to be used to create {@link SuggestedWordInfo}.
     43      * @param word the word to be used to create {@link SuggestedWordInfo}.
     44      * @return a new instance of {@link SuggestedWordInfo}.
     45      */
     46     private static SuggestedWordInfo createWordInfo(final String word, final int kindAndFlags) {
     47         return new SuggestedWordInfo(word, "" /* prevWordsContext */, 1 /* score */, kindAndFlags,
     48                 null /* sourceDict */,
     49                 SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
     50                 SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */);
     51     }
     52 
     53     private static void assertNotSuggestionSpan(final String expectedText,
     54             final CharSequence actualText) {
     55         assertTrue(TextUtils.equals(expectedText, actualText));
     56         if (!(actualText instanceof Spanned)) {
     57             return;
     58         }
     59         final Spanned spanned = (Spanned)actualText;
     60         final SuggestionSpan[] suggestionSpans = spanned.getSpans(0, spanned.length(),
     61                 SuggestionSpan.class);
     62         assertEquals(0, suggestionSpans.length);
     63     }
     64 
     65     private static void assertSuggestionSpan(final String expectedText,
     66             final int reuiredSuggestionSpanFlags, final int requiredSpanFlags,
     67             final String[] expectedSuggestions, @Nullable final Locale expectedLocale,
     68             final CharSequence actualText) {
     69         assertTrue(TextUtils.equals(expectedText, actualText));
     70         assertTrue(actualText instanceof Spanned);
     71         final Spanned spanned = (Spanned)actualText;
     72         final SuggestionSpan[] suggestionSpans = spanned.getSpans(0, spanned.length(),
     73                 SuggestionSpan.class);
     74         assertEquals(1, suggestionSpans.length);
     75         final SuggestionSpan suggestionSpan = suggestionSpans[0];
     76         if (reuiredSuggestionSpanFlags != 0) {
     77             assertTrue((suggestionSpan.getFlags() & reuiredSuggestionSpanFlags) != 0);
     78         }
     79         if (requiredSpanFlags != 0) {
     80             assertTrue((spanned.getSpanFlags(suggestionSpan) & requiredSpanFlags) != 0);
     81         }
     82         if (expectedSuggestions != null) {
     83             final String[] actualSuggestions = suggestionSpan.getSuggestions();
     84             assertEquals(expectedSuggestions.length, actualSuggestions.length);
     85             for (int i = 0; i < expectedSuggestions.length; ++i) {
     86                 assertEquals(expectedSuggestions[i], actualSuggestions[i]);
     87             }
     88         }
     89         // CAVEAT: SuggestionSpan#getLocale() returns String rather than Locale object.
     90         assertEquals(expectedLocale.toString(), suggestionSpan.getLocale());
     91     }
     92 
     93     @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
     94     public void testGetTextWithAutoCorrectionIndicatorUnderline() {
     95         final String ORIGINAL_TEXT = "Hey!";
     96         final Locale NONNULL_LOCALE = new Locale("en", "GB");
     97         final CharSequence text = SuggestionSpanUtils.getTextWithAutoCorrectionIndicatorUnderline(
     98                 getContext(), ORIGINAL_TEXT, NONNULL_LOCALE);
     99         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
    100             assertNotSuggestionSpan(ORIGINAL_TEXT, text);
    101             return;
    102         }
    103         assertSuggestionSpan(ORIGINAL_TEXT,
    104                 SuggestionSpan.FLAG_AUTO_CORRECTION /* reuiredSuggestionSpanFlags */,
    105                 Spanned.SPAN_COMPOSING | Spanned.SPAN_EXCLUSIVE_EXCLUSIVE /* requiredSpanFlags */,
    106                 new String[]{}, NONNULL_LOCALE, text);
    107     }
    108 
    109     @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
    110     public void testGetTextWithAutoCorrectionIndicatorUnderlineRootLocale() {
    111         final String ORIGINAL_TEXT = "Hey!";
    112         final CharSequence text = SuggestionSpanUtils.getTextWithAutoCorrectionIndicatorUnderline(
    113                 getContext(), ORIGINAL_TEXT, Locale.ROOT);
    114         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
    115             assertNotSuggestionSpan(ORIGINAL_TEXT, text);
    116             return;
    117         }
    118         assertSuggestionSpan(ORIGINAL_TEXT,
    119                 SuggestionSpan.FLAG_AUTO_CORRECTION /* reuiredSuggestionSpanFlags */,
    120                 Spanned.SPAN_COMPOSING | Spanned.SPAN_EXCLUSIVE_EXCLUSIVE /* requiredSpanFlags */,
    121                 new String[]{}, Locale.ROOT, text);
    122     }
    123 
    124     public void testGetTextWithSuggestionSpan() {
    125         final SuggestedWordInfo prediction1 =
    126                 createWordInfo("Quality", SuggestedWordInfo.KIND_PREDICTION);
    127         final SuggestedWordInfo prediction2 =
    128                 createWordInfo("Speed", SuggestedWordInfo.KIND_PREDICTION);
    129         final SuggestedWordInfo prediction3 =
    130                 createWordInfo("Price", SuggestedWordInfo.KIND_PREDICTION);
    131 
    132         final SuggestedWordInfo typed =
    133                 createWordInfo("Hey", SuggestedWordInfo.KIND_TYPED);
    134 
    135         final SuggestedWordInfo[] corrections =
    136                 new SuggestedWordInfo[SuggestionSpan.SUGGESTIONS_MAX_SIZE * 2];
    137         for (int i = 0; i < corrections.length; ++i) {
    138             corrections[i] = createWordInfo("correction" + i, SuggestedWordInfo.KIND_CORRECTION);
    139         }
    140 
    141         final Locale NONNULL_LOCALE = new Locale("en", "GB");
    142 
    143         // SuggestionSpan will not be attached when {@link SuggestedWords#INPUT_STYLE_PREDICTION}
    144         // is specified.
    145         {
    146             final SuggestedWords predictedWords = new SuggestedWords(
    147                     new ArrayList<>(Arrays.asList(prediction1, prediction2, prediction3)),
    148                     null /* rawSuggestions */,
    149                     null /* typedWord */,
    150                     false /* typedWordValid */,
    151                     false /* willAutoCorrect */,
    152                     false /* isObsoleteSuggestions */,
    153                     SuggestedWords.INPUT_STYLE_PREDICTION,
    154                     SuggestedWords.NOT_A_SEQUENCE_NUMBER);
    155             final String PICKED_WORD = prediction2.mWord;
    156             // Note that the framework uses the context locale as a fallback locale.
    157             assertNotSuggestionSpan(
    158                     PICKED_WORD,
    159                     SuggestionSpanUtils.getTextWithSuggestionSpan(getContext(), PICKED_WORD,
    160                             predictedWords, NONNULL_LOCALE));
    161         }
    162 
    163         final ArrayList<SuggestedWordInfo> suggestedWordList = new ArrayList<>();
    164         suggestedWordList.add(typed);
    165         suggestedWordList.add(prediction1);
    166         suggestedWordList.add(prediction2);
    167         suggestedWordList.add(prediction3);
    168         suggestedWordList.addAll(Arrays.asList(corrections));
    169         final SuggestedWords typedAndCollectedWords = new SuggestedWords(
    170                 suggestedWordList,
    171                 null /* rawSuggestions */,
    172                 null /* typedWord */,
    173                 false /* typedWordValid */,
    174                 false /* willAutoCorrect */,
    175                 false /* isObsoleteSuggestions */,
    176                 SuggestedWords.INPUT_STYLE_TYPING,
    177                 SuggestedWords.NOT_A_SEQUENCE_NUMBER);
    178 
    179         for (final SuggestedWordInfo pickedWord : suggestedWordList) {
    180             final String PICKED_WORD = pickedWord.mWord;
    181 
    182             final ArrayList<String> expectedSuggestions = new ArrayList<>();
    183             for (SuggestedWordInfo suggestedWordInfo : suggestedWordList) {
    184                 if (expectedSuggestions.size() >= SuggestionSpan.SUGGESTIONS_MAX_SIZE) {
    185                     break;
    186                 }
    187                 if (suggestedWordInfo.isKindOf(SuggestedWordInfo.KIND_PREDICTION)) {
    188                     // Currently predictions are not filled into SuggestionSpan.
    189                     continue;
    190                 }
    191                 final String suggestedWord = suggestedWordInfo.mWord;
    192                 if (TextUtils.equals(PICKED_WORD, suggestedWord)) {
    193                     // Typed word itself is not added to SuggestionSpan.
    194                     continue;
    195                 }
    196                 expectedSuggestions.add(suggestedWord);
    197             }
    198 
    199             // non-null locale
    200             assertSuggestionSpan(
    201                     PICKED_WORD,
    202                     0 /* reuiredSuggestionSpanFlags */,
    203                     Spanned.SPAN_EXCLUSIVE_EXCLUSIVE /* requiredSpanFlags */,
    204                     expectedSuggestions.toArray(new String[expectedSuggestions.size()]),
    205                     NONNULL_LOCALE,
    206                     SuggestionSpanUtils.getTextWithSuggestionSpan(getContext(), PICKED_WORD,
    207                             typedAndCollectedWords, NONNULL_LOCALE));
    208 
    209             // root locale
    210             assertSuggestionSpan(
    211                     PICKED_WORD,
    212                     0 /* reuiredSuggestionSpanFlags */,
    213                     Spanned.SPAN_EXCLUSIVE_EXCLUSIVE /* requiredSpanFlags */,
    214                     expectedSuggestions.toArray(new String[expectedSuggestions.size()]),
    215                     Locale.ROOT,
    216                     SuggestionSpanUtils.getTextWithSuggestionSpan(getContext(), PICKED_WORD,
    217                             typedAndCollectedWords, Locale.ROOT));
    218         }
    219     }
    220 
    221     public void testFindFirstLocaleFromSuggestionSpans() {
    222         final String[] suggestions = new String[] {"Quality", "Speed", "Price"};
    223         final SuggestionSpan nullLocaleSpan = new SuggestionSpan((Locale)null, suggestions, 0);
    224         final SuggestionSpan emptyLocaleSpan = new SuggestionSpan(new Locale(""), suggestions, 0);
    225         final SuggestionSpan enUsLocaleSpan = new SuggestionSpan(Locale.US, suggestions, 0);
    226         final SuggestionSpan jaJpLocaleSpan = new SuggestionSpan(Locale.JAPAN, suggestions, 0);
    227 
    228         assertEquals(null, SuggestionSpanUtils.findFirstLocaleFromSuggestionSpans(
    229                 new SuggestionSpan[] {}));
    230 
    231         assertEquals(null, SuggestionSpanUtils.findFirstLocaleFromSuggestionSpans(
    232                 new SuggestionSpan[] {emptyLocaleSpan}));
    233 
    234         assertEquals(Locale.US, SuggestionSpanUtils.findFirstLocaleFromSuggestionSpans(
    235                 new SuggestionSpan[] {enUsLocaleSpan}));
    236 
    237         assertEquals(Locale.US, SuggestionSpanUtils.findFirstLocaleFromSuggestionSpans(
    238                 new SuggestionSpan[] {nullLocaleSpan, enUsLocaleSpan}));
    239 
    240         assertEquals(Locale.US, SuggestionSpanUtils.findFirstLocaleFromSuggestionSpans(
    241                 new SuggestionSpan[] {nullLocaleSpan, emptyLocaleSpan, enUsLocaleSpan}));
    242 
    243         assertEquals(Locale.JAPAN, SuggestionSpanUtils.findFirstLocaleFromSuggestionSpans(
    244                 new SuggestionSpan[] {nullLocaleSpan, jaJpLocaleSpan, enUsLocaleSpan}));
    245     }
    246 }
    247