diff options
Diffstat (limited to 'java/src/com/android/inputmethod')
15 files changed, 470 insertions, 303 deletions
diff --git a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java index 80586b753..2b7e25591 100644 --- a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java +++ b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java @@ -16,6 +16,7 @@ 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; @@ -56,6 +57,14 @@ public class InputMethodManagerCompatWrapper { private static final InputMethodManagerCompatWrapper sInstance = new InputMethodManagerCompatWrapper(); + public static final boolean SUBTYPE_SUPPORTED; + + static { + // This static initializer guarantees that METHOD_getShortcutInputMethodsAndSubtypes is + // already instantiated. + SUBTYPE_SUPPORTED = METHOD_getShortcutInputMethodsAndSubtypes != null; + } + // For the compatibility, IMM will create dummy subtypes if subtypes are not found. // This is required to be false if the current behavior is broken. For now, it's ok to be true. private static final boolean ALLOW_DUMMY_SUBTYPE = true; @@ -64,7 +73,9 @@ public class InputMethodManagerCompatWrapper { private static final String KEYBOARD_MODE = "keyboard"; private InputMethodManager mImm; + private LanguageSwitcherProxy mLanguageSwitcherProxy; private String mLatinImePackageName; + private InputMethodManagerCompatWrapper() { } @@ -81,15 +92,30 @@ public class InputMethodManagerCompatWrapper { if (context instanceof LatinIME) { mLatinImePackageName = context.getPackageName(); } + mLanguageSwitcherProxy = LanguageSwitcherProxy.getInstance(); } public InputMethodSubtypeCompatWrapper getCurrentInputMethodSubtype() { + if (!SUBTYPE_SUPPORTED) { + return new InputMethodSubtypeCompatWrapper( + 0, 0, mLanguageSwitcherProxy.getInputLocale().toString(), KEYBOARD_MODE, ""); + } Object o = CompatUtils.invoke(mImm, null, METHOD_getCurrentInputMethodSubtype); return new InputMethodSubtypeCompatWrapper(o); } public List<InputMethodSubtypeCompatWrapper> getEnabledInputMethodSubtypeList( InputMethodInfoCompatWrapper imi, boolean allowsImplicitlySelectedSubtypes) { + if (!SUBTYPE_SUPPORTED) { + String[] languages = mLanguageSwitcherProxy.getEnabledLanguages( + allowsImplicitlySelectedSubtypes); + List<InputMethodSubtypeCompatWrapper> subtypeList = + new ArrayList<InputMethodSubtypeCompatWrapper>(); + for (String lang: languages) { + subtypeList.add(new InputMethodSubtypeCompatWrapper(0, 0, lang, KEYBOARD_MODE, "")); + } + return subtypeList; + } Object retval = CompatUtils.invoke(mImm, null, METHOD_getEnabledInputMethodSubtypeList, (imi != null ? imi.getInputMethodInfo() : null), allowsImplicitlySelectedSubtypes); if (retval == null || !(retval instanceof List) || ((List<?>)retval).isEmpty()) { diff --git a/java/src/com/android/inputmethod/compat/InputMethodServiceCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodServiceCompatWrapper.java index e02aac704..399dcf2dd 100644 --- a/java/src/com/android/inputmethod/compat/InputMethodServiceCompatWrapper.java +++ b/java/src/com/android/inputmethod/compat/InputMethodServiceCompatWrapper.java @@ -16,23 +16,13 @@ package com.android.inputmethod.compat; +import com.android.inputmethod.deprecated.LanguageSwitcherProxy; 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(). @@ -62,17 +52,13 @@ public class InputMethodServiceCompatWrapper extends InputMethodService { subtype = mImm.getCurrentInputMethodSubtype(); } if (subtype != null) { + if (!InputMethodManagerCompatWrapper.SUBTYPE_SUPPORTED) { + LanguageSwitcherProxy.getInstance().setLocale(subtype.getLocale()); + } SubtypeSwitcher.getInstance().updateSubtype(subtype); } } - 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 // ////////////////////////////////////// diff --git a/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatWrapper.java index 317b02216..86c8af37f 100644 --- a/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatWrapper.java +++ b/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatWrapper.java @@ -58,9 +58,6 @@ public final class InputMethodSubtypeCompatWrapper extends AbstractCompatWrapper public InputMethodSubtypeCompatWrapper(Object subtype) { super((CLASS_InputMethodSubtype != null && CLASS_InputMethodSubtype.isInstance(subtype)) ? subtype : null); - if (DBG) { - Log.d(TAG, "CreateInputMethodSubtypeCompatWrapper"); - } mDummyNameResId = 0; mDummyIconResId = 0; mDummyLocale = DEFAULT_LOCALE; diff --git a/java/src/com/android/inputmethod/deprecated/LanguageSwitcherProxy.java b/java/src/com/android/inputmethod/deprecated/LanguageSwitcherProxy.java new file mode 100644 index 000000000..73f0b7a2d --- /dev/null +++ b/java/src/com/android/inputmethod/deprecated/LanguageSwitcherProxy.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2011 Google Inc. + * + * 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.deprecated; + +import com.android.inputmethod.compat.InputMethodManagerCompatWrapper; +import com.android.inputmethod.deprecated.languageswitcher.LanguageSwitcher; +import com.android.inputmethod.latin.LatinIME; +import com.android.inputmethod.latin.Settings; + +import android.content.SharedPreferences; +import android.content.res.Configuration; + +import java.util.Locale; + +// This class is used only when the IME doesn't use method.xml for language switching. +public class LanguageSwitcherProxy implements SharedPreferences.OnSharedPreferenceChangeListener { + private static final LanguageSwitcherProxy sInstance = new LanguageSwitcherProxy(); + private LanguageSwitcher mLanguageSwitcher; + private SharedPreferences mPrefs; + + public static LanguageSwitcherProxy getInstance() { + if (InputMethodManagerCompatWrapper.SUBTYPE_SUPPORTED) return null; + return sInstance; + } + + public static void init(LatinIME service, SharedPreferences prefs) { + if (InputMethodManagerCompatWrapper.SUBTYPE_SUPPORTED) return; + final Configuration conf = service.getResources().getConfiguration(); + sInstance.mLanguageSwitcher = new LanguageSwitcher(service); + sInstance.mLanguageSwitcher.loadLocales(prefs, conf.locale); + sInstance.mPrefs = prefs; + prefs.registerOnSharedPreferenceChangeListener(sInstance); + } + + public static void onConfigurationChanged(Configuration conf) { + if (InputMethodManagerCompatWrapper.SUBTYPE_SUPPORTED) return; + sInstance.mLanguageSwitcher.onConfigurationChanged(conf, sInstance.mPrefs); + } + + public static void loadSettings() { + if (InputMethodManagerCompatWrapper.SUBTYPE_SUPPORTED) return; + sInstance.mLanguageSwitcher.loadLocales(sInstance.mPrefs, null); + } + + public int getLocaleCount() { + return mLanguageSwitcher.getLocaleCount(); + } + + public String[] getEnabledLanguages(boolean allowImplicitlySelectedLanguages) { + return mLanguageSwitcher.getEnabledLanguages(allowImplicitlySelectedLanguages); + } + + public Locale getInputLocale() { + return mLanguageSwitcher.getInputLocale(); + } + + public void setLocale(String localeStr) { + mLanguageSwitcher.setLocale(localeStr); + mLanguageSwitcher.persist(mPrefs); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { + // PREF_SELECTED_LANGUAGES: enabled input subtypes + // PREF_INPUT_LANGUAGE: current input subtype + if (key.equals(Settings.PREF_SELECTED_LANGUAGES) + || key.equals(Settings.PREF_INPUT_LANGUAGE)) { + mLanguageSwitcher.loadLocales(prefs, null); + } + } +} diff --git a/java/src/com/android/inputmethod/latin/LanguageSwitcher.java b/java/src/com/android/inputmethod/deprecated/languageswitcher/LanguageSwitcher.java index 6faf7f95e..e4b2e035c 100644 --- a/java/src/com/android/inputmethod/latin/LanguageSwitcher.java +++ b/java/src/com/android/inputmethod/deprecated/languageswitcher/LanguageSwitcher.java @@ -14,11 +14,19 @@ * the License. */ -package com.android.inputmethod.latin; +package com.android.inputmethod.deprecated.languageswitcher; + +import com.android.inputmethod.compat.InputMethodSubtypeCompatWrapper; +import com.android.inputmethod.latin.LatinIME; +import com.android.inputmethod.latin.LatinImeLogger; +import com.android.inputmethod.latin.Settings; +import com.android.inputmethod.latin.SharedPreferencesCompat; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; +import android.content.res.Configuration; import android.text.TextUtils; +import android.util.Log; import java.util.ArrayList; import java.util.Locale; @@ -28,10 +36,14 @@ import java.util.Locale; * input language that the user has selected. */ public class LanguageSwitcher { + private static final String TAG = LanguageSwitcher.class.getSimpleName(); + + private static final String KEYBOARD_MODE = "keyboard"; + private static final String[] EMPTY_STIRNG_ARRAY = new String[0]; private final ArrayList<Locale> mLocales = new ArrayList<Locale>(); private final LatinIME mIme; - private String[] mSelectedLanguageArray; + private String[] mSelectedLanguageArray = EMPTY_STIRNG_ARRAY; private String mSelectedLanguages; private int mCurrentIndex = 0; private String mDefaultInputLanguage; @@ -46,15 +58,31 @@ public class LanguageSwitcher { return mLocales.size(); } + public void onConfigurationChanged(Configuration conf, SharedPreferences prefs) { + final Locale newLocale = conf.locale; + if (!getSystemLocale().toString().equals(newLocale.toString())) { + loadLocales(prefs, newLocale); + } + } + /** * Loads the currently selected input languages from shared preferences. - * @param sp + * @param sp shared preference for getting the current input language and enabled languages + * @param systemLocale the current system locale, stored for changing the current input language + * based on the system current system locale. * @return whether there was any change */ - public boolean loadLocales(SharedPreferences sp) { + public boolean loadLocales(SharedPreferences sp, Locale systemLocale) { + if (LatinImeLogger.sDBG) { + Log.d(TAG, "load locales"); + } + if (systemLocale != null) { + setSystemLocale(systemLocale); + } String selectedLanguages = sp.getString(Settings.PREF_SELECTED_LANGUAGES, null); String currentLanguage = sp.getString(Settings.PREF_INPUT_LANGUAGE, null); - if (selectedLanguages == null || selectedLanguages.length() < 1) { + if (TextUtils.isEmpty(selectedLanguages)) { + mSelectedLanguageArray = EMPTY_STIRNG_ARRAY; loadDefaults(); if (mLocales.size() == 0) { return false; @@ -84,6 +112,9 @@ public class LanguageSwitcher { } private void loadDefaults() { + if (LatinImeLogger.sDBG) { + Log.d(TAG, "load default locales:"); + } mDefaultInputLocale = mIme.getResources().getConfiguration().locale; String country = mDefaultInputLocale.getCountry(); mDefaultInputLanguage = mDefaultInputLocale.getLanguage() + @@ -112,7 +143,10 @@ public class LanguageSwitcher { /** * Returns the list of enabled language codes. */ - public String[] getEnabledLanguages() { + public String[] getEnabledLanguages(boolean allowImplicitlySelectedLanguages) { + if (mSelectedLanguageArray.length == 0 && allowImplicitlySelectedLanguages) { + return new String[] { mDefaultInputLanguage }; + } return mSelectedLanguageArray; } @@ -151,7 +185,7 @@ public class LanguageSwitcher { * Sets the system locale (display UI) used for comparing with the input language. * @param locale the locale of the system */ - public void setSystemLocale(Locale locale) { + private void setSystemLocale(Locale locale) { mSystemLocale = locale; } @@ -159,7 +193,7 @@ public class LanguageSwitcher { * Returns the system locale. * @return the system locale */ - public Locale getSystemLocale() { + private Locale getSystemLocale() { return mSystemLocale; } @@ -185,6 +219,15 @@ public class LanguageSwitcher { mCurrentIndex = prevLocaleIndex(); } + public void setLocale(String localeStr) { + final int N = mLocales.size(); + for (int i = 0; i < N; ++i) { + if (mLocales.get(i).toString().equals(localeStr)) { + mCurrentIndex = i; + } + } + } + public void persist(SharedPreferences prefs) { Editor editor = prefs.edit(); editor.putString(Settings.PREF_INPUT_LANGUAGE, getInputLanguage()); diff --git a/java/src/com/android/inputmethod/keyboard/KeyDetector.java b/java/src/com/android/inputmethod/keyboard/KeyDetector.java index 1a4f90195..bf0fb9a89 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyDetector.java +++ b/java/src/com/android/inputmethod/keyboard/KeyDetector.java @@ -17,7 +17,6 @@ package com.android.inputmethod.keyboard; import java.util.Arrays; -import java.util.HashMap; import java.util.List; public abstract class KeyDetector { @@ -110,31 +109,4 @@ public abstract class KeyDetector { * @return The nearest key index */ abstract public int getKeyIndexAndNearbyCodes(int x, int y, final int[] allCodes); - - /** - * Compute the most common key width in order to use it as proximity key detection threshold. - * - * @param keyboard The keyboard to compute the most common key width - * @return The most common key width in the keyboard - */ - public static int getMostCommonKeyWidth(final Keyboard keyboard) { - if (keyboard == null) return 0; - final List<Key> keys = keyboard.getKeys(); - if (keys == null || keys.size() == 0) return 0; - final HashMap<Integer, Integer> histogram = new HashMap<Integer, Integer>(); - int maxCount = 0; - int mostCommonWidth = 0; - for (final Key key : keys) { - final Integer width = key.mWidth + key.mGap; - Integer count = histogram.get(width); - if (count == null) - count = 0; - histogram.put(width, ++count); - if (count > maxCount) { - maxCount = count; - mostCommonWidth = width; - } - } - return mostCommonWidth; - } } diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java index f720334f1..9b8d75e8f 100644 --- a/java/src/com/android/inputmethod/keyboard/Keyboard.java +++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java @@ -405,6 +405,29 @@ public class Keyboard { return EMPTY_INT_ARRAY; } + /** + * Compute the most common key width in order to use it as proximity key detection threshold. + * + * @return The most common key width in the keyboard + */ + public int getMostCommonKeyWidth() { + final HashMap<Integer, Integer> histogram = new HashMap<Integer, Integer>(); + int maxCount = 0; + int mostCommonWidth = 0; + for (final Key key : mKeys) { + final Integer width = key.mWidth + key.mGap; + Integer count = histogram.get(width); + if (count == null) + count = 0; + histogram.put(width, ++count); + if (count > maxCount) { + maxCount = count; + mostCommonWidth = width; + } + } + return mostCommonWidth; + } + private void loadKeyboard(Context context, int xmlLayoutResId) { try { KeyboardParser parser = new KeyboardParser(this, context.getResources()); diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index 7b570d7ed..1e19a8ad4 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -45,8 +45,9 @@ import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; -import android.view.ViewGroup.LayoutParams; -import android.view.WindowManager; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.LinearLayout; import android.widget.PopupWindow; import android.widget.TextView; @@ -110,14 +111,12 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { // Key preview popup private boolean mInForeground; private TextView mPreviewText; - private PopupWindow mPreviewPopup; private int mPreviewTextSizeLarge; - private int[] mOffsetInWindow; + private final int[] mOffsetInWindow = new int[2]; private int mOldPreviewKeyIndex = KeyDetector.NOT_A_KEY; private boolean mShowPreview = true; private int mPopupPreviewOffsetX; private int mPopupPreviewOffsetY; - private int mWindowY; private int mPopupPreviewDisplayedY; private final int mDelayBeforePreview; private final int mDelayAfterPreview; @@ -125,7 +124,6 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { // Popup mini keyboard private PopupWindow mMiniKeyboardPopup; private KeyboardView mMiniKeyboardView; - private View mMiniKeyboardParent; private final WeakHashMap<Key, View> mMiniKeyboardCache = new WeakHashMap<Key, View>(); private int mMiniKeyboardOriginX; private int mMiniKeyboardOriginY; @@ -204,7 +202,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { showKey(msg.arg1, (PointerTracker)msg.obj); break; case MSG_DISMISS_PREVIEW: - mPreviewPopup.dismiss(); + mPreviewText.setVisibility(View.INVISIBLE); break; case MSG_REPEAT_KEY: { final PointerTracker tracker = (PointerTracker)msg.obj; @@ -227,12 +225,11 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { public void popupPreview(long delay, int keyIndex, PointerTracker tracker) { removeMessages(MSG_POPUP_PREVIEW); - if (mPreviewPopup.isShowing() && mPreviewText.getVisibility() == VISIBLE) { + if (mPreviewText.getVisibility() == VISIBLE) { // Show right away, if it's already visible and finger is moving around showKey(keyIndex, tracker); } else { - sendMessageDelayed(obtainMessage(MSG_POPUP_PREVIEW, keyIndex, 0, tracker), - delay); + sendMessageDelayed(obtainMessage(MSG_POPUP_PREVIEW, keyIndex, 0, tracker), delay); } } @@ -241,9 +238,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { } public void dismissPreview(long delay) { - if (mPreviewPopup.isShowing()) { - sendMessageDelayed(obtainMessage(MSG_DISMISS_PREVIEW), delay); - } + sendMessageDelayed(obtainMessage(MSG_DISMISS_PREVIEW), delay); } public void cancelDismissPreview() { @@ -366,24 +361,17 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { final Resources res = getResources(); - mPreviewPopup = new PopupWindow(context); if (previewLayout != 0) { mPreviewText = (TextView) LayoutInflater.from(context).inflate(previewLayout, null); mPreviewTextSizeLarge = (int) res.getDimension(R.dimen.key_preview_text_size_large); - mPreviewPopup.setContentView(mPreviewText); - mPreviewPopup.setBackgroundDrawable(null); } else { mShowPreview = false; } - mPreviewPopup.setTouchable(false); - mPreviewPopup.setAnimationStyle(R.style.KeyPreviewAnimation); - mPreviewPopup.setClippingEnabled(false); mDelayBeforePreview = res.getInteger(R.integer.config_delay_before_preview); mDelayAfterPreview = res.getInteger(R.integer.config_delay_after_preview); mKeyLabelHorizontalPadding = (int)res.getDimension( R.dimen.key_label_horizontal_alignment_padding); - mMiniKeyboardParent = this; mMiniKeyboardPopup = new PopupWindow(context); mMiniKeyboardPopup.setBackgroundDrawable(null); mMiniKeyboardPopup.setAnimationStyle(R.style.MiniKeyboardAnimation); @@ -513,7 +501,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { requestLayout(); mKeyboardChanged = true; invalidateAllKeys(); - mKeyDetector.setProximityThreshold(KeyDetector.getMostCommonKeyWidth(keyboard)); + mKeyDetector.setProximityThreshold(keyboard.getMostCommonKeyWidth()); mMiniKeyboardCache.clear(); } @@ -583,7 +571,6 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { public void setPopupOffset(int x, int y) { mPopupPreviewOffsetX = x; mPopupPreviewOffsetY = y; - mPreviewPopup.dismiss(); } /** @@ -915,9 +902,25 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { } } - // TODO Must fix popup preview on xlarge layout + // TODO: Introduce minimum duration for displaying key previews + // TODO: Display up to two key previews when the user presses two keys at the same time private void showKey(final int keyIndex, PointerTracker tracker) { - Key key = tracker.getKey(keyIndex); + // If the preview popup has no parent view yet, add it to the screen FrameLayout. + if (mPreviewText.getParent() == null) { + final FrameLayout screenContent = (FrameLayout) getRootView() + .findViewById(android.R.id.content); + if (android.os.Build.VERSION.SDK_INT >= /* HONEYCOMB */ 11) { + screenContent.addView(mPreviewText, new FrameLayout.LayoutParams(0, 0)); + } else { + // Insert LinearLayout to be able to setMargin because pre-Honeycomb FrameLayout + // could not handle setMargin properly. + final LinearLayout placer = new LinearLayout(getContext()); + screenContent.addView(placer); + placer.addView(mPreviewText, new LinearLayout.LayoutParams(0, 0)); + } + } + + final Key key = tracker.getKey(keyIndex); // If keyIndex is invalid or IME is already closed, we must not show key preview. // Trying to show preview PopupWindow while root window is closed causes // WindowManager.BadTokenException. @@ -948,57 +951,31 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { int popupWidth = Math.max(mPreviewText.getMeasuredWidth(), keyDrawWidth + mPreviewText.getPaddingLeft() + mPreviewText.getPaddingRight()); final int popupHeight = mPreviewHeight; - LayoutParams lp = mPreviewText.getLayoutParams(); - if (lp != null) { - lp.width = popupWidth; - lp.height = popupHeight; - } + final ViewGroup.LayoutParams lp = mPreviewText.getLayoutParams(); + lp.width = popupWidth; + lp.height = popupHeight; int popupPreviewX = keyDrawX - (popupWidth - keyDrawWidth) / 2; int popupPreviewY = key.mY - popupHeight + mPreviewOffset; mHandler.cancelDismissPreview(); - if (mOffsetInWindow == null) { - mOffsetInWindow = new int[2]; - getLocationInWindow(mOffsetInWindow); - mOffsetInWindow[0] += mPopupPreviewOffsetX; // Offset may be zero - mOffsetInWindow[1] += mPopupPreviewOffsetY; // Offset may be zero - int[] windowLocation = new int[2]; - getLocationOnScreen(windowLocation); - mWindowY = windowLocation[1]; - } + getLocationInWindow(mOffsetInWindow); + mOffsetInWindow[0] += mPopupPreviewOffsetX; // Offset may be zero + mOffsetInWindow[1] += mPopupPreviewOffsetY; // Offset may be zero + // Set the preview background state mPreviewText.getBackground().setState( key.mPopupCharacters != null ? LONG_PRESSABLE_STATE_SET : EMPTY_STATE_SET); popupPreviewX += mOffsetInWindow[0]; popupPreviewY += mOffsetInWindow[1]; - // If the popup cannot be shown above the key, put it on the side - if (popupPreviewY + mWindowY < 0) { - // If the key you're pressing is on the left side of the keyboard, show the popup on - // the right, offset by enough to see at least one key to the left/right. - if (keyDrawX + keyDrawWidth <= getWidth() / 2) { - popupPreviewX += (int) (keyDrawWidth * 2.5); - } else { - popupPreviewX -= (int) (keyDrawWidth * 2.5); - } - popupPreviewY += popupHeight; - } - - try { - if (mPreviewPopup.isShowing()) { - mPreviewPopup.update(popupPreviewX, popupPreviewY, popupWidth, popupHeight); - } else { - mPreviewPopup.setWidth(popupWidth); - mPreviewPopup.setHeight(popupHeight); - mPreviewPopup.showAtLocation(mMiniKeyboardParent, Gravity.NO_GRAVITY, - popupPreviewX, popupPreviewY); - } - } catch (WindowManager.BadTokenException e) { - // Swallow the exception which will be happened when IME is already closed. - Log.w(TAG, "LatinIME is already closed when tried showing key preview."); + // Place the key preview. + // TODO: Adjust position of key previews which touch screen edges + if (lp instanceof ViewGroup.MarginLayoutParams) { + ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams)lp; + mlp.setMargins(popupPreviewX, popupPreviewY, 0, 0); } - // Record popup preview position to display mini-keyboard later at the same positon + // Record popup preview position to display mini-keyboard later at the same position mPopupPreviewDisplayedY = popupPreviewY; mPreviewText.setVisibility(VISIBLE); } @@ -1114,7 +1091,6 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { final Keyboard keyboard = new MiniKeyboardBuilder(this, mKeyboard.getPopupKeyboardResId(), popupKey).build(); miniKeyboardView.setKeyboard(keyboard); - miniKeyboardView.mMiniKeyboardParent = this; container.measure(MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.AT_MOST)); @@ -1349,7 +1325,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { } public void closing() { - mPreviewPopup.dismiss(); + mPreviewText.setVisibility(View.GONE); mHandler.cancelAllMessages(); dismissPopupKeyboard(); diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java index 9b87df3fe..9d9793e1e 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java @@ -271,7 +271,7 @@ public class LatinKeyboard extends Keyboard { canvas.drawText(language, width / 2, baseline - descent, paint); // Put arrows that are already layed out on either side of the text - if (SubtypeSwitcher.getInstance().useSpacebarLanguageSwitcher() + if (subtypeSwitcher.useSpacebarLanguageSwitcher() && subtypeSwitcher.getEnabledKeyboardLocaleCount() > 1) { mButtonArrowLeftIcon.draw(canvas); mButtonArrowRightIcon.draw(canvas); diff --git a/java/src/com/android/inputmethod/keyboard/MiniKeyboardBuilder.java b/java/src/com/android/inputmethod/keyboard/MiniKeyboardBuilder.java index 53dab9440..e540fa106 100644 --- a/java/src/com/android/inputmethod/keyboard/MiniKeyboardBuilder.java +++ b/java/src/com/android/inputmethod/keyboard/MiniKeyboardBuilder.java @@ -34,7 +34,7 @@ public class MiniKeyboardBuilder { /* package */ static class MiniKeyboardLayoutParams { public final int mKeyWidth; public final int mRowHeight; - /* package */ final boolean mTopRowNeedsCentering; + /* package */ final int mTopRowAdjustment; public final int mNumRows; public final int mNumColumns; public final int mLeftKeys; @@ -55,29 +55,52 @@ public class MiniKeyboardBuilder { if (parentKeyboardWidth / keyWidth < maxColumns) throw new IllegalArgumentException("Keyboard is too small to hold mini keyboard: " + parentKeyboardWidth + " " + keyWidth + " " + maxColumns); - final int numRows = (numKeys + maxColumns - 1) / maxColumns; mKeyWidth = keyWidth; mRowHeight = rowHeight; - mNumRows = numRows; - final int numColumns = Math.min(numKeys, maxColumns); - final int topRowKeys = numKeys % numColumns; + final int numRows = (numKeys + maxColumns - 1) / maxColumns; + mNumRows = numRows; + final int numColumns = getOptimizedColumns(numKeys, maxColumns); mNumColumns = numColumns; - mTopRowNeedsCentering = topRowKeys != 0 && (numColumns - topRowKeys) % 2 != 0; final int numLeftKeys = (numColumns - 1) / 2; final int numRightKeys = numColumns - numLeftKeys; // including default key. final int maxLeftKeys = coordXInParent / keyWidth; final int maxRightKeys = Math.max(1, (parentKeyboardWidth - coordXInParent) / keyWidth); + int leftKeys, rightKeys; if (numLeftKeys > maxLeftKeys) { - mLeftKeys = maxLeftKeys; - mRightKeys = numColumns - maxLeftKeys; + leftKeys = maxLeftKeys; + rightKeys = numColumns - maxLeftKeys; } else if (numRightKeys > maxRightKeys) { - mLeftKeys = numColumns - maxRightKeys; - mRightKeys = maxRightKeys; + leftKeys = numColumns - maxRightKeys; + rightKeys = maxRightKeys; } else { - mLeftKeys = numLeftKeys; - mRightKeys = numRightKeys; + leftKeys = numLeftKeys; + rightKeys = numRightKeys; + } + // Shift right if the left edge of mini keyboard is on the edge of parent keyboard + // unless the parent key is on the left edge. + if (leftKeys * keyWidth >= coordXInParent && leftKeys > 0) { + leftKeys--; + rightKeys++; + } + // Shift left if the right edge of mini keyboard is on the edge of parent keyboard + // unless the parent key is on the right edge. + if (rightKeys * keyWidth + coordXInParent >= parentKeyboardWidth && rightKeys > 1) { + leftKeys++; + rightKeys--; + } + mLeftKeys = leftKeys; + mRightKeys = rightKeys; + + // Centering of the top row. + final boolean onEdge = (leftKeys == 0 || rightKeys == 1); + if (numRows < 2 || onEdge || getTopRowEmptySlots(numKeys, numColumns) % 2 == 0) { + mTopRowAdjustment = 0; + } else if (mLeftKeys < mRightKeys - 1) { + mTopRowAdjustment = 1; + } else { + mTopRowAdjustment = -1; } } @@ -113,14 +136,32 @@ public class MiniKeyboardBuilder { return pos; } + private static int getTopRowEmptySlots(int numKeys, int numColumns) { + final int remainingKeys = numKeys % numColumns; + if (remainingKeys == 0) { + return 0; + } else { + return numColumns - remainingKeys; + } + } + + private int getOptimizedColumns(int numKeys, int maxColumns) { + int numColumns = Math.min(numKeys, maxColumns); + while (getTopRowEmptySlots(numKeys, numColumns) >= mNumRows) { + numColumns--; + } + return numColumns; + } + public int getDefaultKeyCoordX() { return mLeftKeys * mKeyWidth; } public int getX(int n, int row) { final int x = getColumnPos(n) * mKeyWidth + getDefaultKeyCoordX(); - if (isLastRow(row) && mTopRowNeedsCentering) - return x - mKeyWidth / 2; + if (isTopRow(row)) { + return x + mTopRowAdjustment * (mKeyWidth / 2); + } return x; } @@ -131,27 +172,27 @@ public class MiniKeyboardBuilder { public int getRowFlags(int row) { int rowFlags = 0; if (row == 0) rowFlags |= Keyboard.EDGE_TOP; - if (isLastRow(row)) rowFlags |= Keyboard.EDGE_BOTTOM; + if (isTopRow(row)) rowFlags |= Keyboard.EDGE_BOTTOM; return rowFlags; } - private boolean isLastRow(int rowCount) { + private boolean isTopRow(int rowCount) { return rowCount == mNumRows - 1; } } - public MiniKeyboardBuilder(KeyboardView view, int layoutTemplateResId, Key popupKey) { + public MiniKeyboardBuilder(KeyboardView view, int layoutTemplateResId, Key parentKey) { final Context context = view.getContext(); mRes = context.getResources(); final MiniKeyboard keyboard = new MiniKeyboard(context, layoutTemplateResId, null); mKeyboard = keyboard; - mPopupCharacters = popupKey.mPopupCharacters; + mPopupCharacters = parentKey.mPopupCharacters; final int keyWidth = getMaxKeyWidth(view, mPopupCharacters, keyboard.getKeyWidth()); final MiniKeyboardLayoutParams params = new MiniKeyboardLayoutParams( - mPopupCharacters.length, popupKey.mMaxPopupColumn, + mPopupCharacters.length, parentKey.mMaxPopupColumn, keyWidth, keyboard.getRowHeight(), - popupKey.mX + (popupKey.mWidth + popupKey.mGap) / 2 - keyWidth / 2, + parentKey.mX + (parentKey.mWidth + parentKey.mGap) / 2 - keyWidth / 2, view.getMeasuredWidth()); mParams = params; diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index eb5335ffd..add38cf45 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -549,7 +549,6 @@ public class PointerTracker { final Key key = getKey(keyIndex); if (key != null && !key.mEnabled) return; - updateKeyGraphics(keyIndex); // The modifier key, such as shift key, should not be shown as preview when multi-touch is // supported. On the other hand, if multi-touch is not supported, the modifier key should // be shown as preview. If accessibility is turned on, the modifier key should be shown as @@ -559,6 +558,7 @@ public class PointerTracker { } else { mProxy.showPreview(keyIndex, this); } + updateKeyGraphics(keyIndex); } private void startLongPressTimer(int keyIndex) { diff --git a/java/src/com/android/inputmethod/latin/CandidateView.java b/java/src/com/android/inputmethod/latin/CandidateView.java index 5719b9012..6fb80adf0 100644 --- a/java/src/com/android/inputmethod/latin/CandidateView.java +++ b/java/src/com/android/inputmethod/latin/CandidateView.java @@ -133,7 +133,6 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo ViewGroup.LayoutParams.WRAP_CONTENT); mPreviewPopup.setContentView(mPreviewText); mPreviewPopup.setBackgroundDrawable(null); - mPreviewPopup.setAnimationStyle(R.style.KeyPreviewAnimation); mConfigCandidateHighlightFontColorEnabled = res.getBoolean(R.bool.config_candidate_highlight_font_color_enabled); mColorNormal = res.getColor(R.color.candidate_normal); diff --git a/java/src/com/android/inputmethod/latin/DictionaryPackInstallBroadcastReceiver.java b/java/src/com/android/inputmethod/latin/DictionaryPackInstallBroadcastReceiver.java index c7864621d..9d30af84b 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryPackInstallBroadcastReceiver.java +++ b/java/src/com/android/inputmethod/latin/DictionaryPackInstallBroadcastReceiver.java @@ -30,6 +30,11 @@ import android.net.Uri; public class DictionaryPackInstallBroadcastReceiver extends BroadcastReceiver { final LatinIME mService; + /** + * The action of the intent for publishing that new dictionary data is available. + */ + /* package */ static final String NEW_DICTIONARY_INTENT_ACTION = + "com.android.inputmethod.latin.dictionarypack.newdict"; public DictionaryPackInstallBroadcastReceiver(final LatinIME service) { mService = service; @@ -77,6 +82,8 @@ public class DictionaryPackInstallBroadcastReceiver extends BroadcastReceiver { // TODO: Only reload dictionary on REMOVED when the removed package is the one we // read dictionary from? mService.resetSuggestMainDict(); + } else if (action.equals(NEW_DICTIONARY_INTENT_ACTION)) { + mService.resetSuggestMainDict(); } } } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 6a858fe99..88b3ded8e 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -23,6 +23,7 @@ import com.android.inputmethod.compat.InputMethodManagerCompatWrapper; import com.android.inputmethod.compat.InputMethodServiceCompatWrapper; import com.android.inputmethod.compat.InputTypeCompatUtils; import com.android.inputmethod.compat.VibratorCompatWrapper; +import com.android.inputmethod.deprecated.LanguageSwitcherProxy; import com.android.inputmethod.deprecated.VoiceProxy; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardActionListener; @@ -56,7 +57,6 @@ import android.util.DisplayMetrics; import android.util.Log; import android.util.PrintWriterPrinter; import android.util.Printer; -import android.view.Gravity; import android.view.HapticFeedbackConstants; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -70,8 +70,6 @@ import android.view.inputmethod.EditorInfo; import android.view.inputmethod.ExtractedText; import android.view.inputmethod.ExtractedTextRequest; import android.view.inputmethod.InputConnection; -import android.widget.FrameLayout; -import android.widget.HorizontalScrollView; import android.widget.LinearLayout; import java.io.FileDescriptor; @@ -143,6 +141,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar }; private View mCandidateViewContainer; + private int mCandidateStripHeight; private CandidateView mCandidateView; private Suggest mSuggest; private CompletionInfo[] mApplicationSpecifiedCompletions; @@ -376,6 +375,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); mPrefs = prefs; LatinImeLogger.init(this, prefs); + LanguageSwitcherProxy.init(this, prefs); SubtypeSwitcher.init(this, prefs); KeyboardSwitcher.init(this, prefs); AccessibilityUtils.init(this, prefs); @@ -440,6 +440,11 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); packageFilter.addDataScheme(SCHEME_PACKAGE); registerReceiver(mDictionaryPackInstallReceiver, packageFilter); + + final IntentFilter newDictFilter = new IntentFilter(); + newDictFilter.addAction( + DictionaryPackInstallBroadcastReceiver.NEW_DICTIONARY_INTENT_ACTION); + registerReceiver(mDictionaryPackInstallReceiver, newDictFilter); } private void initSuggest() { @@ -516,6 +521,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar super.onConfigurationChanged(conf); mVoiceProxy.onConfigurationChanged(conf); mConfigurationChanging = false; + + // This will work only when the subtype is not supported. + LanguageSwitcherProxy.onConfigurationChanged(conf); } @Override @@ -528,12 +536,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar LayoutInflater inflater = getLayoutInflater(); LinearLayout container = (LinearLayout)inflater.inflate(R.layout.candidates, null); mCandidateViewContainer = container; - if (container.getPaddingRight() != 0) { - HorizontalScrollView scrollView = - (HorizontalScrollView) container.findViewById(R.id.candidates_scroll_view); - setOverScrollModeNever(scrollView); - container.setGravity(Gravity.CENTER_HORIZONTAL); - } + mCandidateStripHeight = (int)mResources.getDimension(R.dimen.candidate_strip_height); mCandidateView = (CandidateView) container.findViewById(R.id.candidates); mCandidateView.setService(this); setCandidatesViewShown(true); @@ -581,8 +584,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar switcher.updateShiftState(); } - setCandidatesViewShownInternal(isCandidateStripVisible(), - false /* needsInputViewShown */ ); + setCandidatesViewShownInternal(isCandidateStripVisible(), false /* needsInputViewShown */ ); // Delay updating suggestions because keyboard input view may not be shown at this point. mHandler.postUpdateSuggestions(); @@ -872,10 +874,21 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } private void setCandidatesViewShownInternal(boolean shown, boolean needsInputViewShown) { - // TODO: Remove this if we support candidates with hard keyboard + // TODO: Modify this if we support candidates with hard keyboard if (onEvaluateInputViewShown()) { - super.setCandidatesViewShown(shown - && (needsInputViewShown ? mKeyboardSwitcher.isInputViewShown() : true)); + final boolean shouldShowCandidates = shown + && (needsInputViewShown ? mKeyboardSwitcher.isInputViewShown() : true); + if (isExtractViewShown()) { + // No need to have extra space to show the key preview. + mCandidateViewContainer.setMinimumHeight(0); + super.setCandidatesViewShown(shown); + } else { + // We must control the visibility of the suggestion strip in order to avoid clipped + // key previews, even when we don't show the suggestion strip. + mCandidateViewContainer.setVisibility( + shouldShowCandidates ? View.VISIBLE : View.INVISIBLE); + super.setCandidatesViewShown(true); + } } } @@ -887,35 +900,25 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar @Override public void onComputeInsets(InputMethodService.Insets outInsets) { super.onComputeInsets(outInsets); - if (!isFullscreenMode()) { - outInsets.contentTopInsets = outInsets.visibleTopInsets; - } - KeyboardView inputView = mKeyboardSwitcher.getInputView(); + final KeyboardView inputView = mKeyboardSwitcher.getInputView(); // Need to set touchable region only if input view is being shown if (inputView != null && mKeyboardSwitcher.isInputViewShown()) { - final int x = 0; - int y = 0; - final int width = inputView.getWidth(); - int height = inputView.getHeight() + EXTENDED_TOUCHABLE_REGION_HEIGHT; - if (mCandidateViewContainer != null) { - ViewParent candidateParent = mCandidateViewContainer.getParent(); - if (candidateParent instanceof FrameLayout) { - FrameLayout fl = (FrameLayout) candidateParent; - if (fl != null) { - // Check frame layout's visibility - if (fl.getVisibility() == View.INVISIBLE) { - y = fl.getHeight(); - height += y; - } else if (fl.getVisibility() == View.VISIBLE) { - height += fl.getHeight(); - } - } - } + final int containerHeight = mCandidateViewContainer.getHeight(); + int touchY = containerHeight; + if (mCandidateViewContainer.getVisibility() == View.VISIBLE) { + touchY -= mCandidateStripHeight; } + outInsets.contentTopInsets = touchY; + outInsets.visibleTopInsets = touchY; + final int touchWidth = inputView.getWidth(); + final int touchHeight = inputView.getHeight() + containerHeight + // Extend touchable region below the keyboard. + + EXTENDED_TOUCHABLE_REGION_HEIGHT; if (DEBUG) { - Log.d(TAG, "Touchable region " + x + ", " + y + ", " + width + ", " + height); + Log.d(TAG, "Touchable region: y=" + touchY + " width=" + touchWidth + + " height=" + touchHeight); } - setTouchableRegionCompat(outInsets, x, y, width, height); + setTouchableRegionCompat(outInsets, 0, touchY, touchWidth, touchHeight); } } @@ -1155,10 +1158,10 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar onSettingsKeyLongPressed(); break; case Keyboard.CODE_NEXT_LANGUAGE: - toggleLanguage(false, true); + toggleLanguage(true); break; case Keyboard.CODE_PREV_LANGUAGE: - toggleLanguage(false, false); + toggleLanguage(false); break; case Keyboard.CODE_CAPSLOCK: switcher.toggleCapsLock(); @@ -1930,17 +1933,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar return mWord.isFirstCharCapitalized(); } - // Notify that language or mode have been changed and toggleLanguage will update KeyboaredID + // Notify that language or mode have been changed and toggleLanguage will update KeyboardID // according to new language or mode. public void onRefreshKeyboard() { - toggleLanguage(true, true); - } - - // "reset" and "next" are used only for USE_SPACEBAR_LANGUAGE_SWITCHER. - private void toggleLanguage(boolean reset, boolean next) { - if (mSubtypeSwitcher.useSpacebarLanguageSwitcher()) { - mSubtypeSwitcher.toggleLanguage(reset, next); - } // Reload keyboard because the current language has been changed. mKeyboardSwitcher.loadKeyboard(getCurrentInputEditorInfo(), mSubtypeSwitcher.isShortcutImeEnabled() && mVoiceProxy.isVoiceButtonEnabled(), @@ -1949,6 +1944,14 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mKeyboardSwitcher.updateShiftState(); } + // "reset" and "next" are used only for USE_SPACEBAR_LANGUAGE_SWITCHER. + private void toggleLanguage(boolean next) { + if (mSubtypeSwitcher.useSpacebarLanguageSwitcher()) { + mSubtypeSwitcher.toggleLanguage(next); + } + onRefreshKeyboard();// no need?? + } + @Override public void onSwipeDown() { if (mConfigSwipeDownDismissKeyboardEnabled) @@ -2134,7 +2137,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar updateCorrectionMode(); updateAutoTextEnabled(); updateSuggestionVisibility(prefs); - SubtypeSwitcher.getInstance().loadSettings(); + + // This will work only when the subtype is not supported. + LanguageSwitcherProxy.loadSettings(); } /** diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java index 053e2abe4..2cdc4d2cd 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java +++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java @@ -57,7 +57,6 @@ public class SubtypeSwitcher { private static final SubtypeSwitcher sInstance = new SubtypeSwitcher(); private /* final */ LatinIME mService; - private /* final */ SharedPreferences mPrefs; private /* final */ InputMethodManagerCompatWrapper mImm; private /* final */ Resources mResources; private /* final */ ConnectivityManager mConnectivityManager; @@ -66,6 +65,7 @@ public class SubtypeSwitcher { mEnabledKeyboardSubtypesOfCurrentInputMethod = new ArrayList<InputMethodSubtypeCompatWrapper>(); private final ArrayList<String> mEnabledLanguagesOfCurrentInputMethod = new ArrayList<String>(); + private final LanguageBarInfo mLanguageBarInfo = new LanguageBarInfo(); /*-----------------------------------------------------------*/ // Variants which should be changed only by reload functions. @@ -78,6 +78,7 @@ public class SubtypeSwitcher { private Locale mSystemLocale; private Locale mInputLocale; private String mInputLocaleStr; + private String mInputMethodId; private VoiceProxy.VoiceInputWrapper mVoiceInputWrapper; /*-----------------------------------------------------------*/ @@ -100,7 +101,6 @@ public class SubtypeSwitcher { private void initialize(LatinIME service, SharedPreferences prefs) { mService = service; - mPrefs = prefs; mResources = service.getResources(); mImm = InputMethodManagerCompatWrapper.getInstance(service); mConnectivityManager = (ConnectivityManager) service.getSystemService( @@ -114,13 +114,12 @@ public class SubtypeSwitcher { mAllEnabledSubtypesOfCurrentInputMethod = null; // TODO: Voice input should be created here mVoiceInputWrapper = null; - mConfigUseSpacebarLanguageSwitcher = mResources.getBoolean( + mConfigUseSpacebarLanguageSwitcher = service.getResources().getBoolean( R.bool.config_use_spacebar_language_switcher); - if (mConfigUseSpacebarLanguageSwitcher) - initLanguageSwitcher(service); final NetworkInfo info = mConnectivityManager.getActiveNetworkInfo(); mIsNetworkConnected = (info != null && info.isConnected()); + mInputMethodId = Utils.getInputMethodId(mImm, service.getPackageName()); } // Update all parameters stored in SubtypeSwitcher. @@ -134,11 +133,7 @@ public class SubtypeSwitcher { // Update parameters which are changed outside LatinIME. This parameters affect UI so they // should be updated every time onStartInputview. public void updateParametersOnStartInputView() { - if (mConfigUseSpacebarLanguageSwitcher) { - updateForSpacebarLanguageSwitch(); - } else { - updateEnabledSubtypes(); - } + updateEnabledSubtypes(); updateShortcutIME(); } @@ -150,7 +145,7 @@ public class SubtypeSwitcher { null, true); mEnabledLanguagesOfCurrentInputMethod.clear(); mEnabledKeyboardSubtypesOfCurrentInputMethod.clear(); - for (InputMethodSubtypeCompatWrapper ims: mAllEnabledSubtypesOfCurrentInputMethod) { + for (InputMethodSubtypeCompatWrapper ims : mAllEnabledSubtypesOfCurrentInputMethod) { final String locale = ims.getLocale(); final String mode = ims.getMode(); mLocaleSplitter.setString(locale); @@ -172,6 +167,10 @@ public class SubtypeSwitcher { Log.w(TAG, "Last subtype was disabled. Update to the current one."); } updateSubtype(mImm.getCurrentInputMethodSubtype()); + } else { + // mLanguageBarInfo.update() will be called in updateSubtype so there is no need + // to call this in the if-clause above. + mLanguageBarInfo.update(); } } @@ -269,6 +268,7 @@ public class SubtypeSwitcher { mVoiceInputWrapper.reset(); } } + mLanguageBarInfo.update(); } // Update the current input locale from Locale string. @@ -303,12 +303,21 @@ public class SubtypeSwitcher { //////////////////////////// public void switchToShortcutIME() { - final IBinder token = mService.getWindow().getWindow().getAttributes().token; - if (token == null || mShortcutInputMethodInfo == null) { + if (mShortcutInputMethodInfo == null) { return; } + final String imiId = mShortcutInputMethodInfo.getId(); final InputMethodSubtypeCompatWrapper subtype = mShortcutSubtype; + switchToTargetIME(imiId, subtype); + } + + private void switchToTargetIME( + final String imiId, final InputMethodSubtypeCompatWrapper subtype) { + final IBinder token = mService.getWindow().getWindow().getAttributes().token; + if (token == null) { + return; + } new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... params) { @@ -412,11 +421,7 @@ public class SubtypeSwitcher { ////////////////////////////////// public int getEnabledKeyboardLocaleCount() { - if (mConfigUseSpacebarLanguageSwitcher) { - return mLanguageSwitcher.getLocaleCount(); - } else { - return mEnabledKeyboardSubtypesOfCurrentInputMethod.size(); - } + return mEnabledKeyboardSubtypesOfCurrentInputMethod.size(); } public boolean useSpacebarLanguageSwitcher() { @@ -428,74 +433,37 @@ public class SubtypeSwitcher { } public Locale getInputLocale() { - if (mConfigUseSpacebarLanguageSwitcher) { - return mLanguageSwitcher.getInputLocale(); - } else { - return mInputLocale; - } + return mInputLocale; } public String getInputLocaleStr() { - if (mConfigUseSpacebarLanguageSwitcher) { - String inputLanguage = null; - inputLanguage = mLanguageSwitcher.getInputLanguage(); - // Should return system locale if there is no Language available. - if (inputLanguage == null) { - inputLanguage = getSystemLocale().getLanguage(); - } - return inputLanguage; - } else { - return mInputLocaleStr; - } + return mInputLocaleStr; } public String[] getEnabledLanguages() { - if (mConfigUseSpacebarLanguageSwitcher) { - return mLanguageSwitcher.getEnabledLanguages(); - } else { - int enabledLanguageCount = mEnabledLanguagesOfCurrentInputMethod.size(); - // Workaround for explicitly specifying the voice language - if (enabledLanguageCount == 1) { - mEnabledLanguagesOfCurrentInputMethod.add( - mEnabledLanguagesOfCurrentInputMethod.get(0)); - ++enabledLanguageCount; - } - return mEnabledLanguagesOfCurrentInputMethod.toArray( - new String[enabledLanguageCount]); + int enabledLanguageCount = mEnabledLanguagesOfCurrentInputMethod.size(); + // Workaround for explicitly specifying the voice language + if (enabledLanguageCount == 1) { + mEnabledLanguagesOfCurrentInputMethod.add(mEnabledLanguagesOfCurrentInputMethod + .get(0)); + ++enabledLanguageCount; } + return mEnabledLanguagesOfCurrentInputMethod.toArray(new String[enabledLanguageCount]); } public Locale getSystemLocale() { - if (mConfigUseSpacebarLanguageSwitcher) { - return mLanguageSwitcher.getSystemLocale(); - } else { - return mSystemLocale; - } + return mSystemLocale; } public boolean isSystemLanguageSameAsInputLanguage() { - if (mConfigUseSpacebarLanguageSwitcher) { - return getSystemLocale().getLanguage().equalsIgnoreCase( - getInputLocaleStr().substring(0, 2)); - } else { - return mIsSystemLanguageSameAsInputLanguage; - } + return mIsSystemLanguageSameAsInputLanguage; } public void onConfigurationChanged(Configuration conf) { final Locale systemLocale = conf.locale; // If system configuration was changed, update all parameters. if (!TextUtils.equals(systemLocale.toString(), mSystemLocale.toString())) { - if (mConfigUseSpacebarLanguageSwitcher) { - // If the system locale changes and is different from the saved - // locale (mSystemLocale), then reload the input locale list from the - // latin ime settings (shared prefs) and reset the input locale - // to the first one. - mLanguageSwitcher.loadLocales(mPrefs); - mLanguageSwitcher.setSystemLocale(systemLocale); - } else { - updateAllParameters(); - } + updateAllParameters(); } } @@ -554,7 +522,70 @@ public class SubtypeSwitcher { // Spacebar Language Switch support // ////////////////////////////////////// - private LanguageSwitcher mLanguageSwitcher; + private class LanguageBarInfo { + private int mCurrentKeyboardSubtypeIndex; + private InputMethodSubtypeCompatWrapper mNextKeyboardSubtype; + private InputMethodSubtypeCompatWrapper mPreviousKeyboardSubtype; + private String mNextLanguage; + private String mPreviousLanguage; + public LanguageBarInfo() { + update(); + } + + private String getNextLanguage() { + return mNextLanguage; + } + + private String getPreviousLanguage() { + return mPreviousLanguage; + } + + public InputMethodSubtypeCompatWrapper getNextKeyboardSubtype() { + return mNextKeyboardSubtype; + } + + public InputMethodSubtypeCompatWrapper getPreviousKeyboardSubtype() { + return mPreviousKeyboardSubtype; + } + + public void update() { + if (!mConfigUseSpacebarLanguageSwitcher + || mEnabledKeyboardSubtypesOfCurrentInputMethod == null + || mEnabledKeyboardSubtypesOfCurrentInputMethod.size() == 0) return; + mCurrentKeyboardSubtypeIndex = getCurrentIndex(); + mNextKeyboardSubtype = getNextKeyboardSubtypeInternal(mCurrentKeyboardSubtypeIndex); + Locale locale = new Locale(mNextKeyboardSubtype.getLocale()); + mNextLanguage = getDisplayLanguage(locale); + mPreviousKeyboardSubtype = getPreviousKeyboardSubtypeInternal( + mCurrentKeyboardSubtypeIndex); + locale = new Locale(mPreviousKeyboardSubtype.getLocale()); + mPreviousLanguage = getDisplayLanguage(locale); + } + + private int normalize(int index) { + final int N = mEnabledKeyboardSubtypesOfCurrentInputMethod.size(); + final int ret = index % N; + return ret < 0 ? ret + N : ret; + } + + private int getCurrentIndex() { + final int N = mEnabledKeyboardSubtypesOfCurrentInputMethod.size(); + for (int i = 0; i < N; ++i) { + if (mEnabledKeyboardSubtypesOfCurrentInputMethod.get(i).equals(mCurrentSubtype)) { + return i; + } + } + return 0; + } + + private InputMethodSubtypeCompatWrapper getNextKeyboardSubtypeInternal(int index) { + return mEnabledKeyboardSubtypesOfCurrentInputMethod.get(normalize(index + 1)); + } + + private InputMethodSubtypeCompatWrapper getPreviousKeyboardSubtypeInternal(int index) { + return mEnabledKeyboardSubtypesOfCurrentInputMethod.get(normalize(index - 1)); + } + } public static String getFullDisplayName(Locale locale, boolean returnsNameInThisLocale) { if (returnsNameInThisLocale) { @@ -579,32 +610,16 @@ public class SubtypeSwitcher { return Character.toUpperCase(s.charAt(0)) + s.substring(1); } - private void updateForSpacebarLanguageSwitch() { - // We need to update mNeedsToDisplayLanguage in onStartInputView because - // getEnabledKeyboardLocaleCount could have been changed. - mNeedsToDisplayLanguage = !(getEnabledKeyboardLocaleCount() <= 1 - && getSystemLocale().getLanguage().equalsIgnoreCase( - getInputLocale().getLanguage())); - } - public String getInputLanguageName() { return getDisplayLanguage(getInputLocale()); } public String getNextInputLanguageName() { - if (mConfigUseSpacebarLanguageSwitcher) { - return getDisplayLanguage(mLanguageSwitcher.getNextInputLocale()); - } else { - return ""; - } + return mLanguageBarInfo.getNextLanguage(); } public String getPreviousInputLanguageName() { - if (mConfigUseSpacebarLanguageSwitcher) { - return getDisplayLanguage(mLanguageSwitcher.getPrevInputLocale()); - } else { - return ""; - } + return mLanguageBarInfo.getPreviousLanguage(); } ///////////////////////////// @@ -644,31 +659,23 @@ public class SubtypeSwitcher { return voiceInputSupportedLocales.contains(locale); } - public void loadSettings() { - if (mConfigUseSpacebarLanguageSwitcher) { - mLanguageSwitcher.loadLocales(mPrefs); - } + private void changeToNextSubtype() { + final InputMethodSubtypeCompatWrapper subtype = + mLanguageBarInfo.getNextKeyboardSubtype(); + switchToTargetIME(mInputMethodId, subtype); } - public void toggleLanguage(boolean reset, boolean next) { - if (mConfigUseSpacebarLanguageSwitcher) { - if (reset) { - mLanguageSwitcher.reset(); - } else { - if (next) { - mLanguageSwitcher.next(); - } else { - mLanguageSwitcher.prev(); - } - } - mLanguageSwitcher.persist(mPrefs); - } + private void changeToPreviousSubtype() { + final InputMethodSubtypeCompatWrapper subtype = + mLanguageBarInfo.getPreviousKeyboardSubtype(); + switchToTargetIME(mInputMethodId, subtype); } - private void initLanguageSwitcher(LatinIME service) { - final Configuration conf = service.getResources().getConfiguration(); - mLanguageSwitcher = new LanguageSwitcher(service); - mLanguageSwitcher.loadLocales(mPrefs); - mLanguageSwitcher.setSystemLocale(conf.locale); + public void toggleLanguage(boolean next) { + if (next) { + changeToNextSubtype(); + } else { + changeToPreviousSubtype(); + } } } |