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