diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java
index 79d088f2e0a0f08e04e86ffc74a20b542eb85e03..6c9b5adc326447001f7369fb2484517c954566f9 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java
@@ -34,29 +34,47 @@ public final class KeyboardIconsSet {
     public static final int ICON_UNDEFINED = 0;
     private static final int ATTR_UNDEFINED = 0;
 
+    private static final String NAME_UNDEFINED = "undefined";
+    public static final String NAME_SHIFT_KEY = "shift_key";
+    public static final String NAME_SHIFT_KEY_SHIFTED = "shift_key_shifted";
+    public static final String NAME_DELETE_KEY = "delete_key";
+    public static final String NAME_SETTINGS_KEY = "settings_key";
+    public static final String NAME_SPACE_KEY = "space_key";
+    public static final String NAME_SPACE_KEY_FOR_NUMBER_LAYOUT = "space_key_for_number_layout";
+    public static final String NAME_ENTER_KEY = "enter_key";
+    public static final String NAME_SEARCH_KEY = "search_key";
+    public static final String NAME_TAB_KEY = "tab_key";
+    public static final String NANE_TAB_KEY_PREVIEW = "tab_key_preview";
+    public static final String NAME_SHORTCUT_KEY = "shortcut_key";
+    public static final String NAME_SHORTCUT_KEY_DISABLED = "shortcut_key_disabled";
+    public static final String NAME_LANGUAGE_SWITCH_KEY = "language_switch_key";
+    public static final String NAME_ZWNJ_KEY = "zwnj_key";
+    public static final String NAME_ZWJ_KEY = "zwj_key";
+    public static final String NAME_EMOJI_KEY = "emoji_key";
+
     private static final SparseIntArray ATTR_ID_TO_ICON_ID = new SparseIntArray();
 
     // Icon name to icon id map.
     private static final HashMap<String, Integer> sNameToIdsMap = CollectionUtils.newHashMap();
 
     private static final Object[] NAMES_AND_ATTR_IDS = {
-        "undefined",                    ATTR_UNDEFINED,
-        "shift_key",                    R.styleable.Keyboard_iconShiftKey,
-        "delete_key",                   R.styleable.Keyboard_iconDeleteKey,
-        "settings_key",                 R.styleable.Keyboard_iconSettingsKey,
-        "space_key",                    R.styleable.Keyboard_iconSpaceKey,
-        "enter_key",                    R.styleable.Keyboard_iconEnterKey,
-        "search_key",                   R.styleable.Keyboard_iconSearchKey,
-        "tab_key",                      R.styleable.Keyboard_iconTabKey,
-        "shortcut_key",                 R.styleable.Keyboard_iconShortcutKey,
-        "space_key_for_number_layout",  R.styleable.Keyboard_iconSpaceKeyForNumberLayout,
-        "shift_key_shifted",            R.styleable.Keyboard_iconShiftKeyShifted,
-        "shortcut_key_disabled",        R.styleable.Keyboard_iconShortcutKeyDisabled,
-        "tab_key_preview",              R.styleable.Keyboard_iconTabKeyPreview,
-        "language_switch_key",          R.styleable.Keyboard_iconLanguageSwitchKey,
-        "zwnj_key",                     R.styleable.Keyboard_iconZwnjKey,
-        "zwj_key",                      R.styleable.Keyboard_iconZwjKey,
-        "emoji_key",                    R.styleable.Keyboard_iconEmojiKey,
+        NAME_UNDEFINED,                   ATTR_UNDEFINED,
+        NAME_SHIFT_KEY,                   R.styleable.Keyboard_iconShiftKey,
+        NAME_DELETE_KEY,                  R.styleable.Keyboard_iconDeleteKey,
+        NAME_SETTINGS_KEY,                R.styleable.Keyboard_iconSettingsKey,
+        NAME_SPACE_KEY,                   R.styleable.Keyboard_iconSpaceKey,
+        NAME_ENTER_KEY,                   R.styleable.Keyboard_iconEnterKey,
+        NAME_SEARCH_KEY,                  R.styleable.Keyboard_iconSearchKey,
+        NAME_TAB_KEY,                     R.styleable.Keyboard_iconTabKey,
+        NAME_SHORTCUT_KEY,                R.styleable.Keyboard_iconShortcutKey,
+        NAME_SPACE_KEY_FOR_NUMBER_LAYOUT, R.styleable.Keyboard_iconSpaceKeyForNumberLayout,
+        NAME_SHIFT_KEY_SHIFTED,           R.styleable.Keyboard_iconShiftKeyShifted,
+        NAME_SHORTCUT_KEY_DISABLED,       R.styleable.Keyboard_iconShortcutKeyDisabled,
+        NANE_TAB_KEY_PREVIEW,             R.styleable.Keyboard_iconTabKeyPreview,
+        NAME_LANGUAGE_SWITCH_KEY,         R.styleable.Keyboard_iconLanguageSwitchKey,
+        NAME_ZWNJ_KEY,                    R.styleable.Keyboard_iconZwnjKey,
+        NAME_ZWJ_KEY,                     R.styleable.Keyboard_iconZwjKey,
+        NAME_EMOJI_KEY,                   R.styleable.Keyboard_iconEmojiKey,
     };
 
     private static int NUM_ICONS = NAMES_AND_ATTR_IDS.length / 2;
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/AlphabetShifted.java b/tests/src/com/android/inputmethod/keyboard/layout/AlphabetShifted.java
deleted file mode 100644
index b81061ab8a28bd64d34a28540d6be202261a8f7e..0000000000000000000000000000000000000000
--- a/tests/src/com/android/inputmethod/keyboard/layout/AlphabetShifted.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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.layout;
-
-import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
-import com.android.inputmethod.keyboard.layout.expected.ExpectedKey;
-import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder;
-import com.android.inputmethod.keyboard.layout.expected.LayoutBase;
-import com.android.inputmethod.latin.Constants;
-
-import java.util.Locale;
-
-/**
- * The generic upper case alphabet keyboard layout.
- */
-public final class AlphabetShifted extends LayoutBase {
-    public static ExpectedKey[][] getDefaultLayout(final ExpectedKey[][] lowerCaseKeyboard,
-            final Locale locale) {
-        final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder(lowerCaseKeyboard);
-        builder.toUpperCase(locale);
-        builder.replaceKeysOfAll(SHIFT_KEY, SHIFTED_SHIFT_KEY);
-        return builder.build();
-    }
-
-    // Icon id.
-    private static final int ICON_SHIFTED_SHIFT = KeyboardIconsSet.getIconId("shift_key_shifted");
-
-    // Functional key.
-    private static final ExpectedKey SHIFTED_SHIFT_KEY = key(
-            ICON_SHIFTED_SHIFT, Constants.CODE_SHIFT, CAPSLOCK_MORE_KEY);
-}
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/LayoutBase.java b/tests/src/com/android/inputmethod/keyboard/layout/LayoutBase.java
new file mode 100644
index 0000000000000000000000000000000000000000..02a3900b4d38acd84e8d23eb454065f3877771e8
--- /dev/null
+++ b/tests/src/com/android/inputmethod/keyboard/layout/LayoutBase.java
@@ -0,0 +1,346 @@
+/*
+ * 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.layout;
+
+import com.android.inputmethod.keyboard.KeyboardId;
+import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
+import com.android.inputmethod.keyboard.layout.expected.AbstractLayoutBase;
+import com.android.inputmethod.keyboard.layout.expected.ExpectedKey;
+import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder;
+import com.android.inputmethod.latin.Constants;
+
+import java.util.Locale;
+
+/**
+ * The base class of keyboard layout.
+ */
+public abstract class LayoutBase extends AbstractLayoutBase {
+
+    /**
+     * This class is used to customize common keyboard layout to language specific layout.
+     */
+    public static class LayoutCustomizer {
+        private final Locale mLocale;
+
+        // Empty keys definition to remove keys by adding this.
+        protected static final ExpectedKey[] EMPTY_KEYS = joinKeys();
+
+        public LayoutCustomizer(final Locale locale) {
+            mLocale = locale;
+        }
+
+        public final Locale getLocale() {
+            return mLocale;
+        }
+
+        /**
+         * Set accented letters to common layout.
+         * @param builder the {@link ExpectedKeyboardBuilder} object that contains common keyboard
+         *        layout.
+         * @return the {@link ExpectedKeyboardBuilder} object that contains accented letters as
+         *        "more keys".
+         */
+        public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) {
+            return builder;
+        }
+
+        /**
+         * Get the function key to switch to alphabet layout.
+         * @return the {@link ExpectedKey} of the alphabet key.
+         */
+        public ExpectedKey getAlphabetKey() { return ALPHABET_KEY; }
+
+        /**
+         * Get the function key to switch to symbols layout.
+         * @return the {@link ExpectedKey} of the symbols key.
+         */
+        public ExpectedKey getSymbolsKey() { return SYMBOLS_KEY; }
+
+        /**
+         * Get the function key to switch to symbols shift layout.
+         * @param isPhone true if requesting phone's key.
+         * @return the {@link ExpectedKey} of the symbols shift key.
+         */
+        public ExpectedKey getSymbolsShiftKey(boolean isPhone) {
+            return isPhone ? SYMBOLS_SHIFT_KEY : TABLET_SYMBOLS_SHIFT_KEY;
+        }
+
+        /**
+         * Get the function key to switch from symbols shift to symbols layout.
+         * @return the {@link ExpectedKey} of the back to symbols key.
+         */
+        public ExpectedKey getBackToSymbolsKey() { return BACK_TO_SYMBOLS_KEY; }
+
+        /**
+         * Get the currency key.
+         * @return the {@link ExpectedKey} of the currency key.
+         */
+        public ExpectedKey getCurrencyKey() { return Symbols.CURRENCY_DOLLAR; }
+
+        /**
+         * Get other currencies keys.
+         * @return the array of {@link ExpectedKey} that represents other currency keys.
+         */
+        public ExpectedKey[] getOtherCurrencyKeys() {
+            return SymbolsShifted.CURRENCIES_OTHER_THAN_DOLLAR;
+        }
+
+        /**
+         * Get "more keys" of double quotation mark.
+         * @return the array of {@link ExpectedKey} of more double quotation marks in natural order.
+         */
+        public ExpectedKey[] getDoubleQuoteMoreKeys() { return Symbols.DOUBLE_QUOTES_9LR; }
+
+        /**
+         * Get "more keys" of single quotation mark.
+         * @return the array of {@link ExpectedKey} of more single quotation marks in natural order.
+         */
+        public ExpectedKey[] getSingleQuoteMoreKeys() { return Symbols.SINGLE_QUOTES_9LR; }
+
+        /**
+         * Get double angle quotation marks in natural order.
+         * @return the array of {@link ExpectedKey} of double angle quotation marks in natural
+         *         order.
+         */
+        public ExpectedKey[] getDoubleAngleQuoteKeys() { return Symbols.DOUBLE_ANGLE_QUOTES_LR; }
+
+        /**
+         * Get single angle quotation marks in natural order.
+         * @return the array of {@link ExpectedKey} of single angle quotation marks in natural
+         *         order.
+         */
+        public ExpectedKey[] getSingleAngleQuoteKeys() { return Symbols.SINGLE_ANGLE_QUOTES_LR; }
+
+        /**
+         * Get the left shift keys.
+         * @param isPhone true if requesting phone's keys.
+         * @return the array of {@link ExpectedKey} that should be placed at left edge of the
+         *         keyboard.
+         */
+        public ExpectedKey[] getLeftShiftKeys(final boolean isPhone) {
+            return joinKeys(SHIFT_KEY);
+        }
+
+        /**
+         * Get the right shift keys.
+         * @param isPhone true if requesting phone's keys.
+         * @return the array of {@link ExpectedKey} that should be placed at right edge of the
+         *         keyboard.
+         */
+        public ExpectedKey[] getRightShiftKeys(final boolean isPhone) {
+            return isPhone ? EMPTY_KEYS : joinKeys(EXCLAMATION_AND_QUESTION_MARKS, SHIFT_KEY);
+        }
+
+        /**
+         * Get the keys left to the spacebar.
+         * @param isPhone true if requesting phone's keys.
+         * @return the array of {@link ExpectedKey} that should be placed at left of the spacebar.
+         */
+        public ExpectedKey[] getKeysLeftToSpacebar(final boolean isPhone) {
+            return isPhone ? joinKeys(key(",", SETTINGS_KEY)) : joinKeys(key("/"));
+        }
+
+        /**
+         * Get the keys right to the spacebar.
+         * @param isPhone true if requesting phone's keys.
+         * @return the array of {@link ExpectedKey} that should be placed at right of the spacebar.
+         */
+        public ExpectedKey[] getKeysRightToSpacebar(final boolean isPhone) {
+            final ExpectedKey periodKey = key(".", getPunctuationMoreKeys(isPhone));
+            return isPhone ? joinKeys(periodKey) : joinKeys(key(","), periodKey);
+        }
+
+        /**
+         * Get "more keys" for the punctuation key (usually the period key).
+         * @param isPhone true if requesting phone's keys.
+         * @return the array of {@link ExpectedKey} that are "more keys" of the punctuation key.
+         */
+        public ExpectedKey[] getPunctuationMoreKeys(final boolean isPhone) {
+            return isPhone ? PHONE_PUNCTUATION_MORE_KEYS
+                    : TABLET_PUNCTUATION_MORE_KEYS;
+        }
+    }
+
+    /**
+     * The layout customize class for countries that use Euro.
+     */
+    public static class EuroLayoutCustomizer extends LayoutCustomizer {
+        public EuroLayoutCustomizer(final Locale locale) {
+            super(locale);
+        }
+
+        @Override
+        public final ExpectedKey getCurrencyKey() { return Symbols.CURRENCY_EURO; }
+
+        @Override
+        public final ExpectedKey[] getOtherCurrencyKeys() {
+            return SymbolsShifted.CURRENCIES_OTHER_THAN_EURO;
+        }
+    }
+
+    private final LayoutCustomizer mCustomizer;
+    private final Symbols mSymbols;
+    private final SymbolsShifted mSymbolsShifted;
+
+    LayoutBase(final LayoutCustomizer customizer, final Class<? extends Symbols> symbolsClass,
+            final Class<? extends SymbolsShifted> symbolsShiftedClass) {
+        mCustomizer = customizer;
+        try {
+            mSymbols = symbolsClass.getDeclaredConstructor(LayoutCustomizer.class)
+                    .newInstance(customizer);
+            mSymbolsShifted = symbolsShiftedClass.getDeclaredConstructor(LayoutCustomizer.class)
+                    .newInstance(customizer);
+        } catch (final Exception e) {
+            throw new RuntimeException("Unknown Symbols/SymbolsShifted class", e);
+        }
+    }
+
+    /**
+     * The layout name.
+     * @return the name of this layout.
+     */
+    public abstract String getName();
+
+    /**
+     * The locale of this layout.
+     * @return the locale of this layout.
+     */
+    public final Locale getLocale() { return mCustomizer.getLocale(); }
+
+    /**
+     * The layout customizer for this layout.
+     * @return the layout customizer;
+     */
+    public final LayoutCustomizer getCustomizer() { return mCustomizer; }
+
+    // Icon id.
+    private static final int ICON_SHIFT = KeyboardIconsSet.getIconId(
+            KeyboardIconsSet.NAME_SHIFT_KEY);
+    private static final int ICON_SHIFTED_SHIFT = KeyboardIconsSet.getIconId(
+            KeyboardIconsSet.NAME_SHIFT_KEY_SHIFTED);
+
+    // Functional key.
+    static final ExpectedKey CAPSLOCK_MORE_KEY = key(" ", Constants.CODE_CAPSLOCK);
+    static final ExpectedKey SHIFT_KEY = key(ICON_SHIFT,
+            Constants.CODE_SHIFT, CAPSLOCK_MORE_KEY);
+    static final ExpectedKey SHIFTED_SHIFT_KEY = key(ICON_SHIFTED_SHIFT,
+            Constants.CODE_SHIFT, CAPSLOCK_MORE_KEY);
+    static final ExpectedKey ALPHABET_KEY = key("ABC", Constants.CODE_SWITCH_ALPHA_SYMBOL);
+    static final ExpectedKey SYMBOLS_KEY = key("?123", Constants.CODE_SWITCH_ALPHA_SYMBOL);
+    static final ExpectedKey BACK_TO_SYMBOLS_KEY = key("?123", Constants.CODE_SHIFT);
+    static final ExpectedKey SYMBOLS_SHIFT_KEY = key("= \\ <", Constants.CODE_SHIFT);
+    static final ExpectedKey TABLET_SYMBOLS_SHIFT_KEY = key("~ [ <", Constants.CODE_SHIFT);
+
+    // U+00A1: "¡" INVERTED EXCLAMATION MARK
+    // U+00BF: "¿" INVERTED QUESTION MARK
+    static final ExpectedKey[] EXCLAMATION_AND_QUESTION_MARKS = joinKeys(
+            key("!", moreKey("\u00A1")), key("?", moreKey("\u00BF")));
+
+
+    // Punctuation more keys for phone form factor.
+    public static final ExpectedKey[] PHONE_PUNCTUATION_MORE_KEYS = joinKeys(
+            ";", "/", "(", ")", "#", "!", ",", "?",
+            "&", "%", "+", "\"", "-", ":", "'", "@");
+
+    // Punctuation more keys for tablet form factor.
+    public static final ExpectedKey[] TABLET_PUNCTUATION_MORE_KEYS = joinKeys(
+            ";", "/", "(", ")", "#", "'", ",",
+            "&", "%", "+", "\"", "-", ":", "@");
+
+   /**
+     * Helper method to create alphabet layout adding special function keys.
+     * @param builder the {@link ExpectedKeyboardBuilder} object that contains common keyboard
+     *     layout
+     * @param isPhone true if requesting phone's layout.
+     * @return the {@link ExpectedKeyboardBuilder} object that is customized and have special keys.
+     */
+    ExpectedKeyboardBuilder convertCommonLayoutToKeyboard(final ExpectedKeyboardBuilder builder,
+            final boolean isPhone) {
+        final LayoutCustomizer customizer = getCustomizer();
+        final ExpectedKey[] spacebar = joinKeys(
+                customizer.getKeysLeftToSpacebar(isPhone),
+                SPACEBAR,
+                customizer.getKeysRightToSpacebar(isPhone));
+        builder.setKeysOfRow(4, spacebar);
+        if (isPhone) {
+            builder.addKeysOnTheRightOfRow(3, DELETE_KEY)
+                    .addKeysOnTheLeftOfRow(4, customizer.getSymbolsKey())
+                    .addKeysOnTheRightOfRow(4, key(ENTER_KEY, EMOJI_KEY));
+        } else {
+            builder.addKeysOnTheRightOfRow(1, DELETE_KEY)
+                    .addKeysOnTheRightOfRow(2, ENTER_KEY)
+                    .addKeysOnTheLeftOfRow(4, customizer.getSymbolsKey(), SETTINGS_KEY)
+                    .addKeysOnTheRightOfRow(4, EMOJI_KEY);
+
+        }
+        builder.addKeysOnTheLeftOfRow(3, customizer.getLeftShiftKeys(isPhone))
+            .addKeysOnTheRightOfRow(3, customizer.getRightShiftKeys(isPhone));
+        return builder;
+    }
+
+    /**
+     * Get common alphabet layout. This layout doesn't contain any special keys.
+     * @param isPhone true if requesting phone's layout.
+     * @return the common alphabet keyboard layout.
+     */
+    abstract ExpectedKey[][] getCommonAlphabetLayout(boolean isPhone);
+
+    /**
+     * Get common alphabet shifted layout. This layout doesn't contain any special keys.
+     * @param isPhone true if requesting phone's layout.
+     * @param elementId the element id of the requesting shifted mode.
+     * @return the common alphabet shifted keyboard layout.
+     */
+    ExpectedKey[][] getCommonAlphabetShiftLayout(final boolean isPhone, final int elementId) {
+        final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder(
+                getCommonAlphabetLayout(isPhone));
+        getCustomizer().setAccentedLetters(builder);
+        builder.toUpperCase(getLocale());
+        return builder.build();
+    }
+
+    /**
+     * Get the complete expected keyboard layout.
+     * @param isPhone true if requesting phone's layout.
+     * @param elementId the element id of the requesting keyboard mode.
+     * @return
+     */
+    public ExpectedKey[][] getLayout(final boolean isPhone, final int elementId) {
+        if (elementId == KeyboardId.ELEMENT_SYMBOLS) {
+            return mSymbols.getLayout(isPhone);
+        }
+        if (elementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED) {
+            return mSymbolsShifted.getLayout(isPhone);
+        }
+        final ExpectedKeyboardBuilder builder;
+        if (elementId == KeyboardId.ELEMENT_ALPHABET) {
+            builder = new ExpectedKeyboardBuilder(getCommonAlphabetLayout(isPhone));
+            getCustomizer().setAccentedLetters(builder);
+        } else {
+            final ExpectedKey[][] commonLayout = getCommonAlphabetShiftLayout(isPhone, elementId);
+            if (commonLayout == null) {
+                return null;
+            }
+            builder = new ExpectedKeyboardBuilder(commonLayout);
+        }
+        convertCommonLayoutToKeyboard(builder, isPhone);
+        if (elementId != KeyboardId.ELEMENT_ALPHABET) {
+            builder.replaceKeysOfAll(SHIFT_KEY, SHIFTED_SHIFT_KEY);
+        }
+        return builder.build();
+    }
+}
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Qwerty.java b/tests/src/com/android/inputmethod/keyboard/layout/Qwerty.java
index 325b78450f74913d525624545beebc396fe9dc46..f17c59d8f3f19b48d0a6b2a604df6a44c1728541 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/Qwerty.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/Qwerty.java
@@ -18,18 +18,23 @@ package com.android.inputmethod.keyboard.layout;
 
 import com.android.inputmethod.keyboard.layout.expected.ExpectedKey;
 import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder;
-import com.android.inputmethod.keyboard.layout.expected.LayoutBase;
 
 /**
  * The QWERTY alphabet keyboard.
  */
 public final class Qwerty extends LayoutBase {
-    public static final String LAYOUT_NAME = "qwerty";
+    private static final String LAYOUT_NAME = "qwerty";
 
-    public static ExpectedKey[][] getLayout(final boolean isPhone) {
-        return getDefaultAlphabetLayout(ALPHABET_COMMON, isPhone);
+    public Qwerty(final LayoutCustomizer customizer) {
+        super(customizer, Symbols.class, SymbolsShifted.class);
     }
 
+    @Override
+    public String getName() { return LAYOUT_NAME; }
+
+    @Override
+    ExpectedKey[][] getCommonAlphabetLayout(final boolean isPhone) { return ALPHABET_COMMON; }
+
     private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder(10, 9, 7, 3)
             .setLabelsOfRow(1, "q", "w", "e", "r", "t", "y", "u", "i", "o", "p")
             .setMoreKeysOf("q", "1")
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Symbols.java b/tests/src/com/android/inputmethod/keyboard/layout/Symbols.java
index 6fcfa052037d56d5fa02a2cd470bc614980a7a57..ca3c711c198a5ef60f2d3417d6e4d69ccb876212 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/Symbols.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/Symbols.java
@@ -16,36 +16,34 @@
 
 package com.android.inputmethod.keyboard.layout;
 
+import com.android.inputmethod.keyboard.layout.LayoutBase.LayoutCustomizer;
+import com.android.inputmethod.keyboard.layout.expected.AbstractLayoutBase;
 import com.android.inputmethod.keyboard.layout.expected.ExpectedKey;
 import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder;
-import com.android.inputmethod.keyboard.layout.expected.LayoutBase;
-import com.android.inputmethod.latin.Constants;
 
 /**
  * The symbols keyboard layout.
  */
-public final class Symbols extends LayoutBase {
-    public static ExpectedKey[][] getLayout(final boolean isPhone) {
-        return isPhone ? toPhoneSymbol(SYMBOLS_COMMON) : toTabletSymbols(SYMBOLS_COMMON);
+public class Symbols extends AbstractLayoutBase {
+    private final LayoutCustomizer mCustomizer;
+
+    public Symbols(final LayoutCustomizer customizer) {
+        mCustomizer = customizer;
     }
 
-    public static ExpectedKey[][] getDefaultLayout(final boolean isPhone) {
-        final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder(getLayout(isPhone));
-        builder.replaceKeyOfLabel(CURRENCY, Symbols.CURRENCY_DOLLAR);
-        builder.replaceKeyOfLabel(DOUBLE_QUOTE,
-                key("\"", join(Symbols.DOUBLE_QUOTES_9LR, Symbols.DOUBLE_ANGLE_QUOTES_LR)));
-        builder.replaceKeyOfLabel(SINGLE_QUOTE,
-                key("'", join(Symbols.SINGLE_QUOTES_9LR, Symbols.SINGLE_ANGLE_QUOTES_LR)));
+    public ExpectedKey[][] getLayout(final boolean isPhone) {
+        final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder(isPhone
+                ? toPhoneSymbol(SYMBOLS_COMMON) : toTabletSymbols(SYMBOLS_COMMON));
+        builder.replaceKeyOfLabel(CURRENCY, mCustomizer.getCurrencyKey());
+        builder.replaceKeyOfLabel(DOUBLE_QUOTE, key("\"", joinKeys(
+                mCustomizer.getDoubleQuoteMoreKeys(), mCustomizer.getDoubleAngleQuoteKeys())));
+        builder.replaceKeyOfLabel(SINGLE_QUOTE, key("'", joinKeys(
+                mCustomizer.getSingleQuoteMoreKeys(), mCustomizer.getSingleAngleQuoteKeys())));
         return builder.build();
     }
 
-    // Functional keys.
-    public static final ExpectedKey ALPHABET_KEY = key("ABC", Constants.CODE_SWITCH_ALPHA_SYMBOL);
-    public static final ExpectedKey SYMBOLS_SHIFT_KEY = key("= \\ <", Constants.CODE_SHIFT);
-    public static final ExpectedKey TABLET_SYMBOLS_SHIFT_KEY = key("~ [ <", Constants.CODE_SHIFT);
-
     // Variations of the "currency" key on the 2nd row.
-    public static final String CURRENCY = "currency";
+    public static final String CURRENCY = "CURRENCY";
     // U+00A2: "¢" CENT SIGN
     // U+00A3: "£" POUND SIGN
     // U+00A5: "Â¥" YEN SIGN
@@ -63,13 +61,13 @@ public final class Symbols extends LayoutBase {
             CENT_SIGN, POUND_SIGN, DOLLAR_SIGN, YEN_SIGN, PESO_SIGN);
 
     // Variations of the "double quote" key's "more keys" on the 3rd row.
-    public static final String DOUBLE_QUOTE = "double_quote";
+    public static final String DOUBLE_QUOTE = "DOUBLE_QUOTE";
     // U+201C: "“" LEFT DOUBLE QUOTATION MARK
     // U+201D: "”" RIGHT DOUBLE QUOTATION MARK
     // U+201E: "„" DOUBLE LOW-9 QUOTATION MARK
-    static final ExpectedKey DQUOTE_LEFT = key("\u201C");
-    static final ExpectedKey DQUOTE_RIGHT = key("\u201D");
-    static final ExpectedKey DQUOTE_LOW9 = key("\u201E");
+    private static final ExpectedKey DQUOTE_LEFT = key("\u201C");
+    private static final ExpectedKey DQUOTE_RIGHT = key("\u201D");
+    private static final ExpectedKey DQUOTE_LOW9 = key("\u201E");
     public static ExpectedKey[] DOUBLE_QUOTES_9LR = { DQUOTE_LOW9, DQUOTE_LEFT, DQUOTE_RIGHT };
     public static ExpectedKey[] DOUBLE_QUOTES_R9L = { DQUOTE_RIGHT, DQUOTE_LOW9, DQUOTE_LEFT };
     public static ExpectedKey[] DOUBLE_QUOTES_L9R = { DQUOTE_LEFT, DQUOTE_LOW9, DQUOTE_RIGHT };
@@ -78,20 +76,17 @@ public final class Symbols extends LayoutBase {
     // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     private static final ExpectedKey DAQUOTE_LEFT = key("\u00AB");
     private static final ExpectedKey DAQUOTE_RIGHT = key("\u00BB");
-    private static final ExpectedKey DAQUOTE_LEFT_RTL = key("\u00AB", "\u00BB");
-    private static final ExpectedKey DAQUOTE_RIGHT_RTL = key("\u00BB", "\u00AB");
     public static ExpectedKey[] DOUBLE_ANGLE_QUOTES_LR = { DAQUOTE_LEFT, DAQUOTE_RIGHT };
     public static ExpectedKey[] DOUBLE_ANGLE_QUOTES_RL = { DAQUOTE_RIGHT, DAQUOTE_LEFT };
-    public static ExpectedKey[] DOUBLE_ANGLE_QUOTES_RTL = { DAQUOTE_LEFT_RTL, DAQUOTE_RIGHT_RTL };
 
     // Variations of the "single quote" key's "more keys" on the 3rd row.
-    public static final String SINGLE_QUOTE = "single_quote";
+    public static final String SINGLE_QUOTE = "SINGLE_QUOTE";
     // U+2018: "‘" LEFT SINGLE QUOTATION MARK
     // U+2019: "’" RIGHT SINGLE QUOTATION MARK
     // U+201A: "‚" SINGLE LOW-9 QUOTATION MARK
-    static final ExpectedKey SQUOTE_LEFT = key("\u2018");
-    static final ExpectedKey SQUOTE_RIGHT = key("\u2019");
-    static final ExpectedKey SQUOTE_LOW9 = key("\u201A");
+    private static final ExpectedKey SQUOTE_LEFT = key("\u2018");
+    private static final ExpectedKey SQUOTE_RIGHT = key("\u2019");
+    private static final ExpectedKey SQUOTE_LOW9 = key("\u201A");
     public static ExpectedKey[] SINGLE_QUOTES_9LR = { SQUOTE_LOW9, SQUOTE_LEFT, SQUOTE_RIGHT };
     public static ExpectedKey[] SINGLE_QUOTES_R9L = { SQUOTE_RIGHT, SQUOTE_LOW9, SQUOTE_LEFT };
     public static ExpectedKey[] SINGLE_QUOTES_L9R = { SQUOTE_LEFT, SQUOTE_LOW9, SQUOTE_RIGHT };
@@ -100,14 +95,11 @@ public final class Symbols extends LayoutBase {
     // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
     private static final ExpectedKey SAQUOTE_LEFT = key("\u2039");
     private static final ExpectedKey SAQUOTE_RIGHT = key("\u203A");
-    private static final ExpectedKey SAQUOTE_LEFT_RTL = key("\u2039", "\u203A");
-    private static final ExpectedKey SAQUOTE_RIGHT_RTL = key("\u203A", "\u2039");
     public static ExpectedKey[] SINGLE_ANGLE_QUOTES_LR = { SAQUOTE_LEFT, SAQUOTE_RIGHT };
     public static ExpectedKey[] SINGLE_ANGLE_QUOTES_RL = { SAQUOTE_RIGHT, SAQUOTE_LEFT };
-    public static ExpectedKey[] SINGLE_ANGLE_QUOTES_RTL = { SAQUOTE_LEFT_RTL, SAQUOTE_RIGHT_RTL };
 
     // Common symbols keyboard layout.
-    public static final ExpectedKey[][] SYMBOLS_COMMON = new ExpectedKeyboardBuilder(10, 9, 7, 5)
+    private static final ExpectedKey[][] SYMBOLS_COMMON = new ExpectedKeyboardBuilder(10, 9, 7, 5)
             .setLabelsOfRow(1, "1", "2", "3", "4", "5", "6", "7", "8", "9", "0")
             // U+00B9: "¹" SUPERSCRIPT ONE
             // U+00BD: "½" VULGAR FRACTION ONE HALF
@@ -156,25 +148,56 @@ public final class Symbols extends LayoutBase {
             .setMoreKeysOf(".", "\u2026")
             .build();
 
-    private static ExpectedKey[][] toPhoneSymbol(final ExpectedKey[][] common) {
+    private ExpectedKey[][] toPhoneSymbol(final ExpectedKey[][] common) {
         return new ExpectedKeyboardBuilder(common)
-                .addKeysOnTheLeftOfRow(3, Symbols.SYMBOLS_SHIFT_KEY)
+                .addKeysOnTheLeftOfRow(3, mCustomizer.getSymbolsShiftKey(true /* isPhone */))
                 .addKeysOnTheRightOfRow(3, DELETE_KEY)
-                .addKeysOnTheLeftOfRow(4, Symbols.ALPHABET_KEY)
+                .addKeysOnTheLeftOfRow(4, mCustomizer.getAlphabetKey())
                 .addKeysOnTheRightOfRow(4, key(ENTER_KEY, EMOJI_KEY))
                 .build();
     }
 
-    private static ExpectedKey[][] toTabletSymbols(final ExpectedKey[][] common) {
+    private ExpectedKey[][] toTabletSymbols(final ExpectedKey[][] common) {
         return new ExpectedKeyboardBuilder(common)
                 .addKeysOnTheLeftOfRow(3,
                         key("\\"), key("="))
                 .addKeysOnTheRightOfRow(1, DELETE_KEY)
                 .addKeysOnTheRightOfRow(2, ENTER_KEY)
-                .addKeysOnTheLeftOfRow(3, Symbols.TABLET_SYMBOLS_SHIFT_KEY)
-                .addKeysOnTheRightOfRow(3, Symbols.TABLET_SYMBOLS_SHIFT_KEY)
-                .addKeysOnTheLeftOfRow(4, Symbols.ALPHABET_KEY)
+                .addKeysOnTheLeftOfRow(3, mCustomizer.getSymbolsShiftKey(false /* isPhone */))
+                .addKeysOnTheRightOfRow(3, mCustomizer.getSymbolsShiftKey(false /* isPhone */))
+                .addKeysOnTheLeftOfRow(4, mCustomizer.getAlphabetKey())
                 .addKeysOnTheRightOfRow(4, EMOJI_KEY)
                 .build();
     }
+
+    public static class RtlSymbols extends Symbols {
+        public RtlSymbols(final LayoutCustomizer customizer) {
+            super(customizer);
+        }
+
+        // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+        // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+        private static final ExpectedKey DAQUOTE_LEFT_RTL = key("\u00AB", "\u00BB");
+        private static final ExpectedKey DAQUOTE_RIGHT_RTL = key("\u00BB", "\u00AB");
+        public static ExpectedKey[] DOUBLE_ANGLE_QUOTES_LR_RTL = {
+                DAQUOTE_LEFT_RTL, DAQUOTE_RIGHT_RTL
+        };
+        // U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+        // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+        private static final ExpectedKey SAQUOTE_LEFT_RTL = key("\u2039", "\u203A");
+        private static final ExpectedKey SAQUOTE_RIGHT_RTL = key("\u203A", "\u2039");
+        public static ExpectedKey[] SINGLE_ANGLE_QUOTES_LR_RTL = {
+                SAQUOTE_LEFT_RTL, SAQUOTE_RIGHT_RTL
+        };
+
+        @Override
+        public ExpectedKey[][] getLayout(final boolean isPhone) {
+            return new ExpectedKeyboardBuilder(super.getLayout(isPhone))
+                    .replaceKeyOfLabel("(", key("(", ")",
+                            moreKey("<", ">"), moreKey("{", "}"), moreKey("[", "]")))
+                    .replaceKeyOfLabel(")", key(")", "(",
+                            moreKey(">", "<"), moreKey("}", "{"), moreKey("]", "[")))
+                    .build();
+        }
+    }
 }
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/SymbolsShifted.java b/tests/src/com/android/inputmethod/keyboard/layout/SymbolsShifted.java
index 4d9ae4348d7ca82aec743ba7dbecd1583a99ea3c..96b40101ceb3661fa23c34fcaeae91826f64ae3a 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/SymbolsShifted.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/SymbolsShifted.java
@@ -16,31 +16,31 @@
 
 package com.android.inputmethod.keyboard.layout;
 
+import com.android.inputmethod.keyboard.layout.LayoutBase.LayoutCustomizer;
 import com.android.inputmethod.keyboard.layout.expected.ExpectedKey;
 import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder;
-import com.android.inputmethod.keyboard.layout.expected.LayoutBase;
-import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.keyboard.layout.expected.AbstractLayoutBase;
 
 /**
  * The symbols shifted keyboard layout.
  */
-public final class SymbolsShifted extends LayoutBase {
-    public static ExpectedKey[][] getLayout(final boolean isPhone) {
-        return isPhone ? toPhoneSymbolsShifted(SYMBOLS_SHIFTED_COMMON)
-                : toTabletSymbolsShifted(SYMBOLS_SHIFTED_COMMON);
+public class SymbolsShifted extends AbstractLayoutBase {
+    private final LayoutCustomizer mCustomizer;
+
+    public SymbolsShifted(final LayoutCustomizer customizer) {
+        mCustomizer = customizer;
     }
 
-    public static ExpectedKey[][] getDefaultLayout(final boolean isPhone) {
-        final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder(getLayout(isPhone));
-        builder.replaceKeyOfLabel(OTHER_CURRENCIES, SymbolsShifted.CURRENCIES_OTHER_THAN_DOLLAR);
+    public ExpectedKey[][] getLayout(final boolean isPhone) {
+        final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder(isPhone
+                ? toPhoneSymbolsShifted(SYMBOLS_SHIFTED_COMMON)
+                : toTabletSymbolsShifted(SYMBOLS_SHIFTED_COMMON));
+        builder.replaceKeyOfLabel(OTHER_CURRENCIES, mCustomizer.getOtherCurrencyKeys());
         return builder.build();
     }
 
-    // Functional key.
-    public static final ExpectedKey BACK_TO_SYMBOLS_KEY = key("?123", Constants.CODE_SHIFT);
-
     // Variations of the "other currencies" keys on the 2rd row.
-    public static final String OTHER_CURRENCIES = "other_currencies";
+    public static final String OTHER_CURRENCIES = "OTHER_CURRENCY";
     public static final ExpectedKey[] CURRENCIES_OTHER_THAN_DOLLAR = {
         Symbols.POUND_SIGN, Symbols.CENT_SIGN, Symbols.EURO_SIGN, Symbols.YEN_SIGN
     };
@@ -50,7 +50,7 @@ public final class SymbolsShifted extends LayoutBase {
     };
 
     // Common symbols shifted keyboard layout.
-    public static final ExpectedKey[][] SYMBOLS_SHIFTED_COMMON =
+    private static final ExpectedKey[][] SYMBOLS_SHIFTED_COMMON =
             new ExpectedKeyboardBuilder(10, 1 /* other_currencies */ + 5, 7, 5)
             // U+0060: "`" GRAVE ACCENT
             // U+2022: "•" BULLET
@@ -112,16 +112,16 @@ public final class SymbolsShifted extends LayoutBase {
             .setMoreKeysOf(".", "\u2026")
             .build();
 
-    private static ExpectedKey[][] toPhoneSymbolsShifted(final ExpectedKey[][] common) {
+    private ExpectedKey[][] toPhoneSymbolsShifted(final ExpectedKey[][] common) {
         return new ExpectedKeyboardBuilder(common)
-                .addKeysOnTheLeftOfRow(3, BACK_TO_SYMBOLS_KEY)
+                .addKeysOnTheLeftOfRow(3, mCustomizer.getBackToSymbolsKey())
                 .addKeysOnTheRightOfRow(3, DELETE_KEY)
-                .addKeysOnTheLeftOfRow(4, Symbols.ALPHABET_KEY)
+                .addKeysOnTheLeftOfRow(4, mCustomizer.getAlphabetKey())
                 .addKeysOnTheRightOfRow(4, key(ENTER_KEY, EMOJI_KEY))
                 .build();
     }
 
-    private static ExpectedKey[][] toTabletSymbolsShifted(final ExpectedKey[][] common) {
+    private ExpectedKey[][] toTabletSymbolsShifted(final ExpectedKey[][] common) {
         return new ExpectedKeyboardBuilder(common)
                 // U+00BF: "¿" INVERTED QUESTION MARK
                 // U+00A1: "¡" INVERTED EXCLAMATION MARK
@@ -129,10 +129,38 @@ public final class SymbolsShifted extends LayoutBase {
                         key("\u00A1"), key("\u00BF"))
                 .addKeysOnTheRightOfRow(1, DELETE_KEY)
                 .addKeysOnTheRightOfRow(2, ENTER_KEY)
-                .addKeysOnTheLeftOfRow(3, BACK_TO_SYMBOLS_KEY)
-                .addKeysOnTheRightOfRow(3, BACK_TO_SYMBOLS_KEY)
-                .addKeysOnTheLeftOfRow(4, Symbols.ALPHABET_KEY)
+                .addKeysOnTheLeftOfRow(3, mCustomizer.getBackToSymbolsKey())
+                .addKeysOnTheRightOfRow(3, mCustomizer.getBackToSymbolsKey())
+                .addKeysOnTheLeftOfRow(4, mCustomizer.getAlphabetKey())
                 .addKeysOnTheRightOfRow(4, EMOJI_KEY)
                 .build();
     }
+
+    public static class RtlSymbolsShifted extends SymbolsShifted {
+        public RtlSymbolsShifted(final LayoutCustomizer customizer) {
+            super(customizer);
+        }
+
+        @Override
+        public ExpectedKey[][] getLayout(final boolean isPhone) {
+            return new ExpectedKeyboardBuilder(super.getLayout(isPhone))
+                .replaceKeyOfLabel("{", key("{", "}"))
+                .replaceKeyOfLabel("}", key("}", "{"))
+                .replaceKeyOfLabel("[", key("[", "]"))
+                .replaceKeyOfLabel("]", key("]", "["))
+                // U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+                // U+2264: "≤" LESS-THAN OR EQUAL TO
+                // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+                .replaceKeyOfLabel("<", key("<", ">",
+                        moreKey("\u2039", "\u203A"), moreKey("\u2264", "\u2265"),
+                        moreKey("\u00AB", "\u00BB")))
+                // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+                // U+2265: "≥" GREATER-THAN EQUAL TO
+                // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+                .replaceKeyOfLabel(">", key(">", "<",
+                        moreKey("\u203A", "\u2039"), moreKey("\u2265", "\u2264"),
+                        moreKey("\u00BB", "\u00AB")))
+                .build();
+        }
+    }
 }
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/expected/LayoutBase.java b/tests/src/com/android/inputmethod/keyboard/layout/expected/AbstractLayoutBase.java
similarity index 55%
rename from tests/src/com/android/inputmethod/keyboard/layout/expected/LayoutBase.java
rename to tests/src/com/android/inputmethod/keyboard/layout/expected/AbstractLayoutBase.java
index 1d242d0b8f73571a2f77c8faa3c84e4f75401a89..d8d66c2366048d780aae6c905586fb803d59b6c6 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/expected/LayoutBase.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/expected/AbstractLayoutBase.java
@@ -19,6 +19,7 @@ package com.android.inputmethod.keyboard.layout.expected;
 import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
 import com.android.inputmethod.latin.Constants;
 import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.StringUtils;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -26,7 +27,7 @@ import java.util.Arrays;
 /**
  * Base class to create an expected keyboard for unit test.
  */
-public class LayoutBase {
+public abstract class AbstractLayoutBase {
     // Those helper methods have a lower case name to be readable when defining expected keyboard
     // layouts.
 
@@ -77,7 +78,7 @@ public class LayoutBase {
 
     // Helper method to create {@link ExpectedKey} array by joining {@link ExpectedKey},
     // {@link ExpectedKey} array, and {@link String}.
-    public static ExpectedKey[] join(final Object ... keys) {
+    public static ExpectedKey[] joinKeys(final Object ... keys) {
         final ArrayList<ExpectedKey> list = CollectionUtils.newArrayList();
         for (final Object key : keys) {
             if (key instanceof ExpectedKey) {
@@ -94,81 +95,20 @@ public class LayoutBase {
     }
 
     // Icon ids.
-    private static final int ICON_SHIFT = KeyboardIconsSet.getIconId("shift_key");
-    private static final int ICON_DELETE = KeyboardIconsSet.getIconId("delete_key");
-    private static final int ICON_SETTINGS = KeyboardIconsSet.getIconId("settings_key");
-    private static final int ICON_ENTER = KeyboardIconsSet.getIconId("enter_key");
-    private static final int ICON_EMOJI = KeyboardIconsSet.getIconId("emoji_key");
+    private static final int ICON_DELETE = KeyboardIconsSet.getIconId(
+            KeyboardIconsSet.NAME_DELETE_KEY);
+    private static final int ICON_SETTINGS = KeyboardIconsSet.getIconId(
+            KeyboardIconsSet.NAME_SETTINGS_KEY);
+    private static final int ICON_ENTER = KeyboardIconsSet.getIconId(
+            KeyboardIconsSet.NAME_ENTER_KEY);
+    private static final int ICON_EMOJI = KeyboardIconsSet.getIconId(
+            KeyboardIconsSet.NAME_EMOJI_KEY);
 
     // Functional keys.
-    public static final ExpectedKey CAPSLOCK_MORE_KEY = key(" ", Constants.CODE_CAPSLOCK);
-    public static final ExpectedKey SHIFT_KEY = key(ICON_SHIFT, Constants.CODE_SHIFT);
     public static final ExpectedKey DELETE_KEY = key(ICON_DELETE, Constants.CODE_DELETE);
-    public static final ExpectedKey SYMBOLS_KEY = key("?123", Constants.CODE_SWITCH_ALPHA_SYMBOL);
     public static final ExpectedKey SETTINGS_KEY = key(ICON_SETTINGS, Constants.CODE_SETTINGS);
     public static final ExpectedKey ENTER_KEY = key(ICON_ENTER, Constants.CODE_ENTER);
     public static final ExpectedKey EMOJI_KEY = key(ICON_EMOJI, Constants.CODE_EMOJI);
-
-    // Punctuation more keys for phone form factor.
-    public static final String[] PHONE_PUNCTUATION_MORE_KEYS = {
-            ";", "/", "(", ")", "#", "!", ",", "?",
-            "&", "%", "+", "\"", "-", ":", "'", "@"
-    };
-
-    // Punctuation more keys for tablet form factor.
-    public static final String[] TABLET_PUNCTUATION_MORE_KEYS = {
-            ";", "/", "(", ")", "#", "'", ",",
-            "&", "%", "+", "\"", "-", ":", "@"
-    };
-
-    // Helper method to create alphabet layout for phone by adding special function keys except
-    // shift key.
-    private static ExpectedKeyboardBuilder convertToPhoneAlphabetKeyboardBuilder(
-            final ExpectedKey[][] commonLayout) {
-        return new ExpectedKeyboardBuilder(commonLayout)
-                .addKeysOnTheRightOfRow(3, DELETE_KEY)
-                .setLabelsOfRow(4, ",", " ", ".")
-                .setMoreKeysOf(",", SETTINGS_KEY)
-                .setMoreKeysOf(".", PHONE_PUNCTUATION_MORE_KEYS)
-                .addKeysOnTheLeftOfRow(4, SYMBOLS_KEY)
-                .addKeysOnTheRightOfRow(4, key(ENTER_KEY, EMOJI_KEY));
-    }
-
-    // Helper method to create alphabet layout for tablet by adding special function keys except
-    // shift key.
-    private static ExpectedKeyboardBuilder convertToTabletAlphabetKeyboardBuilder(
-            final ExpectedKey[][] commonLayout) {
-        return new ExpectedKeyboardBuilder(commonLayout)
-                // U+00BF: "¿" INVERTED QUESTION MARK
-                // U+00A1: "¡" INVERTED EXCLAMATION MARK
-                .addKeysOnTheRightOfRow(3,
-                        key("!", moreKey("\u00A1")), key("?", moreKey("\u00BF")))
-                .addKeysOnTheRightOfRow(1, DELETE_KEY)
-                .addKeysOnTheRightOfRow(2, ENTER_KEY)
-                .setLabelsOfRow(4, "/", " ", ",", ".")
-                .setMoreKeysOf(".", TABLET_PUNCTUATION_MORE_KEYS)
-                .addKeysOnTheLeftOfRow(4, SYMBOLS_KEY, SETTINGS_KEY)
-                .addKeysOnTheRightOfRow(4, EMOJI_KEY);
-    }
-
-    // Helper method to create alphabet layout by adding special function keys.
-    public static ExpectedKey[][] getAlphabetLayoutWithoutShiftKeys(
-            final ExpectedKey[][] commonLayout, final boolean isPhone) {
-        return isPhone ? convertToPhoneAlphabetKeyboardBuilder(commonLayout).build()
-                : convertToTabletAlphabetKeyboardBuilder(commonLayout).build();
-    }
-
-    // Helper method to create alphabet layout by adding special function keys.
-    public static ExpectedKey[][] getDefaultAlphabetLayout(final ExpectedKey[][] commonLayout,
-            final boolean isPhone) {
-        final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder(
-                getAlphabetLayoutWithoutShiftKeys(commonLayout, isPhone));
-        if (isPhone) {
-            builder.addKeysOnTheLeftOfRow(3, key(SHIFT_KEY, CAPSLOCK_MORE_KEY));
-        } else {
-            builder.addKeysOnTheLeftOfRow(3, key(SHIFT_KEY, CAPSLOCK_MORE_KEY))
-                    .addKeysOnTheRightOfRow(3, key(SHIFT_KEY, CAPSLOCK_MORE_KEY));
-        }
-        return builder.build();
-    }
+    public static final ExpectedKey SPACEBAR = key(
+            StringUtils.newSingleCodePointString(Constants.CODE_SPACE));
 }
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyboardBuilder.java b/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyboardBuilder.java
index 57f842b74e36f05ca228e3d5c95dfe0185e8c9a0..795bcb28eefbb4824431a47d30404051d4ee29ea 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyboardBuilder.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyboardBuilder.java
@@ -120,6 +120,17 @@ public final class ExpectedKeyboardBuilder extends AbstractKeyboardBuilder<Expec
         return this;
     }
 
+    /**
+     * Set the row with specified keys.
+     * @param row the row number to set keys.
+     * @param keys the keys to be set at <code>row</code>.
+     * @return this builder.
+     */
+    public ExpectedKeyboardBuilder setKeysOfRow(final int row, final ExpectedKey ... keys) {
+        setRowAt(row, keys);
+        return this;
+    }
+
     /**
      * Set the "more keys" of the key that has the specified label.
      * @param label the label of the key to set the "more keys".
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/LayoutTestsBase.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/LayoutTestsBase.java
index 5c51d088b4e5ce870261f82f07bdffb0fcbc0058..b9678444b93734f4e8f9a63f815c212b93829504 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/tests/LayoutTestsBase.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/LayoutTestsBase.java
@@ -24,22 +24,20 @@ import com.android.inputmethod.keyboard.Keyboard;
 import com.android.inputmethod.keyboard.KeyboardId;
 import com.android.inputmethod.keyboard.KeyboardLayoutSet;
 import com.android.inputmethod.keyboard.KeyboardLayoutSetTestsBase;
-import com.android.inputmethod.keyboard.layout.AlphabetShifted;
-import com.android.inputmethod.keyboard.layout.Symbols;
-import com.android.inputmethod.keyboard.layout.SymbolsShifted;
+import com.android.inputmethod.keyboard.layout.LayoutBase;
+import com.android.inputmethod.keyboard.layout.expected.AbstractLayoutBase;
 import com.android.inputmethod.keyboard.layout.expected.ActualKeyboardBuilder;
 import com.android.inputmethod.keyboard.layout.expected.ExpectedKey;
 import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder;
-import com.android.inputmethod.keyboard.layout.expected.LayoutBase;
 import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
 
 import java.util.Arrays;
-import java.util.Locale;
 
 /**
  * Base class for keyboard layout unit test.
  */
 abstract class LayoutTestsBase extends KeyboardLayoutSetTestsBase {
+    private LayoutBase mLayout;
     private InputMethodSubtype mSubtype;
     private String mLogTag;
     private KeyboardLayoutSet mKeyboardLayoutSet;
@@ -48,7 +46,8 @@ abstract class LayoutTestsBase extends KeyboardLayoutSetTestsBase {
     protected void setUp() throws Exception {
         super.setUp();
 
-        mSubtype = getSubtype(getTestLocale(), getTestKeyboardLayout());
+        mLayout = getLayout();
+        mSubtype = getSubtype(mLayout.getLocale(), mLayout.getName());
         mLogTag = SubtypeLocaleUtils.getSubtypeNameForLogging(mSubtype) + "/"
                 + (isPhone() ? "phone" : "tablet");
         mKeyboardLayoutSet = createKeyboardLayoutSet(mSubtype, null /* editorInfo */);
@@ -59,115 +58,77 @@ abstract class LayoutTestsBase extends KeyboardLayoutSetTestsBase {
 
     // Helper method to create {@link ExpectedKey} object that has the label.
     static ExpectedKey key(final String label, final ExpectedKey ... moreKeys) {
-        return LayoutBase.key(label, moreKeys);
+        return AbstractLayoutBase.key(label, moreKeys);
     }
 
     // Helper method to create {@link ExpectedKey} object that has the label and the output text.
     static ExpectedKey key(final String label, final String outputText,
             final ExpectedKey ... moreKeys) {
-        return LayoutBase.key(label, outputText, moreKeys);
+        return AbstractLayoutBase.key(label, outputText, moreKeys);
     }
 
     // Helper method to create {@link ExpectedKey} object that has new "more keys".
     static ExpectedKey key(final ExpectedKey key, final ExpectedKey ... moreKeys) {
-        return LayoutBase.key(key, moreKeys);
+        return AbstractLayoutBase.key(key, moreKeys);
     }
 
     // Helper method to create {@link ExpectedKey} object for "more key" that has the label.
     static ExpectedKey moreKey(final String label) {
-        return LayoutBase.moreKey(label);
+        return AbstractLayoutBase.moreKey(label);
     }
 
     // Helper method to create {@link ExpectedKey} object for "more key" that has the label and the
     // output text.
     static ExpectedKey moreKey(final String label, final String outputText) {
-        return LayoutBase.moreKey(label, outputText);
+        return AbstractLayoutBase.moreKey(label, outputText);
     }
 
     // Helper method to create {@link ExpectedKey} array by joining {@link ExpectedKey},
     // {@link ExpectedKey} array, and {@link String}.
-    static ExpectedKey[] join(final Object ... keys) {
-        return LayoutBase.join(keys);
+    static ExpectedKey[] joinKeys(final Object ... keys) {
+        return AbstractLayoutBase.joinKeys(keys);
     }
 
-    // Locale for testing subtype.
-    abstract Locale getTestLocale();
+    // Keyboard layout for testing subtype.
+    abstract LayoutBase getLayout();
 
-    // Keyboard layout name for testing subtype.
-    abstract String getTestKeyboardLayout();
-
-    // Alphabet keyboard for testing subtype.
-    abstract ExpectedKey[][] getAlphabetLayout(final boolean isPhone);
-
-    // Alphabet automatic shifted keyboard for testing subtype.
-    ExpectedKey[][] getAlphabetAutomaticShiftedLayout(final boolean isPhone) {
-        return AlphabetShifted.getDefaultLayout(getAlphabetLayout(isPhone), getTestLocale());
-    }
-
-    // Alphabet manual shifted  keyboard for testing subtype.
-    ExpectedKey[][] getAlphabetManualShiftedLayout(final boolean isPhone) {
-        return AlphabetShifted.getDefaultLayout(getAlphabetLayout(isPhone), getTestLocale());
-    }
-
-    // Alphabet shift locked keyboard for testing subtype.
-    ExpectedKey[][] getAlphabetShiftLockedLayout(final boolean isPhone) {
-        return AlphabetShifted.getDefaultLayout(getAlphabetLayout(isPhone), getTestLocale());
-    }
-
-    // Alphabet shift lock shifted keyboard for testing subtype.
-    ExpectedKey[][] getAlphabetShiftLockShiftedLayout(final boolean isPhone) {
-        return AlphabetShifted.getDefaultLayout(getAlphabetLayout(isPhone), getTestLocale());
-    }
-
-    // Symbols keyboard for testing subtype.
-    ExpectedKey[][] getSymbolsLayout(final boolean isPhone) {
-        return Symbols.getDefaultLayout(isPhone);
-    }
-
-    // Symbols shifted keyboard for testing subtype.
-    ExpectedKey[][] getSymbolsShiftedLayout(final boolean isPhone) {
-        return SymbolsShifted.getDefaultLayout(isPhone);
+    ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) {
+        return builder;
     }
 
     // TODO: Add phone, phone symbols, number, number password layout tests.
 
     public final void testAlphabet() {
-        final int elementId = KeyboardId.ELEMENT_ALPHABET;
-        doKeyboardTests(elementId, getAlphabetLayout(isPhone()));
+        doKeyboardTests(KeyboardId.ELEMENT_ALPHABET);
     }
 
     public final void testAlphabetAutomaticShifted() {
-        final int elementId = KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED;
-        doKeyboardTests(elementId, getAlphabetAutomaticShiftedLayout(isPhone()));
+        doKeyboardTests(KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED);
     }
 
     public final void testAlphabetManualShifted() {
-        final int elementId = KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED;
-        doKeyboardTests(elementId, getAlphabetManualShiftedLayout(isPhone()));
+        doKeyboardTests(KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED);
     }
 
     public final void testAlphabetShiftLocked() {
-        final int elementId = KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED;
-        doKeyboardTests(elementId, getAlphabetShiftLockedLayout(isPhone()));
+        doKeyboardTests(KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED);
     }
 
     public final void testAlphabetShiftLockShifted() {
-        final int elementId = KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED;
-        doKeyboardTests(elementId, getAlphabetShiftLockShiftedLayout(isPhone()));
+        doKeyboardTests(KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED);
     }
 
     public final void testSymbols() {
-        final int elementId = KeyboardId.ELEMENT_SYMBOLS;
-        doKeyboardTests(elementId, getSymbolsLayout(isPhone()));
+        doKeyboardTests(KeyboardId.ELEMENT_SYMBOLS);
     }
 
     public final void testSymbolsShifted() {
-        final int elementId = KeyboardId.ELEMENT_SYMBOLS_SHIFTED;
-        doKeyboardTests(elementId, getSymbolsShiftedLayout(isPhone()));
+        doKeyboardTests(KeyboardId.ELEMENT_SYMBOLS_SHIFTED);
     }
 
     // Comparing expected keyboard and actual keyboard.
-    private void doKeyboardTests(final int elementId, final ExpectedKey[][] expectedKeyboard) {
+    private void doKeyboardTests(final int elementId) {
+        final ExpectedKey[][] expectedKeyboard = mLayout.getLayout(isPhone(), elementId);
         // Skip test if no keyboard is defined.
         if (expectedKeyboard == null) {
             return;
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEnglishUS.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEnglishUS.java
index fd1a6061906c2f204439204770e3d90f69db72b2..594322f780388ea80c5df4b2652349dec271c84c 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEnglishUS.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEnglishUS.java
@@ -18,8 +18,9 @@ package com.android.inputmethod.keyboard.layout.tests;
 
 import android.test.suitebuilder.annotation.SmallTest;
 
+import com.android.inputmethod.keyboard.layout.LayoutBase;
+import com.android.inputmethod.keyboard.layout.LayoutBase.LayoutCustomizer;
 import com.android.inputmethod.keyboard.layout.Qwerty;
-import com.android.inputmethod.keyboard.layout.expected.ExpectedKey;
 import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder;
 
 import java.util.Locale;
@@ -28,71 +29,64 @@ import java.util.Locale;
  * en_US: English (United States)/qwerty
  */
 @SmallTest
-public final class TestsEnglishUS extends LayoutTestsBase {
-    @Override
-    Locale getTestLocale() {
-        return new Locale("en", "US");
-    }
+public class TestsEnglishUS extends LayoutTestsBase {
+    private static final Locale LOCALE = new Locale("en", "US");
+    private static final LayoutBase LAYOUT = new Qwerty(new EnglishCustomizer(LOCALE));
 
     @Override
-    String getTestKeyboardLayout() {
-        return Qwerty.LAYOUT_NAME;
-    }
+    LayoutBase getLayout() { return LAYOUT; }
 
-    @Override
-    ExpectedKey[][] getAlphabetLayout(final boolean isPhone) {
-        final ExpectedKey[][] keyboard = Qwerty.getLayout(isPhone);
-        final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder(keyboard);
-        setAccentedLetters(builder);
-        return builder.build();
-    }
+    static class EnglishCustomizer extends LayoutCustomizer {
+        public EnglishCustomizer(final Locale locale) { super(locale); }
 
-    static ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) {
-        return builder
-                // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
-                // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
-                // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
-                // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS
-                // U+0113: "Ä“" LATIN SMALL LETTER E WITH MACRON
-                .setMoreKeysOf("e", "3", "\u00E8", "\u00E9", "\u00EA", "\u00EB", "\u0113")
-                // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
-                // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
-                // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
-                // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
-                // U+016B: "Å«" LATIN SMALL LETTER U WITH MACRON
-                .setMoreKeysOf("u", "7", "\u00FB", "\u00FC", "\u00F9", "\u00FA", "\u016B")
-                // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX
-                // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
-                // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE
-                // U+012B: "Ä«" LATIN SMALL LETTER I WITH MACRON
-                // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE
-                .setMoreKeysOf("i", "8", "\u00EE", "\u00EF", "\u00ED", "\u012B", "\u00EC")
-                // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
-                // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
-                // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
-                // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
-                // U+0153: "Å“" LATIN SMALL LIGATURE OE
-                // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
-                // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
-                // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
-                .setMoreKeysOf("o",
-                        "9", "\u00F4", "\u00F6", "\u00F2", "\u00F3", "\u0153", "\u00F8", "\u014D",
-                        "\u00F5")
-                // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
-                // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
-                // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
-                // U+00E6: "æ" LATIN SMALL LETTER AE
-                // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
-                // U+00E5: "Ã¥" LATIN SMALL LETTER A WITH RING ABOVE
-                // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
-                .setMoreKeysOf("a",
-                        "\u00E0", "\u00E1", "\u00E2", "\u00E4", "\u00E6", "\u00E3", "\u00E5",
-                        "\u0101")
-                // U+00DF: "ß" LATIN SMALL LETTER SHARP S
-                .setMoreKeysOf("s", "\u00DF")
-                // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
-                .setMoreKeysOf("c", "\u00E7")
-                // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
-                .setMoreKeysOf("n", "\u00F1");
+        @Override
+        public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) {
+            return builder
+                    // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
+                    // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
+                    // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
+                    // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS
+                    // U+0113: "Ä“" LATIN SMALL LETTER E WITH MACRON
+                    .setMoreKeysOf("e", "3", "\u00E8", "\u00E9", "\u00EA", "\u00EB", "\u0113")
+                    // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
+                    // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
+                    // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
+                    // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
+                    // U+016B: "Å«" LATIN SMALL LETTER U WITH MACRON
+                    .setMoreKeysOf("u", "7", "\u00FB", "\u00FC", "\u00F9", "\u00FA", "\u016B")
+                    // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX
+                    // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
+                    // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE
+                    // U+012B: "Ä«" LATIN SMALL LETTER I WITH MACRON
+                    // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE
+                    .setMoreKeysOf("i", "8", "\u00EE", "\u00EF", "\u00ED", "\u012B", "\u00EC")
+                    // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+                    // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+                    // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
+                    // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+                    // U+0153: "Å“" LATIN SMALL LIGATURE OE
+                    // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+                    // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
+                    // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+                    .setMoreKeysOf("o",
+                            "9", "\u00F4", "\u00F6", "\u00F2", "\u00F3", "\u0153", "\u00F8",
+                            "\u014D", "\u00F5")
+                    // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
+                    // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
+                    // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+                    // U+00E6: "æ" LATIN SMALL LETTER AE
+                    // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
+                    // U+00E5: "Ã¥" LATIN SMALL LETTER A WITH RING ABOVE
+                    // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
+                    .setMoreKeysOf("a",
+                            "\u00E0", "\u00E1", "\u00E2", "\u00E4", "\u00E6", "\u00E3", "\u00E5",
+                            "\u0101")
+                    // U+00DF: "ß" LATIN SMALL LETTER SHARP S
+                    .setMoreKeysOf("s", "\u00DF")
+                    // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
+                    .setMoreKeysOf("c", "\u00E7")
+                    // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
+                    .setMoreKeysOf("n", "\u00F1");
+        }
     }
 }