diff --git a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java
index 80586b753807fda0a41e2827cd0d79fa8a283ecd..e7eaba2d8450c6275250ab6cec72c25a3ed940d0 100644
--- a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java
+++ b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java
@@ -16,6 +16,7 @@
 
 package com.android.inputmethod.compat;
 
+import com.android.inputmethod.deprecated.LanguageSwitcherProxy;
 import com.android.inputmethod.latin.LatinIME;
 import com.android.inputmethod.latin.SubtypeSwitcher;
 import com.android.inputmethod.latin.Utils;
@@ -56,6 +57,14 @@ public class InputMethodManagerCompatWrapper {
     private static final InputMethodManagerCompatWrapper sInstance =
             new InputMethodManagerCompatWrapper();
 
+    public static final boolean SUBTYPE_SUPPORTED;
+
+    static {
+        // This static initializer guarantees that METHOD_getShortcutInputMethodsAndSubtypes is
+        // already instantiated.
+        SUBTYPE_SUPPORTED = METHOD_getShortcutInputMethodsAndSubtypes != null;
+    }
+
     // For the compatibility, IMM will create dummy subtypes if subtypes are not found.
     // This is required to be false if the current behavior is broken. For now, it's ok to be true.
     private static final boolean ALLOW_DUMMY_SUBTYPE = true;
@@ -64,7 +73,9 @@ public class InputMethodManagerCompatWrapper {
     private static final String KEYBOARD_MODE = "keyboard";
 
     private InputMethodManager mImm;
+    private LanguageSwitcherProxy mLanguageSwitcherProxy;
     private String mLatinImePackageName;
+
     private InputMethodManagerCompatWrapper() {
     }
 
@@ -81,15 +92,29 @@ public class InputMethodManagerCompatWrapper {
         if (context instanceof LatinIME) {
             mLatinImePackageName = context.getPackageName();
         }
+        mLanguageSwitcherProxy = LanguageSwitcherProxy.getInstance();
     }
 
     public InputMethodSubtypeCompatWrapper getCurrentInputMethodSubtype() {
+        if (!SUBTYPE_SUPPORTED) {
+            return new InputMethodSubtypeCompatWrapper(
+                    0, 0, mLanguageSwitcherProxy.getInputLocale().toString(), KEYBOARD_MODE, "");
+        }
         Object o = CompatUtils.invoke(mImm, null, METHOD_getCurrentInputMethodSubtype);
         return new InputMethodSubtypeCompatWrapper(o);
     }
 
     public List<InputMethodSubtypeCompatWrapper> getEnabledInputMethodSubtypeList(
             InputMethodInfoCompatWrapper imi, boolean allowsImplicitlySelectedSubtypes) {
+        if (!SUBTYPE_SUPPORTED) {
+            String[] languages = mLanguageSwitcherProxy.getEnabledLanguages();
+            List<InputMethodSubtypeCompatWrapper> subtypeList =
+                    new ArrayList<InputMethodSubtypeCompatWrapper>();
+            for (String lang: languages) {
+                subtypeList.add(new InputMethodSubtypeCompatWrapper(0, 0, lang, KEYBOARD_MODE, ""));
+            }
+            return subtypeList;
+        }
         Object retval = CompatUtils.invoke(mImm, null, METHOD_getEnabledInputMethodSubtypeList,
                 (imi != null ? imi.getInputMethodInfo() : null), allowsImplicitlySelectedSubtypes);
         if (retval == null || !(retval instanceof List) || ((List<?>)retval).isEmpty()) {
@@ -170,6 +195,10 @@ public class InputMethodManagerCompatWrapper {
 
     public void setInputMethodAndSubtype(
             IBinder token, String id, InputMethodSubtypeCompatWrapper subtype) {
+        if (!SUBTYPE_SUPPORTED) {
+            mLanguageSwitcherProxy.setLocale(subtype.getLocale());
+            return;
+        }
         CompatUtils.invoke(mImm, null, METHOD_setInputMethodAndSubtype,
                 token, id, subtype.getOriginalObject());
     }
diff --git a/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatWrapper.java
index 317b02216a0e9793dfc12555ec6092cb5c23616f..86c8af37f8b574c090734f3c027b37f22100b3f1 100644
--- a/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatWrapper.java
+++ b/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatWrapper.java
@@ -58,9 +58,6 @@ public final class InputMethodSubtypeCompatWrapper extends AbstractCompatWrapper
     public InputMethodSubtypeCompatWrapper(Object subtype) {
         super((CLASS_InputMethodSubtype != null && CLASS_InputMethodSubtype.isInstance(subtype))
                 ? subtype : null);
-        if (DBG) {
-            Log.d(TAG, "CreateInputMethodSubtypeCompatWrapper");
-        }
         mDummyNameResId = 0;
         mDummyIconResId = 0;
         mDummyLocale = DEFAULT_LOCALE;
diff --git a/java/src/com/android/inputmethod/deprecated/LanguageSwitcherProxy.java b/java/src/com/android/inputmethod/deprecated/LanguageSwitcherProxy.java
new file mode 100644
index 0000000000000000000000000000000000000000..5d165cda91eafb6bd55fb6d9b599f45e73bbfa60
--- /dev/null
+++ b/java/src/com/android/inputmethod/deprecated/LanguageSwitcherProxy.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2011 Google Inc.
+ *
+ * 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.deprecated;
+
+import com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
+import com.android.inputmethod.deprecated.languageswitcher.LanguageSwitcher;
+import com.android.inputmethod.latin.LatinIME;
+
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+
+import java.util.Locale;
+
+// This class is used only when the IME doesn't use method.xml for language switching.
+public class LanguageSwitcherProxy {
+    private static final LanguageSwitcherProxy sInstance = new LanguageSwitcherProxy();
+    private LanguageSwitcher mLanguageSwitcher;
+    private SharedPreferences mPrefs;
+
+    public static LanguageSwitcherProxy getInstance() {
+        if (InputMethodManagerCompatWrapper.SUBTYPE_SUPPORTED) return null;
+        return sInstance;
+    }
+
+    public static void init(LatinIME service, SharedPreferences prefs) {
+        if (InputMethodManagerCompatWrapper.SUBTYPE_SUPPORTED) return;
+        final Configuration conf = service.getResources().getConfiguration();
+        sInstance.mLanguageSwitcher = new LanguageSwitcher(service);
+        sInstance.mLanguageSwitcher.loadLocales(prefs, conf.locale);
+        sInstance.mPrefs = prefs;
+    }
+
+    public static void onConfigurationChanged(Configuration conf) {
+        if (InputMethodManagerCompatWrapper.SUBTYPE_SUPPORTED) return;
+        sInstance.mLanguageSwitcher.onConfigurationChanged(conf, sInstance.mPrefs);
+    }
+
+    public static void loadSettings() {
+        if (InputMethodManagerCompatWrapper.SUBTYPE_SUPPORTED) return;
+        sInstance.mLanguageSwitcher.loadLocales(sInstance.mPrefs, null);
+    }
+
+    public int getLocaleCount() {
+        return mLanguageSwitcher.getLocaleCount();
+    }
+
+    public String[] getEnabledLanguages() {
+        return mLanguageSwitcher.getEnabledLanguages();
+    }
+
+    public Locale getInputLocale() {
+        return mLanguageSwitcher.getInputLocale();
+    }
+
+    public void setLocale(String localeStr) {
+        mLanguageSwitcher.setLocale(localeStr);
+        mLanguageSwitcher.persist(mPrefs);
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/LanguageSwitcher.java b/java/src/com/android/inputmethod/deprecated/languageswitcher/LanguageSwitcher.java
similarity index 77%
rename from java/src/com/android/inputmethod/latin/LanguageSwitcher.java
rename to java/src/com/android/inputmethod/deprecated/languageswitcher/LanguageSwitcher.java
index 6faf7f95e32e62428a52fd12c4a3fe9bd007f2b4..639b7cdd073eb180ed9a48ba461bfa7292ac4374 100644
--- a/java/src/com/android/inputmethod/latin/LanguageSwitcher.java
+++ b/java/src/com/android/inputmethod/deprecated/languageswitcher/LanguageSwitcher.java
@@ -14,10 +14,16 @@
  * the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.deprecated.languageswitcher;
+
+import com.android.inputmethod.compat.InputMethodSubtypeCompatWrapper;
+import com.android.inputmethod.latin.LatinIME;
+import com.android.inputmethod.latin.Settings;
+import com.android.inputmethod.latin.SharedPreferencesCompat;
 
 import android.content.SharedPreferences;
 import android.content.SharedPreferences.Editor;
+import android.content.res.Configuration;
 import android.text.TextUtils;
 
 import java.util.ArrayList;
@@ -29,6 +35,8 @@ import java.util.Locale;
  */
 public class LanguageSwitcher {
 
+    private static final String KEYBOARD_MODE = "keyboard";
+
     private final ArrayList<Locale> mLocales = new ArrayList<Locale>();
     private final LatinIME mIme;
     private String[] mSelectedLanguageArray;
@@ -46,12 +54,24 @@ public class LanguageSwitcher {
         return mLocales.size();
     }
 
+    public void onConfigurationChanged(Configuration conf, SharedPreferences prefs) {
+        final Locale newLocale = conf.locale;
+        if (!getSystemLocale().toString().equals(newLocale.toString())) {
+            loadLocales(prefs, newLocale);
+        }
+    }
+
     /**
      * Loads the currently selected input languages from shared preferences.
-     * @param sp
+     * @param sp shared preference for getting the current input language and enabled languages
+     * @param systemLocale the current system locale, stored for changing the current input language
+     * based on the system current system locale.
      * @return whether there was any change
      */
-    public boolean loadLocales(SharedPreferences sp) {
+    public boolean loadLocales(SharedPreferences sp, Locale systemLocale) {
+        if (systemLocale != null) {
+            setSystemLocale(systemLocale);
+        }
         String selectedLanguages = sp.getString(Settings.PREF_SELECTED_LANGUAGES, null);
         String currentLanguage   = sp.getString(Settings.PREF_INPUT_LANGUAGE, null);
         if (selectedLanguages == null || selectedLanguages.length() < 1) {
@@ -151,7 +171,7 @@ public class LanguageSwitcher {
      * Sets the system locale (display UI) used for comparing with the input language.
      * @param locale the locale of the system
      */
-    public void setSystemLocale(Locale locale) {
+    private void setSystemLocale(Locale locale) {
         mSystemLocale = locale;
     }
 
@@ -159,7 +179,7 @@ public class LanguageSwitcher {
      * Returns the system locale.
      * @return the system locale
      */
-    public Locale getSystemLocale() {
+    private Locale getSystemLocale() {
         return mSystemLocale;
     }
 
@@ -185,9 +205,22 @@ public class LanguageSwitcher {
         mCurrentIndex = prevLocaleIndex();
     }
 
+    public void setLocale(String localeStr) {
+        final int N = mLocales.size();
+        for (int i = 0; i < N; ++i) {
+            if (mLocales.get(i).toString().equals(localeStr)) {
+                mCurrentIndex = i;
+            }
+        }
+    }
+
     public void persist(SharedPreferences prefs) {
         Editor editor = prefs.edit();
         editor.putString(Settings.PREF_INPUT_LANGUAGE, getInputLanguage());
         SharedPreferencesCompat.apply(editor);
+        // When the current language is changed, the event for this change should be handled
+        // internally as a subtype switching.
+        mIme.notifyOnCurrentInputMethodSubtypeChanged(new InputMethodSubtypeCompatWrapper(
+                0, 0, getInputLocale().toString(), KEYBOARD_MODE, ""));
     }
 }
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java
index 9b87df3feefad7409314c6db6c418fcf1de85a5c..9d9793e1ef9daafb21b795ec82629b54153f51d5 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java
@@ -271,7 +271,7 @@ public class LatinKeyboard extends Keyboard {
             canvas.drawText(language, width / 2, baseline - descent, paint);
 
             // Put arrows that are already layed out on either side of the text
-            if (SubtypeSwitcher.getInstance().useSpacebarLanguageSwitcher()
+            if (subtypeSwitcher.useSpacebarLanguageSwitcher()
                     && subtypeSwitcher.getEnabledKeyboardLocaleCount() > 1) {
                 mButtonArrowLeftIcon.draw(canvas);
                 mButtonArrowRightIcon.draw(canvas);
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 6a858fe9905182d680b0461f638d3787e1f67646..3905a4c7aecb07f8298451bd1b273c78d955036a 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -23,6 +23,7 @@ import com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
 import com.android.inputmethod.compat.InputMethodServiceCompatWrapper;
 import com.android.inputmethod.compat.InputTypeCompatUtils;
 import com.android.inputmethod.compat.VibratorCompatWrapper;
+import com.android.inputmethod.deprecated.LanguageSwitcherProxy;
 import com.android.inputmethod.deprecated.VoiceProxy;
 import com.android.inputmethod.keyboard.Keyboard;
 import com.android.inputmethod.keyboard.KeyboardActionListener;
@@ -379,6 +380,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
         SubtypeSwitcher.init(this, prefs);
         KeyboardSwitcher.init(this, prefs);
         AccessibilityUtils.init(this, prefs);
+        LanguageSwitcherProxy.init(this, prefs);
 
         super.onCreate();
 
@@ -516,6 +518,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
         super.onConfigurationChanged(conf);
         mVoiceProxy.onConfigurationChanged(conf);
         mConfigurationChanging = false;
+
+        // This will work only when the subtype is not supported.
+        LanguageSwitcherProxy.onConfigurationChanged(conf);
     }
 
     @Override
@@ -1155,10 +1160,10 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
             onSettingsKeyLongPressed();
             break;
         case Keyboard.CODE_NEXT_LANGUAGE:
-            toggleLanguage(false, true);
+            toggleLanguage(true);
             break;
         case Keyboard.CODE_PREV_LANGUAGE:
-            toggleLanguage(false, false);
+            toggleLanguage(false);
             break;
         case Keyboard.CODE_CAPSLOCK:
             switcher.toggleCapsLock();
@@ -1930,17 +1935,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
         return mWord.isFirstCharCapitalized();
     }
 
-    // Notify that language or mode have been changed and toggleLanguage will update KeyboaredID
+    // Notify that language or mode have been changed and toggleLanguage will update KeyboardID
     // according to new language or mode.
     public void onRefreshKeyboard() {
-        toggleLanguage(true, true);
-    }
-
-    // "reset" and "next" are used only for USE_SPACEBAR_LANGUAGE_SWITCHER.
-    private void toggleLanguage(boolean reset, boolean next) {
-        if (mSubtypeSwitcher.useSpacebarLanguageSwitcher()) {
-            mSubtypeSwitcher.toggleLanguage(reset, next);
-        }
         // Reload keyboard because the current language has been changed.
         mKeyboardSwitcher.loadKeyboard(getCurrentInputEditorInfo(),
                 mSubtypeSwitcher.isShortcutImeEnabled() && mVoiceProxy.isVoiceButtonEnabled(),
@@ -1949,6 +1946,14 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
         mKeyboardSwitcher.updateShiftState();
     }
 
+    // "reset" and "next" are used only for USE_SPACEBAR_LANGUAGE_SWITCHER.
+    private void toggleLanguage(boolean next) {
+        if (mSubtypeSwitcher.useSpacebarLanguageSwitcher()) {
+            mSubtypeSwitcher.toggleLanguage(next);
+        }
+        onRefreshKeyboard();// no need??
+    }
+
     @Override
     public void onSwipeDown() {
         if (mConfigSwipeDownDismissKeyboardEnabled)
@@ -2134,7 +2139,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
         updateCorrectionMode();
         updateAutoTextEnabled();
         updateSuggestionVisibility(prefs);
-        SubtypeSwitcher.getInstance().loadSettings();
+
+        // This will work only when the subtype is not supported.
+        LanguageSwitcherProxy.loadSettings();
     }
 
     /**
diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
index 053e2abe401a966e27d26be9bef50cda23d99850..2cdc4d2cda5cc947684ae1edf40434abca67e785 100644
--- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
+++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
@@ -57,7 +57,6 @@ public class SubtypeSwitcher {
 
     private static final SubtypeSwitcher sInstance = new SubtypeSwitcher();
     private /* final */ LatinIME mService;
-    private /* final */ SharedPreferences mPrefs;
     private /* final */ InputMethodManagerCompatWrapper mImm;
     private /* final */ Resources mResources;
     private /* final */ ConnectivityManager mConnectivityManager;
@@ -66,6 +65,7 @@ public class SubtypeSwitcher {
             mEnabledKeyboardSubtypesOfCurrentInputMethod =
                     new ArrayList<InputMethodSubtypeCompatWrapper>();
     private final ArrayList<String> mEnabledLanguagesOfCurrentInputMethod = new ArrayList<String>();
+    private final LanguageBarInfo mLanguageBarInfo = new LanguageBarInfo();
 
     /*-----------------------------------------------------------*/
     // Variants which should be changed only by reload functions.
@@ -78,6 +78,7 @@ public class SubtypeSwitcher {
     private Locale mSystemLocale;
     private Locale mInputLocale;
     private String mInputLocaleStr;
+    private String mInputMethodId;
     private VoiceProxy.VoiceInputWrapper mVoiceInputWrapper;
     /*-----------------------------------------------------------*/
 
@@ -100,7 +101,6 @@ public class SubtypeSwitcher {
 
     private void initialize(LatinIME service, SharedPreferences prefs) {
         mService = service;
-        mPrefs = prefs;
         mResources = service.getResources();
         mImm = InputMethodManagerCompatWrapper.getInstance(service);
         mConnectivityManager = (ConnectivityManager) service.getSystemService(
@@ -114,13 +114,12 @@ public class SubtypeSwitcher {
         mAllEnabledSubtypesOfCurrentInputMethod = null;
         // TODO: Voice input should be created here
         mVoiceInputWrapper = null;
-        mConfigUseSpacebarLanguageSwitcher = mResources.getBoolean(
+        mConfigUseSpacebarLanguageSwitcher = service.getResources().getBoolean(
                 R.bool.config_use_spacebar_language_switcher);
-        if (mConfigUseSpacebarLanguageSwitcher)
-            initLanguageSwitcher(service);
 
         final NetworkInfo info = mConnectivityManager.getActiveNetworkInfo();
         mIsNetworkConnected = (info != null && info.isConnected());
+        mInputMethodId = Utils.getInputMethodId(mImm, service.getPackageName());
     }
 
     // Update all parameters stored in SubtypeSwitcher.
@@ -134,11 +133,7 @@ public class SubtypeSwitcher {
     // Update parameters which are changed outside LatinIME. This parameters affect UI so they
     // should be updated every time onStartInputview.
     public void updateParametersOnStartInputView() {
-        if (mConfigUseSpacebarLanguageSwitcher) {
-            updateForSpacebarLanguageSwitch();
-        } else {
-            updateEnabledSubtypes();
-        }
+        updateEnabledSubtypes();
         updateShortcutIME();
     }
 
@@ -150,7 +145,7 @@ public class SubtypeSwitcher {
                 null, true);
         mEnabledLanguagesOfCurrentInputMethod.clear();
         mEnabledKeyboardSubtypesOfCurrentInputMethod.clear();
-        for (InputMethodSubtypeCompatWrapper ims: mAllEnabledSubtypesOfCurrentInputMethod) {
+        for (InputMethodSubtypeCompatWrapper ims : mAllEnabledSubtypesOfCurrentInputMethod) {
             final String locale = ims.getLocale();
             final String mode = ims.getMode();
             mLocaleSplitter.setString(locale);
@@ -172,6 +167,10 @@ public class SubtypeSwitcher {
                 Log.w(TAG, "Last subtype was disabled. Update to the current one.");
             }
             updateSubtype(mImm.getCurrentInputMethodSubtype());
+        } else {
+            // mLanguageBarInfo.update() will be called in updateSubtype so there is no need
+            // to call this in the if-clause above.
+            mLanguageBarInfo.update();
         }
     }
 
@@ -269,6 +268,7 @@ public class SubtypeSwitcher {
                 mVoiceInputWrapper.reset();
             }
         }
+        mLanguageBarInfo.update();
     }
 
     // Update the current input locale from Locale string.
@@ -303,12 +303,21 @@ public class SubtypeSwitcher {
     ////////////////////////////
 
     public void switchToShortcutIME() {
-        final IBinder token = mService.getWindow().getWindow().getAttributes().token;
-        if (token == null || mShortcutInputMethodInfo == null) {
+        if (mShortcutInputMethodInfo == null) {
             return;
         }
+
         final String imiId = mShortcutInputMethodInfo.getId();
         final InputMethodSubtypeCompatWrapper subtype = mShortcutSubtype;
+        switchToTargetIME(imiId, subtype);
+    }
+
+    private void switchToTargetIME(
+            final String imiId, final InputMethodSubtypeCompatWrapper subtype) {
+        final IBinder token = mService.getWindow().getWindow().getAttributes().token;
+        if (token == null) {
+            return;
+        }
         new AsyncTask<Void, Void, Void>() {
             @Override
             protected Void doInBackground(Void... params) {
@@ -412,11 +421,7 @@ public class SubtypeSwitcher {
     //////////////////////////////////
 
     public int getEnabledKeyboardLocaleCount() {
-        if (mConfigUseSpacebarLanguageSwitcher) {
-            return mLanguageSwitcher.getLocaleCount();
-        } else {
-            return mEnabledKeyboardSubtypesOfCurrentInputMethod.size();
-        }
+        return mEnabledKeyboardSubtypesOfCurrentInputMethod.size();
     }
 
     public boolean useSpacebarLanguageSwitcher() {
@@ -428,74 +433,37 @@ public class SubtypeSwitcher {
     }
 
     public Locale getInputLocale() {
-        if (mConfigUseSpacebarLanguageSwitcher) {
-            return mLanguageSwitcher.getInputLocale();
-        } else {
-            return mInputLocale;
-        }
+        return mInputLocale;
     }
 
     public String getInputLocaleStr() {
-        if (mConfigUseSpacebarLanguageSwitcher) {
-            String inputLanguage = null;
-            inputLanguage = mLanguageSwitcher.getInputLanguage();
-            // Should return system locale if there is no Language available.
-            if (inputLanguage == null) {
-                inputLanguage = getSystemLocale().getLanguage();
-            }
-            return inputLanguage;
-        } else {
-            return mInputLocaleStr;
-        }
+        return mInputLocaleStr;
     }
 
     public String[] getEnabledLanguages() {
-        if (mConfigUseSpacebarLanguageSwitcher) {
-            return mLanguageSwitcher.getEnabledLanguages();
-        } else {
-            int enabledLanguageCount = mEnabledLanguagesOfCurrentInputMethod.size();
-            // Workaround for explicitly specifying the voice language
-            if (enabledLanguageCount == 1) {
-                mEnabledLanguagesOfCurrentInputMethod.add(
-                        mEnabledLanguagesOfCurrentInputMethod.get(0));
-                ++enabledLanguageCount;
-            }
-            return mEnabledLanguagesOfCurrentInputMethod.toArray(
-                    new String[enabledLanguageCount]);
+        int enabledLanguageCount = mEnabledLanguagesOfCurrentInputMethod.size();
+        // Workaround for explicitly specifying the voice language
+        if (enabledLanguageCount == 1) {
+            mEnabledLanguagesOfCurrentInputMethod.add(mEnabledLanguagesOfCurrentInputMethod
+                    .get(0));
+            ++enabledLanguageCount;
         }
+        return mEnabledLanguagesOfCurrentInputMethod.toArray(new String[enabledLanguageCount]);
     }
 
     public Locale getSystemLocale() {
-        if (mConfigUseSpacebarLanguageSwitcher) {
-            return mLanguageSwitcher.getSystemLocale();
-        } else {
-            return mSystemLocale;
-        }
+        return mSystemLocale;
     }
 
     public boolean isSystemLanguageSameAsInputLanguage() {
-        if (mConfigUseSpacebarLanguageSwitcher) {
-            return getSystemLocale().getLanguage().equalsIgnoreCase(
-                    getInputLocaleStr().substring(0, 2));
-        } else {
-            return mIsSystemLanguageSameAsInputLanguage;
-        }
+        return mIsSystemLanguageSameAsInputLanguage;
     }
 
     public void onConfigurationChanged(Configuration conf) {
         final Locale systemLocale = conf.locale;
         // If system configuration was changed, update all parameters.
         if (!TextUtils.equals(systemLocale.toString(), mSystemLocale.toString())) {
-            if (mConfigUseSpacebarLanguageSwitcher) {
-                // If the system locale changes and is different from the saved
-                // locale (mSystemLocale), then reload the input locale list from the
-                // latin ime settings (shared prefs) and reset the input locale
-                // to the first one.
-                mLanguageSwitcher.loadLocales(mPrefs);
-                mLanguageSwitcher.setSystemLocale(systemLocale);
-            } else {
-                updateAllParameters();
-            }
+            updateAllParameters();
         }
     }
 
@@ -554,7 +522,70 @@ public class SubtypeSwitcher {
     // Spacebar Language Switch support //
     //////////////////////////////////////
 
-    private LanguageSwitcher mLanguageSwitcher;
+    private class LanguageBarInfo {
+        private int mCurrentKeyboardSubtypeIndex;
+        private InputMethodSubtypeCompatWrapper mNextKeyboardSubtype;
+        private InputMethodSubtypeCompatWrapper mPreviousKeyboardSubtype;
+        private String mNextLanguage;
+        private String mPreviousLanguage;
+        public LanguageBarInfo() {
+            update();
+        }
+
+        private String getNextLanguage() {
+            return mNextLanguage;
+        }
+
+        private String getPreviousLanguage() {
+            return mPreviousLanguage;
+        }
+
+        public InputMethodSubtypeCompatWrapper getNextKeyboardSubtype() {
+            return mNextKeyboardSubtype;
+        }
+
+        public InputMethodSubtypeCompatWrapper getPreviousKeyboardSubtype() {
+            return mPreviousKeyboardSubtype;
+        }
+
+        public void update() {
+            if (!mConfigUseSpacebarLanguageSwitcher
+                    || mEnabledKeyboardSubtypesOfCurrentInputMethod == null
+                    || mEnabledKeyboardSubtypesOfCurrentInputMethod.size() == 0) return;
+            mCurrentKeyboardSubtypeIndex = getCurrentIndex();
+            mNextKeyboardSubtype = getNextKeyboardSubtypeInternal(mCurrentKeyboardSubtypeIndex);
+            Locale locale = new Locale(mNextKeyboardSubtype.getLocale());
+            mNextLanguage = getDisplayLanguage(locale);
+            mPreviousKeyboardSubtype = getPreviousKeyboardSubtypeInternal(
+                    mCurrentKeyboardSubtypeIndex);
+            locale = new Locale(mPreviousKeyboardSubtype.getLocale());
+            mPreviousLanguage = getDisplayLanguage(locale);
+        }
+
+        private int normalize(int index) {
+            final int N = mEnabledKeyboardSubtypesOfCurrentInputMethod.size();
+            final int ret = index % N;
+            return ret < 0 ? ret + N : ret;
+        }
+
+        private int getCurrentIndex() {
+            final int N = mEnabledKeyboardSubtypesOfCurrentInputMethod.size();
+            for (int i = 0; i < N; ++i) {
+                if (mEnabledKeyboardSubtypesOfCurrentInputMethod.get(i).equals(mCurrentSubtype)) {
+                    return i;
+                }
+            }
+            return 0;
+        }
+
+        private InputMethodSubtypeCompatWrapper getNextKeyboardSubtypeInternal(int index) {
+            return mEnabledKeyboardSubtypesOfCurrentInputMethod.get(normalize(index + 1));
+        }
+
+        private InputMethodSubtypeCompatWrapper getPreviousKeyboardSubtypeInternal(int index) {
+            return mEnabledKeyboardSubtypesOfCurrentInputMethod.get(normalize(index - 1));
+        }
+    }
 
     public static String getFullDisplayName(Locale locale, boolean returnsNameInThisLocale) {
         if (returnsNameInThisLocale) {
@@ -579,32 +610,16 @@ public class SubtypeSwitcher {
         return Character.toUpperCase(s.charAt(0)) + s.substring(1);
     }
 
-    private void updateForSpacebarLanguageSwitch() {
-        // We need to update mNeedsToDisplayLanguage in onStartInputView because
-        // getEnabledKeyboardLocaleCount could have been changed.
-        mNeedsToDisplayLanguage = !(getEnabledKeyboardLocaleCount() <= 1
-                && getSystemLocale().getLanguage().equalsIgnoreCase(
-                        getInputLocale().getLanguage()));
-    }
-
     public String getInputLanguageName() {
         return getDisplayLanguage(getInputLocale());
     }
 
     public String getNextInputLanguageName() {
-        if (mConfigUseSpacebarLanguageSwitcher) {
-            return getDisplayLanguage(mLanguageSwitcher.getNextInputLocale());
-        } else {
-            return "";
-        }
+        return mLanguageBarInfo.getNextLanguage();
     }
 
     public String getPreviousInputLanguageName() {
-        if (mConfigUseSpacebarLanguageSwitcher) {
-            return getDisplayLanguage(mLanguageSwitcher.getPrevInputLocale());
-        } else {
-            return "";
-        }
+        return mLanguageBarInfo.getPreviousLanguage();
     }
 
     /////////////////////////////
@@ -644,31 +659,23 @@ public class SubtypeSwitcher {
         return voiceInputSupportedLocales.contains(locale);
     }
 
-    public void loadSettings() {
-        if (mConfigUseSpacebarLanguageSwitcher) {
-            mLanguageSwitcher.loadLocales(mPrefs);
-        }
+    private void changeToNextSubtype() {
+        final InputMethodSubtypeCompatWrapper subtype =
+                mLanguageBarInfo.getNextKeyboardSubtype();
+        switchToTargetIME(mInputMethodId, subtype);
     }
 
-    public void toggleLanguage(boolean reset, boolean next) {
-        if (mConfigUseSpacebarLanguageSwitcher) {
-            if (reset) {
-                mLanguageSwitcher.reset();
-            } else {
-                if (next) {
-                    mLanguageSwitcher.next();
-                } else {
-                    mLanguageSwitcher.prev();
-                }
-            }
-            mLanguageSwitcher.persist(mPrefs);
-        }
+    private void changeToPreviousSubtype() {
+        final InputMethodSubtypeCompatWrapper subtype =
+                mLanguageBarInfo.getPreviousKeyboardSubtype();
+        switchToTargetIME(mInputMethodId, subtype);
     }
 
-    private void initLanguageSwitcher(LatinIME service) {
-        final Configuration conf = service.getResources().getConfiguration();
-        mLanguageSwitcher = new LanguageSwitcher(service);
-        mLanguageSwitcher.loadLocales(mPrefs);
-        mLanguageSwitcher.setSystemLocale(conf.locale);
+    public void toggleLanguage(boolean next) {
+        if (next) {
+            changeToNextSubtype();
+        } else {
+            changeToPreviousSubtype();
+        }
     }
 }