diff options
Diffstat (limited to 'java/src')
17 files changed, 254 insertions, 65 deletions
diff --git a/java/src/com/android/inputmethod/compat/AbstractCompatWrapper.java b/java/src/com/android/inputmethod/compat/AbstractCompatWrapper.java index 65949357f..2c31c55b0 100644 --- a/java/src/com/android/inputmethod/compat/AbstractCompatWrapper.java +++ b/java/src/com/android/inputmethod/compat/AbstractCompatWrapper.java @@ -24,7 +24,7 @@ public abstract class AbstractCompatWrapper { public AbstractCompatWrapper(Object obj) { if (obj == null) { - Log.e(TAG, "Invalid input to AbstructCompatWrapper"); + Log.e(TAG, "Invalid input to AbstractCompatWrapper"); } mObj = obj; } diff --git a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java index 7e216e5c8..9dd0a599d 100644 --- a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java +++ b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java @@ -49,6 +49,8 @@ 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_getLastInputMethodSubtype = + CompatUtils.getMethod(InputMethodManager.class, "getLastInputMethodSubtype"); private static final Method METHOD_getEnabledInputMethodSubtypeList = CompatUtils.getMethod(InputMethodManager.class, "getEnabledInputMethodSubtypeList", InputMethodInfo.class, boolean.class); @@ -60,6 +62,8 @@ public class InputMethodManagerCompatWrapper { String.class, InputMethodSubtypeCompatWrapper.CLASS_InputMethodSubtype); private static final Method METHOD_switchToLastInputMethod = CompatUtils.getMethod( InputMethodManager.class, "switchToLastInputMethod", IBinder.class); + private static final Method METHOD_switchToNextInputMethod = CompatUtils.getMethod( + InputMethodManager.class, "switchToNextInputMethod", IBinder.class, Boolean.TYPE); private static final InputMethodManagerCompatWrapper sInstance = new InputMethodManagerCompatWrapper(); @@ -111,6 +115,15 @@ public class InputMethodManagerCompatWrapper { return new InputMethodSubtypeCompatWrapper(o); } + public InputMethodSubtypeCompatWrapper getLastInputMethodSubtype() { + if (!SUBTYPE_SUPPORTED) { + return new InputMethodSubtypeCompatWrapper( + 0, 0, mLanguageSwitcherProxy.getInputLocale().toString(), KEYBOARD_MODE, ""); + } + Object o = CompatUtils.invoke(mImm, null, METHOD_getLastInputMethodSubtype); + return new InputMethodSubtypeCompatWrapper(o); + } + public List<InputMethodSubtypeCompatWrapper> getEnabledInputMethodSubtypeList( InputMethodInfoCompatWrapper imi, boolean allowsImplicitlySelectedSubtypes) { if (!SUBTYPE_SUPPORTED) { @@ -221,6 +234,14 @@ public class InputMethodManagerCompatWrapper { return (Boolean)CompatUtils.invoke(mImm, false, METHOD_switchToLastInputMethod, token); } + public boolean switchToNextInputMethod(IBinder token, boolean onlyCurrentIme) { + if (SubtypeSwitcher.getInstance().isDummyVoiceMode()) { + return true; + } + return (Boolean)CompatUtils.invoke(mImm, false, METHOD_switchToNextInputMethod, token, + onlyCurrentIme); + } + public List<InputMethodInfoCompatWrapper> getEnabledInputMethodList() { if (mImm == null) return null; List<InputMethodInfoCompatWrapper> imis = new ArrayList<InputMethodInfoCompatWrapper>(); diff --git a/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatWrapper.java index a6bb83adf..574158825 100644 --- a/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatWrapper.java +++ b/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatWrapper.java @@ -29,7 +29,7 @@ import java.util.Locale; // TODO: Override this class with the concrete implementation if we need to take care of the // performance. -public final class InputMethodSubtypeCompatWrapper extends AbstractCompatWrapper { +public class InputMethodSubtypeCompatWrapper extends AbstractCompatWrapper { private static final boolean DBG = LatinImeLogger.sDBG; private static final String TAG = InputMethodSubtypeCompatWrapper.class.getSimpleName(); private static final String DEFAULT_LOCALE = "en_US"; @@ -65,7 +65,7 @@ public final class InputMethodSubtypeCompatWrapper extends AbstractCompatWrapper public InputMethodSubtypeCompatWrapper(Object subtype) { super((CLASS_InputMethodSubtype != null && CLASS_InputMethodSubtype.isInstance(subtype)) - ? subtype : null); + ? subtype : new Object()); mDummyNameResId = 0; mDummyIconResId = 0; mDummyLocale = DEFAULT_LOCALE; @@ -76,7 +76,7 @@ public final class InputMethodSubtypeCompatWrapper extends AbstractCompatWrapper // Constructor for creating a dummy subtype. public InputMethodSubtypeCompatWrapper(int nameResId, int iconResId, String locale, String mode, String extraValues) { - super(null); + super(new Object()); if (DBG) { Log.d(TAG, "CreateInputMethodSubtypeCompatWrapper"); } diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java index 79c7ce0fd..f3923834b 100644 --- a/java/src/com/android/inputmethod/keyboard/Key.java +++ b/java/src/com/android/inputmethod/keyboard/Key.java @@ -108,8 +108,8 @@ public class Key { private static final int MORE_KEYS_COLUMN_MASK = 0x000000ff; private static final int MORE_KEYS_FLAGS_FIXED_COLUMN_ORDER = 0x80000000; private static final int MORE_KEYS_FLAGS_HAS_LABELS = 0x40000000; - private static final int MORE_KEYS_FLAGS_NEEDS_DIVIDERS = 0x40000000; - private static final int MORE_KEYS_FLAGS_EMBEDDED_MORE_KEY = 0x20000000; + private static final int MORE_KEYS_FLAGS_NEEDS_DIVIDERS = 0x20000000; + private static final int MORE_KEYS_FLAGS_EMBEDDED_MORE_KEY = 0x10000000; private static final String MORE_KEYS_AUTO_COLUMN_ORDER = "!autoColumnOrder!"; private static final String MORE_KEYS_FIXED_COLUMN_ORDER = "!fixedColumnOrder!"; private static final String MORE_KEYS_HAS_LABELS = "!hasLabels!"; diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java index c6cdf7986..320b1bea2 100644 --- a/java/src/com/android/inputmethod/keyboard/Keyboard.java +++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java @@ -99,8 +99,9 @@ public class Keyboard { public static final int CODE_ACTION_ENTER = -7; public static final int CODE_ACTION_NEXT = -8; public static final int CODE_ACTION_PREVIOUS = -9; + public static final int CODE_LANGUAGE_SWITCH = -10; // Code value representing the code is not specified. - public static final int CODE_UNSPECIFIED = -10; + public static final int CODE_UNSPECIFIED = -11; public final KeyboardId mId; public final int mThemeId; @@ -387,6 +388,7 @@ public class Keyboard { } } + // TODO: Move this method to KeyboardSwitcher. public static String toThemeName(int themeId) { // This should be aligned with theme-*.xml resource files' themeId attribute. switch (themeId) { @@ -1076,6 +1078,9 @@ public class Keyboard { R.styleable.Keyboard_Case_shortcutKeyEnabled, id.mShortcutKeyEnabled); final boolean hasShortcutKeyMatched = matchBoolean(a, R.styleable.Keyboard_Case_hasShortcutKey, id.mHasShortcutKey); + final boolean languageSwitchKeyEnabledMatched = matchBoolean(a, + R.styleable.Keyboard_Case_languageSwitchKeyEnabled, + id.mLanguageSwitchKeyEnabled); final boolean isMultiLineMatched = matchBoolean(a, R.styleable.Keyboard_Case_isMultiLine, id.isMultiLine()); final boolean imeActionMatched = matchInteger(a, @@ -1089,11 +1094,12 @@ public class Keyboard { final boolean selected = keyboardSetElementMatched && modeMatched && navigateNextMatched && navigatePreviousMatched && passwordInputMatched && clobberSettingsKeyMatched && shortcutKeyEnabledMatched - && hasShortcutKeyMatched && isMultiLineMatched && imeActionMatched - && localeCodeMatched && languageCodeMatched && countryCodeMatched; + && hasShortcutKeyMatched && languageSwitchKeyEnabledMatched + && isMultiLineMatched && imeActionMatched && localeCodeMatched + && languageCodeMatched && countryCodeMatched; if (DEBUG) { - startTag("<%s%s%s%s%s%s%s%s%s%s%s%s%s%s>%s", TAG_CASE, + startTag("<%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s>%s", TAG_CASE, textAttr(a.getString(R.styleable.Keyboard_Case_keyboardSetElement), "keyboardSetElement"), textAttr(a.getString(R.styleable.Keyboard_Case_mode), "mode"), @@ -1111,6 +1117,8 @@ public class Keyboard { "shortcutKeyEnabled"), booleanAttr(a, R.styleable.Keyboard_Case_hasShortcutKey, "hasShortcutKey"), + booleanAttr(a, R.styleable.Keyboard_Case_languageSwitchKeyEnabled, + "languageSwitchKeyEnabled"), booleanAttr(a, R.styleable.Keyboard_Case_isMultiLine, "isMultiLine"), textAttr(a.getString(R.styleable.Keyboard_Case_localeCode), diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java index f5752962e..6703b9301 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java @@ -62,13 +62,14 @@ public class KeyboardId { public final boolean mClobberSettingsKey; public final boolean mShortcutKeyEnabled; public final boolean mHasShortcutKey; + public final boolean mLanguageSwitchKeyEnabled; public final String mCustomActionLabel; private final int mHashCode; public KeyboardId(int elementId, Locale locale, int orientation, int width, int mode, EditorInfo editorInfo, boolean clobberSettingsKey, boolean shortcutKeyEnabled, - boolean hasShortcutKey) { + boolean hasShortcutKey, boolean languageSwitchKeyEnabled) { this.mLocale = locale; this.mOrientation = orientation; this.mWidth = width; @@ -78,6 +79,7 @@ public class KeyboardId { this.mClobberSettingsKey = clobberSettingsKey; this.mShortcutKeyEnabled = shortcutKeyEnabled; this.mHasShortcutKey = hasShortcutKey; + this.mLanguageSwitchKeyEnabled = languageSwitchKeyEnabled; this.mCustomActionLabel = (editorInfo.actionLabel != null) ? editorInfo.actionLabel.toString() : null; @@ -94,6 +96,7 @@ public class KeyboardId { id.mClobberSettingsKey, id.mShortcutKeyEnabled, id.mHasShortcutKey, + id.mLanguageSwitchKeyEnabled, id.isMultiLine(), id.imeAction(), id.mCustomActionLabel, @@ -114,6 +117,7 @@ public class KeyboardId { && other.mClobberSettingsKey == this.mClobberSettingsKey && other.mShortcutKeyEnabled == this.mShortcutKeyEnabled && other.mHasShortcutKey == this.mHasShortcutKey + && other.mLanguageSwitchKeyEnabled == this.mLanguageSwitchKeyEnabled && other.isMultiLine() == this.isMultiLine() && other.imeAction() == this.imeAction() && TextUtils.equals(other.mCustomActionLabel, this.mCustomActionLabel) @@ -172,7 +176,7 @@ public class KeyboardId { @Override public String toString() { - return String.format("[%s %s %s%d %s %s %s%s%s%s%s%s%s]", + return String.format("[%s %s %s%d %s %s %s%s%s%s%s%s%s%s]", elementIdToName(mElementId), mLocale, (mOrientation == 1 ? "port" : "land"), mWidth, @@ -184,6 +188,7 @@ public class KeyboardId { (passwordInput() ? " passwordInput" : ""), (mShortcutKeyEnabled ? " shortcutKeyEnabled" : ""), (mHasShortcutKey ? " hasShortcutKey" : ""), + (mLanguageSwitchKeyEnabled ? " languageSwitchKeyEnabled" : ""), (isMultiLine() ? "isMultiLine" : "") ); } diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java index ee882edc0..731aaf7c5 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java @@ -101,6 +101,7 @@ public class KeyboardSet { boolean mVoiceKeyEnabled; boolean mVoiceKeyOnMain; boolean mNoSettingsKey; + boolean mLanguageSwitchKeyEnabled; Locale mLocale; int mOrientation; int mWidth; @@ -196,7 +197,7 @@ public class KeyboardSet { && (isSymbols != params.mVoiceKeyOnMain); return new KeyboardId(keyboardSetElementId, params.mLocale, params.mOrientation, params.mWidth, params.mMode, params.mEditorInfo, params.mNoSettingsKey, - params.mVoiceKeyEnabled, hasShortcutKey); + params.mVoiceKeyEnabled, hasShortcutKey, params.mLanguageSwitchKeyEnabled); } public static class Builder { @@ -239,7 +240,8 @@ public class KeyboardSet { return this; } - public Builder setOptions(boolean voiceKeyEnabled, boolean voiceKeyOnMain) { + public Builder setOptions(boolean voiceKeyEnabled, boolean voiceKeyOnMain, + boolean languageSwitchKeyEnabled) { @SuppressWarnings("deprecation") final boolean deprecatedNoMicrophone = Utils.inPrivateImeOptions( null, LatinIME.IME_OPTION_NO_MICROPHONE_COMPAT, mEditorInfo); @@ -248,6 +250,7 @@ public class KeyboardSet { || deprecatedNoMicrophone; mParams.mVoiceKeyEnabled = voiceKeyEnabled && !noMicrophone; mParams.mVoiceKeyOnMain = voiceKeyOnMain; + mParams.mLanguageSwitchKeyEnabled = languageSwitchKeyEnabled; return this; } diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index e1c6f2604..efe5aa9cf 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -39,8 +39,7 @@ import com.android.inputmethod.latin.SettingsValues; import com.android.inputmethod.latin.SubtypeSwitcher; import com.android.inputmethod.latin.Utils; -public class KeyboardSwitcher implements KeyboardState.SwitchActions, - SharedPreferences.OnSharedPreferenceChangeListener { +public class KeyboardSwitcher implements KeyboardState.SwitchActions { private static final String TAG = KeyboardSwitcher.class.getSimpleName(); public static final String PREF_KEYBOARD_LAYOUT = "pref_keyboard_layout_20110916"; @@ -94,7 +93,6 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions, mSubtypeSwitcher = SubtypeSwitcher.getInstance(); mState = new KeyboardState(this); setContextThemeWrapper(ims, getKeyboardThemeIndex(ims, prefs)); - prefs.registerOnSharedPreferenceChangeListener(this); mForceNonDistinctMultitouch = prefs.getBoolean( DebugSettings.FORCE_NON_DISTINCT_MULTITOUCH_KEY, false); } @@ -133,7 +131,8 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions, LatinIME.SUBTYPE_EXTRA_VALUE_SUPPORT_TOUCH_POSITION_CORRECTION)); builder.setOptions( settingsValues.isVoiceKeyEnabled(editorInfo), - settingsValues.isVoiceKeyOnMain()); + settingsValues.isVoiceKeyOnMain(), + settingsValues.isLanguageSwitchKeyEnabled(mThemeContext)); mKeyboardSet = builder.build(); try { mState.onLoadKeyboard(mResources.getString(R.string.layout_switch_back_symbols)); @@ -340,34 +339,26 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions, } public View onCreateInputView() { - return createInputView(mThemeIndex, true); - } - - private View createInputView(final int newThemeIndex, final boolean forceRecreate) { - if (mCurrentInputView != null && mThemeIndex == newThemeIndex && !forceRecreate) - return mCurrentInputView; - if (mKeyboardView != null) { mKeyboardView.closing(); } - final int oldThemeIndex = mThemeIndex; Utils.GCUtils.getInstance().reset(); boolean tryGC = true; for (int i = 0; i < Utils.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) { try { - setContextThemeWrapper(mInputMethodService, newThemeIndex); + setContextThemeWrapper(mInputMethodService, mThemeIndex); mCurrentInputView = (InputView)LayoutInflater.from(mThemeContext).inflate( R.layout.input_view, null); tryGC = false; } catch (OutOfMemoryError e) { Log.w(TAG, "load keyboard failed: " + e); tryGC = Utils.GCUtils.getInstance().tryGCOrWait( - oldThemeIndex + "," + newThemeIndex, e); + Keyboard.toThemeName(mThemeIndex), e); } catch (InflateException e) { Log.w(TAG, "load keyboard failed: " + e); tryGC = Utils.GCUtils.getInstance().tryGCOrWait( - oldThemeIndex + "," + newThemeIndex, e); + Keyboard.toThemeName(mThemeIndex), e); } } @@ -384,27 +375,6 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions, return mCurrentInputView; } - private void postSetInputView(final View newInputView) { - final LatinIME latinIme = mInputMethodService; - latinIme.mHandler.post(new Runnable() { - @Override - public void run() { - if (newInputView != null) { - latinIme.setInputView(newInputView); - } - latinIme.updateInputViewShown(); - } - }); - } - - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - if (PREF_KEYBOARD_LAYOUT.equals(key)) { - final int themeIndex = getKeyboardThemeIndex(mInputMethodService, sharedPreferences); - postSetInputView(createInputView(themeIndex, false)); - } - } - public void onNetworkStateChanged() { if (mKeyboardView != null) { mKeyboardView.updateShortcutKey(SubtypeSwitcher.getInstance().isShortcutImeReady()); diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java index 78c371ff0..afc4932e9 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java @@ -489,7 +489,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke KeyboardSwitcher.getInstance().hapticAndAudioFeedback(primaryCode); return true; } - if (primaryCode == Keyboard.CODE_SPACE) { + if (primaryCode == Keyboard.CODE_SPACE || primaryCode == Keyboard.CODE_LANGUAGE_SWITCH) { // Long pressing the space key invokes IME switcher dialog. if (invokeCustomRequest(LatinIME.CODE_SHOW_INPUT_METHOD_PICKER)) { tracker.onLongPressed(); @@ -782,6 +782,11 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke && Utils.hasMultipleEnabledIMEsOrSubtypes(true /* include aux subtypes */)) { drawKeyPopupHint(key, canvas, paint, params); } + } else if (key.mCode == Keyboard.CODE_LANGUAGE_SWITCH) { + super.onDrawKeyTopVisuals(key, canvas, paint, params); + if (Utils.hasMultipleEnabledIMEsOrSubtypes(true /* include aux subtypes */)) { + drawKeyPopupHint(key, canvas, paint, params); + } } else { super.onDrawKeyTopVisuals(key, canvas, paint, params); } diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java index f96f71e8a..721ea135f 100644 --- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java +++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java @@ -44,10 +44,11 @@ public class ProximityInfo { // TODO: Find a proper name for mKeyboardMinWidth private final int mKeyboardMinWidth; private final int mKeyboardHeight; + private final int mMostCommonKeyWidth; private final Key[][] mGridNeighbors; - ProximityInfo(int gridWidth, int gridHeight, int minWidth, int height, int keyWidth, - int keyHeight, Set<Key> keys, TouchPositionCorrection touchPositionCorrection, + ProximityInfo(int gridWidth, int gridHeight, int minWidth, int height, int mostCommonKeyWidth, + int mostCommonKeyHeight, Set<Key> keys, TouchPositionCorrection touchPositionCorrection, Map<Integer, List<Integer>> additionalProximityChars) { mGridWidth = gridWidth; mGridHeight = gridHeight; @@ -56,13 +57,15 @@ public class ProximityInfo { mCellHeight = (height + mGridHeight - 1) / mGridHeight; mKeyboardMinWidth = minWidth; mKeyboardHeight = height; - mKeyHeight = keyHeight; + mKeyHeight = mostCommonKeyHeight; + mMostCommonKeyWidth = mostCommonKeyWidth; mGridNeighbors = new Key[mGridSize][]; if (minWidth == 0 || height == 0) { // No proximity required. Keyboard might be more keys keyboard. return; } - computeNearestNeighbors(keyWidth, keys, touchPositionCorrection, additionalProximityChars); + computeNearestNeighbors( + mostCommonKeyWidth, keys, touchPositionCorrection, additionalProximityChars); } public static ProximityInfo createDummyProximityInfo() { @@ -74,8 +77,8 @@ public class ProximityInfo { final ProximityInfo spellCheckerProximityInfo = createDummyProximityInfo(); spellCheckerProximityInfo.mNativeProximityInfo = spellCheckerProximityInfo.setProximityInfoNative( - SpellCheckerProximityInfo.ROW_SIZE, 480, 300, 11, 3, proximity, 0, - null, null, null, null, null, null, null, null); + SpellCheckerProximityInfo.ROW_SIZE, 480, 300, 11, 3, (480 / 10), proximity, + 0, null, null, null, null, null, null, null, null); return spellCheckerProximityInfo; } @@ -85,7 +88,8 @@ public class ProximityInfo { } private native long setProximityInfoNative(int maxProximityCharsSize, int displayWidth, - int displayHeight, int gridWidth, int gridHeight, int[] proximityCharsArray, + int displayHeight, int gridWidth, int gridHeight, + int mostCommonKeyWidth, int[] proximityCharsArray, int keyCount, int[] keyXCoordinates, int[] keyYCoordinates, int[] keyWidths, int[] keyHeights, int[] keyCharCodes, float[] sweetSpotCenterX, float[] sweetSpotCenterY, float[] sweetSpotRadii); @@ -151,7 +155,8 @@ public class ProximityInfo { } mNativeProximityInfo = setProximityInfoNative(MAX_PROXIMITY_CHARS_SIZE, - keyboardWidth, keyboardHeight, mGridWidth, mGridHeight, proximityCharsArray, + keyboardWidth, keyboardHeight, mGridWidth, mGridHeight, mMostCommonKeyWidth, + proximityCharsArray, keyCount, keyXCoordinates, keyYCoordinates, keyWidths, keyHeights, keyCharCodes, sweetSpotCenterXs, sweetSpotCenterYs, sweetSpotRadii); } diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java index 7c8fd1225..ca711ec7d 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java @@ -31,7 +31,7 @@ public class KeyboardIconsSet { // The value should be aligned with the enum value of Key.keyIcon. public static final int ICON_UNDEFINED = 0; - private static final int NUM_ICONS = 13; + private static final int NUM_ICONS = 14; private final Drawable[] mIcons = new Drawable[NUM_ICONS + 1]; @@ -57,6 +57,7 @@ public class KeyboardIconsSet { addIconIdMap(11, "shiftKeyShifted", R.styleable.Keyboard_iconShiftKeyShifted); addIconIdMap(12, "disabledShortcurKey", R.styleable.Keyboard_iconDisabledShortcutKey); addIconIdMap(13, "previewTabKey", R.styleable.Keyboard_iconPreviewTabKey); + addIconIdMap(14, "languageSwitchKey", R.styleable.Keyboard_iconLanguageSwitchKey); } private static void addIconIdMap(int iconId, String name, int attrId) { diff --git a/java/src/com/android/inputmethod/latin/DebugSettings.java b/java/src/com/android/inputmethod/latin/DebugSettings.java index 3805da154..870b33f9a 100644 --- a/java/src/com/android/inputmethod/latin/DebugSettings.java +++ b/java/src/com/android/inputmethod/latin/DebugSettings.java @@ -25,6 +25,8 @@ import android.preference.CheckBoxPreference; import android.preference.PreferenceActivity; import android.util.Log; +import com.android.inputmethod.keyboard.KeyboardSwitcher; + public class DebugSettings extends PreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener { @@ -61,7 +63,8 @@ public class DebugSettings extends PreferenceActivity updateDebugMode(); mServiceNeedsRestart = true; } - } else if (key.equals(FORCE_NON_DISTINCT_MULTITOUCH_KEY)) { + } else if (key.equals(FORCE_NON_DISTINCT_MULTITOUCH_KEY) + || key.equals(KeyboardSwitcher.PREF_KEYBOARD_LAYOUT)) { mServiceNeedsRestart = true; } } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index d17c83313..dad97456c 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -25,10 +25,12 @@ import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.res.Configuration; import android.content.res.Resources; +import android.graphics.Rect; import android.inputmethodservice.InputMethodService; import android.media.AudioManager; import android.net.ConnectivityManager; import android.os.Debug; +import android.os.IBinder; import android.os.Message; import android.os.SystemClock; import android.preference.PreferenceActivity; @@ -43,6 +45,7 @@ import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; +import android.view.ViewGroup.LayoutParams; import android.view.inputmethod.CompletionInfo; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.ExtractedText; @@ -55,6 +58,7 @@ 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.compat.InputMethodSubtypeCompatWrapper; import com.android.inputmethod.compat.InputTypeCompatUtils; import com.android.inputmethod.compat.SuggestionSpanUtils; import com.android.inputmethod.compat.VibratorCompatWrapper; @@ -196,6 +200,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private final KeyboardSwitcher mKeyboardSwitcher; private final SubtypeSwitcher mSubtypeSwitcher; private VoiceProxy mVoiceProxy; + private boolean mShouldSwitchToLastSubtype = true; private UserDictionary mUserDictionary; private UserBigramDictionary mUserBigramDictionary; @@ -1019,12 +1024,34 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar setSuggestionStripShownInternal(shown, /* needsInputViewShown */true); } + private void adjustInputViewHeight() { + if (mKeyPreviewBackingView.getHeight() > 0) { + return; + } + + final KeyboardView keyboardView = mKeyboardSwitcher.getKeyboardView(); + if (keyboardView == null) return; + final int keyboardHeight = keyboardView.getHeight(); + final int suggestionsHeight = mSuggestionsContainer.getHeight(); + final int displayHeight = mResources.getDisplayMetrics().heightPixels; + final Rect rect = new Rect(); + mKeyPreviewBackingView.getWindowVisibleDisplayFrame(rect); + final int notificationBarHeight = rect.top; + final int remainingHeight = displayHeight - notificationBarHeight - suggestionsHeight + - keyboardHeight; + + final LayoutParams params = mKeyPreviewBackingView.getLayoutParams(); + params.height = mSuggestionsView.setMoreSuggestionsHeight(remainingHeight); + mKeyPreviewBackingView.setLayoutParams(params); + } + @Override public void onComputeInsets(InputMethodService.Insets outInsets) { super.onComputeInsets(outInsets); final KeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); if (inputView == null || mSuggestionsContainer == null) return; + adjustInputViewHeight(); // In fullscreen mode, the height of the extract area managed by InputMethodService should // be considered. // See {@link android.inputmethodservice.InputMethodService#onComputeInsets}. @@ -1264,6 +1291,25 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } } + private void handleLanguageSwitchKey() { + final boolean includesOtherImes = !mSettingsValues.mIncludesOtherImesInLanguageSwitchList; + final IBinder token = getWindow().getWindow().getAttributes().token; + if (mShouldSwitchToLastSubtype) { + final InputMethodSubtypeCompatWrapper lastSubtype = mImm.getLastInputMethodSubtype(); + final boolean lastSubtypeBelongsToThisIme = Utils.checkIfSubtypeBelongsToThisIme( + this, lastSubtype); + if ((includesOtherImes || lastSubtypeBelongsToThisIme) + && mImm.switchToLastInputMethod(token)) { + mShouldSwitchToLastSubtype = false; + } else { + mImm.switchToNextInputMethod(token, !includesOtherImes); + mShouldSwitchToLastSubtype = true; + } + } else { + mImm.switchToNextInputMethod(token, !includesOtherImes); + } + } + private void sendKeyCodePoint(int code) { // TODO: Remove this special handling of digit letters. // For backward compatibility. See {@link InputMethodService#sendKeyChar(char)}. @@ -1308,6 +1354,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar handleBackspace(spaceState); mDeleteCount++; mExpectingUpdateSelection = true; + mShouldSwitchToLastSubtype = true; LatinImeLogger.logOnDelete(); break; case Keyboard.CODE_SHIFT: @@ -1329,6 +1376,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar case Keyboard.CODE_ACTION_PREVIOUS: EditorInfoCompatUtils.performEditorActionPrevious(getCurrentInputConnection()); break; + case Keyboard.CODE_LANGUAGE_SWITCH: + handleLanguageSwitchKey(); + break; default: mSpaceState = SPACE_STATE_NONE; if (mSettingsValues.isWordSeparator(primaryCode)) { @@ -1337,6 +1387,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar handleCharacter(primaryCode, x, y, spaceState); } mExpectingUpdateSelection = true; + mShouldSwitchToLastSubtype = true; break; } switcher.onCodeInput(primaryCode); @@ -1898,6 +1949,14 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mVoiceProxy.flushAndLogAllTextModificationCounters(index, suggestion, mSettingsValues.mWordSeparators); + if (SPACE_STATE_PHANTOM == mSpaceState && suggestion.length() > 0) { + int firstChar = Character.codePointAt(suggestion, 0); + if ((!mSettingsValues.isWeakSpaceStripper(firstChar)) + && (!mSettingsValues.isWeakSpaceSwapper(firstChar))) { + sendKeyCodePoint(Keyboard.CODE_SPACE); + } + } + if (mInputAttributes.mApplicationSpecifiedCompletionOn && mApplicationSpecifiedCompletions != null && index >= 0 && index < mApplicationSpecifiedCompletions.length) { @@ -2269,6 +2328,14 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } initSuggest(); loadSettings(); + // Since we just changed languages, we should re-evaluate suggestions with whatever word + // we are currently composing. If we are not composing anything, we may want to display + // predictions or punctuation signs (which is done by updateBigramPredictions anyway). + if (isCursorTouchingWord()) { + mHandler.postUpdateSuggestions(); + } else { + mHandler.postUpdateBigramPredictions(); + } } public void hapticAndAudioFeedback(int primaryCode) { diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java index 3029057be..305cef22d 100644 --- a/java/src/com/android/inputmethod/latin/Settings.java +++ b/java/src/com/android/inputmethod/latin/Settings.java @@ -43,7 +43,6 @@ import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.TextView; import com.android.inputmethod.compat.CompatUtils; -import com.android.inputmethod.compat.InputMethodManagerCompatWrapper; import com.android.inputmethod.compat.InputMethodServiceCompatWrapper; import com.android.inputmethod.compat.VibratorCompatWrapper; import com.android.inputmethod.deprecated.VoiceProxy; @@ -73,6 +72,10 @@ public class Settings extends InputMethodSettingsActivity public static final String PREF_MISC_SETTINGS = "misc_settings"; public static final String PREF_USABILITY_STUDY_MODE = "usability_study_mode"; public static final String PREF_ADVANCED_SETTINGS = "pref_advanced_settings"; + public static final String PREF_SUPPRESS_LANGUAGE_SWITCH_KEY = + "pref_suppress_language_switch_key"; + public static final String PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST = + "pref_include_other_imes_in_language_switch_list"; public static final String PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY = "pref_key_preview_popup_dismiss_delay"; public static final String PREF_KEY_USE_CONTACTS_DICT = "pref_key_use_contacts_dict"; @@ -204,6 +207,11 @@ public class Settings extends InputMethodSettingsActivity } } + final CheckBoxPreference includeOtherImesInLanguageSwitchList = + (CheckBoxPreference)findPreference(PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST); + includeOtherImesInLanguageSwitchList.setEnabled( + !SettingsValues.isLanguageSwitchKeySupressed(prefs)); + mKeyPreviewPopupDismissDelay = (ListPreference)findPreference(PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY); final String[] entries = new String[] { @@ -316,6 +324,12 @@ public class Settings extends InputMethodSettingsActivity if (null != popupDismissDelay) { popupDismissDelay.setEnabled(prefs.getBoolean(PREF_POPUP_ON, true)); } + } else if (key.equals(PREF_SUPPRESS_LANGUAGE_SWITCH_KEY)) { + final CheckBoxPreference includeOtherImesInLanguageSwicthList = + (CheckBoxPreference)findPreference( + PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST); + includeOtherImesInLanguageSwicthList.setEnabled( + !SettingsValues.isLanguageSwitchKeySupressed(prefs)); } ensureConsistencyOfAutoCorrectionSettings(); mVoiceOn = !(prefs.getString(PREF_VOICE_MODE, mVoiceModeOff) diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java index 6d65a74c8..69e45f619 100644 --- a/java/src/com/android/inputmethod/latin/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/SettingsValues.java @@ -23,11 +23,14 @@ import android.os.Build; import android.util.Log; import android.view.inputmethod.EditorInfo; +import com.android.inputmethod.compat.InputMethodInfoCompatWrapper; import com.android.inputmethod.compat.InputTypeCompatUtils; import com.android.inputmethod.compat.VibratorCompatWrapper; import com.android.inputmethod.keyboard.internal.KeySpecParser; import java.util.Arrays; +import java.util.Collections; +import java.util.List; import java.util.Locale; public class SettingsValues { @@ -55,6 +58,8 @@ public class SettingsValues { public final String mShowSuggestionsSetting; @SuppressWarnings("unused") // TODO: Use this private final boolean mUsabilityStudyMode; + public final boolean mIncludesOtherImesInLanguageSwitchList; + public final boolean mIsLanguageSwitchKeySuppressed; @SuppressWarnings("unused") // TODO: Use this private final String mKeyPreviewPopupDismissDelayRawValue; public final boolean mUseContactsDict; @@ -127,6 +132,9 @@ public class SettingsValues { mShowSuggestionsSetting = prefs.getString(Settings.PREF_SHOW_SUGGESTIONS_SETTING, res.getString(R.string.prefs_suggestion_visibility_default_value)); mUsabilityStudyMode = getUsabilityStudyMode(prefs); + mIncludesOtherImesInLanguageSwitchList = prefs.getBoolean( + Settings.PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST, false); + mIsLanguageSwitchKeySuppressed = isLanguageSwitchKeySupressed(prefs); mKeyPreviewPopupDismissDelayRawValue = prefs.getString( Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY, Integer.toString(res.getInteger(R.integer.config_key_preview_linger_timeout))); @@ -309,6 +317,22 @@ public class SettingsValues { return mVoiceKeyOnMain; } + public static boolean isLanguageSwitchKeySupressed(SharedPreferences sp) { + return sp.getBoolean(Settings.PREF_SUPPRESS_LANGUAGE_SWITCH_KEY, false); + } + + public boolean isLanguageSwitchKeyEnabled(Context context) { + if (mIsLanguageSwitchKeySuppressed) { + return false; + } + if (mIncludesOtherImesInLanguageSwitchList) { + return Utils.hasMultipleEnabledIMEsOrSubtypes(/* include aux subtypes */false); + } else { + return Utils.hasMultipleEnabledSubtypesInThisIme( + context, /* include aux subtypes */false); + } + } + public boolean isFullscreenModeAllowed(Resources res) { return res.getBoolean(R.bool.config_use_fullscreen_mode); } diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index 33d4b877e..a8679e07a 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -52,6 +52,7 @@ import java.io.PrintWriter; import java.nio.channels.FileChannel; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Locale; @@ -117,16 +118,51 @@ public class Utils { } } + // TODO: Move InputMethodSubtype related utility methods to its own utility class. + // TODO: Cache my InputMethodInfo and/or InputMethodSubtype list. + public static boolean checkIfSubtypeBelongsToThisIme(Context context, + InputMethodSubtypeCompatWrapper ims) { + final InputMethodManagerCompatWrapper imm = InputMethodManagerCompatWrapper.getInstance(); + if (imm == null) return false; + + final InputMethodInfoCompatWrapper myImi = Utils.getInputMethodInfo( + context.getPackageName()); + final List<InputMethodSubtypeCompatWrapper> subtypes = + imm.getEnabledInputMethodSubtypeList(myImi, true); + for (final InputMethodSubtypeCompatWrapper subtype : subtypes) { + if (subtype.equals(ims)) { + return true; + } + } + return false; + } + public static boolean hasMultipleEnabledIMEsOrSubtypes( final boolean shouldIncludeAuxiliarySubtypes) { final InputMethodManagerCompatWrapper imm = InputMethodManagerCompatWrapper.getInstance(); if (imm == null) return false; + final List<InputMethodInfoCompatWrapper> enabledImis = imm.getEnabledInputMethodList(); + return hasMultipleEnabledSubtypes(shouldIncludeAuxiliarySubtypes, enabledImis); + } + + public static boolean hasMultipleEnabledSubtypesInThisIme(Context context, + final boolean shouldIncludeAuxiliarySubtypes) { + final InputMethodInfoCompatWrapper myImi = Utils.getInputMethodInfo( + context.getPackageName()); + final List<InputMethodInfoCompatWrapper> imiList = Collections.singletonList(myImi); + return Utils.hasMultipleEnabledSubtypes(shouldIncludeAuxiliarySubtypes, imiList); + } + + private static boolean hasMultipleEnabledSubtypes(final boolean shouldIncludeAuxiliarySubtypes, + List<InputMethodInfoCompatWrapper> imiList) { + final InputMethodManagerCompatWrapper imm = InputMethodManagerCompatWrapper.getInstance(); + if (imm == null) return false; // Number of the filtered IMEs int filteredImisCount = 0; - for (InputMethodInfoCompatWrapper imi : enabledImis) { + for (InputMethodInfoCompatWrapper imi : imiList) { // We can return true immediately after we find two or more filtered IMEs. if (filteredImisCount > 1) return true; final List<InputMethodSubtypeCompatWrapper> subtypes = @@ -564,6 +600,7 @@ public class Utils { } } + // TODO: Move this method to KeyboardSet class. public static int getKeyboardMode(EditorInfo editorInfo) { if (editorInfo == null) return KeyboardId.MODE_TEXT; diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java index d3362940f..075fb68ee 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java +++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java @@ -137,7 +137,8 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener, public final int mDividerWidth; public final int mSuggestionsStripHeight; public final int mSuggestionsCountInStrip; - public final int mMaxMoreSuggestionsRow; + public final int mMoreSuggestionsRowHeight; + private int mMaxMoreSuggestionsRow; public final float mMinMoreSuggestionsWidth; public final int mMoreSuggestionsBottomGap; @@ -225,12 +226,34 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener, mCenterSuggestionIndex = mSuggestionsCountInStrip / 2; mMoreSuggestionsBottomGap = res.getDimensionPixelOffset( R.dimen.more_suggestions_bottom_gap); + mMoreSuggestionsRowHeight = res.getDimensionPixelSize( + R.dimen.more_suggestions_row_height); final LayoutInflater inflater = LayoutInflater.from(context); mWordToSaveView = (TextView)inflater.inflate(R.layout.suggestion_word, null); mHintToSaveView = (TextView)inflater.inflate(R.layout.suggestion_word, null); } + public int getMaxMoreSuggestionsRow() { + return mMaxMoreSuggestionsRow; + } + + private int getMoreSuggestionsHeight() { + return mMaxMoreSuggestionsRow * mMoreSuggestionsRowHeight + mMoreSuggestionsBottomGap; + } + + public int setMoreSuggestionsHeight(int remainingHeight) { + final int currentHeight = getMoreSuggestionsHeight(); + if (currentHeight <= remainingHeight) { + return currentHeight; + } + + mMaxMoreSuggestionsRow = (remainingHeight - mMoreSuggestionsBottomGap) + / mMoreSuggestionsRowHeight; + final int newHeight = getMoreSuggestionsHeight(); + return newHeight; + } + private static Drawable getMoreSuggestionsHint(Resources res, float textSize, int color) { final Paint paint = new Paint(); paint.setAntiAlias(true); @@ -645,6 +668,9 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener, mParams.layout(mSuggestedWords, mSuggestionsStrip, this, getWidth()); } + public int setMoreSuggestionsHeight(int remainingHeight) { + return mParams.setMoreSuggestionsHeight(remainingHeight); + } public boolean isShowingAddToDictionaryHint() { return mSuggestionsStrip.getChildCount() > 0 @@ -735,7 +761,7 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener, final MoreSuggestions.Builder builder = mMoreSuggestionsBuilder; builder.layout(mSuggestedWords, params.mSuggestionsCountInStrip, maxWidth, (int)(maxWidth * params.mMinMoreSuggestionsWidth), - params.mMaxMoreSuggestionsRow); + params.getMaxMoreSuggestionsRow()); mMoreSuggestionsView.setKeyboard(builder.build()); container.measure( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); |