From 8ffe4bc9321e582a4d882f21e465d5886616f489 Mon Sep 17 00:00:00 2001
From: Jean Chalard <jchalard@google.com>
Date: Mon, 18 Aug 2014 20:20:20 +0900
Subject: [PATCH] [ML1] Introduce RichInputMethodSubtype

Bug: 11230254
Change-Id: Ic7a1bf938a5a186dcff527b556295aba2406e8b9
---
 .../MainKeyboardAccessibilityDelegate.java    |   2 +-
 .../compat/InputMethodSubtypeCompatUtils.java |   9 +-
 .../inputmethod/keyboard/KeyboardId.java      |   4 +-
 .../keyboard/KeyboardLayoutSet.java           |   8 +-
 .../keyboard/MainKeyboardView.java            |  11 +-
 .../internal/LanguageOnSpacebarHelper.java    |   5 +-
 .../android/inputmethod/latin/LatinIME.java   |   3 +-
 .../latin/RichInputMethodManager.java         |  10 +-
 .../latin/RichInputMethodSubtype.java         | 125 +++++++++
 .../inputmethod/latin/SubtypeSwitcher.java    |  47 ++--
 .../AndroidSpellCheckerService.java           |   3 +-
 ...terCheckingExactMatchesAndSuggestions.java |   3 +-
 .../latin/utils/SpacebarLanguageUtils.java    |  58 -----
 .../latin/utils/SubtypeLocaleUtils.java       |  26 +-
 .../keyboard/KeyboardLayoutSetTestsBase.java  |   3 +-
 .../LanguageOnSpacebarHelperTests.java        |  64 ++---
 .../utils/SpacebarLanguageUtilsTests.java     | 240 ++++++++----------
 .../latin/utils/SubtypeLocaleUtilsTests.java  |  17 +-
 18 files changed, 354 insertions(+), 284 deletions(-)
 create mode 100644 java/src/com/android/inputmethod/latin/RichInputMethodSubtype.java
 delete mode 100644 java/src/com/android/inputmethod/latin/utils/SpacebarLanguageUtils.java

diff --git a/java/src/com/android/inputmethod/accessibility/MainKeyboardAccessibilityDelegate.java b/java/src/com/android/inputmethod/accessibility/MainKeyboardAccessibilityDelegate.java
index b84d402fbc..94a1ee6eba 100644
--- a/java/src/com/android/inputmethod/accessibility/MainKeyboardAccessibilityDelegate.java
+++ b/java/src/com/android/inputmethod/accessibility/MainKeyboardAccessibilityDelegate.java
@@ -121,7 +121,7 @@ public final class MainKeyboardAccessibilityDelegate
      */
     private void announceKeyboardLanguage(final Keyboard keyboard) {
         final String languageText = SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(
-                keyboard.mId.mSubtype);
+                keyboard.mId.mSubtype.getRawSubtype());
         sendWindowStateChanged(languageText);
     }
 
diff --git a/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatUtils.java b/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatUtils.java
index 365867257a..3abfa3fc9a 100644
--- a/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatUtils.java
+++ b/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatUtils.java
@@ -20,7 +20,7 @@ import android.os.Build;
 import android.view.inputmethod.InputMethodSubtype;
 
 import com.android.inputmethod.annotations.UsedForTesting;
-import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.RichInputMethodSubtype;
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
@@ -64,9 +64,12 @@ public final class InputMethodSubtypeCompatUtils {
                 overridesImplicitlyEnabledSubtype, id);
     }
 
+    public static boolean isAsciiCapable(final RichInputMethodSubtype subtype) {
+        return isAsciiCapable(subtype.getRawSubtype());
+    }
+
     public static boolean isAsciiCapable(final InputMethodSubtype subtype) {
-        return isAsciiCapableWithAPI(subtype)
-                || subtype.containsExtraValueKey(Constants.Subtype.ExtraValue.ASCII_CAPABLE);
+        return InputMethodSubtypeCompatUtils.isAsciiCapableWithAPI(subtype);
     }
 
     @UsedForTesting
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
index 3c1167538c..538e515bc9 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
@@ -21,9 +21,9 @@ import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.KEYBOAR
 import android.text.InputType;
 import android.text.TextUtils;
 import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputMethodSubtype;
 
 import com.android.inputmethod.compat.EditorInfoCompatUtils;
+import com.android.inputmethod.latin.RichInputMethodSubtype;
 import com.android.inputmethod.latin.utils.InputTypeUtils;
 import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
 
@@ -62,7 +62,7 @@ public final class KeyboardId {
     public static final int ELEMENT_EMOJI_CATEGORY5 = 15;
     public static final int ELEMENT_EMOJI_CATEGORY6 = 16;
 
-    public final InputMethodSubtype mSubtype;
+    public final RichInputMethodSubtype mSubtype;
     public final Locale mLocale;
     public final int mWidth;
     public final int mHeight;
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
index d6d0b21205..0804cebc4d 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
@@ -28,7 +28,6 @@ import android.util.Log;
 import android.util.SparseArray;
 import android.util.Xml;
 import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputMethodSubtype;
 
 import com.android.inputmethod.compat.EditorInfoCompatUtils;
 import com.android.inputmethod.compat.InputMethodSubtypeCompatUtils;
@@ -37,6 +36,7 @@ import com.android.inputmethod.keyboard.internal.KeyboardParams;
 import com.android.inputmethod.keyboard.internal.KeysCache;
 import com.android.inputmethod.latin.InputAttributes;
 import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.RichInputMethodSubtype;
 import com.android.inputmethod.latin.SubtypeSwitcher;
 import com.android.inputmethod.latin.define.DebugFlags;
 import com.android.inputmethod.latin.utils.InputTypeUtils;
@@ -109,7 +109,7 @@ public final class KeyboardLayoutSet {
         boolean mVoiceInputKeyEnabled;
         boolean mNoSettingsKey;
         boolean mLanguageSwitchKeyEnabled;
-        InputMethodSubtype mSubtype;
+        RichInputMethodSubtype mSubtype;
         boolean mIsSpellChecker;
         int mKeyboardWidth;
         int mKeyboardHeight;
@@ -245,7 +245,7 @@ public final class KeyboardLayoutSet {
             return this;
         }
 
-        public Builder setSubtype(final InputMethodSubtype subtype) {
+        public Builder setSubtype(final RichInputMethodSubtype subtype) {
             final boolean asciiCapable = InputMethodSubtypeCompatUtils.isAsciiCapable(subtype);
             // TODO: Consolidate with {@link InputAttributes}.
             @SuppressWarnings("deprecation")
@@ -254,7 +254,7 @@ public final class KeyboardLayoutSet {
             final boolean forceAscii = EditorInfoCompatUtils.hasFlagForceAscii(
                     mParams.mEditorInfo.imeOptions)
                     || deprecatedForceAscii;
-            final InputMethodSubtype keyboardSubtype = (forceAscii && !asciiCapable)
+            final RichInputMethodSubtype keyboardSubtype = (forceAscii && !asciiCapable)
                     ? SubtypeSwitcher.getInstance().getNoLanguageSubtype()
                     : subtype;
             mParams.mSubtype = keyboardSubtype;
diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
index 1ef53a65db..847d907117 100644
--- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
@@ -34,7 +34,6 @@ import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.inputmethod.InputMethodSubtype;
 
 import com.android.inputmethod.accessibility.AccessibilityUtils;
 import com.android.inputmethod.accessibility.MainKeyboardAccessibilityDelegate;
@@ -54,10 +53,10 @@ import com.android.inputmethod.keyboard.internal.SlidingKeyInputDrawingPreview;
 import com.android.inputmethod.keyboard.internal.TimerHandler;
 import com.android.inputmethod.latin.Constants;
 import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.RichInputMethodSubtype;
 import com.android.inputmethod.latin.SuggestedWords;
 import com.android.inputmethod.latin.settings.DebugSettings;
 import com.android.inputmethod.latin.utils.CoordinateUtils;
-import com.android.inputmethod.latin.utils.SpacebarLanguageUtils;
 import com.android.inputmethod.latin.utils.TypefaceUtils;
 
 import java.util.WeakHashMap;
@@ -849,16 +848,16 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
 
     // Layout language name on spacebar.
     private String layoutLanguageOnSpacebar(final Paint paint,
-            final InputMethodSubtype subtype, final int width) {
+            final RichInputMethodSubtype subtype, final int width) {
         // Choose appropriate language name to fit into the width.
         if (mLanguageOnSpacebarFormatType == LanguageOnSpacebarHelper.FORMAT_TYPE_FULL_LOCALE) {
-            final String fullText = SpacebarLanguageUtils.getFullDisplayName(subtype);
+            final String fullText = subtype.getFullDisplayName();
             if (fitsTextIntoWidth(width, fullText, paint)) {
                 return fullText;
             }
         }
 
-        final String middleText = SpacebarLanguageUtils.getMiddleDisplayName(subtype);
+        final String middleText = subtype.getMiddleDisplayName();
         if (fitsTextIntoWidth(width, middleText, paint)) {
             return middleText;
         }
@@ -872,7 +871,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
         paint.setTextAlign(Align.CENTER);
         paint.setTypeface(Typeface.DEFAULT);
         paint.setTextSize(mLanguageOnSpacebarTextSize);
-        final InputMethodSubtype subtype = getKeyboard().mId.mSubtype;
+        final RichInputMethodSubtype subtype = getKeyboard().mId.mSubtype;
         final String language = layoutLanguageOnSpacebar(paint, subtype, width);
         // Draw language text with shadow
         final float descent = paint.descent();
diff --git a/java/src/com/android/inputmethod/keyboard/internal/LanguageOnSpacebarHelper.java b/java/src/com/android/inputmethod/keyboard/internal/LanguageOnSpacebarHelper.java
index 6400a24401..72ad2bd97d 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/LanguageOnSpacebarHelper.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/LanguageOnSpacebarHelper.java
@@ -18,6 +18,7 @@ package com.android.inputmethod.keyboard.internal;
 
 import android.view.inputmethod.InputMethodSubtype;
 
+import com.android.inputmethod.latin.RichInputMethodSubtype;
 import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
 
 import java.util.Collections;
@@ -34,8 +35,8 @@ public final class LanguageOnSpacebarHelper {
     private List<InputMethodSubtype> mEnabledSubtypes = Collections.emptyList();
     private boolean mIsSystemLanguageSameAsInputLanguage;
 
-    public int getLanguageOnSpacebarFormatType(final InputMethodSubtype subtype) {
-        if (SubtypeLocaleUtils.isNoLanguage(subtype)) {
+    public int getLanguageOnSpacebarFormatType(final RichInputMethodSubtype subtype) {
+        if (subtype.isNoLanguage()) {
             return FORMAT_TYPE_FULL_LOCALE;
         }
         // Only this subtype is enabled and equals to the system locale.
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index b4d6ca736e..2a2bbdff4f 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -747,7 +747,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
     public void onCurrentInputMethodSubtypeChanged(final InputMethodSubtype subtype) {
         // Note that the calling sequence of onCreate() and onCurrentInputMethodSubtypeChanged()
         // is not guaranteed. It may even be called at the same time on a different thread.
-        mSubtypeSwitcher.onSubtypeChanged(subtype);
+        final RichInputMethodSubtype richSubtype = new RichInputMethodSubtype(subtype);
+        mSubtypeSwitcher.onSubtypeChanged(richSubtype);
         mInputLogic.onSubtypeChanged(SubtypeLocaleUtils.getCombiningRulesExtraValue(subtype));
         loadKeyboard();
     }
diff --git a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java
index 7cf4eff92c..fc7a53a029 100644
--- a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java
+++ b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java
@@ -297,10 +297,14 @@ public final class RichInputMethodManager {
         return INDEX_NOT_FOUND;
     }
 
-    public InputMethodSubtype getCurrentInputMethodSubtype(
-            final InputMethodSubtype defaultSubtype) {
+    public RichInputMethodSubtype getCurrentInputMethodSubtype(
+            final RichInputMethodSubtype defaultSubtype) {
         final InputMethodSubtype currentSubtype = mImmWrapper.mImm.getCurrentInputMethodSubtype();
-        return (currentSubtype != null) ? currentSubtype : defaultSubtype;
+        if (currentSubtype == null) {
+            return defaultSubtype;
+        }
+        // TODO: Determine locales to use for multi-lingual use.
+        return new RichInputMethodSubtype(currentSubtype);
     }
 
     public boolean hasMultipleEnabledIMEsOrSubtypes(final boolean shouldIncludeAuxiliarySubtypes) {
diff --git a/java/src/com/android/inputmethod/latin/RichInputMethodSubtype.java b/java/src/com/android/inputmethod/latin/RichInputMethodSubtype.java
new file mode 100644
index 0000000000..0b08c48e55
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/RichInputMethodSubtype.java
@@ -0,0 +1,125 @@
+/*
+ * 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.latin;
+
+import android.view.inputmethod.InputMethodSubtype;
+
+import com.android.inputmethod.latin.utils.LocaleUtils;
+import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
+
+import java.util.Arrays;
+import java.util.Locale;
+
+/**
+ * Enrichment class for InputMethodSubtype to enable concurrent multi-lingual input.
+ *
+ * Right now, this returns the extra value of its primary subtype.
+ */
+public final class RichInputMethodSubtype {
+    private final InputMethodSubtype mSubtype;
+    private final Locale[] mLocales;
+
+    public RichInputMethodSubtype(final InputMethodSubtype subtype, final Locale... locales) {
+        mSubtype = subtype;
+        mLocales = new Locale[locales.length+1];
+        mLocales[0] = LocaleUtils.constructLocaleFromString(mSubtype.getLocale());
+        System.arraycopy(locales, 0, mLocales, 1, locales.length);
+    }
+
+    // Extra values are determined by the primary subtype. This is probably right, but
+    // we may have to revisit this later.
+    public String getExtraValueOf(final String key) {
+        return mSubtype.getExtraValueOf(key);
+    }
+
+    // The mode is also determined by the primary subtype.
+    public String getMode() {
+        return mSubtype.getMode();
+    }
+
+    public boolean isNoLanguage() {
+        if (mLocales.length > 1) {
+            return false;
+        }
+        return SubtypeLocaleUtils.NO_LANGUAGE.equals(mSubtype.getLocale());
+    }
+
+    public String getNameForLogging() {
+        return toString();
+    }
+
+    // InputMethodSubtype's display name for spacebar text in its locale.
+    //        isAdditionalSubtype (T=true, F=false)
+    // locale layout  |  Middle      Full
+    // ------ ------- - --------- ----------------------
+    //  en_US qwerty  F  English   English (US)           exception
+    //  en_GB qwerty  F  English   English (UK)           exception
+    //  es_US spanish F  Español   Español (EE.UU.)       exception
+    //  fr    azerty  F  Français  Français
+    //  fr_CA qwerty  F  Français  Français (Canada)
+    //  fr_CH swiss   F  Français  Français (Suisse)
+    //  de    qwertz  F  Deutsch   Deutsch
+    //  de_CH swiss   T  Deutsch   Deutsch (Schweiz)
+    //  zz    qwerty  F  QWERTY    QWERTY
+    //  fr    qwertz  T  Français  Français
+    //  de    qwerty  T  Deutsch   Deutsch
+    //  en_US azerty  T  English   English (US)
+    //  zz    azerty  T  AZERTY    AZERTY
+    // Get the RichInputMethodSubtype's full display name in its locale.
+    public String getFullDisplayName() {
+        if (isNoLanguage()) {
+            return SubtypeLocaleUtils.getKeyboardLayoutSetDisplayName(mSubtype);
+        }
+        return SubtypeLocaleUtils.getSubtypeLocaleDisplayName(mSubtype.getLocale());
+    }
+
+    // Get the RichInputMethodSubtype's middle display name in its locale.
+    public String getMiddleDisplayName() {
+        if (isNoLanguage()) {
+            return SubtypeLocaleUtils.getKeyboardLayoutSetDisplayName(mSubtype);
+        }
+        return SubtypeLocaleUtils.getSubtypeLanguageDisplayName(mSubtype.getLocale());
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof RichInputMethodSubtype)) {
+            return false;
+        }
+        final RichInputMethodSubtype other = (RichInputMethodSubtype)o;
+        return mSubtype.equals(other.mSubtype) && Arrays.equals(mLocales, other.mLocales);
+    }
+
+    @Override
+    public int hashCode() {
+        return mSubtype.hashCode() + Arrays.hashCode(mLocales);
+    }
+
+    @Override
+    public String toString() {
+        return "Multi-lingual subtype: " + mSubtype.toString() + ", " + Arrays.toString(mLocales);
+    }
+
+    // TODO: remove this method! We can always have several locales. Multi-lingual input will only
+    // be done when this method is gone.
+    public String getLocale() {
+        return mSubtype.getLocale();
+    }
+
+    // TODO: remove this method
+    public InputMethodSubtype getRawSubtype() { return mSubtype; }
+}
diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
index a725e16118..c39c2542c8 100644
--- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
+++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
@@ -58,8 +58,8 @@ public final class SubtypeSwitcher {
             new LanguageOnSpacebarHelper();
     private InputMethodInfo mShortcutInputMethodInfo;
     private InputMethodSubtype mShortcutSubtype;
-    private InputMethodSubtype mNoLanguageSubtype;
-    private InputMethodSubtype mEmojiSubtype;
+    private RichInputMethodSubtype mNoLanguageSubtype;
+    private RichInputMethodSubtype mEmojiSubtype;
     private boolean mIsNetworkConnected;
 
     private static final String KEYBOARD_MODE = "keyboard";
@@ -70,26 +70,26 @@ public final class SubtypeSwitcher {
             + "," + Constants.Subtype.ExtraValue.ASCII_CAPABLE
             + "," + Constants.Subtype.ExtraValue.ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE
             + "," + Constants.Subtype.ExtraValue.EMOJI_CAPABLE;
-    private static final InputMethodSubtype DUMMY_NO_LANGUAGE_SUBTYPE =
-            InputMethodSubtypeCompatUtils.newInputMethodSubtype(
+    private static final RichInputMethodSubtype DUMMY_NO_LANGUAGE_SUBTYPE =
+            new RichInputMethodSubtype(InputMethodSubtypeCompatUtils.newInputMethodSubtype(
                     R.string.subtype_no_language_qwerty, R.drawable.ic_ime_switcher_dark,
                     SubtypeLocaleUtils.NO_LANGUAGE, KEYBOARD_MODE,
                     EXTRA_VALUE_OF_DUMMY_NO_LANGUAGE_SUBTYPE,
                     false /* isAuxiliary */, false /* overridesImplicitlyEnabledSubtype */,
-                    SUBTYPE_ID_OF_DUMMY_NO_LANGUAGE_SUBTYPE);
+                    SUBTYPE_ID_OF_DUMMY_NO_LANGUAGE_SUBTYPE));
     // Caveat: We probably should remove this when we add an Emoji subtype in {@link R.xml.method}.
     // Dummy Emoji subtype. See {@link R.xml.method}.
     private static final int SUBTYPE_ID_OF_DUMMY_EMOJI_SUBTYPE = 0xd78b2ed0;
     private static final String EXTRA_VALUE_OF_DUMMY_EMOJI_SUBTYPE =
             "KeyboardLayoutSet=" + SubtypeLocaleUtils.EMOJI
             + "," + Constants.Subtype.ExtraValue.EMOJI_CAPABLE;
-    private static final InputMethodSubtype DUMMY_EMOJI_SUBTYPE =
+    private static final RichInputMethodSubtype DUMMY_EMOJI_SUBTYPE = new RichInputMethodSubtype(
             InputMethodSubtypeCompatUtils.newInputMethodSubtype(
                     R.string.subtype_emoji, R.drawable.ic_ime_switcher_dark,
                     SubtypeLocaleUtils.NO_LANGUAGE, KEYBOARD_MODE,
                     EXTRA_VALUE_OF_DUMMY_EMOJI_SUBTYPE,
                     false /* isAuxiliary */, false /* overridesImplicitlyEnabledSubtype */,
-                    SUBTYPE_ID_OF_DUMMY_EMOJI_SUBTYPE);
+                    SUBTYPE_ID_OF_DUMMY_EMOJI_SUBTYPE));
 
     public static SubtypeSwitcher getInstance() {
         return sInstance;
@@ -165,18 +165,17 @@ public final class SubtypeSwitcher {
     }
 
     // Update the current subtype. LatinIME.onCurrentInputMethodSubtypeChanged calls this function.
-    public void onSubtypeChanged(final InputMethodSubtype newSubtype) {
+    public void onSubtypeChanged(final RichInputMethodSubtype newSubtype) {
         if (DBG) {
-            Log.w(TAG, "onSubtypeChanged: "
-                    + SubtypeLocaleUtils.getSubtypeNameForLogging(newSubtype));
+            Log.w(TAG, "onSubtypeChanged: " + newSubtype.getNameForLogging());
         }
 
         final Locale newLocale = SubtypeLocaleUtils.getSubtypeLocale(newSubtype);
         final Locale systemLocale = mResources.getConfiguration().locale;
         final boolean sameLocale = systemLocale.equals(newLocale);
         final boolean sameLanguage = systemLocale.getLanguage().equals(newLocale.getLanguage());
-        final boolean implicitlyEnabled =
-                mRichImm.checkIfSubtypeBelongsToThisImeAndImplicitlyEnabled(newSubtype);
+        final boolean implicitlyEnabled = mRichImm
+                .checkIfSubtypeBelongsToThisImeAndImplicitlyEnabled(newSubtype.getRawSubtype());
         mLanguageOnSpacebarHelper.updateIsSystemLanguageSameAsInputLanguage(
                 sameLocale || (sameLanguage && implicitlyEnabled));
 
@@ -250,7 +249,7 @@ public final class SubtypeSwitcher {
     // Subtype Switching functions //
     //////////////////////////////////
 
-    public int getLanguageOnSpacebarFormatType(final InputMethodSubtype subtype) {
+    public int getLanguageOnSpacebarFormatType(final RichInputMethodSubtype subtype) {
         return mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(subtype);
     }
 
@@ -279,10 +278,10 @@ public final class SubtypeSwitcher {
         return true;
     }
 
-    private static InputMethodSubtype sForcedSubtypeForTesting = null;
+    private static RichInputMethodSubtype sForcedSubtypeForTesting = null;
     @UsedForTesting
     void forceSubtype(final InputMethodSubtype subtype) {
-        sForcedSubtypeForTesting = subtype;
+        sForcedSubtypeForTesting = new RichInputMethodSubtype(subtype);
     }
 
     public Locale getCurrentSubtypeLocale() {
@@ -292,17 +291,18 @@ public final class SubtypeSwitcher {
         return SubtypeLocaleUtils.getSubtypeLocale(getCurrentSubtype());
     }
 
-    public InputMethodSubtype getCurrentSubtype() {
+    public RichInputMethodSubtype getCurrentSubtype() {
         if (null != sForcedSubtypeForTesting) {
             return sForcedSubtypeForTesting;
         }
         return mRichImm.getCurrentInputMethodSubtype(getNoLanguageSubtype());
     }
 
-    public InputMethodSubtype getNoLanguageSubtype() {
+    public RichInputMethodSubtype getNoLanguageSubtype() {
         if (mNoLanguageSubtype == null) {
-            mNoLanguageSubtype = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
-                    SubtypeLocaleUtils.NO_LANGUAGE, SubtypeLocaleUtils.QWERTY);
+            mNoLanguageSubtype = new RichInputMethodSubtype(
+                    mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                            SubtypeLocaleUtils.NO_LANGUAGE, SubtypeLocaleUtils.QWERTY));
         }
         if (mNoLanguageSubtype != null) {
             return mNoLanguageSubtype;
@@ -313,10 +313,11 @@ public final class SubtypeSwitcher {
         return DUMMY_NO_LANGUAGE_SUBTYPE;
     }
 
-    public InputMethodSubtype getEmojiSubtype() {
+    public RichInputMethodSubtype getEmojiSubtype() {
         if (mEmojiSubtype == null) {
-            mEmojiSubtype = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
-                    SubtypeLocaleUtils.NO_LANGUAGE, SubtypeLocaleUtils.EMOJI);
+            mEmojiSubtype = new RichInputMethodSubtype(
+                    mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                            SubtypeLocaleUtils.NO_LANGUAGE, SubtypeLocaleUtils.EMOJI));
         }
         if (mEmojiSubtype != null) {
             return mEmojiSubtype;
@@ -328,6 +329,6 @@ public final class SubtypeSwitcher {
     }
 
     public String getCombiningRulesExtraValueOfCurrentSubtype() {
-        return SubtypeLocaleUtils.getCombiningRulesExtraValue(getCurrentSubtype());
+        return SubtypeLocaleUtils.getCombiningRulesExtraValue(getCurrentSubtype().getRawSubtype());
     }
 }
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
index 90398deb2d..47bff3ebb2 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
@@ -39,6 +39,7 @@ import com.android.inputmethod.latin.DictionaryFacilitator;
 import com.android.inputmethod.latin.DictionaryFactory;
 import com.android.inputmethod.latin.PrevWordsInfo;
 import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.RichInputMethodSubtype;
 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
 import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion;
 import com.android.inputmethod.latin.UserBinaryDictionary;
@@ -334,7 +335,7 @@ public final class AndroidSpellCheckerService extends SpellCheckerService
         final KeyboardLayoutSet.Builder builder = new KeyboardLayoutSet.Builder(this, editorInfo);
         builder.setKeyboardGeometry(
                 SPELLCHECKER_DUMMY_KEYBOARD_WIDTH, SPELLCHECKER_DUMMY_KEYBOARD_HEIGHT);
-        builder.setSubtype(subtype);
+        builder.setSubtype(new RichInputMethodSubtype(subtype));
         builder.setIsSpellChecker(true /* isSpellChecker */);
         builder.disableTouchPositionCorrectionData();
         return builder.build();
diff --git a/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java b/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java
index 27973287d6..2207ffea9f 100644
--- a/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java
+++ b/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java
@@ -35,6 +35,7 @@ import com.android.inputmethod.keyboard.KeyboardId;
 import com.android.inputmethod.keyboard.KeyboardLayoutSet;
 import com.android.inputmethod.latin.DictionaryFacilitator;
 import com.android.inputmethod.latin.PrevWordsInfo;
+import com.android.inputmethod.latin.RichInputMethodSubtype;
 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
 import com.android.inputmethod.latin.WordComposer;
 import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion;
@@ -131,7 +132,7 @@ public class DistracterFilterCheckingExactMatchesAndSuggestions implements Distr
         final int keyboardWidth = ResourceUtils.getDefaultKeyboardWidth(res);
         final int keyboardHeight = ResourceUtils.getDefaultKeyboardHeight(res);
         builder.setKeyboardGeometry(keyboardWidth, keyboardHeight);
-        builder.setSubtype(subtype);
+        builder.setSubtype(new RichInputMethodSubtype(subtype));
         builder.setIsSpellChecker(false /* isSpellChecker */);
         final KeyboardLayoutSet layoutSet = builder.build();
         mKeyboard = layoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET);
diff --git a/java/src/com/android/inputmethod/latin/utils/SpacebarLanguageUtils.java b/java/src/com/android/inputmethod/latin/utils/SpacebarLanguageUtils.java
deleted file mode 100644
index 1ca895fdba..0000000000
--- a/java/src/com/android/inputmethod/latin/utils/SpacebarLanguageUtils.java
+++ /dev/null
@@ -1,58 +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.latin.utils;
-
-import android.view.inputmethod.InputMethodSubtype;
-
-public final class SpacebarLanguageUtils {
-    private SpacebarLanguageUtils() {
-        // Intentional empty constructor for utility class.
-    }
-
-    // InputMethodSubtype's display name for spacebar text in its locale.
-    //        isAdditionalSubtype (T=true, F=false)
-    // locale layout  |  Middle      Full
-    // ------ ------- - --------- ----------------------
-    //  en_US qwerty  F  English   English (US)           exception
-    //  en_GB qwerty  F  English   English (UK)           exception
-    //  es_US spanish F  Español   Español (EE.UU.)       exception
-    //  fr    azerty  F  Français  Français
-    //  fr_CA qwerty  F  Français  Français (Canada)
-    //  fr_CH swiss   F  Français  Français (Suisse)
-    //  de    qwertz  F  Deutsch   Deutsch
-    //  de_CH swiss   T  Deutsch   Deutsch (Schweiz)
-    //  zz    qwerty  F  QWERTY    QWERTY
-    //  fr    qwertz  T  Français  Français
-    //  de    qwerty  T  Deutsch   Deutsch
-    //  en_US azerty  T  English   English (US)
-    //  zz    azerty  T  AZERTY    AZERTY
-    // Get InputMethodSubtype's full display name in its locale.
-    public static String getFullDisplayName(final InputMethodSubtype subtype) {
-        if (SubtypeLocaleUtils.isNoLanguage(subtype)) {
-            return SubtypeLocaleUtils.getKeyboardLayoutSetDisplayName(subtype);
-        }
-        return SubtypeLocaleUtils.getSubtypeLocaleDisplayName(subtype.getLocale());
-    }
-
-    // Get InputMethodSubtype's middle display name in its locale.
-    public static String getMiddleDisplayName(final InputMethodSubtype subtype) {
-        if (SubtypeLocaleUtils.isNoLanguage(subtype)) {
-            return SubtypeLocaleUtils.getKeyboardLayoutSetDisplayName(subtype);
-        }
-        return SubtypeLocaleUtils.getSubtypeLanguageDisplayName(subtype.getLocale());
-    }
-}
diff --git a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java
index 0db4106c53..96a6510fc9 100644
--- a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java
@@ -27,12 +27,17 @@ import android.view.inputmethod.InputMethodSubtype;
 
 import com.android.inputmethod.latin.Constants;
 import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.RichInputMethodSubtype;
 
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Locale;
 
+/**
+ * A helper class to deal with subtype locales.
+  */
+// TODO: consolidate this into RichInputMethodSubtype
 public final class SubtypeLocaleUtils {
     private static final String TAG = SubtypeLocaleUtils.class.getSimpleName();
 
@@ -109,10 +114,10 @@ public final class SubtypeLocaleUtils {
             sKeyboardLayoutToNameIdsMap.put(key, noLanguageResId);
         }
 
-        final String[] excetionalLocaleInRootLocale = res.getStringArray(
+        final String[] exceptionalLocaleInRootLocale = res.getStringArray(
                 R.array.subtype_locale_displayed_in_root_locale);
-        for (int i = 0; i < excetionalLocaleInRootLocale.length; i++) {
-            sExceptionalLocaleDisplayedInRootLocale.add(excetionalLocaleInRootLocale[i]);
+        for (int i = 0; i < exceptionalLocaleInRootLocale.length; i++) {
+            sExceptionalLocaleDisplayedInRootLocale.add(exceptionalLocaleInRootLocale[i]);
         }
 
         final String[] exceptionalLocales = res.getStringArray(
@@ -260,6 +265,7 @@ public final class SubtypeLocaleUtils {
     private static String getSubtypeDisplayNameInternal(final InputMethodSubtype subtype,
             final Locale displayLocale) {
         final String replacementString = getReplacementString(subtype, displayLocale);
+        // TODO: rework this for multi-lingual subtypes
         final int nameResId = subtype.getNameResId();
         final RunInLocale<String> getSubtypeName = new RunInLocale<String>() {
             @Override
@@ -282,12 +288,14 @@ public final class SubtypeLocaleUtils {
                 getSubtypeName.runInLocale(sResources, displayLocale), displayLocale);
     }
 
-    public static boolean isNoLanguage(final InputMethodSubtype subtype) {
+    public static Locale getSubtypeLocale(final InputMethodSubtype subtype) {
         final String localeString = subtype.getLocale();
-        return NO_LANGUAGE.equals(localeString);
+        return LocaleUtils.constructLocaleFromString(localeString);
     }
 
-    public static Locale getSubtypeLocale(final InputMethodSubtype subtype) {
+    // TODO: remove this. When RichInputMethodSubtype#getLocale is removed we can do away with this
+    // method at the same time.
+    public static Locale getSubtypeLocale(final RichInputMethodSubtype subtype) {
         final String localeString = subtype.getLocale();
         return LocaleUtils.constructLocaleFromString(localeString);
     }
@@ -301,6 +309,10 @@ public final class SubtypeLocaleUtils {
         return sKeyboardLayoutToDisplayNameMap.get(layoutName);
     }
 
+    public static String getKeyboardLayoutSetName(final RichInputMethodSubtype subtype) {
+        return getKeyboardLayoutSetName(subtype.getRawSubtype());
+    }
+
     public static String getKeyboardLayoutSetName(final InputMethodSubtype subtype) {
         String keyboardLayoutSet = subtype.getExtraValueOf(KEYBOARD_LAYOUT_SET);
         if (keyboardLayoutSet == null) {
@@ -336,7 +348,7 @@ public final class SubtypeLocaleUtils {
         return Arrays.binarySearch(SORTED_RTL_LANGUAGES, language) >= 0;
     }
 
-    public static boolean isRtlLanguage(final InputMethodSubtype subtype) {
+    public static boolean isRtlLanguage(final RichInputMethodSubtype subtype) {
         return isRtlLanguage(getSubtypeLocale(subtype));
     }
 
diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java
index cf884bfeab..22460ef7d0 100644
--- a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java
+++ b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java
@@ -29,6 +29,7 @@ import com.android.inputmethod.keyboard.KeyboardLayoutSet.Builder;
 import com.android.inputmethod.latin.Constants;
 import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.RichInputMethodManager;
+import com.android.inputmethod.latin.RichInputMethodSubtype;
 import com.android.inputmethod.latin.utils.AdditionalSubtypeUtils;
 import com.android.inputmethod.latin.utils.ResourceUtils;
 import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
@@ -127,7 +128,7 @@ public abstract class KeyboardLayoutSetTestsBase extends AndroidTestCase {
         final int keyboardHeight = ResourceUtils.getDefaultKeyboardHeight(res);
         final Builder builder = new Builder(context, editorInfo);
         builder.setKeyboardGeometry(keyboardWidth, keyboardHeight)
-                .setSubtype(subtype)
+                .setSubtype(new RichInputMethodSubtype(subtype))
                 .setVoiceInputKeyEnabled(voiceInputKeyEnabled)
                 .setLanguageSwitchKeyEnabled(languageSwitchKeyEnabled);
         return builder.build();
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/LanguageOnSpacebarHelperTests.java b/tests/src/com/android/inputmethod/keyboard/internal/LanguageOnSpacebarHelperTests.java
index 6ea27588eb..e6198015a0 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/LanguageOnSpacebarHelperTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/LanguageOnSpacebarHelperTests.java
@@ -26,6 +26,7 @@ import android.test.suitebuilder.annotation.SmallTest;
 import android.view.inputmethod.InputMethodSubtype;
 
 import com.android.inputmethod.latin.RichInputMethodManager;
+import com.android.inputmethod.latin.RichInputMethodSubtype;
 import com.android.inputmethod.latin.utils.AdditionalSubtypeUtils;
 import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
 
@@ -40,14 +41,14 @@ public class LanguageOnSpacebarHelperTests extends AndroidTestCase {
 
     private RichInputMethodManager mRichImm;
 
-    InputMethodSubtype EN_US_QWERTY;
-    InputMethodSubtype EN_GB_QWERTY;
-    InputMethodSubtype FR_AZERTY;
-    InputMethodSubtype FR_CA_QWERTY;
-    InputMethodSubtype FR_CH_SWISS;
-    InputMethodSubtype FR_CH_QWERTY;
-    InputMethodSubtype FR_CH_QWERTZ;
-    InputMethodSubtype ZZ_QWERTY;
+    RichInputMethodSubtype EN_US_QWERTY;
+    RichInputMethodSubtype EN_GB_QWERTY;
+    RichInputMethodSubtype FR_AZERTY;
+    RichInputMethodSubtype FR_CA_QWERTY;
+    RichInputMethodSubtype FR_CH_SWISS;
+    RichInputMethodSubtype FR_CH_QWERTY;
+    RichInputMethodSubtype FR_CH_QWERTZ;
+    RichInputMethodSubtype ZZ_QWERTY;
 
     @Override
     protected void setUp() throws Exception {
@@ -57,22 +58,22 @@ public class LanguageOnSpacebarHelperTests extends AndroidTestCase {
         mRichImm = RichInputMethodManager.getInstance();
         SubtypeLocaleUtils.init(context);
 
-        EN_US_QWERTY = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
-                Locale.US.toString(), "qwerty");
-        EN_GB_QWERTY = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
-                Locale.UK.toString(), "qwerty");
-        FR_AZERTY = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
-                Locale.FRENCH.toString(), "azerty");
-        FR_CA_QWERTY = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
-                Locale.CANADA_FRENCH.toString(), "qwerty");
-        FR_CH_SWISS = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
-                "fr_CH", "swiss");
-        FR_CH_QWERTZ = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
-                "fr_CH", "qwertz");
-        FR_CH_QWERTY = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
-                "fr_CH", "qwerty");
-        ZZ_QWERTY = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
-                SubtypeLocaleUtils.NO_LANGUAGE, "qwerty");
+        EN_US_QWERTY = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                Locale.US.toString(), "qwerty"));
+        EN_GB_QWERTY = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                Locale.UK.toString(), "qwerty"));
+        FR_AZERTY = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                Locale.FRENCH.toString(), "azerty"));
+        FR_CA_QWERTY = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                Locale.CANADA_FRENCH.toString(), "qwerty"));
+        FR_CH_SWISS = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                "fr_CH", "swiss"));
+        FR_CH_QWERTZ = new RichInputMethodSubtype(
+                AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype("fr_CH", "qwertz"));
+        FR_CH_QWERTY = new RichInputMethodSubtype(
+                AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype("fr_CH", "qwerty"));
+        ZZ_QWERTY = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                SubtypeLocaleUtils.NO_LANGUAGE, "qwerty"));
     }
 
     private static List<InputMethodSubtype> asList(final InputMethodSubtype ... subtypes) {
@@ -80,14 +81,14 @@ public class LanguageOnSpacebarHelperTests extends AndroidTestCase {
     }
 
     public void testOneSubtype() {
-        mLanguageOnSpacebarHelper.updateEnabledSubtypes(asList(EN_US_QWERTY));
+        mLanguageOnSpacebarHelper.updateEnabledSubtypes(asList(EN_US_QWERTY.getRawSubtype()));
         mLanguageOnSpacebarHelper.updateIsSystemLanguageSameAsInputLanguage(true /* isSame */);
         assertEquals("one same English (US)", FORMAT_TYPE_NONE,
                 mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(EN_US_QWERTY));
         assertEquals("one same NoLanguage", FORMAT_TYPE_FULL_LOCALE,
                 mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(ZZ_QWERTY));
 
-        mLanguageOnSpacebarHelper.updateEnabledSubtypes(asList(FR_AZERTY));
+        mLanguageOnSpacebarHelper.updateEnabledSubtypes(asList(FR_AZERTY.getRawSubtype()));
         mLanguageOnSpacebarHelper.updateIsSystemLanguageSameAsInputLanguage(false /* isSame */);
         assertEquals("one diff English (US)", FORMAT_TYPE_LANGUAGE_ONLY,
                 mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(EN_US_QWERTY));
@@ -96,8 +97,8 @@ public class LanguageOnSpacebarHelperTests extends AndroidTestCase {
     }
 
     public void testTwoSubtypes() {
-        mLanguageOnSpacebarHelper.updateEnabledSubtypes(asList(EN_US_QWERTY, FR_AZERTY));
-
+        mLanguageOnSpacebarHelper.updateEnabledSubtypes(asList(EN_US_QWERTY.getRawSubtype(),
+                FR_AZERTY.getRawSubtype()));
         mLanguageOnSpacebarHelper.updateIsSystemLanguageSameAsInputLanguage(true /* isSame */);
         assertEquals("two same English (US)", FORMAT_TYPE_LANGUAGE_ONLY,
                 mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(EN_US_QWERTY));
@@ -117,7 +118,8 @@ public class LanguageOnSpacebarHelperTests extends AndroidTestCase {
 
     public void testSameLanuageSubtypes() {
         mLanguageOnSpacebarHelper.updateEnabledSubtypes(
-                asList(EN_US_QWERTY, EN_GB_QWERTY, FR_AZERTY, ZZ_QWERTY));
+                asList(EN_US_QWERTY.getRawSubtype(), EN_GB_QWERTY.getRawSubtype(),
+                        FR_AZERTY.getRawSubtype(), ZZ_QWERTY.getRawSubtype()));
 
         mLanguageOnSpacebarHelper.updateIsSystemLanguageSameAsInputLanguage(true /* isSame */);
         assertEquals("two same English (US)", FORMAT_TYPE_FULL_LOCALE,
@@ -138,7 +140,9 @@ public class LanguageOnSpacebarHelperTests extends AndroidTestCase {
 
     public void testMultiSameLanuageSubtypes() {
         mLanguageOnSpacebarHelper.updateEnabledSubtypes(
-                asList(FR_AZERTY, FR_CA_QWERTY, FR_CH_SWISS, FR_CH_QWERTY, FR_CH_QWERTZ));
+                asList(FR_AZERTY.getRawSubtype(), FR_CA_QWERTY.getRawSubtype(),
+                        FR_CH_SWISS.getRawSubtype(), FR_CH_QWERTY.getRawSubtype(),
+                        FR_CH_QWERTZ.getRawSubtype()));
 
         mLanguageOnSpacebarHelper.updateIsSystemLanguageSameAsInputLanguage(true /* isSame */);
         assertEquals("multi same French", FORMAT_TYPE_LANGUAGE_ONLY,
diff --git a/tests/src/com/android/inputmethod/latin/utils/SpacebarLanguageUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/SpacebarLanguageUtilsTests.java
index aef517ca84..b766ab2e7f 100644
--- a/tests/src/com/android/inputmethod/latin/utils/SpacebarLanguageUtilsTests.java
+++ b/tests/src/com/android/inputmethod/latin/utils/SpacebarLanguageUtilsTests.java
@@ -24,6 +24,7 @@ import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodSubtype;
 
 import com.android.inputmethod.latin.RichInputMethodManager;
+import com.android.inputmethod.latin.RichInputMethodSubtype;
 
 import java.util.ArrayList;
 import java.util.Locale;
@@ -31,28 +32,28 @@ import java.util.Locale;
 @SmallTest
 public class SpacebarLanguageUtilsTests extends AndroidTestCase {
     // All input method subtypes of LatinIME.
-    private final ArrayList<InputMethodSubtype> mSubtypesList = new ArrayList<>();
+    private final ArrayList<RichInputMethodSubtype> mSubtypesList = new ArrayList<>();
 
     private RichInputMethodManager mRichImm;
     private Resources mRes;
 
-    InputMethodSubtype EN_US;
-    InputMethodSubtype EN_GB;
-    InputMethodSubtype ES_US;
-    InputMethodSubtype FR;
-    InputMethodSubtype FR_CA;
-    InputMethodSubtype FR_CH;
-    InputMethodSubtype DE;
-    InputMethodSubtype DE_CH;
-    InputMethodSubtype HI_ZZ;
-    InputMethodSubtype ZZ;
-    InputMethodSubtype DE_QWERTY;
-    InputMethodSubtype FR_QWERTZ;
-    InputMethodSubtype EN_US_AZERTY;
-    InputMethodSubtype EN_UK_DVORAK;
-    InputMethodSubtype ES_US_COLEMAK;
-    InputMethodSubtype ZZ_AZERTY;
-    InputMethodSubtype ZZ_PC;
+    RichInputMethodSubtype EN_US;
+    RichInputMethodSubtype EN_GB;
+    RichInputMethodSubtype ES_US;
+    RichInputMethodSubtype FR;
+    RichInputMethodSubtype FR_CA;
+    RichInputMethodSubtype FR_CH;
+    RichInputMethodSubtype DE;
+    RichInputMethodSubtype DE_CH;
+    RichInputMethodSubtype HI_ZZ;
+    RichInputMethodSubtype ZZ;
+    RichInputMethodSubtype DE_QWERTY;
+    RichInputMethodSubtype FR_QWERTZ;
+    RichInputMethodSubtype EN_US_AZERTY;
+    RichInputMethodSubtype EN_UK_DVORAK;
+    RichInputMethodSubtype ES_US_COLEMAK;
+    RichInputMethodSubtype ZZ_AZERTY;
+    RichInputMethodSubtype ZZ_PC;
 
     @Override
     protected void setUp() throws Exception {
@@ -67,53 +68,60 @@ public class SpacebarLanguageUtilsTests extends AndroidTestCase {
         final int subtypeCount = imi.getSubtypeCount();
         for (int index = 0; index < subtypeCount; index++) {
             final InputMethodSubtype subtype = imi.getSubtypeAt(index);
-            mSubtypesList.add(subtype);
+            mSubtypesList.add(new RichInputMethodSubtype(subtype));
         }
 
-        EN_US = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
-                Locale.US.toString(), "qwerty");
-        EN_GB = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
-                Locale.UK.toString(), "qwerty");
-        ES_US = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
-                "es_US", "spanish");
-        FR = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
-                Locale.FRENCH.toString(), "azerty");
-        FR_CA = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
-                Locale.CANADA_FRENCH.toString(), "qwerty");
-        FR_CH = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
-                "fr_CH", "swiss");
-        DE = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
-                Locale.GERMAN.toString(), "qwertz");
-        DE_CH = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
-                "de_CH", "swiss");
-        HI_ZZ = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
-                "hi_ZZ", "qwerty");
-        ZZ = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
-                SubtypeLocaleUtils.NO_LANGUAGE, "qwerty");
-        DE_QWERTY = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
-                Locale.GERMAN.toString(), "qwerty");
-        FR_QWERTZ = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
-                Locale.FRENCH.toString(), "qwertz");
-        EN_US_AZERTY = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
-                Locale.US.toString(), "azerty");
-        EN_UK_DVORAK = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
-                Locale.UK.toString(), "dvorak");
-        ES_US_COLEMAK = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
-                "es_US", "colemak");
-        ZZ_AZERTY = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
-                SubtypeLocaleUtils.NO_LANGUAGE, "azerty");
-        ZZ_PC = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
-                SubtypeLocaleUtils.NO_LANGUAGE, "pcqwerty");
+        EN_US = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                Locale.US.toString(), "qwerty"));
+        EN_GB = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                Locale.UK.toString(), "qwerty"));
+        ES_US = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                "es_US", "spanish"));
+        FR = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                Locale.FRENCH.toString(), "azerty"));
+        FR_CA = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                Locale.CANADA_FRENCH.toString(), "qwerty"));
+        FR_CH = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                "fr_CH", "swiss"));
+        DE = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                Locale.GERMAN.toString(), "qwertz"));
+        DE_CH = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                "de_CH", "swiss"));
+        HI_ZZ = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                "hi_ZZ", "qwerty"));
+        ZZ = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                SubtypeLocaleUtils.NO_LANGUAGE, "qwerty"));
+        DE_QWERTY = new RichInputMethodSubtype(
+                AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+                    Locale.GERMAN.toString(), "qwerty"));
+        FR_QWERTZ = new RichInputMethodSubtype(
+                AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+                    Locale.FRENCH.toString(), "qwertz"));
+        EN_US_AZERTY = new RichInputMethodSubtype(
+                AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+                    Locale.US.toString(), "azerty"));
+        EN_UK_DVORAK = new RichInputMethodSubtype(
+                AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+                    Locale.UK.toString(), "dvorak"));
+        ES_US_COLEMAK = new RichInputMethodSubtype(
+                AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+                    "es_US", "colemak"));
+        ZZ_AZERTY = new RichInputMethodSubtype(
+                AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+                    SubtypeLocaleUtils.NO_LANGUAGE, "azerty"));
+        ZZ_PC = new RichInputMethodSubtype(
+                AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+                    SubtypeLocaleUtils.NO_LANGUAGE, "pcqwerty"));
     }
 
     public void testAllFullDisplayNameForSpacebar() {
-        for (final InputMethodSubtype subtype : mSubtypesList) {
+        for (final RichInputMethodSubtype subtype : mSubtypesList) {
             final String subtypeName = SubtypeLocaleUtils
-                    .getSubtypeDisplayNameInSystemLocale(subtype);
-            final String spacebarText = SpacebarLanguageUtils.getFullDisplayName(subtype);
+                    .getSubtypeDisplayNameInSystemLocale(subtype.getRawSubtype());
+            final String spacebarText = subtype.getFullDisplayName();
             final String languageName = SubtypeLocaleUtils
                     .getSubtypeLocaleDisplayName(subtype.getLocale());
-            if (SubtypeLocaleUtils.isNoLanguage(subtype)) {
+            if (subtype.isNoLanguage()) {
                 assertFalse(subtypeName, spacebarText.contains(languageName));
             } else {
                 assertTrue(subtypeName, spacebarText.contains(languageName));
@@ -122,19 +130,19 @@ public class SpacebarLanguageUtilsTests extends AndroidTestCase {
     }
 
    public void testAllMiddleDisplayNameForSpacebar() {
-        for (final InputMethodSubtype subtype : mSubtypesList) {
+        for (final RichInputMethodSubtype subtype : mSubtypesList) {
             final String subtypeName = SubtypeLocaleUtils
-                    .getSubtypeDisplayNameInSystemLocale(subtype);
+                    .getSubtypeDisplayNameInSystemLocale(subtype.getRawSubtype());
             if (SubtypeLocaleUtils.sExceptionalLocaleDisplayedInRootLocale.contains(
                     subtype.getLocale())) {
                 // Skip test because the language part of this locale string doesn't represent
                 // the locale to be displayed on the spacebar (for example hi_ZZ and Hinglish).
                 continue;
             }
-            final String spacebarText = SpacebarLanguageUtils.getMiddleDisplayName(subtype);
-            if (SubtypeLocaleUtils.isNoLanguage(subtype)) {
-                assertEquals(subtypeName,
-                        SubtypeLocaleUtils.getKeyboardLayoutSetDisplayName(subtype), spacebarText);
+            final String spacebarText = subtype.getMiddleDisplayName();
+            if (subtype.isNoLanguage()) {
+                assertEquals(subtypeName, SubtypeLocaleUtils.getKeyboardLayoutSetDisplayName(
+                        subtype.getRawSubtype()), spacebarText);
             } else {
                 final Locale locale = SubtypeLocaleUtils.getSubtypeLocale(subtype);
                 assertEquals(subtypeName,
@@ -166,47 +174,27 @@ public class SpacebarLanguageUtilsTests extends AndroidTestCase {
     private final RunInLocale<Void> testsPredefinedSubtypesForSpacebar = new RunInLocale<Void>() {
         @Override
         protected Void job(final Resources res) {
-            assertEquals("en_US", "English (US)",
-                    SpacebarLanguageUtils.getFullDisplayName(EN_US));
-            assertEquals("en_GB", "English (UK)",
-                    SpacebarLanguageUtils.getFullDisplayName(EN_GB));
-            assertEquals("es_US", "Español (EE.UU.)",
-                    SpacebarLanguageUtils.getFullDisplayName(ES_US));
-            assertEquals("fr", "Français",
-                    SpacebarLanguageUtils.getFullDisplayName(FR));
-            assertEquals("fr_CA", "Français (Canada)",
-                    SpacebarLanguageUtils.getFullDisplayName(FR_CA));
-            assertEquals("fr_CH", "Français (Suisse)",
-                    SpacebarLanguageUtils.getFullDisplayName(FR_CH));
-            assertEquals("de", "Deutsch",
-                    SpacebarLanguageUtils.getFullDisplayName(DE));
-            assertEquals("de_CH", "Deutsch (Schweiz)",
-                    SpacebarLanguageUtils.getFullDisplayName(DE_CH));
-            assertEquals("hi_ZZ", "Hinglish",
-                    SpacebarLanguageUtils.getFullDisplayName(HI_ZZ));
-            assertEquals("zz", "QWERTY",
-                    SpacebarLanguageUtils.getFullDisplayName(ZZ));
-
-            assertEquals("en_US", "English",
-                    SpacebarLanguageUtils.getMiddleDisplayName(EN_US));
-            assertEquals("en_GB", "English",
-                    SpacebarLanguageUtils.getMiddleDisplayName(EN_GB));
-            assertEquals("es_US", "Español",
-                    SpacebarLanguageUtils.getMiddleDisplayName(ES_US));
-            assertEquals("fr", "Français",
-                    SpacebarLanguageUtils.getMiddleDisplayName(FR));
-            assertEquals("fr_CA", "Français",
-                    SpacebarLanguageUtils.getMiddleDisplayName(FR_CA));
-            assertEquals("fr_CH", "Français",
-                    SpacebarLanguageUtils.getMiddleDisplayName(FR_CH));
-            assertEquals("de", "Deutsch",
-                    SpacebarLanguageUtils.getMiddleDisplayName(DE));
-            assertEquals("de_CH", "Deutsch",
-                    SpacebarLanguageUtils.getMiddleDisplayName(DE_CH));
-            assertEquals("hi_ZZ", "Hinglish",
-                    SpacebarLanguageUtils.getMiddleDisplayName(HI_ZZ));
-            assertEquals("zz", "QWERTY",
-                    SpacebarLanguageUtils.getMiddleDisplayName(ZZ));
+            assertEquals("en_US", "English (US)", EN_US.getFullDisplayName());
+            assertEquals("en_GB", "English (UK)", EN_GB.getFullDisplayName());
+            assertEquals("es_US", "Español (EE.UU.)", ES_US.getFullDisplayName());
+            assertEquals("fr", "Français", FR.getFullDisplayName());
+            assertEquals("fr_CA", "Français (Canada)", FR_CA.getFullDisplayName());
+            assertEquals("fr_CH", "Français (Suisse)", FR_CH.getFullDisplayName());
+            assertEquals("de", "Deutsch", DE.getFullDisplayName());
+            assertEquals("de_CH", "Deutsch (Schweiz)", DE_CH.getFullDisplayName());
+            assertEquals("hi_ZZ", "Hinglish", HI_ZZ.getFullDisplayName());
+            assertEquals("zz", "QWERTY", ZZ.getFullDisplayName());
+
+            assertEquals("en_US", "English", EN_US.getMiddleDisplayName());
+            assertEquals("en_GB", "English", EN_GB.getMiddleDisplayName());
+            assertEquals("es_US", "Español", ES_US.getMiddleDisplayName());
+            assertEquals("fr", "Français", FR.getMiddleDisplayName());
+            assertEquals("fr_CA", "Français", FR_CA.getMiddleDisplayName());
+            assertEquals("fr_CH", "Français", FR_CH.getMiddleDisplayName());
+            assertEquals("de", "Deutsch", DE.getMiddleDisplayName());
+            assertEquals("de_CH", "Deutsch", DE_CH.getMiddleDisplayName());
+            assertEquals("hi_ZZ", "Hinglish", HI_ZZ.getMiddleDisplayName());
+            assertEquals("zz", "QWERTY", ZZ.getMiddleDisplayName());
             return null;
         }
     };
@@ -214,35 +202,21 @@ public class SpacebarLanguageUtilsTests extends AndroidTestCase {
     private final RunInLocale<Void> testsAdditionalSubtypesForSpacebar = new RunInLocale<Void>() {
         @Override
         protected Void job(final Resources res) {
-            assertEquals("fr qwertz", "Français",
-                    SpacebarLanguageUtils.getFullDisplayName(FR_QWERTZ));
-            assertEquals("de qwerty", "Deutsch",
-                    SpacebarLanguageUtils.getFullDisplayName(DE_QWERTY));
-            assertEquals("en_US azerty", "English (US)",
-                    SpacebarLanguageUtils.getFullDisplayName(EN_US_AZERTY));
-            assertEquals("en_UK dvorak", "English (UK)",
-                    SpacebarLanguageUtils.getFullDisplayName(EN_UK_DVORAK));
-            assertEquals("es_US colemak", "Español (EE.UU.)",
-                    SpacebarLanguageUtils.getFullDisplayName(ES_US_COLEMAK));
-            assertEquals("zz azerty", "AZERTY",
-                    SpacebarLanguageUtils.getFullDisplayName(ZZ_AZERTY));
-            assertEquals("zz pc", "PC",
-                    SpacebarLanguageUtils.getFullDisplayName(ZZ_PC));
-
-            assertEquals("fr qwertz", "Français",
-                    SpacebarLanguageUtils.getMiddleDisplayName(FR_QWERTZ));
-            assertEquals("de qwerty", "Deutsch",
-                    SpacebarLanguageUtils.getMiddleDisplayName(DE_QWERTY));
-            assertEquals("en_US azerty", "English",
-                    SpacebarLanguageUtils.getMiddleDisplayName(EN_US_AZERTY));
-            assertEquals("en_UK dvorak", "English",
-                    SpacebarLanguageUtils.getMiddleDisplayName(EN_UK_DVORAK));
-            assertEquals("es_US colemak", "Español",
-                    SpacebarLanguageUtils.getMiddleDisplayName(ES_US_COLEMAK));
-            assertEquals("zz azerty", "AZERTY",
-                    SpacebarLanguageUtils.getMiddleDisplayName(ZZ_AZERTY));
-            assertEquals("zz pc", "PC",
-                    SpacebarLanguageUtils.getMiddleDisplayName(ZZ_PC));
+            assertEquals("fr qwertz", "Français", FR_QWERTZ.getFullDisplayName());
+            assertEquals("de qwerty", "Deutsch", DE_QWERTY.getFullDisplayName());
+            assertEquals("en_US azerty", "English (US)", EN_US_AZERTY.getFullDisplayName());
+            assertEquals("en_UK dvorak", "English (UK)", EN_UK_DVORAK.getFullDisplayName());
+            assertEquals("es_US colemak", "Español (EE.UU.)", ES_US_COLEMAK.getFullDisplayName());
+            assertEquals("zz azerty", "AZERTY", ZZ_AZERTY.getFullDisplayName());
+            assertEquals("zz pc", "PC", ZZ_PC.getFullDisplayName());
+
+            assertEquals("fr qwertz", "Français", FR_QWERTZ.getMiddleDisplayName());
+            assertEquals("de qwerty", "Deutsch", DE_QWERTY.getMiddleDisplayName());
+            assertEquals("en_US azerty", "English", EN_US_AZERTY.getMiddleDisplayName());
+            assertEquals("en_UK dvorak", "English", EN_UK_DVORAK.getMiddleDisplayName());
+            assertEquals("es_US colemak", "Español", ES_US_COLEMAK.getMiddleDisplayName());
+            assertEquals("zz azerty", "AZERTY", ZZ_AZERTY.getMiddleDisplayName());
+            assertEquals("zz pc", "PC", ZZ_PC.getMiddleDisplayName());
             return null;
         }
     };
diff --git a/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java
index 4f0b3ccdc0..40e298c0b1 100644
--- a/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java
+++ b/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java
@@ -24,6 +24,7 @@ import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodSubtype;
 
 import com.android.inputmethod.latin.RichInputMethodManager;
+import com.android.inputmethod.latin.RichInputMethodSubtype;
 
 import java.util.ArrayList;
 import java.util.Locale;
@@ -31,7 +32,7 @@ import java.util.Locale;
 @SmallTest
 public class SubtypeLocaleUtilsTests extends AndroidTestCase {
     // All input method subtypes of LatinIME.
-    private final ArrayList<InputMethodSubtype> mSubtypesList = new ArrayList<>();
+    private final ArrayList<RichInputMethodSubtype> mSubtypesList = new ArrayList<>();
 
     private RichInputMethodManager mRichImm;
     private Resources mRes;
@@ -67,7 +68,7 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase {
         final int subtypeCount = imi.getSubtypeCount();
         for (int index = 0; index < subtypeCount; index++) {
             final InputMethodSubtype subtype = imi.getSubtypeAt(index);
-            mSubtypesList.add(subtype);
+            mSubtypesList.add(new RichInputMethodSubtype(subtype));
         }
 
         EN_US = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
@@ -107,12 +108,12 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase {
     }
 
     public void testAllFullDisplayName() {
-        for (final InputMethodSubtype subtype : mSubtypesList) {
+        for (final RichInputMethodSubtype subtype : mSubtypesList) {
             final String subtypeName = SubtypeLocaleUtils
-                    .getSubtypeDisplayNameInSystemLocale(subtype);
-            if (SubtypeLocaleUtils.isNoLanguage(subtype)) {
+                    .getSubtypeDisplayNameInSystemLocale(subtype.getRawSubtype());
+            if (subtype.isNoLanguage()) {
                 final String layoutName = SubtypeLocaleUtils
-                        .getKeyboardLayoutSetDisplayName(subtype);
+                        .getKeyboardLayoutSetDisplayName(subtype.getRawSubtype());
                 assertTrue(subtypeName, subtypeName.contains(layoutName));
             } else {
                 final String languageName = SubtypeLocaleUtils
@@ -308,9 +309,9 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase {
                 .findSubtypeByLocaleAndKeyboardLayoutSet("iw", "hebrew");
         assertNotNull("Hebrew", HEBREW);
 
-        for (final InputMethodSubtype subtype : mSubtypesList) {
+        for (final RichInputMethodSubtype subtype : mSubtypesList) {
             final String subtypeName = SubtypeLocaleUtils
-                    .getSubtypeDisplayNameInSystemLocale(subtype);
+                    .getSubtypeDisplayNameInSystemLocale(subtype.getRawSubtype());
             if (subtype.equals(ARABIC) || subtype.equals(FARSI) || subtype.equals(HEBREW)) {
                 assertTrue(subtypeName, SubtypeLocaleUtils.isRtlLanguage(subtype));
             } else {
-- 
GitLab