Home | History | Annotate | Download | only in textservice
      1 /*
      2  * Copyright (C) 2015 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.view.textservice;
     18 
     19 import android.os.Parcel;
     20 import android.test.InstrumentationTestCase;
     21 import android.test.suitebuilder.annotation.SmallTest;
     22 
     23 import java.util.Arrays;
     24 import java.util.Locale;
     25 
     26 import static android.test.MoreAsserts.assertNotEqual;
     27 
     28 /**
     29  * TODO: Most of part can be, and probably should be, moved to CTS.
     30  */
     31 public class SpellCheckerSubtypeTest extends InstrumentationTestCase {
     32     private static final int SUBTYPE_SUBTYPE_ID_NONE = 0;
     33     private static final String SUBTYPE_SUBTYPE_LOCALE_STRING_NONE = "";
     34     private static final String SUBTYPE_SUBTYPE_LANGUAGE_TAG_NONE = "";
     35 
     36     private static final String SUBTYPE_SUBTYPE_LOCALE_STRING_A = "en_GB";
     37     private static final String SUBTYPE_SUBTYPE_LANGUAGE_TAG_A = "en-GB";
     38     private static final int SUBTYPE_NAME_RES_ID_A = 0x12345;
     39     private static final String SUBTYPE_EXTRA_VALUE_A = "Key1=Value1,Key2=Value2";
     40     private static final int SUBTYPE_SUBTYPE_ID_A = 42;
     41     private static final String SUBTYPE_SUBTYPE_LOCALE_STRING_B = "en_IN";
     42     private static final String SUBTYPE_SUBTYPE_LANGUAGE_TAG_B = "en-IN";
     43     private static final int SUBTYPE_NAME_RES_ID_B = 0x54321;
     44     private static final String SUBTYPE_EXTRA_VALUE_B = "Key3=Value3,Key4=Value4";
     45     private static final int SUBTYPE_SUBTYPE_ID_B = -42;
     46 
     47     private static int defaultHashCodeAlgorithm(String locale, String extraValue) {
     48         return Arrays.hashCode(new Object[] {locale, extraValue});
     49     }
     50 
     51     private static final SpellCheckerSubtype cloneViaParcel(final SpellCheckerSubtype original) {
     52         Parcel parcel = null;
     53         try {
     54             parcel = Parcel.obtain();
     55             original.writeToParcel(parcel, 0);
     56             parcel.setDataPosition(0);
     57             return SpellCheckerSubtype.CREATOR.createFromParcel(parcel);
     58         } finally {
     59             if (parcel != null) {
     60                 parcel.recycle();
     61             }
     62         }
     63     }
     64 
     65     @SmallTest
     66     public void testSubtypeWithNoSubtypeId() throws Exception {
     67         final SpellCheckerSubtype subtype = new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A,
     68                 SUBTYPE_SUBTYPE_LOCALE_STRING_A, SUBTYPE_SUBTYPE_LANGUAGE_TAG_A,
     69                 SUBTYPE_EXTRA_VALUE_A, SUBTYPE_SUBTYPE_ID_NONE);
     70         assertEquals(SUBTYPE_NAME_RES_ID_A, subtype.getNameResId());
     71         assertEquals(SUBTYPE_SUBTYPE_LOCALE_STRING_A, subtype.getLocale());
     72         assertEquals(SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, subtype.getLanguageTag());
     73         assertEquals("Value1", subtype.getExtraValueOf("Key1"));
     74         assertEquals("Value2", subtype.getExtraValueOf("Key2"));
     75         // Historically we have used SpellCheckerSubtype#hashCode() to track which subtype is
     76         // enabled, and it is supposed to be stored in SecureSettings.  Therefore we have to
     77         // keep using the same algorithm for compatibility reasons.
     78         assertEquals(
     79                 defaultHashCodeAlgorithm(SUBTYPE_SUBTYPE_LOCALE_STRING_A, SUBTYPE_EXTRA_VALUE_A),
     80                 subtype.hashCode());
     81 
     82         final SpellCheckerSubtype clonedSubtype = cloneViaParcel(subtype);
     83         assertEquals(SUBTYPE_NAME_RES_ID_A, clonedSubtype.getNameResId());
     84         assertEquals(SUBTYPE_SUBTYPE_LOCALE_STRING_A, clonedSubtype.getLocale());
     85         assertEquals(SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, clonedSubtype.getLanguageTag());
     86         assertEquals("Value1", clonedSubtype.getExtraValueOf("Key1"));
     87         assertEquals("Value2", clonedSubtype.getExtraValueOf("Key2"));
     88         assertEquals(
     89                 defaultHashCodeAlgorithm(SUBTYPE_SUBTYPE_LOCALE_STRING_A, SUBTYPE_EXTRA_VALUE_A),
     90                 clonedSubtype.hashCode());
     91     }
     92 
     93     public void testSubtypeWithSubtypeId() throws Exception {
     94         final SpellCheckerSubtype subtype = new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A,
     95                 SUBTYPE_SUBTYPE_LOCALE_STRING_A, SUBTYPE_SUBTYPE_LANGUAGE_TAG_A,
     96                 SUBTYPE_EXTRA_VALUE_A, SUBTYPE_SUBTYPE_ID_A);
     97 
     98         assertEquals(SUBTYPE_NAME_RES_ID_A, subtype.getNameResId());
     99         assertEquals(SUBTYPE_SUBTYPE_LOCALE_STRING_A, subtype.getLocale());
    100         assertEquals(SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, subtype.getLanguageTag());
    101         assertEquals("Value1", subtype.getExtraValueOf("Key1"));
    102         assertEquals("Value2", subtype.getExtraValueOf("Key2"));
    103         // Similar to "SubtypeId" in InputMethodSubtype, "SubtypeId" in SpellCheckerSubtype enables
    104         // developers to specify a stable and consistent ID for each subtype.
    105         assertEquals(SUBTYPE_SUBTYPE_ID_A, subtype.hashCode());
    106 
    107         final SpellCheckerSubtype clonedSubtype = cloneViaParcel(subtype);
    108         assertEquals(SUBTYPE_NAME_RES_ID_A, clonedSubtype.getNameResId());
    109         assertEquals(SUBTYPE_SUBTYPE_LOCALE_STRING_A, clonedSubtype.getLocale());
    110         assertEquals(SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, clonedSubtype.getLanguageTag());
    111         assertEquals("Value1", clonedSubtype.getExtraValueOf("Key1"));
    112         assertEquals("Value2", clonedSubtype.getExtraValueOf("Key2"));
    113         assertEquals(SUBTYPE_SUBTYPE_ID_A, clonedSubtype.hashCode());
    114     }
    115 
    116     @SmallTest
    117     public void testGetLocaleObject() throws Exception {
    118         assertEquals(new Locale("en", "GB"),
    119                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, "en_GB",
    120                         SUBTYPE_SUBTYPE_LANGUAGE_TAG_NONE, SUBTYPE_EXTRA_VALUE_A,
    121                         SUBTYPE_SUBTYPE_ID_NONE).getLocaleObject());
    122         assertEquals(new Locale("en", "GB"),
    123                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_NONE,
    124                         "en-GB", SUBTYPE_EXTRA_VALUE_A,
    125                         SUBTYPE_SUBTYPE_ID_NONE).getLocaleObject());
    126 
    127         // If neither locale string nor language tag is specified,
    128         // {@link SpellCheckerSubtype#getLocaleObject} returns null.
    129         assertNull(
    130                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_NONE,
    131                         SUBTYPE_SUBTYPE_LANGUAGE_TAG_NONE, SUBTYPE_EXTRA_VALUE_A,
    132                         SUBTYPE_SUBTYPE_ID_NONE).getLocaleObject());
    133 
    134         // If both locale string and language tag are specified,
    135         // {@link SpellCheckerSubtype#getLocaleObject} uses language tag.
    136         assertEquals(new Locale("en", "GB"),
    137                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, "en_US", "en-GB",
    138                         SUBTYPE_EXTRA_VALUE_A, SUBTYPE_SUBTYPE_ID_NONE).getLocaleObject());
    139 
    140         // Make sure that "tl_PH" is rewritten to "fil_PH" for spell checkers that need to support
    141         // Android KitKat and prior, which do not support 3-letter language codes.
    142         assertEquals(new Locale("fil", "PH"),
    143                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, "tl_PH",
    144                         SUBTYPE_SUBTYPE_LANGUAGE_TAG_NONE, SUBTYPE_EXTRA_VALUE_A,
    145                         SUBTYPE_SUBTYPE_ID_NONE).getLocaleObject());
    146 
    147         // "languageTag" attribute is available in Android N and later, where 3-letter country codes
    148         // are guaranteed to be available.  It's developers' responsibility for specifying a valid
    149         // country subtags here and we do not rewrite "tl" to "fil" for simplicity.
    150         assertEquals("tl",
    151                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_NONE,
    152                         "tl-PH", SUBTYPE_EXTRA_VALUE_A, SUBTYPE_SUBTYPE_ID_NONE)
    153                         .getLocaleObject().getLanguage());
    154     }
    155 
    156     @SmallTest
    157     public void testEquality() throws Exception {
    158         assertEquals(
    159                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
    160                         SUBTYPE_EXTRA_VALUE_A),
    161                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
    162                         SUBTYPE_EXTRA_VALUE_A));
    163         assertNotEqual(
    164                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
    165                         SUBTYPE_EXTRA_VALUE_A),
    166                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_B, SUBTYPE_SUBTYPE_LOCALE_STRING_B,
    167                         SUBTYPE_EXTRA_VALUE_A));
    168         assertNotEqual(
    169                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
    170                         SUBTYPE_EXTRA_VALUE_A),
    171                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_B,
    172                         SUBTYPE_EXTRA_VALUE_A));
    173         assertNotEqual(
    174                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
    175                         SUBTYPE_EXTRA_VALUE_A),
    176                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
    177                         SUBTYPE_EXTRA_VALUE_B));
    178 
    179         // If subtype ID is 0 (== SUBTYPE_SUBTYPE_ID_NONE), we keep the same behavior.
    180         assertEquals(
    181                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
    182                         SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_A,
    183                         SUBTYPE_SUBTYPE_ID_NONE),
    184                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
    185                         SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_A,
    186                         SUBTYPE_SUBTYPE_ID_NONE));
    187         assertNotEqual(
    188                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
    189                         SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_A,
    190                         SUBTYPE_SUBTYPE_ID_NONE),
    191                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_B, SUBTYPE_SUBTYPE_LOCALE_STRING_B,
    192                         SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_A,
    193                         SUBTYPE_SUBTYPE_ID_NONE));
    194         assertNotEqual(
    195                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
    196                         SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_A,
    197                         SUBTYPE_SUBTYPE_ID_NONE),
    198                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_B,
    199                         SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_A,
    200                         SUBTYPE_SUBTYPE_ID_NONE));
    201         assertNotEqual(
    202                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
    203                         SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_A,
    204                         SUBTYPE_SUBTYPE_ID_NONE),
    205                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
    206                         SUBTYPE_SUBTYPE_LANGUAGE_TAG_B, SUBTYPE_EXTRA_VALUE_A,
    207                         SUBTYPE_SUBTYPE_ID_NONE));
    208         assertNotEqual(
    209                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
    210                         SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_A,
    211                         SUBTYPE_SUBTYPE_ID_NONE),
    212                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
    213                         SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_B,
    214                         SUBTYPE_SUBTYPE_ID_NONE));
    215 
    216         // If subtype ID is not 0, we test the equality based only on the subtype ID.
    217         assertEquals(
    218                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
    219                         SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_A,
    220                         SUBTYPE_SUBTYPE_ID_A),
    221                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
    222                         SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_A,
    223                         SUBTYPE_SUBTYPE_ID_A));
    224         assertEquals(
    225                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
    226                         SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_A,
    227                         SUBTYPE_SUBTYPE_ID_A),
    228                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_B, SUBTYPE_SUBTYPE_LOCALE_STRING_B,
    229                         SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_A,
    230                         SUBTYPE_SUBTYPE_ID_A));
    231         assertEquals(
    232                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
    233                         SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_A,
    234                         SUBTYPE_SUBTYPE_ID_A),
    235                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_B,
    236                         SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_A,
    237                         SUBTYPE_SUBTYPE_ID_A));
    238         assertEquals(
    239                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
    240                         SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_A,
    241                         SUBTYPE_SUBTYPE_ID_A),
    242                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
    243                         SUBTYPE_SUBTYPE_LANGUAGE_TAG_B, SUBTYPE_EXTRA_VALUE_A,
    244                         SUBTYPE_SUBTYPE_ID_A));
    245         assertEquals(
    246                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
    247                         SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_A,
    248                         SUBTYPE_SUBTYPE_ID_A),
    249                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
    250                         SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_B,
    251                         SUBTYPE_SUBTYPE_ID_A));
    252         assertNotEqual(
    253                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
    254                         SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_A,
    255                         SUBTYPE_SUBTYPE_ID_A),
    256                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
    257                         SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_A,
    258                         SUBTYPE_SUBTYPE_ID_B));
    259     }
    260 
    261 }
    262