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.keyboard; 18 19 import android.text.InputType; 20 import android.view.inputmethod.EditorInfo; 21 import android.view.inputmethod.InputMethodSubtype; 22 23 import com.android.inputmethod.keyboard.internal.KeyboardIconsSet; 24 import com.android.inputmethod.keyboard.internal.MoreKeySpec; 25 import com.android.inputmethod.latin.Constants; 26 import com.android.inputmethod.latin.R; 27 import com.android.inputmethod.latin.RichInputMethodManager; 28 import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; 29 30 import java.util.Arrays; 31 import java.util.Locale; 32 33 abstract class KeyboardLayoutSetNavigateMoreKeysBase extends KeyboardLayoutSetTestsBase { 34 private ExpectedMoreKey mExpectedNavigateNextMoreKey; 35 private ExpectedMoreKey mExpectedNavigatePreviousMoreKey; 36 private ExpectedMoreKey mExpectedEmojiMoreKey; 37 getExpectedNavigateNextMoreKey()38 protected ExpectedMoreKey getExpectedNavigateNextMoreKey() { 39 return new ExpectedMoreKey(R.string.label_next_key); 40 } 41 getExpectedNavigatePreviousMoreKey()42 protected ExpectedMoreKey getExpectedNavigatePreviousMoreKey() { 43 return new ExpectedMoreKey(R.string.label_previous_key); 44 } 45 getExpectedEmojiMoreKey()46 protected ExpectedMoreKey getExpectedEmojiMoreKey() { 47 return new ExpectedMoreKey(KeyboardIconsSet.NAME_EMOJI_ACTION_KEY); 48 } 49 50 @Override setUp()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 ExpectedMoreKey(final String iconName)68 public ExpectedMoreKey(final String iconName) { 69 mLabelResId = NO_LABEL; 70 mIconId = KeyboardIconsSet.getIconId(iconName); 71 } 72 ExpectedMoreKey(final int labelResId)73 public ExpectedMoreKey(final int labelResId) { 74 mLabelResId = labelResId; 75 mIconId = KeyboardIconsSet.ICON_UNDEFINED; 76 } 77 } 78 doTestMoreKeysOf(final int code, final InputMethodSubtype subtype, final int elementId, final int inputType, final int imeOptions, final ExpectedMoreKey ... expectedMoreKeys)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 doTestNavigationMoreKeysOf(final int code, final InputMethodSubtype subtype, final int elementId, final int inputType)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 doTestNavigationWithEmojiMoreKeysOf(final int code, final InputMethodSubtype subtype, final int elementId, final int inputType)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 doTestNoNavigationMoreKeysOf(final int code, final InputMethodSubtype subtype, final int elementId, final int inputType)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 testMoreKeysOfEnterKey()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