From 2cff4d7e4abdb192151f9b4027fc93fe28a8bdaa Mon Sep 17 00:00:00 2001 From: satok Date: Thu, 17 Mar 2011 11:37:51 +0900 Subject: Added CompatUtils for starting a language selector Change-Id: I158414efaff43d0c6abe1f9af83ed3425992dfb9 --- .../android/inputmethod/compat/CompatUtils.java | 51 ++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 java/src/com/android/inputmethod/compat/CompatUtils.java (limited to 'java/src/com/android/inputmethod/compat/CompatUtils.java') diff --git a/java/src/com/android/inputmethod/compat/CompatUtils.java b/java/src/com/android/inputmethod/compat/CompatUtils.java new file mode 100644 index 000000000..e1e812d83 --- /dev/null +++ b/java/src/com/android/inputmethod/compat/CompatUtils.java @@ -0,0 +1,51 @@ +/* + * 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.Intent; +import android.text.TextUtils; + +public class CompatUtils { + 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 = + "android.settings.INPUT_METHOD_SUBTYPE_SETTINGS"; + private static final String INPUT_LANGUAGE_SELECTION = + "com.android.inputmethod.latin.INPUT_LANGUAGE_SELECTION"; + + public static Intent getInputLanguageSelectionIntent(String inputMethodId, + int flagsForSubtypeSettings) { + final String action; + Intent intent; + if (android.os.Build.VERSION.SDK_INT + >= /* android.os.Build.VERSION_CODES.HONEYCOMB */ 11) { + // Refer to android.provider.Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS + action = INPUT_METHOD_SUBTYPE_SETTINGS; + intent = new Intent(action); + if (!TextUtils.isEmpty(inputMethodId)) { + intent.putExtra(EXTRA_INPUT_METHOD_ID, inputMethodId); + } + if (flagsForSubtypeSettings > 0) { + intent.setFlags(flagsForSubtypeSettings); + } + } else { + action = INPUT_LANGUAGE_SELECTION; + intent = new Intent(action); + } + return intent; + } +} -- cgit v1.2.3-83-g751a From 610f1dc8553cf2ed97e763a06a19380c4a6cd636 Mon Sep 17 00:00:00 2001 From: satok Date: Thu, 17 Mar 2011 22:49:06 -0700 Subject: Use reflections for classes related to InputMethodSubtype Change-Id: Ica53ce879c2b4c5eb47f757fb788a795a881c30e --- .../inputmethod/compat/AbstractCompatWrapper.java | 35 +++++++ .../android/inputmethod/compat/CompatUtils.java | 56 ++++++++++ .../compat/InputMethodManagerCompatWrapper.java | 115 +++++++++++++++++++++ .../compat/InputMethodSubtypeCompatWrapper.java | 93 +++++++++++++++++ .../inputmethod/deprecated/VoiceConnector.java | 6 +- .../inputmethod/keyboard/KeyboardSwitcher.java | 5 +- .../com/android/inputmethod/latin/LatinIME.java | 9 +- .../com/android/inputmethod/latin/Settings.java | 7 +- .../android/inputmethod/latin/SubtypeSwitcher.java | 36 ++++--- java/src/com/android/inputmethod/latin/Utils.java | 6 +- 10 files changed, 333 insertions(+), 35 deletions(-) create mode 100644 java/src/com/android/inputmethod/compat/AbstractCompatWrapper.java create mode 100644 java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java create mode 100644 java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatWrapper.java (limited to 'java/src/com/android/inputmethod/compat/CompatUtils.java') 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 000000000..99262c434 --- /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 e1e812d83..157446654 100644 --- a/java/src/com/android/inputmethod/compat/CompatUtils.java +++ b/java/src/com/android/inputmethod/compat/CompatUtils.java @@ -18,8 +18,15 @@ package com.android.inputmethod.compat; 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 @@ public class CompatUtils { } 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 copyInputMethodSubtypeListToWrappler( + Object listObject) { + if (!(listObject instanceof List)) return null; + final List subtypes = + new ArrayList(); + 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 000000000..648b1892b --- /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 getEnabledInputMethodSubtypeList( + InputMethodInfo imi, boolean allowsImplicitlySelectedSubtypes) { + Object retval = CompatUtils.invoke(mImm, null, METHOD_getEnabledInputMethodSubtypeList, + imi, allowsImplicitlySelectedSubtypes); + return CompatUtils.copyInputMethodSubtypeListToWrappler((List)retval); + } + + public Map> + getShortcutInputMethodsAndSubtypes() { + Object retval = CompatUtils.invoke(mImm, null, METHOD_getShortcutInputMethodsAndSubtypes); + if (!(retval instanceof Map)) return null; + Map> shortcutMap = + new HashMap>(); + 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 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 000000000..ce031eea5 --- /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 7c2260985..5c78e9d24 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.WindowManager; 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 @@ public class VoiceConnector implements VoiceInput.UiListener { 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 @@ public class VoiceConnector implements VoiceInput.UiListener { 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 64a23ab92..cfa3c446e 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.content.res.Resources; 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 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha 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 297abfc6d..b34d4575b 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.EditorInfo; 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 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen private AlertDialog mOptionsDialog; - private InputMethodManager mImm; + private InputMethodManagerCompatWrapper mImm; private Resources mResources; private SharedPreferences mPrefs; private String mInputMethodId; @@ -380,7 +381,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen 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 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen @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 873b9efb5..7bb1745fb 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.AutoText; 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 class Settings extends PreferenceActivity 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 25e52c672..4bdd01556 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.os.IBinder; 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 @@ public class SubtypeSwitcher { 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 mEnabledKeyboardSubtypesOfCurrentInputMethod = - new ArrayList(); + private final ArrayList + mEnabledKeyboardSubtypesOfCurrentInputMethod = + new ArrayList(); private final ArrayList mEnabledLanguagesOfCurrentInputMethod = new ArrayList(); /*-----------------------------------------------------------*/ @@ -70,9 +71,9 @@ public class SubtypeSwitcher { private boolean mNeedsToDisplayLanguage; private boolean mIsSystemLanguageSameAsInputLanguage; private InputMethodInfo mShortcutInputMethodInfo; - private InputMethodSubtype mShortcutSubtype; - private List mAllEnabledSubtypesOfCurrentInputMethod; - private InputMethodSubtype mCurrentSubtype; + private InputMethodSubtypeCompatWrapper mShortcutSubtype; + private List mAllEnabledSubtypesOfCurrentInputMethod; + private InputMethodSubtypeCompatWrapper mCurrentSubtype; private Locale mSystemLocale; private Locale mInputLocale; private String mInputLocaleStr; @@ -100,7 +101,7 @@ public class SubtypeSwitcher { 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 @@ public class SubtypeSwitcher { 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 @@ public class SubtypeSwitcher { + ", " + mShortcutSubtype.getMode()))); } // TODO: Update an icon for shortcut IME - Map> shortcuts = + Map> shortcuts = mImm.getShortcutInputMethodsAndSubtypes(); for (InputMethodInfo imi: shortcuts.keySet()) { - List subtypes = shortcuts.get(imi); + List subtypes = shortcuts.get(imi); // TODO: Returns the first found IMI for now. Should handle all shortcuts as // appropriate. mShortcutInputMethodInfo = imi; @@ -204,7 +205,7 @@ public class SubtypeSwitcher { } // 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 @@ public class SubtypeSwitcher { 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 @@ public class SubtypeSwitcher { 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 @@ public class SubtypeSwitcher { 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 e176f76b8..f48e1184b 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.text.format.DateUtils; 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 class Utils { } } - 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(); -- cgit v1.2.3-83-g751a From 10dd34de0ffcde0104f7d2dae3a3c9fd66abffcc Mon Sep 17 00:00:00 2001 From: satok Date: Fri, 18 Mar 2011 21:22:28 -0700 Subject: Add InputMethodServiceCompatWrapper for moving the callback from LatinIME. Change-Id: If6b0180c63738e5e78a20fe5b938ef50d62865d6 --- .../android/inputmethod/compat/CompatUtils.java | 2 +- .../compat/InputMethodManagerCompatWrapper.java | 4 +- .../compat/InputMethodServiceCompatWrapper.java | 65 ++++++++++++++++++++++ .../inputmethod/deprecated/VoiceConnector.java | 15 ++++- .../com/android/inputmethod/latin/LatinIME.java | 11 +--- .../android/inputmethod/latin/SubtypeSwitcher.java | 19 ++++++- 6 files changed, 100 insertions(+), 16 deletions(-) create mode 100644 java/src/com/android/inputmethod/compat/InputMethodServiceCompatWrapper.java (limited to 'java/src/com/android/inputmethod/compat/CompatUtils.java') diff --git a/java/src/com/android/inputmethod/compat/CompatUtils.java b/java/src/com/android/inputmethod/compat/CompatUtils.java index 157446654..fea15fda5 100644 --- a/java/src/com/android/inputmethod/compat/CompatUtils.java +++ b/java/src/com/android/inputmethod/compat/CompatUtils.java @@ -94,7 +94,7 @@ public class CompatUtils { } } - public static List copyInputMethodSubtypeListToWrappler( + public static List copyInputMethodSubtypeListToWrapper( Object listObject) { if (!(listObject instanceof List)) return null; final List subtypes = diff --git a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java index 648b1892b..81cf02c35 100644 --- a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java +++ b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java @@ -71,7 +71,7 @@ public class InputMethodManagerCompatWrapper { InputMethodInfo imi, boolean allowsImplicitlySelectedSubtypes) { Object retval = CompatUtils.invoke(mImm, null, METHOD_getEnabledInputMethodSubtypeList, imi, allowsImplicitlySelectedSubtypes); - return CompatUtils.copyInputMethodSubtypeListToWrappler((List)retval); + return CompatUtils.copyInputMethodSubtypeListToWrapper((List)retval); } public Map> @@ -86,7 +86,7 @@ public class InputMethodManagerCompatWrapper { Log.e(TAG, "Class type error."); return null; } - shortcutMap.put((InputMethodInfo)key, CompatUtils.copyInputMethodSubtypeListToWrappler( + shortcutMap.put((InputMethodInfo)key, CompatUtils.copyInputMethodSubtypeListToWrapper( retvalMap.get(key))); } return shortcutMap; diff --git a/java/src/com/android/inputmethod/compat/InputMethodServiceCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodServiceCompatWrapper.java new file mode 100644 index 000000000..72f3ca0d0 --- /dev/null +++ b/java/src/com/android/inputmethod/compat/InputMethodServiceCompatWrapper.java @@ -0,0 +1,65 @@ +/* + * 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.SubtypeSwitcher; + +import android.inputmethodservice.InputMethodService; +import android.view.inputmethod.InputMethodSubtype; + +public class InputMethodServiceCompatWrapper extends InputMethodService { + // CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED needs to be false if the API level is 10 + // or previous. Note that InputMethodSubtype was added in the API level 11. + // For the API level 11 or later, LatinIME should override onCurrentInputMethodSubtypeChanged(). + // For the API level 10 or previous, we handle the "subtype changed" events by ourselves + // without having support from framework -- onCurrentInputMethodSubtypeChanged(). + private static final boolean CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED = true; + + private InputMethodManagerCompatWrapper mImm; + + @Override + public void onCreate() { + super.onCreate(); + mImm = InputMethodManagerCompatWrapper.getInstance(this); + } + + // When the API level is 10 or previous, notifyOnCurrentInputMethodSubtypeChanged should + // handle the event the current subtype was changed. LatinIME calls + // notifyOnCurrentInputMethodSubtypeChanged every time LatinIME + // changes the current subtype. + // This call is required to let LatinIME itself know a subtype changed + // event when the API level is 10 or previous. + @SuppressWarnings("unused") + public void notifyOnCurrentInputMethodSubtypeChanged(InputMethodSubtypeCompatWrapper subtype) { + // Do nothing when the API level is 11 or later + if (CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED) return; + if (subtype == null) { + subtype = mImm.getCurrentInputMethodSubtype(); + } + if (subtype != null) { + SubtypeSwitcher.getInstance().updateSubtype(subtype); + } + } + + @Override + public void onCurrentInputMethodSubtypeChanged(InputMethodSubtype subtype) { + // Do nothing when the API level is 10 or previous + if (!CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED) return; + SubtypeSwitcher.getInstance().updateSubtype( + new InputMethodSubtypeCompatWrapper(subtype)); + } +} diff --git a/java/src/com/android/inputmethod/deprecated/VoiceConnector.java b/java/src/com/android/inputmethod/deprecated/VoiceConnector.java index 5c78e9d24..a5c307c5b 100644 --- a/java/src/com/android/inputmethod/deprecated/VoiceConnector.java +++ b/java/src/com/android/inputmethod/deprecated/VoiceConnector.java @@ -566,14 +566,24 @@ public class VoiceConnector implements VoiceInput.UiListener { @Override protected void onPostExecute(Boolean result) { + // Calls in this method need to be done in the same thread as the thread which + // called switchToLastInputMethod() if (!result) { if (DEBUG) { Log.d(TAG, "Couldn't switch back to last IME."); } - // Needs to reset here because LatinIME failed to back to any IME and - // the same voice subtype will be triggered in the next time. + // Because the current IME and subtype failed to switch to any other IME and + // subtype by switchToLastInputMethod, the current IME and subtype should keep + // being LatinIME and voice subtype in the next time. And for re-showing voice + // mode, the state of voice input should be reset and the voice view should be + // hidden. mVoiceInput.reset(); mService.requestHideSelf(0); + } else { + // Notify an event that the current subtype was changed. This event will be + // handled if "onCurrentInputMethodSubtypeChanged" can't be implemented + // when the API level is 10 or previous. + mService.notifyOnCurrentInputMethodSubtypeChanged(null); } } }.execute(); @@ -630,6 +640,7 @@ public class VoiceConnector implements VoiceInput.UiListener { } private boolean shouldShowVoiceButton(FieldContext fieldContext, EditorInfo attribute) { + @SuppressWarnings("deprecation") final boolean noMic = Utils.inPrivateImeOptions(null, LatinIME.IME_OPTION_NO_MICROPHONE_COMPAT, attribute) || Utils.inPrivateImeOptions(mService.getPackageName(), diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index b34d4575b..b89fcbfcf 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -18,7 +18,7 @@ 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.compat.InputMethodServiceCompatWrapper; import com.android.inputmethod.deprecated.VoiceConnector; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardActionListener; @@ -69,7 +69,6 @@ import android.view.inputmethod.EditorInfo; import android.view.inputmethod.ExtractedText; import android.view.inputmethod.ExtractedTextRequest; import android.view.inputmethod.InputConnection; -import android.view.inputmethod.InputMethodSubtype; import android.widget.FrameLayout; import android.widget.HorizontalScrollView; import android.widget.LinearLayout; @@ -83,7 +82,7 @@ import java.util.Locale; /** * Input method implementation for Qwerty'ish keyboard. */ -public class LatinIME extends InputMethodService implements KeyboardActionListener { +public class LatinIME extends InputMethodServiceCompatWrapper implements KeyboardActionListener { private static final String TAG = LatinIME.class.getSimpleName(); private static final boolean PERF_DEBUG = false; private static final boolean TRACE = false; @@ -96,6 +95,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen * * @deprecated Use {@link LatinIME#IME_OPTION_NO_MICROPHONE} with package name prefixed. */ + @SuppressWarnings("dep-ann") public static final String IME_OPTION_NO_MICROPHONE_COMPAT = "nm"; /** @@ -2339,9 +2339,4 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen for (int i = 0; i < CPS_BUFFER_SIZE; i++) total += mCpsIntervals[i]; System.out.println("CPS = " + ((CPS_BUFFER_SIZE * 1000f) / total)); } - - @Override - public void onCurrentInputMethodSubtypeChanged(InputMethodSubtype subtype) { - SubtypeSwitcher.getInstance().updateSubtype(new InputMethodSubtypeCompatWrapper(subtype)); - } } diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java index 4bdd01556..d4db7d0f7 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java +++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java @@ -31,6 +31,7 @@ import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.net.ConnectivityManager; import android.net.NetworkInfo; +import android.os.AsyncTask; import android.os.IBinder; import android.text.TextUtils; import android.util.Log; @@ -308,12 +309,24 @@ public class SubtypeSwitcher { } final String imiId = mShortcutInputMethodInfo.getId(); final InputMethodSubtypeCompatWrapper subtype = mShortcutSubtype; - new Thread("SwitchToShortcutIME") { + new AsyncTask() { @Override - public void run() { + protected Void doInBackground(Void... params) { mImm.setInputMethodAndSubtype(token, imiId, subtype); + return null; } - }.start(); + + @Override + protected void onPostExecute(Void result) { + // Calls in this method need to be done in the same thread as the thread which + // called switchToShortcutIME(). + + // Notify an event that the current subtype was changed. This event will be + // handled if "onCurrentInputMethodSubtypeChanged" can't be implemented + // when the API level is 10 or previous. + mService.notifyOnCurrentInputMethodSubtypeChanged(subtype); + } + }.execute(); } public Drawable getShortcutIcon() { -- cgit v1.2.3-83-g751a From 24119dfd414f948b2da214c021cc76e06b3dd41c Mon Sep 17 00:00:00 2001 From: satok Date: Wed, 23 Mar 2011 16:15:07 -0700 Subject: Moved a functionality of setting touchableRegion to InputMethodServiceCompatWrapper. Change-Id: I8b9fe507885ef5ae7cb09db93a977e23b1bbd0db --- .../android/inputmethod/compat/CompatUtils.java | 35 ++++++++++++++++++++++ .../compat/InputMethodServiceCompatWrapper.java | 6 ++++ .../com/android/inputmethod/latin/LatinIME.java | 3 +- 3 files changed, 42 insertions(+), 2 deletions(-) (limited to 'java/src/com/android/inputmethod/compat/CompatUtils.java') diff --git a/java/src/com/android/inputmethod/compat/CompatUtils.java b/java/src/com/android/inputmethod/compat/CompatUtils.java index fea15fda5..8bf59091f 100644 --- a/java/src/com/android/inputmethod/compat/CompatUtils.java +++ b/java/src/com/android/inputmethod/compat/CompatUtils.java @@ -20,6 +20,7 @@ import android.content.Intent; import android.text.TextUtils; import android.util.Log; +import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; @@ -77,6 +78,18 @@ public class CompatUtils { } } + public static Field getField(Class targetClass, String name) { + try { + return targetClass.getField(name); + } catch (SecurityException e) { + // ignore + return null; + } catch (NoSuchFieldException e) { + // ignore + return null; + } + } + public static Object invoke( Object receiver, Object defaultValue, Method method, Object... args) { if (receiver == null || method == null) return defaultValue; @@ -94,6 +107,28 @@ public class CompatUtils { } } + public static Object getFieldValue(Object receiver, Object defaultValue, Field field) { + if (receiver == null || field == null) return defaultValue; + try { + return field.get(receiver); + } catch (IllegalArgumentException e) { + return defaultValue; + } catch (IllegalAccessException e) { + return defaultValue; + } + } + + public static void setFieldValue(Object receiver, Field field, Object value) { + if (receiver == null || field == null) return; + try { + field.set(receiver, value); + } catch (IllegalArgumentException e) { + // ignore + } catch (IllegalAccessException e) { + // ignore + } + } + public static List copyInputMethodSubtypeListToWrapper( Object listObject) { if (!(listObject instanceof List)) return null; diff --git a/java/src/com/android/inputmethod/compat/InputMethodServiceCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodServiceCompatWrapper.java index 72f3ca0d0..606322af7 100644 --- a/java/src/com/android/inputmethod/compat/InputMethodServiceCompatWrapper.java +++ b/java/src/com/android/inputmethod/compat/InputMethodServiceCompatWrapper.java @@ -62,4 +62,10 @@ public class InputMethodServiceCompatWrapper extends InputMethodService { SubtypeSwitcher.getInstance().updateSubtype( new InputMethodSubtypeCompatWrapper(subtype)); } + + protected static void setTouchableRegionCompat(InputMethodService.Insets outInsets, + int x, int y, int width, int height) { + outInsets.touchableInsets = InputMethodService.Insets.TOUCHABLE_INSETS_REGION; + outInsets.touchableRegion.set(x, y, width, height); + } } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index b89fcbfcf..6ae6bd60f 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -914,8 +914,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (DEBUG) { Log.d(TAG, "Touchable region " + x + ", " + y + ", " + width + ", " + height); } - outInsets.touchableInsets = InputMethodService.Insets.TOUCHABLE_INSETS_REGION; - outInsets.touchableRegion.set(x, y, width, height); + setTouchableRegionCompat(outInsets, x, y, width, height); } } -- cgit v1.2.3-83-g751a From a3ef6cde2158b4a76c70070d790959b03ef0e9d1 Mon Sep 17 00:00:00 2001 From: satok Date: Thu, 24 Mar 2011 21:37:21 -0700 Subject: Moved a functionality of setOverScrollMode to InputMethodServiceCompatWrapper Change-Id: Ie473c9fced9f0a8da5643390b44aa4b86128396d --- .../com/android/inputmethod/compat/CompatUtils.java | 8 +++++--- .../compat/InputMethodServiceCompatWrapper.java | 21 +++++++++++++++++++++ .../src/com/android/inputmethod/latin/LatinIME.java | 2 +- 3 files changed, 27 insertions(+), 4 deletions(-) (limited to 'java/src/com/android/inputmethod/compat/CompatUtils.java') diff --git a/java/src/com/android/inputmethod/compat/CompatUtils.java b/java/src/com/android/inputmethod/compat/CompatUtils.java index 8bf59091f..07db4a1bb 100644 --- a/java/src/com/android/inputmethod/compat/CompatUtils.java +++ b/java/src/com/android/inputmethod/compat/CompatUtils.java @@ -96,7 +96,7 @@ public class CompatUtils { try { return method.invoke(receiver, args); } catch (IllegalArgumentException e) { - Log.e(TAG, "Exception in invoke: IllegalArgmentException"); + Log.e(TAG, "Exception in invoke: IllegalArgumentException"); return defaultValue; } catch (IllegalAccessException e) { Log.e(TAG, "Exception in invoke: IllegalAccessException"); @@ -112,8 +112,10 @@ public class CompatUtils { try { return field.get(receiver); } catch (IllegalArgumentException e) { + Log.e(TAG, "Exception in getFieldValue: IllegalArgumentException"); return defaultValue; } catch (IllegalAccessException e) { + Log.e(TAG, "Exception in getFieldValue: IllegalAccessException"); return defaultValue; } } @@ -123,9 +125,9 @@ public class CompatUtils { try { field.set(receiver, value); } catch (IllegalArgumentException e) { - // ignore + Log.e(TAG, "Exception in setFieldValue: IllegalArgumentException"); } catch (IllegalAccessException e) { - // ignore + Log.e(TAG, "Exception in setFieldValue: IllegalAccessException"); } } diff --git a/java/src/com/android/inputmethod/compat/InputMethodServiceCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodServiceCompatWrapper.java index 606322af7..e02aac704 100644 --- a/java/src/com/android/inputmethod/compat/InputMethodServiceCompatWrapper.java +++ b/java/src/com/android/inputmethod/compat/InputMethodServiceCompatWrapper.java @@ -19,9 +19,20 @@ package com.android.inputmethod.compat; import com.android.inputmethod.latin.SubtypeSwitcher; import android.inputmethodservice.InputMethodService; +import android.view.View; import android.view.inputmethod.InputMethodSubtype; +import android.widget.HorizontalScrollView; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; public class InputMethodServiceCompatWrapper extends InputMethodService { + private static final Method METHOD_HorizontalScrollView_setOverScrollMode = + CompatUtils.getMethod(HorizontalScrollView.class, "setOverScrollMode", int.class); + private static final Field FIELD_View_OVER_SCROLL_NEVER = + CompatUtils.getField(View.class, "OVER_SCROLL_NEVER"); + private static final Integer View_OVER_SCROLL_NEVER = + (Integer)CompatUtils.getFieldValue(null, null, FIELD_View_OVER_SCROLL_NEVER); // CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED needs to be false if the API level is 10 // or previous. Note that InputMethodSubtype was added in the API level 11. // For the API level 11 or later, LatinIME should override onCurrentInputMethodSubtypeChanged(). @@ -55,6 +66,16 @@ public class InputMethodServiceCompatWrapper extends InputMethodService { } } + protected static void setOverScrollModeNever(HorizontalScrollView scrollView) { + if (View_OVER_SCROLL_NEVER != null) { + CompatUtils.invoke(scrollView, null, METHOD_HorizontalScrollView_setOverScrollMode, + View_OVER_SCROLL_NEVER); + } + } + + ////////////////////////////////////// + // Functions using API v11 or later // + ////////////////////////////////////// @Override public void onCurrentInputMethodSubtypeChanged(InputMethodSubtype subtype) { // Do nothing when the API level is 10 or previous diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 09a4ead22..4b38e2707 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -530,7 +530,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (container.getPaddingRight() != 0) { HorizontalScrollView scrollView = (HorizontalScrollView) container.findViewById(R.id.candidates_scroll_view); - scrollView.setOverScrollMode(View.OVER_SCROLL_NEVER); + setOverScrollModeNever(scrollView); container.setGravity(Gravity.CENTER_HORIZONTAL); } mCandidateView = (CandidateView) container.findViewById(R.id.candidates); -- cgit v1.2.3-83-g751a From b2707856aba4fc9b063f26305f1fb603b19c1701 Mon Sep 17 00:00:00 2001 From: satok Date: Wed, 23 Mar 2011 23:18:49 -0700 Subject: Added InputConnectionCompatUtils and EditorInfoCompatUtils Change-Id: Ie69d5e90c4ee978d3ecb40b68e6466082569ca7a --- .../android/inputmethod/compat/CompatUtils.java | 14 +++++ .../inputmethod/compat/EditorInfoCompatUtils.java | 59 ++++++++++++++++++++++ .../compat/InputConnectionCompatUtils.java | 58 +++++++++++++++++++++ .../com/android/inputmethod/latin/LatinIME.java | 22 ++++---- 4 files changed, 141 insertions(+), 12 deletions(-) create mode 100644 java/src/com/android/inputmethod/compat/EditorInfoCompatUtils.java create mode 100644 java/src/com/android/inputmethod/compat/InputConnectionCompatUtils.java (limited to 'java/src/com/android/inputmethod/compat/CompatUtils.java') diff --git a/java/src/com/android/inputmethod/compat/CompatUtils.java b/java/src/com/android/inputmethod/compat/CompatUtils.java index 07db4a1bb..a8086919c 100644 --- a/java/src/com/android/inputmethod/compat/CompatUtils.java +++ b/java/src/com/android/inputmethod/compat/CompatUtils.java @@ -20,6 +20,7 @@ import android.content.Intent; import android.text.TextUtils; import android.util.Log; +import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -90,6 +91,19 @@ public class CompatUtils { } } + public static Constructor getConstructor(Class targetClass, Class[] types) { + if (targetClass == null || types == null) return null; + try { + return targetClass.getConstructor(types); + } 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; diff --git a/java/src/com/android/inputmethod/compat/EditorInfoCompatUtils.java b/java/src/com/android/inputmethod/compat/EditorInfoCompatUtils.java new file mode 100644 index 000000000..9d83b5463 --- /dev/null +++ b/java/src/com/android/inputmethod/compat/EditorInfoCompatUtils.java @@ -0,0 +1,59 @@ +/* + * 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.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputConnection; + +import java.lang.reflect.Field; + +public class EditorInfoCompatUtils { + private static final Field FIELD_IME_FLAG_NAVIGATE_NEXT = CompatUtils.getField( + EditorInfo.class, "IME_FLAG_NAVIGATE_NEXT"); + private static final Field FIELD_IME_FLAG_NAVIGATE_PREVIOUS = CompatUtils.getField( + EditorInfo.class, "IME_FLAG_NAVIGATE_PREVIOUS"); + private static final Field FIELD_IME_ACTION_PREVIOUS = CompatUtils.getField( + EditorInfo.class, "IME_FLAG_ACTION_PREVIOUS"); + private static final Integer OBJ_IME_FLAG_NAVIGATE_NEXT = (Integer) CompatUtils + .getFieldValue(null, null, FIELD_IME_FLAG_NAVIGATE_NEXT); + private static final Integer OBJ_IME_FLAG_NAVIGATE_PREVIOUS = (Integer) CompatUtils + .getFieldValue(null, null, FIELD_IME_FLAG_NAVIGATE_PREVIOUS); + private static final Integer OBJ_IME_ACTION_PREVIOUS = (Integer) CompatUtils + .getFieldValue(null, null, FIELD_IME_ACTION_PREVIOUS); + + public static boolean hasFlagNavigateNext(int imeOptions) { + if (OBJ_IME_FLAG_NAVIGATE_NEXT == null) + return false; + return (imeOptions & OBJ_IME_FLAG_NAVIGATE_NEXT) != 0; + } + + public static boolean hasFlagNavigatePrevious(int imeOptions) { + if (OBJ_IME_FLAG_NAVIGATE_PREVIOUS == null) + return false; + return (imeOptions & OBJ_IME_FLAG_NAVIGATE_PREVIOUS) != 0; + } + + public static void performEditorActionNext(InputConnection ic) { + ic.performEditorAction(EditorInfo.IME_ACTION_NEXT); + } + + public static void performEditorActionPrevious(InputConnection ic) { + if (OBJ_IME_ACTION_PREVIOUS == null) + return; + ic.performEditorAction(OBJ_IME_ACTION_PREVIOUS); + } +} diff --git a/java/src/com/android/inputmethod/compat/InputConnectionCompatUtils.java b/java/src/com/android/inputmethod/compat/InputConnectionCompatUtils.java new file mode 100644 index 000000000..b4fe32765 --- /dev/null +++ b/java/src/com/android/inputmethod/compat/InputConnectionCompatUtils.java @@ -0,0 +1,58 @@ +/* + * 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; +import android.view.inputmethod.InputConnection; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class InputConnectionCompatUtils { + private static final String TAG = InputConnectionCompatUtils.class.getSimpleName(); + private static final Class CLASS_CorrectionInfo = CompatUtils + .getClass("android.view.inputmethod.CorrectionInfo"); + private static final Class[] INPUT_TYPE_CorrectionInfo = new Class[] { int.class, + CharSequence.class, CharSequence.class }; + private static final Constructor CONSTRUCTOR_CorrectionInfo = CompatUtils + .getConstructor(CLASS_CorrectionInfo, INPUT_TYPE_CorrectionInfo); + private static final Method METHOD_InputConnection_commitCorrection = CompatUtils + .getMethod(InputConnection.class, "commitCorrection", CLASS_CorrectionInfo); + + public static void commitCorrection(InputConnection ic, int offset, CharSequence oldText, + CharSequence newText) { + if (ic == null || CONSTRUCTOR_CorrectionInfo == null + || METHOD_InputConnection_commitCorrection == null) { + return; + } + Object[] args = { offset, oldText, newText }; + try { + Object correctionInfo = CONSTRUCTOR_CorrectionInfo.newInstance(args); + CompatUtils.invoke(ic, null, METHOD_InputConnection_commitCorrection, + correctionInfo); + } catch (IllegalArgumentException e) { + Log.e(TAG, "Error in commitCorrection: IllegalArgumentException"); + } catch (InstantiationException e) { + Log.e(TAG, "Error in commitCorrection: InstantiationException"); + } catch (IllegalAccessException e) { + Log.e(TAG, "Error in commitCorrection: IllegalAccessException"); + } catch (InvocationTargetException e) { + Log.e(TAG, "Error in commitCorrection: InvocationTargetException"); + } + } +} diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 05169dd9b..c050c834e 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.EditorInfoCompatUtils; +import com.android.inputmethod.compat.InputConnectionCompatUtils; import com.android.inputmethod.compat.InputMethodManagerCompatWrapper; import com.android.inputmethod.compat.InputMethodServiceCompatWrapper; import com.android.inputmethod.deprecated.VoiceProxy; @@ -64,7 +66,6 @@ import android.view.ViewParent; import android.view.Window; import android.view.WindowManager; import android.view.inputmethod.CompletionInfo; -import android.view.inputmethod.CorrectionInfo; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.ExtractedText; import android.view.inputmethod.ExtractedTextRequest; @@ -1267,9 +1268,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private void handleTab() { final int imeOptions = getCurrentInputEditorInfo().imeOptions; - final int navigationFlags = - EditorInfo.IME_FLAG_NAVIGATE_NEXT | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS; - if ((imeOptions & navigationFlags) == 0) { + if (!EditorInfoCompatUtils.hasFlagNavigateNext(imeOptions) + && !EditorInfoCompatUtils.hasFlagNavigatePrevious(imeOptions)) { sendDownUpKeyEvents(KeyEvent.KEYCODE_TAB); return; } @@ -1280,12 +1280,13 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // True if keyboard is in either chording shift or manual temporary upper case mode. final boolean isManualTemporaryUpperCase = mKeyboardSwitcher.isManualTemporaryUpperCase(); - if ((imeOptions & EditorInfo.IME_FLAG_NAVIGATE_NEXT) != 0 + if (EditorInfoCompatUtils.hasFlagNavigateNext(imeOptions) && !isManualTemporaryUpperCase) { + EditorInfoCompatUtils.performEditorActionNext(ic); ic.performEditorAction(EditorInfo.IME_ACTION_NEXT); - } else if ((imeOptions & EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS) != 0 + } else if (EditorInfoCompatUtils.hasFlagNavigatePrevious(imeOptions) && isManualTemporaryUpperCase) { - ic.performEditorAction(EditorInfo.IME_ACTION_PREVIOUS); + EditorInfoCompatUtils.performEditorActionPrevious(ic); } } @@ -1411,11 +1412,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar CharSequence typedWord = mWord.getTypedWord(); TextEntryState.backToAcceptedDefault(typedWord); if (!TextUtils.isEmpty(typedWord) && !typedWord.equals(mBestWord)) { - if (ic != null) { - CorrectionInfo correctionInfo = new CorrectionInfo( - mLastSelectionEnd - typedWord.length(), typedWord, mBestWord); - ic.commitCorrection(correctionInfo); - } + InputConnectionCompatUtils.commitCorrection( + ic, mLastSelectionEnd - typedWord.length(), typedWord, mBestWord); if (mCandidateView != null) mCandidateView.onAutoCorrectionInverted(mBestWord); } -- cgit v1.2.3-83-g751a