diff --git a/java/res/drawable-hdpi/sym_keyboard_language_switch.png b/java/res/drawable-hdpi/sym_keyboard_language_switch.png new file mode 100644 index 0000000000000000000000000000000000000000..fa747642d9d91642bf56f769150e095fa372b542 Binary files /dev/null and b/java/res/drawable-hdpi/sym_keyboard_language_switch.png differ diff --git a/java/res/drawable-mdpi/sym_keyboard_language_switch.png b/java/res/drawable-mdpi/sym_keyboard_language_switch.png new file mode 100644 index 0000000000000000000000000000000000000000..f30c1b640ab60b07865cec8340143a7b1d9303ff Binary files /dev/null and b/java/res/drawable-mdpi/sym_keyboard_language_switch.png differ diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml index a5d590e04de3f2a4b3f6750de2068ed7ce717724..7758074208be18d03cb34ac249f92920db44eaeb 100644 --- a/java/res/values/attrs.xml +++ b/java/res/values/attrs.xml @@ -216,6 +216,7 @@ <attr name="iconShiftKeyShifted" format="reference" /> <attr name="iconDisabledShortcutKey" format="reference" /> <attr name="iconPreviewTabKey" format="reference" /> + <attr name="iconLanguageSwitchKey" format="reference" /> </declare-styleable> <declare-styleable name="Keyboard_Key"> @@ -296,6 +297,7 @@ <enum name="iconShortcutForLabel" value="9" /> <enum name="iconSpaceKeyForNumberLayout" value="10" /> <enum name="iconShiftKeyShifted" value="11" /> + <enum name="iconLanguageSwitchKey" value="14" /> </attr> <!-- The icon for disabled key --> <attr name="keyIconDisabled" format="enum"> @@ -361,6 +363,7 @@ <attr name="clobberSettingsKey" format="boolean" /> <attr name="shortcutKeyEnabled" format="boolean" /> <attr name="hasShortcutKey" format="boolean" /> + <attr name="languageSwitchKeyEnabled" format="boolean" /> <attr name="isMultiLine" format="boolean" /> <attr name="imeAction" format="enum"> <!-- This should be aligned with EditorInfo.IME_ACTION_* --> diff --git a/java/res/values/keyboard-icons-black.xml b/java/res/values/keyboard-icons-black.xml index 1c5a5f720a922d75a5e8d5f7fe61afcc0bf199c8..44fc2b9c12cb35ee80ee8270c324741ff2bc3a79 100644 --- a/java/res/values/keyboard-icons-black.xml +++ b/java/res/values/keyboard-icons-black.xml @@ -34,5 +34,7 @@ <item name="iconShiftKeyShifted">@drawable/sym_bkeyboard_shift_locked</item> <item name="iconDisabledShortcutKey">@drawable/sym_bkeyboard_voice_off</item> <item name="iconPreviewTabKey">@drawable/sym_keyboard_feedback_tab</item> + <!-- TODO: Needs dedicated black theme globe icon --> + <item name="iconLanguageSwitchKey">@drawable/sym_keyboard_language_switch</item> </style> </resources> diff --git a/java/res/values/keyboard-icons-ics.xml b/java/res/values/keyboard-icons-ics.xml index f68be5f1e8498004a19919b04d1e8c5cc3f06889..5fba0253db23b610bfc49d75069cefd1d23e99c2 100644 --- a/java/res/values/keyboard-icons-ics.xml +++ b/java/res/values/keyboard-icons-ics.xml @@ -33,5 +33,6 @@ <item name="iconShiftKeyShifted">@drawable/sym_keyboard_shift_locked_holo</item> <item name="iconDisabledShortcutKey">@drawable/sym_keyboard_voice_off_holo</item> <item name="iconPreviewTabKey">@drawable/sym_keyboard_feedback_tab</item> + <item name="iconLanguageSwitchKey">@drawable/sym_keyboard_language_switch</item> </style> </resources> diff --git a/java/res/values/keyboard-icons-white.xml b/java/res/values/keyboard-icons-white.xml index 35197a1c01f2820cddf6247688bd4e10c442f813..837b1a37acb080df281a15f7cdcd5d8cbd5dd09f 100644 --- a/java/res/values/keyboard-icons-white.xml +++ b/java/res/values/keyboard-icons-white.xml @@ -31,5 +31,6 @@ <!-- TODO: Needs non-holo disabled shortcut icon drawable --> <item name="iconDisabledShortcutKey">@drawable/sym_keyboard_voice_off_holo</item> <item name="iconPreviewTabKey">@drawable/sym_keyboard_feedback_tab</item> + <item name="iconLanguageSwitchKey">@drawable/sym_keyboard_language_switch</item> </style> </resources> diff --git a/java/res/values/keycodes.xml b/java/res/values/keycodes.xml index 7f9e4bda48f852902c12ed6a77edc912c630dccb..d3d9b63244778346669e9278ccb8075e88cff804 100644 --- a/java/res/values/keycodes.xml +++ b/java/res/values/keycodes.xml @@ -32,5 +32,6 @@ <integer name="key_action_enter">-7</integer> <integer name="key_action_next">-8</integer> <integer name="key_action_previous">-9</integer> - <integer name="key_unspecified">-10</integer> + <integer name="key_language_switch">-10</integer> + <integer name="key_unspecified">-11</integer> </resources> diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml index d8a3a689ecfdc6f2fb2a1a5d6a066cc0d15cebdc..f2c02d014edc903e5744e2cb3b4f9a386a4c5f05 100644 --- a/java/res/values/strings.xml +++ b/java/res/values/strings.xml @@ -64,6 +64,13 @@ <!-- Option summary for advanced settings screen [CHAR LIMIT=65 (two lines) or 30 (fits on one line, preferable)] --> <string name="advanced_settings_summary">Options for experts</string> + <!-- Option name for including other IMEs in the language switch list [CHAR LIMIT=25] --> + <string name="include_other_imes_in_language_switch_list">Switch to other input methods</string> + <!-- Option summary for including other IMEs in the language switch list [CHAR LIMIT=65] --> + <string name="include_other_imes_in_language_switch_list_summary">Language switch key covers other input methods too</string> + <!-- Option to suppress language switch key [CHAR LIMIT=25] --> + <string name="suppress_language_switch_key">Suppress language switch key</string> + <!-- Option for the dismiss delay of the key popup [CHAR LIMIT=25] --> <string name="key_preview_popup_dismiss_delay">Key popup dismiss delay</string> <!-- Description for delay for dismissing a popup on keypress: no delay [CHAR LIMIT=15] --> diff --git a/java/res/xml/key_styles_common.xml b/java/res/xml/key_styles_common.xml index 76eacb673bdee594d42c65d683ca2faedae6c5ac..f153a7d96b6183a04e4bcdc8bac5f6122db89b40 100644 --- a/java/res/xml/key_styles_common.xml +++ b/java/res/xml/key_styles_common.xml @@ -117,10 +117,10 @@ latin:altCode="@integer/key_space" latin:parentStyle="f1MoreKeysStyle" /> <key-style - latin:styleName="settingsKeyStyle" - latin:code="@integer/key_settings" - latin:keyIcon="iconSettingsKey" - latin:keyActionFlags="noKeyPreview|altCodeWhileTyping" + latin:styleName="languageSwitchKeyStyle" + latin:code="@integer/key_language_switch" + latin:keyIcon="iconLanguageSwitchKey" + latin:keyActionFlags="noKeyPreview|altCodeWhileTyping|enableLongPress" latin:altCode="@integer/key_space" latin:backgroundType="functional" /> <key-style diff --git a/java/res/xml/prefs.xml b/java/res/xml/prefs.xml index f826ef006ea6c6424b1b6c4466bc7df45889b11b..ebca25089280c9af3dedbd8b009b94ef38096d60 100644 --- a/java/res/xml/prefs.xml +++ b/java/res/xml/prefs.xml @@ -92,6 +92,17 @@ android:key="pref_advanced_settings" android:title="@string/advanced_settings" android:summary="@string/advanced_settings_summary"> + <CheckBoxPreference + android:key="pref_suppress_language_switch_key" + android:title="@string/suppress_language_switch_key" + android:persistent="true" + android:defaultValue="false" /> + <CheckBoxPreference + android:key="pref_include_other_imes_in_language_switch_list" + android:title="@string/include_other_imes_in_language_switch_list" + android:summary="@string/include_other_imes_in_language_switch_list_summary" + android:persistent="true" + android:defaultValue="false" /> <!-- Values for popup dismiss delay are added programatically --> <ListPreference android:key="pref_key_preview_popup_dismiss_delay" diff --git a/java/res/xml/row_qwerty4.xml b/java/res/xml/row_qwerty4.xml index df9c8fe3f04e1aff96ba5aa134146e83b4be8127..0dd2177e82d2927e3d1d1660d9c4ac569c8cdff0 100644 --- a/java/res/xml/row_qwerty4.xml +++ b/java/res/xml/row_qwerty4.xml @@ -57,9 +57,23 @@ latin:keyStyle="f1MoreKeysStyle" /> </default> </switch> - <Key - latin:keyStyle="spaceKeyStyle" - latin:keyWidth="50%p" /> + <switch> + <case + latin:languageSwitchKeyEnabled="true" + > + <Key + latin:keyStyle="languageSwitchKeyStyle" /> + <Key + latin:keyStyle="spaceKeyStyle" + latin:keyWidth="40%p" /> + </case> + <!-- languageSwitchKeyEnabled="false" --> + <default> + <Key + latin:keyStyle="spaceKeyStyle" + latin:keyWidth="50%p" /> + </default> + </switch> <Key latin:keyStyle="punctuationKeyStyle" /> <Key diff --git a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java index 7e216e5c8d61112d465ff7aeb1f9a47fa23cda75..9dd0a599de551afe4a6ccaa37efa84ed94595d16 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/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java index c6cdf7986f9d77e42df76f4be547c030011ad8b9..5660d194260e2a8f9d21195a5d5b1e24478b5f27 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; @@ -1076,6 +1077,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 +1093,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 +1116,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 f5752962e0274b3791577151d9535f9d927a704d..6703b93017a1a8055c886a9364095c7dbae6edb1 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 ee882edc02a4700d7f128f3dec76d12b23fb64e4..731aaf7c52f27c81135a7c33f7bfd8dbd544c665 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 e1c6f26049915e9d89d0b423ff1ac08970fe2f47..ac8dd1b958e2e3a86000497ee4b9a0b4ab2fe24d 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -133,7 +133,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)); diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java index 78c371ff0cd388b44fcac88f8a6dc34beb2d8261..afc4932e93bdd1cd578b189ceaf03251a85b9549 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/internal/KeyboardIconsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java index 7c8fd1225071eb7e8baa5120e89a5c5521da296a..ca711ec7d92b4734d4114b7efe90620f081b7e09 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/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 2bcd947f1566610e0fe35712a13c80e6fcad912d..cb22b4935fd0345a2142cfa64713180454ba039b 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -29,6 +29,7 @@ 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; @@ -55,6 +56,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 +198,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private KeyboardSwitcher mKeyboardSwitcher; private SubtypeSwitcher mSubtypeSwitcher; private VoiceProxy mVoiceProxy; + private boolean mShouldSwitchToLastSubtype = true; private UserDictionary mUserDictionary; private UserBigramDictionary mUserBigramDictionary; @@ -1263,6 +1266,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)}. @@ -1306,6 +1328,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar handleBackspace(spaceState); mDeleteCount++; mExpectingUpdateSelection = true; + mShouldSwitchToLastSubtype = true; LatinImeLogger.logOnDelete(); break; case Keyboard.CODE_SHIFT: @@ -1327,6 +1350,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)) { @@ -1335,6 +1361,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar handleCharacter(primaryCode, x, y, spaceState); } mExpectingUpdateSelection = true; + mShouldSwitchToLastSubtype = true; break; } switcher.onCodeInput(primaryCode); diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java index 3029057be5ff01c867b4820759b8766426fc4b1e..305cef22d130bb642f4bfafc1a345d99570fdc5e 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 6d65a74c8fa5d82db9fa9284df987b4485a8ae11..69e45f61959458816e3be901b408c169a13082d0 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 33d4b877ea7a5fcacbce5670acd8726073871929..a8679e07addd5a3c1410b389016ff3645d515378 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;