Home | History | Annotate | Download | only in keyboard
      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 
     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