diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml
index 739f72f36..63663028f 100644
--- a/java/res/values/strings.xml
+++ b/java/res/values/strings.xml
@@ -301,6 +301,9 @@
Select input method
+
+ Configure input methods
+
Input languages
diff --git a/java/src/com/android/inputmethod/compat/InputMethodInfoCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodInfoCompatWrapper.java
index 8e22bbc79..831559809 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 1cc13f249..51dc4cd37 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 myImsList = getEnabledInputMethodSubtypeList(
+ myImi, true);
+ final InputMethodSubtypeCompatWrapper currentIms = getCurrentInputMethodSubtype();
+ final List imiList = getEnabledInputMethodList();
+ imiList.remove(myImi);
+ Collections.sort(imiList, new Comparator() {
+ @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 7d8c745c3..7aab66d05 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 667d86c42..b6b86a4a0 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 85993ea4d..c82c570ee 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 bb21d7a63..448274ec6 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -822,7 +822,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 248f4ddf2..a820a40e3 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();
@@ -2076,7 +2072,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() {
@@ -2099,28 +2100,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 33e9bc35f..54f0a1b4d 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 8fc19ae87..7f13643ae 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();