Use reflections for classes related to InputMethodSubtype

Change-Id: Ica53ce879c2b4c5eb47f757fb788a795a881c30e
diff --git a/java/src/com/android/inputmethod/compat/AbstractCompatWrapper.java b/java/src/com/android/inputmethod/compat/AbstractCompatWrapper.java
new file mode 100644
index 0000000..99262c4
--- /dev/null
+++ b/java/src/com/android/inputmethod/compat/AbstractCompatWrapper.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2011 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.compat;
+
+import android.util.Log;
+
+public abstract class AbstractCompatWrapper {
+    private static final String TAG = AbstractCompatWrapper.class.getSimpleName();
+    protected final Object mObj;
+
+    public AbstractCompatWrapper(Object obj) {
+        if (obj == null) {
+            Log.e(TAG, "Invalid input to AbstructCompatWrapper");
+        }
+        mObj = obj;
+    }
+
+    public Object getOriginalObject() {
+        return mObj;
+    }
+}
diff --git a/java/src/com/android/inputmethod/compat/CompatUtils.java b/java/src/com/android/inputmethod/compat/CompatUtils.java
index e1e812d..1574466 100644
--- a/java/src/com/android/inputmethod/compat/CompatUtils.java
+++ b/java/src/com/android/inputmethod/compat/CompatUtils.java
@@ -18,8 +18,15 @@
 
 import android.content.Intent;
 import android.text.TextUtils;
+import android.util.Log;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
 
 public class CompatUtils {
+    private static final String TAG = CompatUtils.class.getSimpleName();
     private static final String EXTRA_INPUT_METHOD_ID = "input_method_id";
     // TODO: Can these be constants instead of literal String constants?
     private static final String INPUT_METHOD_SUBTYPE_SETTINGS =
@@ -48,4 +55,53 @@
         }
         return intent;
     }
+
+    public static Class<?> getClass(String className) {
+        try {
+            return Class.forName(className);
+        } catch (ClassNotFoundException e) {
+            return null;
+        }
+    }
+
+    public static Method getMethod(Class<?> targetClass, String name,
+            Class<?>... parameterTypes) {
+        try {
+            return targetClass.getMethod(name, parameterTypes);
+        } catch (SecurityException e) {
+            // ignore
+            return null;
+        } catch (NoSuchMethodException e) {
+            // ignore
+            return null;
+        }
+    }
+
+    public static Object invoke(
+            Object receiver, Object defaultValue, Method method, Object... args) {
+        if (receiver == null || method == null) return defaultValue;
+        try {
+            return method.invoke(receiver, args);
+        } catch (IllegalArgumentException e) {
+            Log.e(TAG, "Exception in invoke: IllegalArgmentException");
+            return defaultValue;
+        } catch (IllegalAccessException e) {
+            Log.e(TAG, "Exception in invoke: IllegalAccessException");
+            return defaultValue;
+        } catch (InvocationTargetException e) {
+            Log.e(TAG, "Exception in invoke: IllegalTargetException");
+            return defaultValue;
+        }
+    }
+
+    public static List<InputMethodSubtypeCompatWrapper> copyInputMethodSubtypeListToWrappler(
+            Object listObject) {
+        if (!(listObject instanceof List<?>)) return null;
+        final List<InputMethodSubtypeCompatWrapper> subtypes =
+                new ArrayList<InputMethodSubtypeCompatWrapper>();
+        for (Object o: (List<?>)listObject) {
+            subtypes.add(new InputMethodSubtypeCompatWrapper(o));
+        }
+        return subtypes;
+    }
 }
diff --git a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java
new file mode 100644
index 0000000..648b189
--- /dev/null
+++ b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2011 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.compat;
+
+import android.content.Context;
+import android.os.IBinder;
+import android.util.Log;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodManager;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+// TODO: Override this class with the concrete implementation if we need to take care of the
+// performance.
+public class InputMethodManagerCompatWrapper {
+    private static final String TAG = InputMethodManagerCompatWrapper.class.getSimpleName();
+    private static final Method METHOD_getCurrentInputMethodSubtype =
+            CompatUtils.getMethod(InputMethodManager.class, "getCurrentInputMethodSubtype");
+    private static final Method METHOD_getEnabledInputMethodSubtypeList =
+            CompatUtils.getMethod(InputMethodManager.class, "getEnabledInputMethodSubtypeList",
+                    InputMethodInfo.class, boolean.class);
+    private static final Method METHOD_getShortcutInputMethodsAndSubtypes =
+            CompatUtils.getMethod(InputMethodManager.class, "getShortcutInputMethodsAndSubtypes");
+    private static final Method METHOD_setInputMethodAndSubtype =
+            CompatUtils.getMethod(
+                    InputMethodManager.class, "setInputMethodAndSubtype", IBinder.class,
+                    String.class, InputMethodSubtypeCompatWrapper.CLASS_InputMethodSubtype);
+
+    private static final InputMethodManagerCompatWrapper sInstance =
+            new InputMethodManagerCompatWrapper();
+
+    private InputMethodManager mImm;
+    private InputMethodManagerCompatWrapper() {
+    }
+
+    public static InputMethodManagerCompatWrapper getInstance(Context context) {
+        if (sInstance.mImm == null) {
+            sInstance.init(context);
+        }
+        return sInstance;
+    }
+
+    private synchronized void init(Context context) {
+        mImm = (InputMethodManager) context.getSystemService(
+                Context.INPUT_METHOD_SERVICE);
+    }
+
+    public InputMethodSubtypeCompatWrapper getCurrentInputMethodSubtype() {
+        return new InputMethodSubtypeCompatWrapper(
+                CompatUtils.invoke(mImm, null, METHOD_getCurrentInputMethodSubtype));
+    }
+
+    public List<InputMethodSubtypeCompatWrapper> getEnabledInputMethodSubtypeList(
+            InputMethodInfo imi, boolean allowsImplicitlySelectedSubtypes) {
+        Object retval = CompatUtils.invoke(mImm, null, METHOD_getEnabledInputMethodSubtypeList,
+                imi, allowsImplicitlySelectedSubtypes);
+        return CompatUtils.copyInputMethodSubtypeListToWrappler((List<?>)retval);
+    }
+
+    public Map<InputMethodInfo, List<InputMethodSubtypeCompatWrapper>>
+            getShortcutInputMethodsAndSubtypes() {
+        Object retval = CompatUtils.invoke(mImm, null, METHOD_getShortcutInputMethodsAndSubtypes);
+        if (!(retval instanceof Map)) return null;
+        Map<InputMethodInfo, List<InputMethodSubtypeCompatWrapper>> shortcutMap =
+                new HashMap<InputMethodInfo, List<InputMethodSubtypeCompatWrapper>>();
+        final Map<?, ?> retvalMap = (Map<?, ?>)retval;
+        for (Object key: retvalMap.keySet()) {
+            if (!(key instanceof InputMethodInfo)) {
+                Log.e(TAG, "Class type error.");
+                return null;
+            }
+            shortcutMap.put((InputMethodInfo)key, CompatUtils.copyInputMethodSubtypeListToWrappler(
+                    retvalMap.get(key)));
+        }
+        return shortcutMap;
+    }
+
+    public void setInputMethodAndSubtype(
+            IBinder token, String id, InputMethodSubtypeCompatWrapper subtype) {
+        CompatUtils.invoke(mImm, null, METHOD_setInputMethodAndSubtype,
+                token, id, subtype.getOriginalObject());
+    }
+
+    public boolean switchToLastInputMethod(IBinder token) {
+        if (mImm == null) return false;
+        return mImm.switchToLastInputMethod(token);
+    }
+
+    public List<InputMethodInfo> getEnabledInputMethodList() {
+        if (mImm == null) return null;
+        return mImm.getEnabledInputMethodList();
+    }
+
+    public void showInputMethodPicker() {
+        if (mImm == null) return;
+        mImm.showInputMethodPicker();
+    }
+}
diff --git a/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatWrapper.java
new file mode 100644
index 0000000..ce031ee
--- /dev/null
+++ b/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatWrapper.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2011 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.compat;
+
+import com.android.inputmethod.latin.LatinImeLogger;
+
+import android.util.Log;
+
+import java.lang.reflect.Method;
+
+// TODO: Override this class with the concrete implementation if we need to take care of the
+// performance.
+public final class InputMethodSubtypeCompatWrapper extends AbstractCompatWrapper {
+    private static final boolean DBG = LatinImeLogger.sDBG;
+    private static final String TAG = InputMethodSubtypeCompatWrapper.class.getSimpleName();
+
+    public static final Class<?> CLASS_InputMethodSubtype =
+            CompatUtils.getClass("android.view.inputmethod.InputMethodSubtype");
+    private static final Method METHOD_getNameResId =
+            CompatUtils.getMethod(CLASS_InputMethodSubtype, "getNameResId");
+    private static final Method METHOD_getIconResId =
+            CompatUtils.getMethod(CLASS_InputMethodSubtype, "getIconResId");
+    private static final Method METHOD_getLocale =
+            CompatUtils.getMethod(CLASS_InputMethodSubtype, "getLocale");
+    private static final Method METHOD_getMode =
+            CompatUtils.getMethod(CLASS_InputMethodSubtype, "getMode");
+    private static final Method METHOD_getExtraValue =
+            CompatUtils.getMethod(CLASS_InputMethodSubtype, "getExtraValue");
+    private static final Method METHOD_containsExtraValueKey =
+            CompatUtils.getMethod(CLASS_InputMethodSubtype, "containsExtraValueKey", String.class);
+    private static final Method METHOD_getExtraValueOf =
+            CompatUtils.getMethod(CLASS_InputMethodSubtype, "getExtraValueOf", String.class);
+
+    public InputMethodSubtypeCompatWrapper(Object subtype) {
+        super(CLASS_InputMethodSubtype.isInstance(subtype) ? subtype : null);
+        if (DBG) {
+            Log.d(TAG, "CreateInputMethodSubtypeCompatWrapper");
+        }
+    }
+
+    public int getNameResId() {
+        return (Integer)CompatUtils.invoke(mObj, 0, METHOD_getNameResId);
+    }
+
+    public int getIconResId() {
+        return (Integer)CompatUtils.invoke(mObj, 0, METHOD_getIconResId);
+    }
+
+    public String getLocale() {
+        return (String)CompatUtils.invoke(mObj, null, METHOD_getLocale);
+    }
+
+    public String getMode() {
+        return (String)CompatUtils.invoke(mObj, null, METHOD_getMode);
+    }
+
+    public String getExtraValue() {
+        return (String)CompatUtils.invoke(mObj, null, METHOD_getExtraValue);
+    }
+
+    public boolean containsExtraValueKey(String key) {
+        return (Boolean)CompatUtils.invoke(mObj, null, METHOD_containsExtraValueKey, key);
+    }
+
+    public String getExtraValueOf(String key) {
+        return (String)CompatUtils.invoke(mObj, null, METHOD_getExtraValueOf, key);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o instanceof InputMethodSubtypeCompatWrapper) {
+            InputMethodSubtypeCompatWrapper subtype = (InputMethodSubtypeCompatWrapper)o;
+            return mObj.equals(subtype.getOriginalObject());
+        } else {
+            return mObj.equals(o);
+        }
+    }
+
+}
diff --git a/java/src/com/android/inputmethod/deprecated/VoiceConnector.java b/java/src/com/android/inputmethod/deprecated/VoiceConnector.java
index 7c22609..5c78e9d 100644
--- a/java/src/com/android/inputmethod/deprecated/VoiceConnector.java
+++ b/java/src/com/android/inputmethod/deprecated/VoiceConnector.java
@@ -16,6 +16,7 @@
 
 package com.android.inputmethod.deprecated;
 
+import com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
 import com.android.inputmethod.deprecated.voice.FieldContext;
 import com.android.inputmethod.deprecated.voice.Hints;
 import com.android.inputmethod.deprecated.voice.SettingsUtil;
@@ -60,7 +61,6 @@
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.ExtractedTextRequest;
 import android.view.inputmethod.InputConnection;
-import android.view.inputmethod.InputMethodManager;
 import android.widget.TextView;
 
 import java.util.ArrayList;
@@ -99,7 +99,7 @@
     private boolean mVoiceButtonOnPrimary;
     private boolean mVoiceInputHighlighted;
 
-    private InputMethodManager mImm;
+    private InputMethodManagerCompatWrapper mImm;
     private LatinIME mService;
     private AlertDialog mVoiceWarningDialog;
     private VoiceInput mVoiceInput;
@@ -123,7 +123,7 @@
     private void initInternal(LatinIME service, SharedPreferences prefs, UIHandler h) {
         mService = service;
         mHandler = h;
-        mImm = (InputMethodManager) service.getSystemService(Context.INPUT_METHOD_SERVICE);
+        mImm = InputMethodManagerCompatWrapper.getInstance(service);
         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 64a23ab..cfa3c44 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -16,6 +16,7 @@
 
 package com.android.inputmethod.keyboard;
 
+import com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
 import com.android.inputmethod.latin.LatinIME;
 import com.android.inputmethod.latin.LatinImeLogger;
 import com.android.inputmethod.latin.R;
@@ -29,7 +30,6 @@
 import android.util.Log;
 import android.view.InflateException;
 import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputMethodManager;
 
 import java.lang.ref.SoftReference;
 import java.util.HashMap;
@@ -752,8 +752,7 @@
             if (settingsKeyMode.equals(resources.getString(SETTINGS_KEY_MODE_ALWAYS_SHOW))
                     || (settingsKeyMode.equals(resources.getString(SETTINGS_KEY_MODE_AUTO))
                             && Utils.hasMultipleEnabledIMEsOrSubtypes(
-                                    ((InputMethodManager) context.getSystemService(
-                                            Context.INPUT_METHOD_SERVICE))))) {
+                                    (InputMethodManagerCompatWrapper.getInstance(context))))) {
                 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 297abfc..b34d457 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -17,6 +17,8 @@
 package com.android.inputmethod.latin;
 
 import com.android.inputmethod.compat.CompatUtils;
+import com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
+import com.android.inputmethod.compat.InputMethodSubtypeCompatWrapper;
 import com.android.inputmethod.deprecated.VoiceConnector;
 import com.android.inputmethod.keyboard.Keyboard;
 import com.android.inputmethod.keyboard.KeyboardActionListener;
@@ -67,7 +69,6 @@
 import android.view.inputmethod.ExtractedText;
 import android.view.inputmethod.ExtractedTextRequest;
 import android.view.inputmethod.InputConnection;
-import android.view.inputmethod.InputMethodManager;
 import android.view.inputmethod.InputMethodSubtype;
 import android.widget.FrameLayout;
 import android.widget.HorizontalScrollView;
@@ -147,7 +148,7 @@
 
     private AlertDialog mOptionsDialog;
 
-    private InputMethodManager mImm;
+    private InputMethodManagerCompatWrapper mImm;
     private Resources mResources;
     private SharedPreferences mPrefs;
     private String mInputMethodId;
@@ -380,7 +381,7 @@
 
         super.onCreate();
 
-        mImm = ((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE));
+        mImm = InputMethodManagerCompatWrapper.getInstance(this);
         mInputMethodId = Utils.getInputMethodId(mImm, getPackageName());
         mSubtypeSwitcher = SubtypeSwitcher.getInstance();
         mKeyboardSwitcher = KeyboardSwitcher.getInstance();
@@ -2341,6 +2342,6 @@
 
     @Override
     public void onCurrentInputMethodSubtypeChanged(InputMethodSubtype subtype) {
-        SubtypeSwitcher.getInstance().updateSubtype(subtype);
+        SubtypeSwitcher.getInstance().updateSubtype(new InputMethodSubtypeCompatWrapper(subtype));
     }
 }
diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java
index 873b9ef..7bb1745 100644
--- a/java/src/com/android/inputmethod/latin/Settings.java
+++ b/java/src/com/android/inputmethod/latin/Settings.java
@@ -17,14 +17,13 @@
 package com.android.inputmethod.latin;
 
 import com.android.inputmethod.compat.CompatUtils;
+import com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
 import com.android.inputmethod.deprecated.VoiceConnector;
 
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.app.backup.BackupManager;
-import android.content.Context;
 import android.content.DialogInterface;
-import android.content.Intent;
 import android.content.SharedPreferences;
 import android.os.Bundle;
 import android.os.Vibrator;
@@ -40,7 +39,6 @@
 import android.text.TextUtils;
 import android.text.method.LinkMovementMethod;
 import android.util.Log;
-import android.view.inputmethod.InputMethodManager;
 import android.widget.TextView;
 
 import java.util.Locale;
@@ -225,8 +223,7 @@
     public boolean onPreferenceClick(Preference pref) {
         if (pref == mInputLanguageSelection) {
             startActivity(CompatUtils.getInputLanguageSelectionIntent(
-                    Utils.getInputMethodId(
-                            (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE),
+                    Utils.getInputMethodId(InputMethodManagerCompatWrapper.getInstance(this),
                             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 25e52c6..4bdd015 100644
--- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
+++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
@@ -16,6 +16,8 @@
 
 package com.android.inputmethod.latin;
 
+import com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
+import com.android.inputmethod.compat.InputMethodSubtypeCompatWrapper;
 import com.android.inputmethod.deprecated.VoiceConnector;
 import com.android.inputmethod.keyboard.KeyboardSwitcher;
 import com.android.inputmethod.keyboard.LatinKeyboard;
@@ -33,8 +35,6 @@
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodManager;
-import android.view.inputmethod.InputMethodSubtype;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -57,12 +57,13 @@
     private static final SubtypeSwitcher sInstance = new SubtypeSwitcher();
     private /* final */ LatinIME mService;
     private /* final */ SharedPreferences mPrefs;
-    private /* final */ InputMethodManager mImm;
+    private /* final */ InputMethodManagerCompatWrapper mImm;
     private /* final */ Resources mResources;
     private /* final */ ConnectivityManager mConnectivityManager;
     private /* final */ boolean mConfigUseSpacebarLanguageSwitcher;
-    private final ArrayList<InputMethodSubtype> mEnabledKeyboardSubtypesOfCurrentInputMethod =
-            new ArrayList<InputMethodSubtype>();
+    private final ArrayList<InputMethodSubtypeCompatWrapper>
+            mEnabledKeyboardSubtypesOfCurrentInputMethod =
+                    new ArrayList<InputMethodSubtypeCompatWrapper>();
     private final ArrayList<String> mEnabledLanguagesOfCurrentInputMethod = new ArrayList<String>();
 
     /*-----------------------------------------------------------*/
@@ -70,9 +71,9 @@
     private boolean mNeedsToDisplayLanguage;
     private boolean mIsSystemLanguageSameAsInputLanguage;
     private InputMethodInfo mShortcutInputMethodInfo;
-    private InputMethodSubtype mShortcutSubtype;
-    private List<InputMethodSubtype> mAllEnabledSubtypesOfCurrentInputMethod;
-    private InputMethodSubtype mCurrentSubtype;
+    private InputMethodSubtypeCompatWrapper mShortcutSubtype;
+    private List<InputMethodSubtypeCompatWrapper> mAllEnabledSubtypesOfCurrentInputMethod;
+    private InputMethodSubtypeCompatWrapper mCurrentSubtype;
     private Locale mSystemLocale;
     private Locale mInputLocale;
     private String mInputLocaleStr;
@@ -100,7 +101,7 @@
         mService = service;
         mPrefs = prefs;
         mResources = service.getResources();
-        mImm = (InputMethodManager) service.getSystemService(Context.INPUT_METHOD_SERVICE);
+        mImm = InputMethodManagerCompatWrapper.getInstance(service);
         mConnectivityManager = (ConnectivityManager) service.getSystemService(
                 Context.CONNECTIVITY_SERVICE);
         mEnabledKeyboardSubtypesOfCurrentInputMethod.clear();
@@ -148,7 +149,7 @@
                 null, true);
         mEnabledLanguagesOfCurrentInputMethod.clear();
         mEnabledKeyboardSubtypesOfCurrentInputMethod.clear();
-        for (InputMethodSubtype ims: mAllEnabledSubtypesOfCurrentInputMethod) {
+        for (InputMethodSubtypeCompatWrapper ims: mAllEnabledSubtypesOfCurrentInputMethod) {
             final String locale = ims.getLocale();
             final String mode = ims.getMode();
             mLocaleSplitter.setString(locale);
@@ -182,10 +183,10 @@
                             + ", " + mShortcutSubtype.getMode())));
         }
         // TODO: Update an icon for shortcut IME
-        Map<InputMethodInfo, List<InputMethodSubtype>> shortcuts =
+        Map<InputMethodInfo, List<InputMethodSubtypeCompatWrapper>> shortcuts =
                 mImm.getShortcutInputMethodsAndSubtypes();
         for (InputMethodInfo imi: shortcuts.keySet()) {
-            List<InputMethodSubtype> subtypes = shortcuts.get(imi);
+            List<InputMethodSubtypeCompatWrapper> subtypes = shortcuts.get(imi);
             // TODO: Returns the first found IMI for now. Should handle all shortcuts as
             // appropriate.
             mShortcutInputMethodInfo = imi;
@@ -204,7 +205,7 @@
     }
 
     // Update the current subtype. LatinIME.onCurrentInputMethodSubtypeChanged calls this function.
-    public void updateSubtype(InputMethodSubtype newSubtype) {
+    public void updateSubtype(InputMethodSubtypeCompatWrapper newSubtype) {
         final String newLocale;
         final String newMode;
         final String oldMode = getCurrentSubtypeMode();
@@ -306,7 +307,7 @@
             return;
         }
         final String imiId = mShortcutInputMethodInfo.getId();
-        final InputMethodSubtype subtype = mShortcutSubtype;
+        final InputMethodSubtypeCompatWrapper subtype = mShortcutSubtype;
         new Thread("SwitchToShortcutIME") {
             @Override
             public void run() {
@@ -319,7 +320,7 @@
         return getSubtypeIcon(mShortcutInputMethodInfo, mShortcutSubtype);
     }
 
-    private Drawable getSubtypeIcon(InputMethodInfo imi, InputMethodSubtype subtype) {
+    private Drawable getSubtypeIcon(InputMethodInfo imi, InputMethodSubtypeCompatWrapper subtype) {
         final PackageManager pm = mService.getPackageManager();
         if (imi != null) {
             final String imiPackageName = imi.getPackageName();
@@ -359,8 +360,9 @@
         if (mShortcutSubtype == null)
             return true;
         final boolean allowsImplicitlySelectedSubtypes = true;
-        for (final InputMethodSubtype enabledSubtype : mImm.getEnabledInputMethodSubtypeList(
-                mShortcutInputMethodInfo, allowsImplicitlySelectedSubtypes)) {
+        for (final InputMethodSubtypeCompatWrapper enabledSubtype :
+                mImm.getEnabledInputMethodSubtypeList(
+                        mShortcutInputMethodInfo, allowsImplicitlySelectedSubtypes)) {
             if (enabledSubtype.equals(mShortcutSubtype))
                 return true;
         }
diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java
index e176f76..f48e118 100644
--- a/java/src/com/android/inputmethod/latin/Utils.java
+++ b/java/src/com/android/inputmethod/latin/Utils.java
@@ -16,6 +16,7 @@
 
 package com.android.inputmethod.latin;
 
+import com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
 import com.android.inputmethod.keyboard.KeyboardId;
 
 import android.content.res.Resources;
@@ -29,7 +30,6 @@
 import android.util.Log;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodManager;
 
 import java.io.BufferedReader;
 import java.io.File;
@@ -101,14 +101,14 @@
         }
     }
 
-    public static boolean hasMultipleEnabledIMEsOrSubtypes(InputMethodManager imm) {
+    public static boolean hasMultipleEnabledIMEsOrSubtypes(InputMethodManagerCompatWrapper imm) {
         return imm.getEnabledInputMethodList().size() > 1
         // imm.getEnabledInputMethodSubtypeList(null, false) will return the current IME's enabled
         // input method subtype (The current IME should be LatinIME.)
                 || imm.getEnabledInputMethodSubtypeList(null, false).size() > 1;
     }
 
-    public static String getInputMethodId(InputMethodManager imm, String packageName) {
+    public static String getInputMethodId(InputMethodManagerCompatWrapper imm, String packageName) {
         for (final InputMethodInfo imi : imm.getEnabledInputMethodList()) {
             if (imi.getPackageName().equals(packageName))
                 return imi.getId();