diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml
index 739f72f366792bb882dbabe73e1a43e4252d656f..63663028f2b93594684f96c20d5cac1ed3cd4a48 100644
--- a/java/res/values/strings.xml
+++ b/java/res/values/strings.xml
@@ -301,6 +301,9 @@
     <!-- Title of the dialog for selecting input methods. [CHAR LIMIT=20] -->
     <string name="selectInputMethod">Select input method</string>
 
+    <!-- Title for configuring input method settings [CHAR LIMIT=35] -->
+    <string name="configure_input_method">Configure input methods</string>
+
     <!-- Title for input language selection screen -->
     <string name="language_selection_title">Input languages</string>
 
diff --git a/java/src/com/android/inputmethod/compat/InputMethodInfoCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodInfoCompatWrapper.java
index 8e22bbc791fd8fc2c5ddc47b5e7cb5ec660e2e98..831559809a825b8d6562f0e834f3531baa5becb6 100644
--- a/java/src/com/android/inputmethod/compat/InputMethodInfoCompatWrapper.java
+++ b/java/src/com/android/inputmethod/compat/InputMethodInfoCompatWrapper.java
@@ -16,6 +16,7 @@
 
 package com.android.inputmethod.compat;
 
+import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
 import android.view.inputmethod.InputMethodInfo;
 
@@ -56,4 +57,21 @@ public class InputMethodInfoCompatWrapper {
         return new InputMethodSubtypeCompatWrapper(CompatUtils.invoke(mImi, null,
                 METHOD_getSubtypeAt, index));
     }
+
+    public CharSequence loadLabel(PackageManager pm) {
+        return mImi.loadLabel(pm);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o instanceof InputMethodInfoCompatWrapper) {
+            return mImi.equals(((InputMethodInfoCompatWrapper)o).mImi);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return mImi.hashCode();
+    }
 }
diff --git a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java
index 1cc13f2498c9a8af50f3404b5a1ebe5699997896..51dc4cd37cadff0cf138fac3fb6f06b1bee52834 100644
--- a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java
+++ b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java
@@ -16,21 +16,28 @@
 
 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;
-
+import android.app.AlertDialog;
 import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
 import android.os.IBinder;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodManager;
 
+import com.android.inputmethod.deprecated.LanguageSwitcherProxy;
+import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.SubtypeSwitcher;
+import com.android.inputmethod.latin.Utils;
+
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
@@ -72,27 +79,27 @@ public class InputMethodManagerCompatWrapper {
     private static final String VOICE_MODE = "voice";
     private static final String KEYBOARD_MODE = "keyboard";
 
+    private InputMethodServiceCompatWrapper mService;
     private InputMethodManager mImm;
+    private PackageManager mPackageManager;
+    private ApplicationInfo mApplicationInfo;
     private LanguageSwitcherProxy mLanguageSwitcherProxy;
     private String mLatinImePackageName;
 
-    private InputMethodManagerCompatWrapper() {
-    }
-
-    public static InputMethodManagerCompatWrapper getInstance(Context context) {
-        if (sInstance.mImm == null) {
-            sInstance.init(context);
-        }
+    public static InputMethodManagerCompatWrapper getInstance() {
+        if (sInstance.mImm == null)
+            Log.w(TAG, "getInstance() is called before initialization");
         return sInstance;
     }
 
-    private synchronized void init(Context context) {
-        mImm = (InputMethodManager) context.getSystemService(
+    public static void init(InputMethodServiceCompatWrapper service) {
+        sInstance.mService = service;
+        sInstance.mImm = (InputMethodManager) service.getSystemService(
                 Context.INPUT_METHOD_SERVICE);
-        if (context instanceof LatinIME) {
-            mLatinImePackageName = context.getPackageName();
-        }
-        mLanguageSwitcherProxy = LanguageSwitcherProxy.getInstance();
+        sInstance.mLatinImePackageName = service.getPackageName();
+        sInstance.mPackageManager = service.getPackageManager();
+        sInstance.mApplicationInfo = service.getApplicationInfo();
+        sInstance.mLanguageSwitcherProxy = LanguageSwitcherProxy.getInstance();
     }
 
     public InputMethodSubtypeCompatWrapper getCurrentInputMethodSubtype() {
@@ -196,11 +203,15 @@ public class InputMethodManagerCompatWrapper {
         return shortcutMap;
     }
 
+    // We don't call this method when we switch between subtypes within this IME.
     public void setInputMethodAndSubtype(
             IBinder token, String id, InputMethodSubtypeCompatWrapper subtype) {
+        // TODO: Support subtype change on non-subtype-supported platform.
         if (subtype != null && subtype.hasOriginalObject()) {
             CompatUtils.invoke(mImm, null, METHOD_setInputMethodAndSubtype,
                     token, id, subtype.getOriginalObject());
+        } else {
+            mImm.setInputMethod(token, id);
         }
     }
 
@@ -222,6 +233,87 @@ public class InputMethodManagerCompatWrapper {
 
     public void showInputMethodPicker() {
         if (mImm == null) return;
-        mImm.showInputMethodPicker();
+        if (SUBTYPE_SUPPORTED) {
+            mImm.showInputMethodPicker();
+            return;
+        }
+
+        // The code below are based on {@link InputMethodManager#showInputMethodMenuInternal}.
+
+        final InputMethodInfoCompatWrapper myImi = Utils.getInputMethodInfo(
+                this, mLatinImePackageName);
+        final List<InputMethodSubtypeCompatWrapper> myImsList = getEnabledInputMethodSubtypeList(
+                myImi, true);
+        final InputMethodSubtypeCompatWrapper currentIms = getCurrentInputMethodSubtype();
+        final List<InputMethodInfoCompatWrapper> imiList = getEnabledInputMethodList();
+        imiList.remove(myImi);
+        Collections.sort(imiList, new Comparator<InputMethodInfoCompatWrapper>() {
+            @Override
+            public int compare(InputMethodInfoCompatWrapper imi1,
+                    InputMethodInfoCompatWrapper imi2) {
+                final CharSequence imiId1 = imi1.loadLabel(mPackageManager) + "/" + imi1.getId();
+                final CharSequence imiId2 = imi2.loadLabel(mPackageManager) + "/" + imi2.getId();
+                return imiId1.toString().compareTo(imiId2.toString());
+            }
+        });
+
+        final int myImsCount = myImsList.size();
+        final int imiCount = imiList.size();
+        final CharSequence[] items = new CharSequence[myImsCount + imiCount];
+
+        int checkedItem = 0;
+        int index = 0;
+        final CharSequence myImiLabel = myImi.loadLabel(mPackageManager);
+        for (int i = 0; i < myImsCount; i++) {
+            InputMethodSubtypeCompatWrapper ims = myImsList.get(i);
+            if (currentIms.equals(ims))
+                checkedItem = index;
+            final CharSequence title = TextUtils.concat(
+                    ims.getDisplayName(mService, mLatinImePackageName, mApplicationInfo),
+                    " (" + myImiLabel, ")");
+            items[index] = title;
+            index++;
+        }
+
+        for (int i = 0; i < imiCount; i++) {
+            final InputMethodInfoCompatWrapper imi = imiList.get(i);
+            final CharSequence title = imi.loadLabel(mPackageManager);
+            items[index] = title;
+            index++;
+        }
+
+        final OnClickListener buttonListener = new OnClickListener() {
+            @Override
+            public void onClick(DialogInterface di, int whichButton) {
+                final Intent intent = new Intent("android.settings.INPUT_METHOD_SETTINGS");
+                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                        | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
+                        | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+                mService.startActivity(intent);
+            }
+        };
+        final InputMethodServiceCompatWrapper service = mService;
+        final IBinder token = service.getWindow().getWindow().getAttributes().token;
+        final OnClickListener selectionListener = new OnClickListener() {
+            @Override
+            public void onClick(DialogInterface di, int which) {
+                di.dismiss();
+                if (which < myImsCount) {
+                    final int imsIndex = which;
+                    final InputMethodSubtypeCompatWrapper ims = myImsList.get(imsIndex);
+                    service.notifyOnCurrentInputMethodSubtypeChanged(ims);
+                } else {
+                    final int imiIndex = which - myImsCount;
+                    final InputMethodInfoCompatWrapper imi = imiList.get(imiIndex);
+                    setInputMethodAndSubtype(token, imi.getId(), null);
+                }
+            }
+        };
+
+        final AlertDialog.Builder builder = new AlertDialog.Builder(mService)
+                .setTitle(mService.getString(R.string.selectInputMethod))
+                .setNeutralButton(R.string.configure_input_method, buttonListener)
+                .setSingleChoiceItems(items, checkedItem, selectionListener);
+        mService.showOptionDialogInternal(builder.create());
     }
 }
diff --git a/java/src/com/android/inputmethod/compat/InputMethodServiceCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodServiceCompatWrapper.java
index 7d8c745c328c444d2d5d83255817a5603fc1e0ed..7aab66d058129c6c0af8ae3fc450ad24e9caa7ef 100644
--- a/java/src/com/android/inputmethod/compat/InputMethodServiceCompatWrapper.java
+++ b/java/src/com/android/inputmethod/compat/InputMethodServiceCompatWrapper.java
@@ -16,10 +16,15 @@
 
 package com.android.inputmethod.compat;
 
+import android.app.AlertDialog;
 import android.inputmethodservice.InputMethodService;
+import android.os.IBinder;
+import android.view.Window;
+import android.view.WindowManager;
 import android.view.inputmethod.InputMethodSubtype;
 
 import com.android.inputmethod.deprecated.LanguageSwitcherProxy;
+import com.android.inputmethod.keyboard.KeyboardSwitcher;
 import com.android.inputmethod.latin.SubtypeSwitcher;
 
 public class InputMethodServiceCompatWrapper extends InputMethodService {
@@ -32,10 +37,33 @@ public class InputMethodServiceCompatWrapper extends InputMethodService {
 
     private InputMethodManagerCompatWrapper mImm;
 
+    // For compatibility of {@link InputMethodManager#showInputMethodPicker}.
+    // TODO: Move this variable back to LatinIME when this compatibility wrapper is removed.
+    protected AlertDialog mOptionsDialog;
+
+    public void showOptionDialogInternal(AlertDialog dialog) {
+        final IBinder windowToken = KeyboardSwitcher.getInstance().getKeyboardView()
+                .getWindowToken();
+        if (windowToken == null) return;
+
+        dialog.setCancelable(true);
+        dialog.setCanceledOnTouchOutside(true);
+
+        final Window window = dialog.getWindow();
+        final WindowManager.LayoutParams lp = window.getAttributes();
+        lp.token = windowToken;
+        lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
+        window.setAttributes(lp);
+        window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
+
+        mOptionsDialog = dialog;
+        dialog.show();
+    }
+
     @Override
     public void onCreate() {
         super.onCreate();
-        mImm = InputMethodManagerCompatWrapper.getInstance(this);
+        mImm = InputMethodManagerCompatWrapper.getInstance();
     }
 
     // When the API level is 10 or previous, notifyOnCurrentInputMethodSubtypeChanged should
diff --git a/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatWrapper.java
index 667d86c42096bb27c80798124ca53d1e298f8563..b6b86a4a0848ac29dc0262419a55965f8a33b3ce 100644
--- a/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatWrapper.java
+++ b/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatWrapper.java
@@ -16,13 +16,16 @@
 
 package com.android.inputmethod.compat;
 
-import com.android.inputmethod.latin.LatinImeLogger;
-
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
 import android.text.TextUtils;
 import android.util.Log;
 
+import com.android.inputmethod.latin.LatinImeLogger;
+
 import java.lang.reflect.Method;
 import java.util.Arrays;
+import java.util.Locale;
 
 // TODO: Override this class with the concrete implementation if we need to take care of the
 // performance.
@@ -50,6 +53,9 @@ public final class InputMethodSubtypeCompatWrapper extends AbstractCompatWrapper
             CompatUtils.getMethod(CLASS_InputMethodSubtype, "getExtraValueOf", String.class);
     private static final Method METHOD_isAuxiliary =
             CompatUtils.getMethod(CLASS_InputMethodSubtype, "isAuxiliary");
+    private static final Method METHOD_getDisplayName =
+            CompatUtils.getMethod(CLASS_InputMethodSubtype, "getDisplayName", Context.class,
+                    String.class, ApplicationInfo.class);
 
     private final int mDummyNameResId;
     private final int mDummyIconResId;
@@ -122,6 +128,28 @@ public final class InputMethodSubtypeCompatWrapper extends AbstractCompatWrapper
         return (Boolean)CompatUtils.invoke(mObj, false, METHOD_isAuxiliary);
     }
 
+    public CharSequence getDisplayName(Context context, String packageName,
+            ApplicationInfo appInfo) {
+        if (mObj != null) {
+            return (CharSequence)CompatUtils.invoke(
+                    mObj, "", METHOD_getDisplayName, context, packageName, appInfo);
+        }
+
+        // The code below are based on {@link InputMethodSubtype#getDisplayName}.
+
+        final Locale locale = new Locale(getLocale());
+        final String localeStr = locale.getDisplayName();
+        if (getNameResId() == 0) {
+            return localeStr;
+        }
+        final CharSequence subtypeName = context.getText(getNameResId());
+        if (!TextUtils.isEmpty(localeStr)) {
+            return String.format(subtypeName.toString(), localeStr);
+        } else {
+            return localeStr;
+        }
+    }
+
     public boolean isDummy() {
         return !hasOriginalObject();
     }
diff --git a/java/src/com/android/inputmethod/deprecated/VoiceProxy.java b/java/src/com/android/inputmethod/deprecated/VoiceProxy.java
index 85993ea4dd54638d879a372d5c1ab49f5621db21..c82c570ee718a924424afa99548c88bfbcd28d18 100644
--- a/java/src/com/android/inputmethod/deprecated/VoiceProxy.java
+++ b/java/src/com/android/inputmethod/deprecated/VoiceProxy.java
@@ -129,7 +129,7 @@ public class VoiceProxy implements VoiceInput.UiListener {
         mHandler = h;
         mMinimumVoiceRecognitionViewHeightPixel = Utils.dipToPixel(
                 Utils.getDipScale(service), RECOGNITIONVIEW_MINIMUM_HEIGHT_DIP);
-        mImm = InputMethodManagerCompatWrapper.getInstance(service);
+        mImm = InputMethodManagerCompatWrapper.getInstance();
         mSubtypeSwitcher = SubtypeSwitcher.getInstance();
         if (VOICE_INSTALLED) {
             mVoiceInput = new VoiceInput(service, this);
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 7ad947c67a2375a35c9948da43da46126327d7da..f9593215d73532597ef09b313821dc2824835ffe 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -821,7 +821,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
             if (settingsKeyMode.equals(res.getString(SETTINGS_KEY_MODE_ALWAYS_SHOW))
                     || (settingsKeyMode.equals(res.getString(SETTINGS_KEY_MODE_AUTO))
                             && Utils.hasMultipleEnabledIMEsOrSubtypes(
-                                    (InputMethodManagerCompatWrapper.getInstance(context))))) {
+                                    (InputMethodManagerCompatWrapper.getInstance())))) {
                 return true;
             }
             return false;
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 95cae6ed58f450b8c68ab245973fc1c6c9abeceb..29cf63de4261ff9e11429881825b6875b03683d8 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -29,7 +29,6 @@ import android.inputmethodservice.InputMethodService;
 import android.media.AudioManager;
 import android.net.ConnectivityManager;
 import android.os.Debug;
-import android.os.IBinder;
 import android.os.Message;
 import android.os.SystemClock;
 import android.preference.PreferenceActivity;
@@ -45,8 +44,6 @@ import android.view.KeyEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewParent;
-import android.view.Window;
-import android.view.WindowManager;
 import android.view.inputmethod.CompletionInfo;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.ExtractedText;
@@ -142,8 +139,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
     private Suggest mSuggest;
     private CompletionInfo[] mApplicationSpecifiedCompletions;
 
-    private AlertDialog mOptionsDialog;
-
     private InputMethodManagerCompatWrapper mImm;
     private Resources mResources;
     private SharedPreferences mPrefs;
@@ -361,6 +356,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
         mPrefs = prefs;
         LatinImeLogger.init(this, prefs);
         LanguageSwitcherProxy.init(this, prefs);
+        InputMethodManagerCompatWrapper.init(this);
         SubtypeSwitcher.init(this, prefs);
         KeyboardSwitcher.init(this, prefs);
         Recorrection.init(this, prefs);
@@ -368,7 +364,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
 
         super.onCreate();
 
-        mImm = InputMethodManagerCompatWrapper.getInstance(this);
+        mImm = InputMethodManagerCompatWrapper.getInstance();
         mInputMethodId = Utils.getInputMethodId(mImm, getPackageName());
         mSubtypeSwitcher = SubtypeSwitcher.getInstance();
         mKeyboardSwitcher = KeyboardSwitcher.getInstance();
@@ -2097,7 +2093,12 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
                 }
             }
         };
-        showOptionsMenuInternal(title, items, listener);
+        final AlertDialog.Builder builder = new AlertDialog.Builder(this)
+                .setIcon(R.drawable.ic_dialog_keyboard)
+                .setNegativeButton(android.R.string.cancel, null)
+                .setItems(items, listener)
+                .setTitle(title);
+        showOptionDialogInternal(builder.create());
     }
 
     private void showOptionsMenu() {
@@ -2120,28 +2121,12 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
                 }
             }
         };
-        showOptionsMenuInternal(title, items, listener);
-    }
-
-    private void showOptionsMenuInternal(CharSequence title, CharSequence[] items,
-            DialogInterface.OnClickListener listener) {
-        final IBinder windowToken = mKeyboardSwitcher.getKeyboardView().getWindowToken();
-        if (windowToken == null) return;
-        AlertDialog.Builder builder = new AlertDialog.Builder(this);
-        builder.setCancelable(true);
-        builder.setIcon(R.drawable.ic_dialog_keyboard);
-        builder.setNegativeButton(android.R.string.cancel, null);
-        builder.setItems(items, listener);
-        builder.setTitle(title);
-        mOptionsDialog = builder.create();
-        mOptionsDialog.setCanceledOnTouchOutside(true);
-        Window window = mOptionsDialog.getWindow();
-        WindowManager.LayoutParams lp = window.getAttributes();
-        lp.token = windowToken;
-        lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
-        window.setAttributes(lp);
-        window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
-        mOptionsDialog.show();
+        final AlertDialog.Builder builder = new AlertDialog.Builder(this)
+                .setIcon(R.drawable.ic_dialog_keyboard)
+                .setNegativeButton(android.R.string.cancel, null)
+                .setItems(items, listener)
+                .setTitle(title);
+        showOptionDialogInternal(builder.create());
     }
 
     @Override
diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java
index 33e9bc35f6c11d880a34bb20baa3455725eefbf4..54f0a1b4de5d7c1fb955e8f40c0d1d0a643a5441 100644
--- a/java/src/com/android/inputmethod/latin/Settings.java
+++ b/java/src/com/android/inputmethod/latin/Settings.java
@@ -498,7 +498,7 @@ public class Settings extends InputMethodSettingsActivity
         if (pref == mInputLanguageSelection) {
             startActivity(CompatUtils.getInputLanguageSelectionIntent(
                     Utils.getInputMethodId(
-                            InputMethodManagerCompatWrapper.getInstance(getActivityInternal()),
+                            InputMethodManagerCompatWrapper.getInstance(),
                             getActivityInternal().getApplicationInfo().packageName), 0));
             return true;
         }
diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
index 8fc19ae8745744e4017a979c78494373b9e31319..7f13643ae99f1a8b3683cba5578db89f1e3b0ca9 100644
--- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
+++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
@@ -104,7 +104,7 @@ public class SubtypeSwitcher {
     private void initialize(LatinIME service, SharedPreferences prefs) {
         mService = service;
         mResources = service.getResources();
-        mImm = InputMethodManagerCompatWrapper.getInstance(service);
+        mImm = InputMethodManagerCompatWrapper.getInstance();
         mConnectivityManager = (ConnectivityManager) service.getSystemService(
                 Context.CONNECTIVITY_SERVICE);
         mEnabledKeyboardSubtypesOfCurrentInputMethod.clear();