Support select input method dialog on pre-HC platform

Bug: 4971680
Change-Id: I641b336da54813e13409bd7874aa22e51f790729
main
Tadashi G. Takaoka 2011-07-17 21:18:47 -07:00
parent fa9f4d1bad
commit bf9d8348d8
10 changed files with 209 additions and 55 deletions

View File

@ -301,6 +301,9 @@
<!-- Title of the dialog for selecting input methods. [CHAR LIMIT=20] --> <!-- Title of the dialog for selecting input methods. [CHAR LIMIT=20] -->
<string name="selectInputMethod">Select input method</string> <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 --> <!-- Title for input language selection screen -->
<string name="language_selection_title">Input languages</string> <string name="language_selection_title">Input languages</string>

View File

@ -16,6 +16,7 @@
package com.android.inputmethod.compat; package com.android.inputmethod.compat;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo; import android.content.pm.ServiceInfo;
import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodInfo;
@ -56,4 +57,21 @@ public class InputMethodInfoCompatWrapper {
return new InputMethodSubtypeCompatWrapper(CompatUtils.invoke(mImi, null, return new InputMethodSubtypeCompatWrapper(CompatUtils.invoke(mImi, null,
METHOD_getSubtypeAt, index)); 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();
}
} }

View File

@ -16,21 +16,28 @@
package com.android.inputmethod.compat; package com.android.inputmethod.compat;
import com.android.inputmethod.deprecated.LanguageSwitcherProxy; import android.app.AlertDialog;
import com.android.inputmethod.latin.LatinIME;
import com.android.inputmethod.latin.SubtypeSwitcher;
import com.android.inputmethod.latin.Utils;
import android.content.Context; 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.os.IBinder;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager; 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.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@ -72,27 +79,27 @@ public class InputMethodManagerCompatWrapper {
private static final String VOICE_MODE = "voice"; private static final String VOICE_MODE = "voice";
private static final String KEYBOARD_MODE = "keyboard"; private static final String KEYBOARD_MODE = "keyboard";
private InputMethodServiceCompatWrapper mService;
private InputMethodManager mImm; private InputMethodManager mImm;
private PackageManager mPackageManager;
private ApplicationInfo mApplicationInfo;
private LanguageSwitcherProxy mLanguageSwitcherProxy; private LanguageSwitcherProxy mLanguageSwitcherProxy;
private String mLatinImePackageName; private String mLatinImePackageName;
private InputMethodManagerCompatWrapper() { public static InputMethodManagerCompatWrapper getInstance() {
} if (sInstance.mImm == null)
Log.w(TAG, "getInstance() is called before initialization");
public static InputMethodManagerCompatWrapper getInstance(Context context) {
if (sInstance.mImm == null) {
sInstance.init(context);
}
return sInstance; return sInstance;
} }
private synchronized void init(Context context) { public static void init(InputMethodServiceCompatWrapper service) {
mImm = (InputMethodManager) context.getSystemService( sInstance.mService = service;
sInstance.mImm = (InputMethodManager) service.getSystemService(
Context.INPUT_METHOD_SERVICE); Context.INPUT_METHOD_SERVICE);
if (context instanceof LatinIME) { sInstance.mLatinImePackageName = service.getPackageName();
mLatinImePackageName = context.getPackageName(); sInstance.mPackageManager = service.getPackageManager();
} sInstance.mApplicationInfo = service.getApplicationInfo();
mLanguageSwitcherProxy = LanguageSwitcherProxy.getInstance(); sInstance.mLanguageSwitcherProxy = LanguageSwitcherProxy.getInstance();
} }
public InputMethodSubtypeCompatWrapper getCurrentInputMethodSubtype() { public InputMethodSubtypeCompatWrapper getCurrentInputMethodSubtype() {
@ -196,11 +203,15 @@ public class InputMethodManagerCompatWrapper {
return shortcutMap; return shortcutMap;
} }
// We don't call this method when we switch between subtypes within this IME.
public void setInputMethodAndSubtype( public void setInputMethodAndSubtype(
IBinder token, String id, InputMethodSubtypeCompatWrapper subtype) { IBinder token, String id, InputMethodSubtypeCompatWrapper subtype) {
// TODO: Support subtype change on non-subtype-supported platform.
if (subtype != null && subtype.hasOriginalObject()) { if (subtype != null && subtype.hasOriginalObject()) {
CompatUtils.invoke(mImm, null, METHOD_setInputMethodAndSubtype, CompatUtils.invoke(mImm, null, METHOD_setInputMethodAndSubtype,
token, id, subtype.getOriginalObject()); token, id, subtype.getOriginalObject());
} else {
mImm.setInputMethod(token, id);
} }
} }
@ -222,6 +233,87 @@ public class InputMethodManagerCompatWrapper {
public void showInputMethodPicker() { public void showInputMethodPicker() {
if (mImm == null) return; if (mImm == null) return;
if (SUBTYPE_SUPPORTED) {
mImm.showInputMethodPicker(); 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());
} }
} }

View File

@ -16,10 +16,15 @@
package com.android.inputmethod.compat; package com.android.inputmethod.compat;
import android.app.AlertDialog;
import android.inputmethodservice.InputMethodService; import android.inputmethodservice.InputMethodService;
import android.os.IBinder;
import android.view.Window;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodSubtype; import android.view.inputmethod.InputMethodSubtype;
import com.android.inputmethod.deprecated.LanguageSwitcherProxy; import com.android.inputmethod.deprecated.LanguageSwitcherProxy;
import com.android.inputmethod.keyboard.KeyboardSwitcher;
import com.android.inputmethod.latin.SubtypeSwitcher; import com.android.inputmethod.latin.SubtypeSwitcher;
public class InputMethodServiceCompatWrapper extends InputMethodService { public class InputMethodServiceCompatWrapper extends InputMethodService {
@ -32,10 +37,33 @@ public class InputMethodServiceCompatWrapper extends InputMethodService {
private InputMethodManagerCompatWrapper mImm; 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 @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
mImm = InputMethodManagerCompatWrapper.getInstance(this); mImm = InputMethodManagerCompatWrapper.getInstance();
} }
// When the API level is 10 or previous, notifyOnCurrentInputMethodSubtypeChanged should // When the API level is 10 or previous, notifyOnCurrentInputMethodSubtypeChanged should

View File

@ -16,13 +16,16 @@
package com.android.inputmethod.compat; 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.text.TextUtils;
import android.util.Log; import android.util.Log;
import com.android.inputmethod.latin.LatinImeLogger;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Arrays; import java.util.Arrays;
import java.util.Locale;
// TODO: Override this class with the concrete implementation if we need to take care of the // TODO: Override this class with the concrete implementation if we need to take care of the
// performance. // performance.
@ -50,6 +53,9 @@ public final class InputMethodSubtypeCompatWrapper extends AbstractCompatWrapper
CompatUtils.getMethod(CLASS_InputMethodSubtype, "getExtraValueOf", String.class); CompatUtils.getMethod(CLASS_InputMethodSubtype, "getExtraValueOf", String.class);
private static final Method METHOD_isAuxiliary = private static final Method METHOD_isAuxiliary =
CompatUtils.getMethod(CLASS_InputMethodSubtype, "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 mDummyNameResId;
private final int mDummyIconResId; private final int mDummyIconResId;
@ -122,6 +128,28 @@ public final class InputMethodSubtypeCompatWrapper extends AbstractCompatWrapper
return (Boolean)CompatUtils.invoke(mObj, false, METHOD_isAuxiliary); 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() { public boolean isDummy() {
return !hasOriginalObject(); return !hasOriginalObject();
} }

View File

@ -129,7 +129,7 @@ public class VoiceProxy implements VoiceInput.UiListener {
mHandler = h; mHandler = h;
mMinimumVoiceRecognitionViewHeightPixel = Utils.dipToPixel( mMinimumVoiceRecognitionViewHeightPixel = Utils.dipToPixel(
Utils.getDipScale(service), RECOGNITIONVIEW_MINIMUM_HEIGHT_DIP); Utils.getDipScale(service), RECOGNITIONVIEW_MINIMUM_HEIGHT_DIP);
mImm = InputMethodManagerCompatWrapper.getInstance(service); mImm = InputMethodManagerCompatWrapper.getInstance();
mSubtypeSwitcher = SubtypeSwitcher.getInstance(); mSubtypeSwitcher = SubtypeSwitcher.getInstance();
if (VOICE_INSTALLED) { if (VOICE_INSTALLED) {
mVoiceInput = new VoiceInput(service, this); mVoiceInput = new VoiceInput(service, this);

View File

@ -822,7 +822,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
if (settingsKeyMode.equals(res.getString(SETTINGS_KEY_MODE_ALWAYS_SHOW)) if (settingsKeyMode.equals(res.getString(SETTINGS_KEY_MODE_ALWAYS_SHOW))
|| (settingsKeyMode.equals(res.getString(SETTINGS_KEY_MODE_AUTO)) || (settingsKeyMode.equals(res.getString(SETTINGS_KEY_MODE_AUTO))
&& Utils.hasMultipleEnabledIMEsOrSubtypes( && Utils.hasMultipleEnabledIMEsOrSubtypes(
(InputMethodManagerCompatWrapper.getInstance(context))))) { (InputMethodManagerCompatWrapper.getInstance())))) {
return true; return true;
} }
return false; return false;

View File

@ -29,7 +29,6 @@ import android.inputmethodservice.InputMethodService;
import android.media.AudioManager; import android.media.AudioManager;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.os.Debug; import android.os.Debug;
import android.os.IBinder;
import android.os.Message; import android.os.Message;
import android.os.SystemClock; import android.os.SystemClock;
import android.preference.PreferenceActivity; import android.preference.PreferenceActivity;
@ -45,8 +44,6 @@ import android.view.KeyEvent;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewParent; import android.view.ViewParent;
import android.view.Window;
import android.view.WindowManager;
import android.view.inputmethod.CompletionInfo; import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.EditorInfo; import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.ExtractedText; import android.view.inputmethod.ExtractedText;
@ -142,8 +139,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
private Suggest mSuggest; private Suggest mSuggest;
private CompletionInfo[] mApplicationSpecifiedCompletions; private CompletionInfo[] mApplicationSpecifiedCompletions;
private AlertDialog mOptionsDialog;
private InputMethodManagerCompatWrapper mImm; private InputMethodManagerCompatWrapper mImm;
private Resources mResources; private Resources mResources;
private SharedPreferences mPrefs; private SharedPreferences mPrefs;
@ -361,6 +356,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
mPrefs = prefs; mPrefs = prefs;
LatinImeLogger.init(this, prefs); LatinImeLogger.init(this, prefs);
LanguageSwitcherProxy.init(this, prefs); LanguageSwitcherProxy.init(this, prefs);
InputMethodManagerCompatWrapper.init(this);
SubtypeSwitcher.init(this, prefs); SubtypeSwitcher.init(this, prefs);
KeyboardSwitcher.init(this, prefs); KeyboardSwitcher.init(this, prefs);
Recorrection.init(this, prefs); Recorrection.init(this, prefs);
@ -368,7 +364,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
super.onCreate(); super.onCreate();
mImm = InputMethodManagerCompatWrapper.getInstance(this); mImm = InputMethodManagerCompatWrapper.getInstance();
mInputMethodId = Utils.getInputMethodId(mImm, getPackageName()); mInputMethodId = Utils.getInputMethodId(mImm, getPackageName());
mSubtypeSwitcher = SubtypeSwitcher.getInstance(); mSubtypeSwitcher = SubtypeSwitcher.getInstance();
mKeyboardSwitcher = KeyboardSwitcher.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() { private void showOptionsMenu() {
@ -2099,28 +2100,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)
private void showOptionsMenuInternal(CharSequence title, CharSequence[] items, .setItems(items, listener)
DialogInterface.OnClickListener listener) { .setTitle(title);
final IBinder windowToken = mKeyboardSwitcher.getKeyboardView().getWindowToken(); showOptionDialogInternal(builder.create());
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();
} }
@Override @Override

View File

@ -498,7 +498,7 @@ public class Settings extends InputMethodSettingsActivity
if (pref == mInputLanguageSelection) { if (pref == mInputLanguageSelection) {
startActivity(CompatUtils.getInputLanguageSelectionIntent( startActivity(CompatUtils.getInputLanguageSelectionIntent(
Utils.getInputMethodId( Utils.getInputMethodId(
InputMethodManagerCompatWrapper.getInstance(getActivityInternal()), InputMethodManagerCompatWrapper.getInstance(),
getActivityInternal().getApplicationInfo().packageName), 0)); getActivityInternal().getApplicationInfo().packageName), 0));
return true; return true;
} }

View File

@ -104,7 +104,7 @@ public class SubtypeSwitcher {
private void initialize(LatinIME service, SharedPreferences prefs) { private void initialize(LatinIME service, SharedPreferences prefs) {
mService = service; mService = service;
mResources = service.getResources(); mResources = service.getResources();
mImm = InputMethodManagerCompatWrapper.getInstance(service); mImm = InputMethodManagerCompatWrapper.getInstance();
mConnectivityManager = (ConnectivityManager) service.getSystemService( mConnectivityManager = (ConnectivityManager) service.getSystemService(
Context.CONNECTIVITY_SERVICE); Context.CONNECTIVITY_SERVICE);
mEnabledKeyboardSubtypesOfCurrentInputMethod.clear(); mEnabledKeyboardSubtypesOfCurrentInputMethod.clear();