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
17package com.android.inputmethod.latin.utils;
18
19import static com.android.inputmethod.latin.common.Constants.Subtype.KEYBOARD_MODE;
20import static com.android.inputmethod.latin.common.Constants.Subtype.ExtraValue.ASCII_CAPABLE;
21import static com.android.inputmethod.latin.common.Constants.Subtype.ExtraValue.EMOJI_CAPABLE;
22import static com.android.inputmethod.latin.common.Constants.Subtype.ExtraValue.IS_ADDITIONAL_SUBTYPE;
23import static com.android.inputmethod.latin.common.Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET;
24import static com.android.inputmethod.latin.common.Constants.Subtype.ExtraValue.UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME;
25
26import android.content.Context;
27import android.os.Build;
28import android.test.AndroidTestCase;
29import android.test.suitebuilder.annotation.SmallTest;
30import android.view.inputmethod.InputMethodSubtype;
31
32import com.android.inputmethod.compat.InputMethodSubtypeCompatUtils;
33
34import java.util.Locale;
35
36@SmallTest
37public class AdditionalSubtypeUtilsTests extends AndroidTestCase {
38
39    /**
40     * Predictable subtype ID for en_US dvorak layout. This is actually a hash code calculated as
41     * follows.
42     * <code>
43     * final boolean isAuxiliary = false;
44     * final boolean overrideImplicitlyEnabledSubtype = false;
45     * final int SUBTYPE_ID_EN_US_DVORAK = Arrays.hashCode(new Object[] {
46     *         "en_US",
47     *         "keyboard",
48     *         "KeyboardLayoutSet=dvorak"
49     *                 + ",AsciiCapable"
50     *                 + ",UntranslatableReplacementStringInSubtypeName=Dvorak"
51     *                 + ",EmojiCapable"
52     *                 + ",isAdditionalSubtype",
53     *         isAuxiliary,
54     *         overrideImplicitlyEnabledSubtype });
55     * </code>
56     */
57    private static int SUBTYPE_ID_EN_US_DVORAK = 0xb3c0cc56;
58    private static String EXTRA_VALUE_EN_US_DVORAK_ICS =
59            "KeyboardLayoutSet=dvorak" +
60            ",AsciiCapable" +
61            ",isAdditionalSubtype";
62    private static String EXTRA_VALUE_EN_US_DVORAK_JELLY_BEAN =
63            "KeyboardLayoutSet=dvorak" +
64            ",AsciiCapable" +
65            ",UntranslatableReplacementStringInSubtypeName=Dvorak" +
66            ",isAdditionalSubtype";
67    private static String EXTRA_VALUE_EN_US_DVORAK_KITKAT =
68            "KeyboardLayoutSet=dvorak" +
69            ",AsciiCapable" +
70            ",UntranslatableReplacementStringInSubtypeName=Dvorak" +
71            ",EmojiCapable" +
72            ",isAdditionalSubtype";
73
74    /**
75     * Predictable subtype ID for azerty layout. This is actually a hash code calculated as follows.
76     * <code>
77     * final boolean isAuxiliary = false;
78     * final boolean overrideImplicitlyEnabledSubtype = false;
79     * final int SUBTYPE_ID_ZZ_AZERTY = Arrays.hashCode(new Object[] {
80     *         "zz",
81     *         "keyboard",
82     *         "KeyboardLayoutSet=azerty"
83     *                 + ",AsciiCapable"
84     *                 + ",EmojiCapable"
85     *                 + ",isAdditionalSubtype",
86     *         isAuxiliary,
87     *         overrideImplicitlyEnabledSubtype });
88     * </code>
89     */
90    private static int SUBTYPE_ID_ZZ_AZERTY = 0x5b6be697;
91    private static String EXTRA_VALUE_ZZ_AZERTY_ICS =
92            "KeyboardLayoutSet=azerty" +
93            ",AsciiCapable" +
94            ",isAdditionalSubtype";
95    private static String EXTRA_VALUE_ZZ_AZERTY_KITKAT =
96            "KeyboardLayoutSet=azerty" +
97            ",AsciiCapable" +
98            ",EmojiCapable" +
99            ",isAdditionalSubtype";
100
101    @Override
102    protected void setUp() throws Exception {
103        super.setUp();
104        final Context context = getContext();
105        SubtypeLocaleUtils.init(context);
106    }
107
108    private static void assertEnUsDvorak(InputMethodSubtype subtype) {
109        assertEquals("en_US", subtype.getLocale());
110        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
111            assertEquals(EXTRA_VALUE_EN_US_DVORAK_KITKAT, subtype.getExtraValue());
112        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
113            assertEquals(EXTRA_VALUE_EN_US_DVORAK_JELLY_BEAN, subtype.getExtraValue());
114        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
115            assertEquals(EXTRA_VALUE_EN_US_DVORAK_ICS, subtype.getExtraValue());
116        }
117        assertTrue(subtype.containsExtraValueKey(ASCII_CAPABLE));
118        assertTrue(InputMethodSubtypeCompatUtils.isAsciiCapable(subtype));
119        // TODO: Enable following test
120        // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
121        //    assertTrue(InputMethodSubtypeCompatUtils.isAsciiCapableWithAPI(subtype));
122        // }
123        assertTrue(subtype.containsExtraValueKey(EMOJI_CAPABLE));
124        assertTrue(subtype.containsExtraValueKey(IS_ADDITIONAL_SUBTYPE));
125        assertEquals("dvorak", subtype.getExtraValueOf(KEYBOARD_LAYOUT_SET));
126        assertEquals("Dvorak", subtype.getExtraValueOf(UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME));
127        assertEquals(KEYBOARD_MODE, subtype.getMode());
128        assertEquals(SUBTYPE_ID_EN_US_DVORAK, subtype.hashCode());
129    }
130
131    private static void assertAzerty(InputMethodSubtype subtype) {
132        assertEquals("zz", subtype.getLocale());
133        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
134            assertEquals(EXTRA_VALUE_ZZ_AZERTY_KITKAT, subtype.getExtraValue());
135        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
136            assertEquals(EXTRA_VALUE_ZZ_AZERTY_ICS, subtype.getExtraValue());
137        }
138        assertTrue(subtype.containsExtraValueKey(ASCII_CAPABLE));
139        assertTrue(InputMethodSubtypeCompatUtils.isAsciiCapable(subtype));
140        // TODO: Enable following test
141        // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
142        //    assertTrue(InputMethodSubtypeCompatUtils.isAsciiCapableWithAPI(subtype));
143        // }
144        assertTrue(subtype.containsExtraValueKey(EMOJI_CAPABLE));
145        assertTrue(subtype.containsExtraValueKey(IS_ADDITIONAL_SUBTYPE));
146        assertEquals("azerty", subtype.getExtraValueOf(KEYBOARD_LAYOUT_SET));
147        assertFalse(subtype.containsExtraValueKey(UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME));
148        assertEquals(KEYBOARD_MODE, subtype.getMode());
149        assertEquals(SUBTYPE_ID_ZZ_AZERTY, subtype.hashCode());
150    }
151
152    public void testRestorable() {
153        final InputMethodSubtype EN_US_DVORAK =
154                AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
155                        Locale.US.toString(), "dvorak");
156        final InputMethodSubtype ZZ_AZERTY =
157                AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
158                        SubtypeLocaleUtils.NO_LANGUAGE, "azerty");
159        assertEnUsDvorak(EN_US_DVORAK);
160        assertAzerty(ZZ_AZERTY);
161
162        // Make sure the subtype can be stored and restored in a deterministic manner.
163        final InputMethodSubtype[] subtypes = { EN_US_DVORAK, ZZ_AZERTY };
164        final String prefSubtype = AdditionalSubtypeUtils.createPrefSubtypes(subtypes);
165        final InputMethodSubtype[] restoredSubtypes =
166                AdditionalSubtypeUtils.createAdditionalSubtypesArray(prefSubtype);
167        assertEquals(2, restoredSubtypes.length);
168        final InputMethodSubtype restored_EN_US_DVORAK = restoredSubtypes[0];
169        final InputMethodSubtype restored_ZZ_AZERTY = restoredSubtypes[1];
170
171        assertEnUsDvorak(restored_EN_US_DVORAK);
172        assertAzerty(restored_ZZ_AZERTY);
173    }
174}
175