Add unit tests for enter key's more keys

Bug: 15681452
Change-Id: I3070c46bb2c0cb8ccaae66eaea132b41c567e135
diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetNavigateMoreKeysBase.java b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetNavigateMoreKeysBase.java
new file mode 100644
index 0000000..1fce362
--- /dev/null
+++ b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetNavigateMoreKeysBase.java
@@ -0,0 +1,324 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.keyboard;
+
+import android.text.InputType;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodSubtype;
+
+import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
+import com.android.inputmethod.keyboard.internal.MoreKeySpec;
+import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.RichInputMethodManager;
+import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
+
+import java.util.Arrays;
+import java.util.Locale;
+
+abstract class KeyboardLayoutSetNavigateMoreKeysBase extends KeyboardLayoutSetTestsBase {
+    private ExpectedMoreKey mExpectedNavigateNextMoreKey;
+    private ExpectedMoreKey mExpectedNavigatePreviousMoreKey;
+    private ExpectedMoreKey mExpectedEmojiMoreKey;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mExpectedNavigateNextMoreKey = new ExpectedMoreKey(R.string.label_next_key);
+        mExpectedNavigatePreviousMoreKey = new ExpectedMoreKey(R.string.label_previous_key);
+        mExpectedEmojiMoreKey = new ExpectedMoreKey(KeyboardIconsSet.NAME_EMOJI_ACTION_KEY);
+    }
+
+    /**
+     * This class represents an expected more key.
+     */
+    protected static class ExpectedMoreKey {
+        public static final int NO_LABEL = 0;
+        public static final ExpectedMoreKey[] EMPTY_MORE_KEYS = new ExpectedMoreKey[0];
+
+        public final int mLabelResId;
+        public final int mIconId;
+
+        public ExpectedMoreKey(final String iconName) {
+            mLabelResId = NO_LABEL;
+            mIconId = KeyboardIconsSet.getIconId(iconName);
+        }
+
+        public ExpectedMoreKey(final int labelResId) {
+            mLabelResId = labelResId;
+            mIconId = KeyboardIconsSet.ICON_UNDEFINED;
+        }
+    }
+
+    private void doTestMoreKeysOf(final int code, final InputMethodSubtype subtype,
+            final int elementId, final int inputType, final int imeOptions,
+            final ExpectedMoreKey ... expectedMoreKeys) {
+        final EditorInfo editorInfo = new EditorInfo();
+        editorInfo.inputType = inputType;
+        editorInfo.imeOptions = imeOptions;
+        final KeyboardLayoutSet layoutSet = createKeyboardLayoutSet(subtype, editorInfo);
+        final Keyboard keyboard = layoutSet.getKeyboard(elementId);
+
+        final Key actualKey = keyboard.getKey(code);
+        final MoreKeySpec[] actualMoreKeys = actualKey.getMoreKeys();
+        final String tag = actualKey.toString() + " moreKeys=" + Arrays.toString(actualMoreKeys);
+        if (expectedMoreKeys.length == 0) {
+            assertEquals(tag, null, actualMoreKeys);
+            return;
+        }
+        if (expectedMoreKeys.length == 1) {
+            assertEquals(tag + " fixedOrder", false, actualKey.isMoreKeysFixedOrder());
+            assertEquals(tag + " fixedColumn", false, actualKey.isMoreKeysFixedColumn());
+        } else {
+            assertEquals(tag + " fixedOrder", true, actualKey.isMoreKeysFixedOrder());
+            assertEquals(tag + " fixedColumn", true, actualKey.isMoreKeysFixedColumn());
+            // TODO: Can't handle multiple rows of more keys.
+            assertEquals(tag + " column",
+                    expectedMoreKeys.length, actualKey.getMoreKeysColumnNumber());
+        }
+        assertEquals(tag, expectedMoreKeys.length, actualMoreKeys.length);
+        for (int index = 0; index < actualMoreKeys.length; index++) {
+            final int expectedLabelResId = expectedMoreKeys[index].mLabelResId;
+            if (expectedLabelResId == ExpectedMoreKey.NO_LABEL) {
+                assertEquals(tag + " label " + index, null, actualMoreKeys[index].mLabel);
+            } else {
+                final CharSequence expectedLabel = getContext().getText(expectedLabelResId);
+                assertEquals(tag + " label " + index, expectedLabel, actualMoreKeys[index].mLabel);
+            }
+            final int expectedIconId = expectedMoreKeys[index].mIconId;
+            assertEquals(tag + " icon " + index, expectedIconId, actualMoreKeys[index].mIconId);
+        }
+    }
+
+    private void doTestNavigationMoreKeysOf(final int code, final InputMethodSubtype subtype,
+            final int elementId, final int inputType) {
+        // No navigate flag.
+        doTestMoreKeysOf(code, subtype, elementId, inputType,
+                EditorInfo.IME_NULL,
+                ExpectedMoreKey.EMPTY_MORE_KEYS);
+        // With next navigate flag.
+        doTestMoreKeysOf(code, subtype, elementId, inputType,
+                EditorInfo.IME_FLAG_NAVIGATE_NEXT,
+                mExpectedNavigateNextMoreKey);
+        // With previous navigate flag.
+        doTestMoreKeysOf(code, subtype, elementId, inputType,
+                EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+                mExpectedNavigatePreviousMoreKey);
+        // With next and previous naviagte flags.
+        doTestMoreKeysOf(code, subtype, elementId, inputType,
+                EditorInfo.IME_FLAG_NAVIGATE_NEXT | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+                mExpectedNavigatePreviousMoreKey, mExpectedNavigateNextMoreKey);
+        // Action next.
+        doTestMoreKeysOf(code, subtype, elementId, inputType,
+                EditorInfo.IME_ACTION_NEXT,
+                ExpectedMoreKey.EMPTY_MORE_KEYS);
+        // Action next with next navigate flag.
+        doTestMoreKeysOf(code, subtype, elementId, inputType,
+                EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NAVIGATE_NEXT,
+                ExpectedMoreKey.EMPTY_MORE_KEYS);
+        // Action next with previous navigate flag.
+        doTestMoreKeysOf(code, subtype, elementId, inputType,
+                EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+                mExpectedNavigatePreviousMoreKey);
+        // Action next with next and previous navigate flags.
+        doTestMoreKeysOf(code, subtype, elementId, inputType,
+                EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NAVIGATE_NEXT
+                        | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+                mExpectedNavigatePreviousMoreKey);
+        // Action previous.
+        doTestMoreKeysOf(code, subtype, elementId, inputType,
+                EditorInfo.IME_ACTION_PREVIOUS,
+                ExpectedMoreKey.EMPTY_MORE_KEYS);
+        // Action previous with next navigate flag.
+        doTestMoreKeysOf(code, subtype, elementId, inputType,
+                EditorInfo.IME_ACTION_PREVIOUS | EditorInfo.IME_FLAG_NAVIGATE_NEXT,
+                mExpectedNavigateNextMoreKey);
+        // Action previous with previous navigate flag.
+        doTestMoreKeysOf(code, subtype, elementId, inputType,
+                EditorInfo.IME_ACTION_PREVIOUS | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+                ExpectedMoreKey.EMPTY_MORE_KEYS);
+        // Action previous with next and previous navigate flags.
+        doTestMoreKeysOf(code, subtype, elementId, inputType,
+                EditorInfo.IME_ACTION_PREVIOUS | EditorInfo.IME_FLAG_NAVIGATE_NEXT
+                        | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+                mExpectedNavigateNextMoreKey);
+    }
+
+    private void doTestNavigationWithEmojiMoreKeysOf(final int code,
+            final InputMethodSubtype subtype, final int elementId, final int inputType) {
+        // No navigate flag.
+        doTestMoreKeysOf(code, subtype, elementId, inputType,
+                EditorInfo.IME_NULL,
+                mExpectedEmojiMoreKey);
+        // With next navigate flag.
+        doTestMoreKeysOf(code, subtype, elementId, inputType,
+                EditorInfo.IME_FLAG_NAVIGATE_NEXT,
+                mExpectedEmojiMoreKey, mExpectedNavigateNextMoreKey);
+        // With previous navigate flag.
+        doTestMoreKeysOf(code, subtype, elementId, inputType,
+                EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+                mExpectedEmojiMoreKey, mExpectedNavigatePreviousMoreKey);
+        // With next and previous naviagte flags.
+        doTestMoreKeysOf(code, subtype, elementId, inputType,
+                EditorInfo.IME_FLAG_NAVIGATE_NEXT | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+                mExpectedEmojiMoreKey, mExpectedNavigatePreviousMoreKey,
+                mExpectedNavigateNextMoreKey);
+        // Action next.
+        doTestMoreKeysOf(code, subtype, elementId, inputType,
+                EditorInfo.IME_ACTION_NEXT,
+                mExpectedEmojiMoreKey);
+        // Action next with next navigate flag.
+        doTestMoreKeysOf(code, subtype, elementId, inputType,
+                EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NAVIGATE_NEXT,
+                mExpectedEmojiMoreKey);
+        // Action next with previous navigate flag.
+        doTestMoreKeysOf(code, subtype, elementId, inputType,
+                EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+                mExpectedEmojiMoreKey, mExpectedNavigatePreviousMoreKey);
+        // Action next with next and previous navigate flags.
+        doTestMoreKeysOf(code, subtype, elementId, inputType,
+                EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NAVIGATE_NEXT
+                        | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+                mExpectedEmojiMoreKey, mExpectedNavigatePreviousMoreKey);
+        // Action previous.
+        doTestMoreKeysOf(code, subtype, elementId, inputType,
+                EditorInfo.IME_ACTION_PREVIOUS,
+                mExpectedEmojiMoreKey);
+        // Action previous with next navigate flag.
+        doTestMoreKeysOf(code, subtype, elementId, inputType,
+                EditorInfo.IME_ACTION_PREVIOUS | EditorInfo.IME_FLAG_NAVIGATE_NEXT,
+                mExpectedEmojiMoreKey, mExpectedNavigateNextMoreKey);
+        // Action previous with previous navigate flag.
+        doTestMoreKeysOf(code, subtype, elementId, inputType,
+                EditorInfo.IME_ACTION_PREVIOUS | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+                mExpectedEmojiMoreKey);
+        // Action previous with next and previous navigate flags.
+        doTestMoreKeysOf(code, subtype, elementId, inputType,
+                EditorInfo.IME_ACTION_PREVIOUS | EditorInfo.IME_FLAG_NAVIGATE_NEXT
+                        | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+                mExpectedEmojiMoreKey, mExpectedNavigateNextMoreKey);
+    }
+
+    private void doTestNoNavigationMoreKeysOf(final int code, final InputMethodSubtype subtype,
+            final int elementId, final int inputType) {
+        // No navigate flag.
+        doTestMoreKeysOf(code, subtype, elementId, inputType,
+                EditorInfo.IME_NULL,
+                ExpectedMoreKey.EMPTY_MORE_KEYS);
+        // With next navigate flag.
+        doTestMoreKeysOf(code, subtype, elementId, inputType,
+                EditorInfo.IME_FLAG_NAVIGATE_NEXT,
+                ExpectedMoreKey.EMPTY_MORE_KEYS);
+        // With previous navigate flag.
+        doTestMoreKeysOf(code, subtype, elementId, inputType,
+                EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+                ExpectedMoreKey.EMPTY_MORE_KEYS);
+        // With next and previous naviagte flags.
+        doTestMoreKeysOf(code, subtype, elementId, inputType,
+                EditorInfo.IME_FLAG_NAVIGATE_NEXT | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+                ExpectedMoreKey.EMPTY_MORE_KEYS);
+        // Action next.
+        doTestMoreKeysOf(code, subtype, elementId, inputType,
+                EditorInfo.IME_ACTION_NEXT,
+                ExpectedMoreKey.EMPTY_MORE_KEYS);
+        // Action next with next navigate flag.
+        doTestMoreKeysOf(code, subtype, elementId, inputType,
+                EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NAVIGATE_NEXT,
+                ExpectedMoreKey.EMPTY_MORE_KEYS);
+        // Action next with previous navigate flag.
+        doTestMoreKeysOf(code, subtype, elementId, inputType,
+                EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+                ExpectedMoreKey.EMPTY_MORE_KEYS);
+        // Action next with next and previous navigate flags.
+        doTestMoreKeysOf(code, subtype, elementId, inputType,
+                EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NAVIGATE_NEXT
+                        | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+                ExpectedMoreKey.EMPTY_MORE_KEYS);
+        // Action previous.
+        doTestMoreKeysOf(code, subtype, elementId, inputType,
+                EditorInfo.IME_ACTION_PREVIOUS,
+                ExpectedMoreKey.EMPTY_MORE_KEYS);
+        // Action previous with next navigate flag.
+        doTestMoreKeysOf(code, subtype, elementId, inputType,
+                EditorInfo.IME_ACTION_PREVIOUS | EditorInfo.IME_FLAG_NAVIGATE_NEXT,
+                ExpectedMoreKey.EMPTY_MORE_KEYS);
+        // Action previous with previous navigate flag.
+        doTestMoreKeysOf(code, subtype, elementId, inputType,
+                EditorInfo.IME_ACTION_PREVIOUS | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+                ExpectedMoreKey.EMPTY_MORE_KEYS);
+        // Action previous with next and previous navigate flags.
+        doTestMoreKeysOf(code, subtype, elementId, inputType,
+                EditorInfo.IME_ACTION_PREVIOUS | EditorInfo.IME_FLAG_NAVIGATE_NEXT
+                        | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+                ExpectedMoreKey.EMPTY_MORE_KEYS);
+    }
+
+    public void testMoreKeysOfEnterKey() {
+        final RichInputMethodManager richImm = RichInputMethodManager.getInstance();
+        final InputMethodSubtype subtype = richImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                Locale.US.toString(), SubtypeLocaleUtils.QWERTY);
+
+        // Password field.
+        doTestNavigationMoreKeysOf(Constants.CODE_ENTER, subtype, KeyboardId.ELEMENT_ALPHABET,
+                InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
+        // Email field.
+        doTestNavigationMoreKeysOf(Constants.CODE_ENTER, subtype, KeyboardId.ELEMENT_ALPHABET,
+                InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
+        // Url field.
+        doTestNavigationMoreKeysOf(Constants.CODE_ENTER, subtype, KeyboardId.ELEMENT_ALPHABET,
+                InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI);
+        // Phone number field.
+        doTestNavigationMoreKeysOf(Constants.CODE_ENTER, subtype, KeyboardId.ELEMENT_PHONE,
+                InputType.TYPE_CLASS_PHONE);
+        // Number field.
+        doTestNavigationMoreKeysOf(Constants.CODE_ENTER, subtype, KeyboardId.ELEMENT_NUMBER,
+                InputType.TYPE_CLASS_NUMBER);
+        // Date-time field.
+        doTestNavigationMoreKeysOf(Constants.CODE_ENTER, subtype, KeyboardId.ELEMENT_NUMBER,
+                InputType.TYPE_CLASS_DATETIME | InputType.TYPE_DATETIME_VARIATION_NORMAL);
+        // Date field.
+        doTestNavigationMoreKeysOf(Constants.CODE_ENTER, subtype, KeyboardId.ELEMENT_NUMBER,
+                InputType.TYPE_CLASS_DATETIME | InputType.TYPE_DATETIME_VARIATION_DATE);
+        // Time field.
+        doTestNavigationMoreKeysOf(Constants.CODE_ENTER, subtype, KeyboardId.ELEMENT_NUMBER,
+                InputType.TYPE_CLASS_DATETIME | InputType.TYPE_DATETIME_VARIATION_TIME);
+        // Text field.
+        if (isPhone()) {
+            // The enter key has an Emoji key as one of more keys.
+            doTestNavigationWithEmojiMoreKeysOf(Constants.CODE_ENTER, subtype,
+                    KeyboardId.ELEMENT_ALPHABET,
+                    InputType.TYPE_CLASS_TEXT);
+        } else {
+            // Tablet has a dedicated Emoji key, so the Enter key has no Emoji more key.
+            doTestNavigationMoreKeysOf(Constants.CODE_ENTER, subtype,
+                    KeyboardId.ELEMENT_ALPHABET,
+                    InputType.TYPE_CLASS_TEXT);
+        }
+        // Short message field.
+        if (isPhone()) {
+            // Enter key is switched to Emoji key on a short message field.
+            // Emoji key has no navigation more keys.
+            doTestNoNavigationMoreKeysOf(Constants.CODE_EMOJI, subtype,
+                    KeyboardId.ELEMENT_ALPHABET,
+                    InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE);
+        } else {
+            doTestNavigationMoreKeysOf(Constants.CODE_ENTER, subtype,
+                    KeyboardId.ELEMENT_ALPHABET,
+                    InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE);
+        }
+    }
+}
diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetNavigateMoreKeysKlpTests.java b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetNavigateMoreKeysKlpTests.java
new file mode 100644
index 0000000..286c69d
--- /dev/null
+++ b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetNavigateMoreKeysKlpTests.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.keyboard;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+@SmallTest
+public class KeyboardLayoutSetNavigateMoreKeysKlpTests
+        extends KeyboardLayoutSetNavigateMoreKeysBase {
+    @Override
+    protected int getKeyboardThemeForTests() {
+        return KeyboardTheme.THEME_ID_KLP;
+    }
+}
diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetNavigateMoreKeysLxxTests.java b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetNavigateMoreKeysLxxTests.java
new file mode 100644
index 0000000..02593cb
--- /dev/null
+++ b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetNavigateMoreKeysLxxTests.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.keyboard;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+@SmallTest
+public class KeyboardLayoutSetNavigateMoreKeysLxxTests
+        extends KeyboardLayoutSetNavigateMoreKeysBase {
+    @Override
+    protected int getKeyboardThemeForTests() {
+        return KeyboardTheme.THEME_ID_LXX_LIGHT;
+    }
+}