KeyboardLayoutSetNavigateMoreKeysBase.java revision 5166e9f0ff2e5df0d82983b19ea2cd1c2df16da2
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.keyboard;
18
19import android.text.InputType;
20import android.view.inputmethod.EditorInfo;
21import android.view.inputmethod.InputMethodSubtype;
22
23import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
24import com.android.inputmethod.keyboard.internal.MoreKeySpec;
25import com.android.inputmethod.latin.Constants;
26import com.android.inputmethod.latin.R;
27import com.android.inputmethod.latin.RichInputMethodManager;
28import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
29
30import java.util.Arrays;
31import java.util.Locale;
32
33abstract class KeyboardLayoutSetNavigateMoreKeysBase extends KeyboardLayoutSetTestsBase {
34    private ExpectedMoreKey mExpectedNavigateNextMoreKey;
35    private ExpectedMoreKey mExpectedNavigatePreviousMoreKey;
36    private ExpectedMoreKey mExpectedEmojiMoreKey;
37
38    protected ExpectedMoreKey getExpectedNavigateNextMoreKey() {
39        return new ExpectedMoreKey(R.string.label_next_key);
40    }
41
42    protected ExpectedMoreKey getExpectedNavigatePreviousMoreKey() {
43        return new ExpectedMoreKey(R.string.label_previous_key);
44    }
45
46    protected ExpectedMoreKey getExpectedEmojiMoreKey() {
47        return new ExpectedMoreKey(KeyboardIconsSet.NAME_EMOJI_ACTION_KEY);
48    }
49
50    @Override
51    protected void setUp() throws Exception {
52        super.setUp();
53        mExpectedNavigateNextMoreKey = getExpectedNavigateNextMoreKey();
54        mExpectedNavigatePreviousMoreKey =  getExpectedNavigatePreviousMoreKey();
55        mExpectedEmojiMoreKey = getExpectedEmojiMoreKey();
56    }
57
58    /**
59     * This class represents an expected more key.
60     */
61    protected static class ExpectedMoreKey {
62        public static final int NO_LABEL = 0;
63        public static final ExpectedMoreKey[] EMPTY_MORE_KEYS = new ExpectedMoreKey[0];
64
65        public final int mLabelResId;
66        public final int mIconId;
67
68        public ExpectedMoreKey(final String iconName) {
69            mLabelResId = NO_LABEL;
70            mIconId = KeyboardIconsSet.getIconId(iconName);
71        }
72
73        public ExpectedMoreKey(final int labelResId) {
74            mLabelResId = labelResId;
75            mIconId = KeyboardIconsSet.ICON_UNDEFINED;
76        }
77    }
78
79    private void doTestMoreKeysOf(final int code, final InputMethodSubtype subtype,
80            final int elementId, final int inputType, final int imeOptions,
81            final ExpectedMoreKey ... expectedMoreKeys) {
82        final EditorInfo editorInfo = new EditorInfo();
83        editorInfo.inputType = inputType;
84        editorInfo.imeOptions = imeOptions;
85        final KeyboardLayoutSet layoutSet = createKeyboardLayoutSet(subtype, editorInfo);
86        final Keyboard keyboard = layoutSet.getKeyboard(elementId);
87
88        final Key actualKey = keyboard.getKey(code);
89        final MoreKeySpec[] actualMoreKeys = actualKey.getMoreKeys();
90        final String tag = actualKey.toString() + " moreKeys=" + Arrays.toString(actualMoreKeys);
91        if (expectedMoreKeys.length == 0) {
92            assertEquals(tag, null, actualMoreKeys);
93            return;
94        }
95        if (expectedMoreKeys.length == 1) {
96            assertEquals(tag + " fixedOrder", false, actualKey.isMoreKeysFixedOrder());
97            assertEquals(tag + " fixedColumn", false, actualKey.isMoreKeysFixedColumn());
98        } else {
99            assertEquals(tag + " fixedOrder", true, actualKey.isMoreKeysFixedOrder());
100            assertEquals(tag + " fixedColumn", true, actualKey.isMoreKeysFixedColumn());
101            // TODO: Can't handle multiple rows of more keys.
102            assertEquals(tag + " column",
103                    expectedMoreKeys.length, actualKey.getMoreKeysColumnNumber());
104        }
105        assertNotNull(tag + " moreKeys", actualMoreKeys);
106        assertEquals(tag, expectedMoreKeys.length, actualMoreKeys.length);
107        for (int index = 0; index < actualMoreKeys.length; index++) {
108            final int expectedLabelResId = expectedMoreKeys[index].mLabelResId;
109            if (expectedLabelResId == ExpectedMoreKey.NO_LABEL) {
110                assertEquals(tag + " label " + index, null, actualMoreKeys[index].mLabel);
111            } else {
112                final CharSequence expectedLabel = getContext().getText(expectedLabelResId);
113                assertEquals(tag + " label " + index, expectedLabel, actualMoreKeys[index].mLabel);
114            }
115            final int expectedIconId = expectedMoreKeys[index].mIconId;
116            assertEquals(tag + " icon " + index, expectedIconId, actualMoreKeys[index].mIconId);
117        }
118    }
119
120    private void doTestNavigationMoreKeysOf(final int code, final InputMethodSubtype subtype,
121            final int elementId, final int inputType) {
122        // No navigate flag.
123        doTestMoreKeysOf(code, subtype, elementId, inputType,
124                EditorInfo.IME_NULL,
125                ExpectedMoreKey.EMPTY_MORE_KEYS);
126        // With next navigate flag.
127        doTestMoreKeysOf(code, subtype, elementId, inputType,
128                EditorInfo.IME_FLAG_NAVIGATE_NEXT,
129                mExpectedNavigateNextMoreKey);
130        // With previous navigate flag.
131        doTestMoreKeysOf(code, subtype, elementId, inputType,
132                EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
133                mExpectedNavigatePreviousMoreKey);
134        // With next and previous naviagte flags.
135        doTestMoreKeysOf(code, subtype, elementId, inputType,
136                EditorInfo.IME_FLAG_NAVIGATE_NEXT | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
137                mExpectedNavigatePreviousMoreKey, mExpectedNavigateNextMoreKey);
138        // Action next.
139        doTestMoreKeysOf(code, subtype, elementId, inputType,
140                EditorInfo.IME_ACTION_NEXT,
141                ExpectedMoreKey.EMPTY_MORE_KEYS);
142        // Action next with next navigate flag.
143        doTestMoreKeysOf(code, subtype, elementId, inputType,
144                EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NAVIGATE_NEXT,
145                ExpectedMoreKey.EMPTY_MORE_KEYS);
146        // Action next with previous navigate flag.
147        doTestMoreKeysOf(code, subtype, elementId, inputType,
148                EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
149                mExpectedNavigatePreviousMoreKey);
150        // Action next with next and previous navigate flags.
151        doTestMoreKeysOf(code, subtype, elementId, inputType,
152                EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NAVIGATE_NEXT
153                        | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
154                mExpectedNavigatePreviousMoreKey);
155        // Action previous.
156        doTestMoreKeysOf(code, subtype, elementId, inputType,
157                EditorInfo.IME_ACTION_PREVIOUS,
158                ExpectedMoreKey.EMPTY_MORE_KEYS);
159        // Action previous with next navigate flag.
160        doTestMoreKeysOf(code, subtype, elementId, inputType,
161                EditorInfo.IME_ACTION_PREVIOUS | EditorInfo.IME_FLAG_NAVIGATE_NEXT,
162                mExpectedNavigateNextMoreKey);
163        // Action previous with previous navigate flag.
164        doTestMoreKeysOf(code, subtype, elementId, inputType,
165                EditorInfo.IME_ACTION_PREVIOUS | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
166                ExpectedMoreKey.EMPTY_MORE_KEYS);
167        // Action previous with next and previous navigate flags.
168        doTestMoreKeysOf(code, subtype, elementId, inputType,
169                EditorInfo.IME_ACTION_PREVIOUS | EditorInfo.IME_FLAG_NAVIGATE_NEXT
170                        | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
171                mExpectedNavigateNextMoreKey);
172    }
173
174    private void doTestNavigationWithEmojiMoreKeysOf(final int code,
175            final InputMethodSubtype subtype, final int elementId, final int inputType) {
176        // No navigate flag.
177        doTestMoreKeysOf(code, subtype, elementId, inputType,
178                EditorInfo.IME_NULL,
179                mExpectedEmojiMoreKey);
180        // With next navigate flag.
181        doTestMoreKeysOf(code, subtype, elementId, inputType,
182                EditorInfo.IME_FLAG_NAVIGATE_NEXT,
183                mExpectedEmojiMoreKey, mExpectedNavigateNextMoreKey);
184        // With previous navigate flag.
185        doTestMoreKeysOf(code, subtype, elementId, inputType,
186                EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
187                mExpectedEmojiMoreKey, mExpectedNavigatePreviousMoreKey);
188        // With next and previous naviagte flags.
189        doTestMoreKeysOf(code, subtype, elementId, inputType,
190                EditorInfo.IME_FLAG_NAVIGATE_NEXT | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
191                mExpectedEmojiMoreKey, mExpectedNavigatePreviousMoreKey,
192                mExpectedNavigateNextMoreKey);
193        // Action next.
194        doTestMoreKeysOf(code, subtype, elementId, inputType,
195                EditorInfo.IME_ACTION_NEXT,
196                mExpectedEmojiMoreKey);
197        // Action next with next navigate flag.
198        doTestMoreKeysOf(code, subtype, elementId, inputType,
199                EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NAVIGATE_NEXT,
200                mExpectedEmojiMoreKey);
201        // Action next with previous navigate flag.
202        doTestMoreKeysOf(code, subtype, elementId, inputType,
203                EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
204                mExpectedEmojiMoreKey, mExpectedNavigatePreviousMoreKey);
205        // Action next with next and previous navigate flags.
206        doTestMoreKeysOf(code, subtype, elementId, inputType,
207                EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NAVIGATE_NEXT
208                        | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
209                mExpectedEmojiMoreKey, mExpectedNavigatePreviousMoreKey);
210        // Action previous.
211        doTestMoreKeysOf(code, subtype, elementId, inputType,
212                EditorInfo.IME_ACTION_PREVIOUS,
213                mExpectedEmojiMoreKey);
214        // Action previous with next navigate flag.
215        doTestMoreKeysOf(code, subtype, elementId, inputType,
216                EditorInfo.IME_ACTION_PREVIOUS | EditorInfo.IME_FLAG_NAVIGATE_NEXT,
217                mExpectedEmojiMoreKey, mExpectedNavigateNextMoreKey);
218        // Action previous with previous navigate flag.
219        doTestMoreKeysOf(code, subtype, elementId, inputType,
220                EditorInfo.IME_ACTION_PREVIOUS | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
221                mExpectedEmojiMoreKey);
222        // Action previous with next and previous navigate flags.
223        doTestMoreKeysOf(code, subtype, elementId, inputType,
224                EditorInfo.IME_ACTION_PREVIOUS | EditorInfo.IME_FLAG_NAVIGATE_NEXT
225                        | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
226                mExpectedEmojiMoreKey, mExpectedNavigateNextMoreKey);
227    }
228
229    private void doTestNoNavigationMoreKeysOf(final int code, final InputMethodSubtype subtype,
230            final int elementId, final int inputType) {
231        // No navigate flag.
232        doTestMoreKeysOf(code, subtype, elementId, inputType,
233                EditorInfo.IME_NULL,
234                ExpectedMoreKey.EMPTY_MORE_KEYS);
235        // With next navigate flag.
236        doTestMoreKeysOf(code, subtype, elementId, inputType,
237                EditorInfo.IME_FLAG_NAVIGATE_NEXT,
238                ExpectedMoreKey.EMPTY_MORE_KEYS);
239        // With previous navigate flag.
240        doTestMoreKeysOf(code, subtype, elementId, inputType,
241                EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
242                ExpectedMoreKey.EMPTY_MORE_KEYS);
243        // With next and previous naviagte flags.
244        doTestMoreKeysOf(code, subtype, elementId, inputType,
245                EditorInfo.IME_FLAG_NAVIGATE_NEXT | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
246                ExpectedMoreKey.EMPTY_MORE_KEYS);
247        // Action next.
248        doTestMoreKeysOf(code, subtype, elementId, inputType,
249                EditorInfo.IME_ACTION_NEXT,
250                ExpectedMoreKey.EMPTY_MORE_KEYS);
251        // Action next with next navigate flag.
252        doTestMoreKeysOf(code, subtype, elementId, inputType,
253                EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NAVIGATE_NEXT,
254                ExpectedMoreKey.EMPTY_MORE_KEYS);
255        // Action next with previous navigate flag.
256        doTestMoreKeysOf(code, subtype, elementId, inputType,
257                EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
258                ExpectedMoreKey.EMPTY_MORE_KEYS);
259        // Action next with next and previous navigate flags.
260        doTestMoreKeysOf(code, subtype, elementId, inputType,
261                EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NAVIGATE_NEXT
262                        | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
263                ExpectedMoreKey.EMPTY_MORE_KEYS);
264        // Action previous.
265        doTestMoreKeysOf(code, subtype, elementId, inputType,
266                EditorInfo.IME_ACTION_PREVIOUS,
267                ExpectedMoreKey.EMPTY_MORE_KEYS);
268        // Action previous with next navigate flag.
269        doTestMoreKeysOf(code, subtype, elementId, inputType,
270                EditorInfo.IME_ACTION_PREVIOUS | EditorInfo.IME_FLAG_NAVIGATE_NEXT,
271                ExpectedMoreKey.EMPTY_MORE_KEYS);
272        // Action previous with previous navigate flag.
273        doTestMoreKeysOf(code, subtype, elementId, inputType,
274                EditorInfo.IME_ACTION_PREVIOUS | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
275                ExpectedMoreKey.EMPTY_MORE_KEYS);
276        // Action previous with next and previous navigate flags.
277        doTestMoreKeysOf(code, subtype, elementId, inputType,
278                EditorInfo.IME_ACTION_PREVIOUS | EditorInfo.IME_FLAG_NAVIGATE_NEXT
279                        | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
280                ExpectedMoreKey.EMPTY_MORE_KEYS);
281    }
282
283    public void testMoreKeysOfEnterKey() {
284        final RichInputMethodManager richImm = RichInputMethodManager.getInstance();
285        final InputMethodSubtype subtype = richImm.findSubtypeByLocaleAndKeyboardLayoutSet(
286                Locale.US.toString(), SubtypeLocaleUtils.QWERTY);
287
288        // Password field.
289        doTestNavigationMoreKeysOf(Constants.CODE_ENTER, subtype, KeyboardId.ELEMENT_ALPHABET,
290                InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
291        // Email field.
292        doTestNavigationMoreKeysOf(Constants.CODE_ENTER, subtype, KeyboardId.ELEMENT_ALPHABET,
293                InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
294        // Url field.
295        doTestNavigationMoreKeysOf(Constants.CODE_ENTER, subtype, KeyboardId.ELEMENT_ALPHABET,
296                InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI);
297        // Phone number field.
298        doTestNavigationMoreKeysOf(Constants.CODE_ENTER, subtype, KeyboardId.ELEMENT_PHONE,
299                InputType.TYPE_CLASS_PHONE);
300        // Number field.
301        doTestNavigationMoreKeysOf(Constants.CODE_ENTER, subtype, KeyboardId.ELEMENT_NUMBER,
302                InputType.TYPE_CLASS_NUMBER);
303        // Date-time field.
304        doTestNavigationMoreKeysOf(Constants.CODE_ENTER, subtype, KeyboardId.ELEMENT_NUMBER,
305                InputType.TYPE_CLASS_DATETIME | InputType.TYPE_DATETIME_VARIATION_NORMAL);
306        // Date field.
307        doTestNavigationMoreKeysOf(Constants.CODE_ENTER, subtype, KeyboardId.ELEMENT_NUMBER,
308                InputType.TYPE_CLASS_DATETIME | InputType.TYPE_DATETIME_VARIATION_DATE);
309        // Time field.
310        doTestNavigationMoreKeysOf(Constants.CODE_ENTER, subtype, KeyboardId.ELEMENT_NUMBER,
311                InputType.TYPE_CLASS_DATETIME | InputType.TYPE_DATETIME_VARIATION_TIME);
312        // Text field.
313        if (isPhone()) {
314            // The enter key has an Emoji key as one of more keys.
315            doTestNavigationWithEmojiMoreKeysOf(Constants.CODE_ENTER, subtype,
316                    KeyboardId.ELEMENT_ALPHABET,
317                    InputType.TYPE_CLASS_TEXT);
318        } else {
319            // Tablet has a dedicated Emoji key, so the Enter key has no Emoji more key.
320            doTestNavigationMoreKeysOf(Constants.CODE_ENTER, subtype,
321                    KeyboardId.ELEMENT_ALPHABET,
322                    InputType.TYPE_CLASS_TEXT);
323        }
324        // Short message field.
325        if (isPhone()) {
326            // Enter key is switched to Emoji key on a short message field.
327            // Emoji key has no navigation more keys.
328            doTestNoNavigationMoreKeysOf(Constants.CODE_EMOJI, subtype,
329                    KeyboardId.ELEMENT_ALPHABET,
330                    InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE);
331        } else {
332            doTestNavigationMoreKeysOf(Constants.CODE_ENTER, subtype,
333                    KeyboardId.ELEMENT_ALPHABET,
334                    InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE);
335        }
336    }
337}
338