aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com/android/inputmethod/latin/KeyboardSwitcher.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/src/com/android/inputmethod/latin/KeyboardSwitcher.java')
-rw-r--r--java/src/com/android/inputmethod/latin/KeyboardSwitcher.java809
1 files changed, 518 insertions, 291 deletions
diff --git a/java/src/com/android/inputmethod/latin/KeyboardSwitcher.java b/java/src/com/android/inputmethod/latin/KeyboardSwitcher.java
index a7b695eb3..00b6f0a43 100644
--- a/java/src/com/android/inputmethod/latin/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/latin/KeyboardSwitcher.java
@@ -16,11 +16,13 @@
package com.android.inputmethod.latin;
+import android.content.Context;
import android.content.SharedPreferences;
-import android.content.res.Configuration;
import android.content.res.Resources;
-import android.preference.PreferenceManager;
+import android.util.Log;
import android.view.InflateException;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
import java.lang.ref.SoftReference;
import java.util.Arrays;
@@ -28,187 +30,169 @@ import java.util.HashMap;
import java.util.Locale;
public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceChangeListener {
-
- public static final int MODE_NONE = 0;
- public static final int MODE_TEXT = 1;
- public static final int MODE_SYMBOLS = 2;
- public static final int MODE_PHONE = 3;
- public static final int MODE_URL = 4;
- public static final int MODE_EMAIL = 5;
- public static final int MODE_IM = 6;
- public static final int MODE_WEB = 7;
-
- // Main keyboard layouts without the settings key
- public static final int KEYBOARDMODE_NORMAL = R.id.mode_normal;
- public static final int KEYBOARDMODE_URL = R.id.mode_url;
- public static final int KEYBOARDMODE_EMAIL = R.id.mode_email;
- public static final int KEYBOARDMODE_IM = R.id.mode_im;
- public static final int KEYBOARDMODE_WEB = R.id.mode_webentry;
- // Main keyboard layouts with the settings key
- public static final int KEYBOARDMODE_NORMAL_WITH_SETTINGS_KEY =
- R.id.mode_normal_with_settings_key;
- public static final int KEYBOARDMODE_URL_WITH_SETTINGS_KEY =
- R.id.mode_url_with_settings_key;
- public static final int KEYBOARDMODE_EMAIL_WITH_SETTINGS_KEY =
- R.id.mode_email_with_settings_key;
- public static final int KEYBOARDMODE_IM_WITH_SETTINGS_KEY =
- R.id.mode_im_with_settings_key;
- public static final int KEYBOARDMODE_WEB_WITH_SETTINGS_KEY =
- R.id.mode_webentry_with_settings_key;
-
- // Symbols keyboard layout without the settings key
- public static final int KEYBOARDMODE_SYMBOLS = R.id.mode_symbols;
- // Symbols keyboard layout with the settings key
- public static final int KEYBOARDMODE_SYMBOLS_WITH_SETTINGS_KEY =
- R.id.mode_symbols_with_settings_key;
-
- public static final String DEFAULT_LAYOUT_ID = "4";
+ private static final String TAG = "KeyboardSwitcher";
+ private static final boolean DEBUG = false;
+ public static final boolean DEBUG_STATE = false;
+
+ public static final int MODE_TEXT = 0;
+ public static final int MODE_URL = 1;
+ public static final int MODE_EMAIL = 2;
+ public static final int MODE_IM = 3;
+ public static final int MODE_WEB = 4;
+ public static final int MODE_PHONE = 5;
+ public static final int MODE_NUMBER = 6;
+
+ // Changing DEFAULT_LAYOUT_ID also requires prefs_for_debug.xml to be matched with.
+ public static final String DEFAULT_LAYOUT_ID = "5";
public static final String PREF_KEYBOARD_LAYOUT = "pref_keyboard_layout_20100902";
private static final int[] THEMES = new int [] {
- R.layout.input_basic, R.layout.input_basic_highcontrast, R.layout.input_stone_normal,
- R.layout.input_stone_bold, R.layout.input_gingerbread};
-
- // Ids for each characters' color in the keyboard
- private static final int CHAR_THEME_COLOR_WHITE = 0;
- private static final int CHAR_THEME_COLOR_BLACK = 1;
-
- // Tables which contains resource ids for each character theme color
- private static final int[] KBD_PHONE = new int[] {R.xml.kbd_phone, R.xml.kbd_phone_black};
- private static final int[] KBD_PHONE_SYMBOLS = new int[] {
- R.xml.kbd_phone_symbols, R.xml.kbd_phone_symbols_black};
- private static final int[] KBD_SYMBOLS = new int[] {
- R.xml.kbd_symbols, R.xml.kbd_symbols_black};
- private static final int[] KBD_SYMBOLS_SHIFT = new int[] {
- R.xml.kbd_symbols_shift, R.xml.kbd_symbols_shift_black};
- private static final int[] KBD_QWERTY = new int[] {R.xml.kbd_qwerty, R.xml.kbd_qwerty_black};
+ R.layout.input_basic,
+ R.layout.input_basic_highcontrast,
+ R.layout.input_stone_normal,
+ R.layout.input_stone_bold,
+ R.layout.input_gingerbread,
+ R.layout.input_honeycomb, // DEFAULT_LAYOUT_ID
+ };
private static final int SYMBOLS_MODE_STATE_NONE = 0;
private static final int SYMBOLS_MODE_STATE_BEGIN = 1;
private static final int SYMBOLS_MODE_STATE_SYMBOL = 2;
+ private SubtypeSwitcher mSubtypeSwitcher;
+ private SharedPreferences mPrefs;
+
private LatinKeyboardView mInputView;
- private static final int[] ALPHABET_MODES = {
- KEYBOARDMODE_NORMAL,
- KEYBOARDMODE_URL,
- KEYBOARDMODE_EMAIL,
- KEYBOARDMODE_IM,
- KEYBOARDMODE_WEB,
- KEYBOARDMODE_NORMAL_WITH_SETTINGS_KEY,
- KEYBOARDMODE_URL_WITH_SETTINGS_KEY,
- KEYBOARDMODE_EMAIL_WITH_SETTINGS_KEY,
- KEYBOARDMODE_IM_WITH_SETTINGS_KEY,
- KEYBOARDMODE_WEB_WITH_SETTINGS_KEY };
-
- private final LatinIME mInputMethodService;
+ private LatinIME mInputMethodService;
+
+ private ShiftKeyState mShiftKeyState = new ShiftKeyState("Shift");
+ private ModifierKeyState mSymbolKeyState = new ModifierKeyState("Symbol");
private KeyboardId mSymbolsId;
private KeyboardId mSymbolsShiftedId;
private KeyboardId mCurrentId;
- private final HashMap<KeyboardId, SoftReference<LatinKeyboard>> mKeyboards;
+ private final HashMap<KeyboardId, SoftReference<LatinKeyboard>> mKeyboardCache =
+ new HashMap<KeyboardId, SoftReference<LatinKeyboard>>();
- private int mMode = MODE_NONE; /** One of the MODE_XXX values */
+ private int mMode = MODE_TEXT; /* default value */
private int mImeOptions;
private boolean mIsSymbols;
/** mIsAutoCompletionActive indicates that auto completed word will be input instead of
* what user actually typed. */
private boolean mIsAutoCompletionActive;
- private boolean mHasVoice;
- private boolean mVoiceOnPrimary;
- private boolean mPreferSymbols;
+ private boolean mVoiceKeyEnabled;
+ private boolean mVoiceButtonOnPrimary;
private int mSymbolsModeState = SYMBOLS_MODE_STATE_NONE;
// Indicates whether or not we have the settings key
private boolean mHasSettingsKey;
private static final int SETTINGS_KEY_MODE_AUTO = R.string.settings_key_mode_auto;
- private static final int SETTINGS_KEY_MODE_ALWAYS_SHOW = R.string.settings_key_mode_always_show;
+ private static final int SETTINGS_KEY_MODE_ALWAYS_SHOW =
+ R.string.settings_key_mode_always_show;
// NOTE: No need to have SETTINGS_KEY_MODE_ALWAYS_HIDE here because it's not being referred to
// in the source code now.
// Default is SETTINGS_KEY_MODE_AUTO.
private static final int DEFAULT_SETTINGS_KEY_MODE = SETTINGS_KEY_MODE_AUTO;
- private int mLastDisplayWidth;
- private LanguageSwitcher mLanguageSwitcher;
- private Locale mInputLocale;
-
private int mLayoutId;
- public KeyboardSwitcher(LatinIME ims) {
- mInputMethodService = ims;
-
- final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ims);
- mLayoutId = Integer.valueOf(prefs.getString(PREF_KEYBOARD_LAYOUT, DEFAULT_LAYOUT_ID));
- updateSettingsKeyState(prefs);
- prefs.registerOnSharedPreferenceChangeListener(this);
+ private static final KeyboardSwitcher sInstance = new KeyboardSwitcher();
- mKeyboards = new HashMap<KeyboardId, SoftReference<LatinKeyboard>>();
- mSymbolsId = makeSymbolsId(false);
- mSymbolsShiftedId = makeSymbolsShiftedId(false);
+ public static KeyboardSwitcher getInstance() {
+ return sInstance;
}
- /**
- * Sets the input locale, when there are multiple locales for input.
- * If no locale switching is required, then the locale should be set to null.
- * @param locale the current input locale, or null for default locale with no locale
- * button.
- */
- public void setLanguageSwitcher(LanguageSwitcher languageSwitcher) {
- mLanguageSwitcher = languageSwitcher;
- mInputLocale = mLanguageSwitcher.getInputLocale();
+ private KeyboardSwitcher() {
}
- private KeyboardId makeSymbolsId(boolean hasVoice) {
- return new KeyboardId(KBD_SYMBOLS[getCharColorId()], mHasSettingsKey ?
- KEYBOARDMODE_SYMBOLS_WITH_SETTINGS_KEY : KEYBOARDMODE_SYMBOLS,
- false, hasVoice);
- }
+ public static void init(LatinIME ims, SharedPreferences prefs) {
+ sInstance.mInputMethodService = ims;
+ sInstance.mPrefs = prefs;
+ sInstance.mSubtypeSwitcher = SubtypeSwitcher.getInstance();
- private KeyboardId makeSymbolsShiftedId(boolean hasVoice) {
- return new KeyboardId(KBD_SYMBOLS_SHIFT[getCharColorId()], mHasSettingsKey ?
- KEYBOARDMODE_SYMBOLS_WITH_SETTINGS_KEY : KEYBOARDMODE_SYMBOLS,
- false, hasVoice);
+ sInstance.mLayoutId = Integer.valueOf(
+ prefs.getString(PREF_KEYBOARD_LAYOUT, DEFAULT_LAYOUT_ID));
+ prefs.registerOnSharedPreferenceChangeListener(sInstance);
}
- public void makeKeyboards(boolean forceCreate) {
- mSymbolsId = makeSymbolsId(mHasVoice && !mVoiceOnPrimary);
- mSymbolsShiftedId = makeSymbolsShiftedId(mHasVoice && !mVoiceOnPrimary);
-
- if (forceCreate) mKeyboards.clear();
- // Configuration change is coming after the keyboard gets recreated. So don't rely on that.
- // If keyboards have already been made, check if we have a screen width change and
- // create the keyboard layouts again at the correct orientation
- int displayWidth = mInputMethodService.getMaxWidth();
- if (displayWidth == mLastDisplayWidth) return;
- mLastDisplayWidth = displayWidth;
- if (!forceCreate) mKeyboards.clear();
+ private void makeSymbolsKeyboardIds() {
+ final Locale locale = mSubtypeSwitcher.getInputLocale();
+ final int orientation = mInputMethodService.getResources().getConfiguration().orientation;
+ final int mode = mMode;
+ final int colorScheme = getColorScheme();
+ final boolean hasSettingsKey = mHasSettingsKey;
+ final boolean voiceKeyEnabled = mVoiceKeyEnabled;
+ final boolean hasVoiceKey = voiceKeyEnabled && !mVoiceButtonOnPrimary;
+ final int imeOptions = mImeOptions;
+ // Note: This comment is only applied for phone number keyboard layout.
+ // On non-xlarge device, "@integer/key_switch_alpha_symbol" key code is used to switch
+ // between "phone keyboard" and "phone symbols keyboard". But on xlarge device,
+ // "@integer/key_shift" key code is used for that purpose in order to properly display
+ // "more" and "locked more" key labels. To achieve these behavior, we should initialize
+ // mSymbolsId and mSymbolsShiftedId to "phone keyboard" and "phone symbols keyboard"
+ // respectively here for xlarge device's layout switching.
+ mSymbolsId = new KeyboardId(locale, orientation, mode,
+ mode == MODE_PHONE ? R.xml.kbd_phone : R.xml.kbd_symbols,
+ colorScheme, hasSettingsKey, voiceKeyEnabled, hasVoiceKey, imeOptions, true);
+ mSymbolsShiftedId = new KeyboardId(locale, orientation, mode,
+ mode == MODE_PHONE ? R.xml.kbd_phone_symbols : R.xml.kbd_symbols_shift,
+ colorScheme, hasSettingsKey, voiceKeyEnabled, hasVoiceKey, imeOptions, true);
}
/**
* Represents the parameters necessary to construct a new LatinKeyboard,
* which also serve as a unique identifier for each keyboard type.
*/
- private static class KeyboardId {
- // TODO: should have locale and portrait/landscape orientation?
- public final int mXml;
- public final int mKeyboardMode; /** A KEYBOARDMODE_XXX value */
+ public static class KeyboardId {
+ public final Locale mLocale;
+ public final int mOrientation;
+ public final int mMode;
+ public final int mXmlId;
+ public final int mColorScheme;
+ public final boolean mHasSettingsKey;
+ public final boolean mVoiceKeyEnabled;
+ public final boolean mHasVoiceKey;
+ public final int mImeOptions;
public final boolean mEnableShiftLock;
- public final boolean mHasVoice;
private final int mHashCode;
- public KeyboardId(int xml, int mode, boolean enableShiftLock, boolean hasVoice) {
- this.mXml = xml;
- this.mKeyboardMode = mode;
+ public KeyboardId(Locale locale, int orientation, int mode,
+ int xmlId, int colorScheme, boolean hasSettingsKey, boolean voiceKeyEnabled,
+ boolean hasVoiceKey, int imeOptions, boolean enableShiftLock) {
+ this.mLocale = locale;
+ this.mOrientation = orientation;
+ this.mMode = mode;
+ this.mXmlId = xmlId;
+ this.mColorScheme = colorScheme;
+ this.mHasSettingsKey = hasSettingsKey;
+ this.mVoiceKeyEnabled = voiceKeyEnabled;
+ this.mHasVoiceKey = hasVoiceKey;
+ // We are interested only in IME_MASK_ACTION enum value and IME_FLAG_NO_ENTER_ACTION.
+ this.mImeOptions = imeOptions
+ & (EditorInfo.IME_MASK_ACTION | EditorInfo.IME_FLAG_NO_ENTER_ACTION);
this.mEnableShiftLock = enableShiftLock;
- this.mHasVoice = hasVoice;
this.mHashCode = Arrays.hashCode(new Object[] {
- xml, mode, enableShiftLock, hasVoice
+ locale,
+ orientation,
+ mode,
+ xmlId,
+ colorScheme,
+ hasSettingsKey,
+ voiceKeyEnabled,
+ hasVoiceKey,
+ imeOptions,
+ enableShiftLock,
});
}
- public KeyboardId(int xml, boolean hasVoice) {
- this(xml, 0, false, hasVoice);
+ public int getXmlId() {
+ return mXmlId;
+ }
+
+ public boolean isAlphabetMode() {
+ return mXmlId == R.xml.kbd_qwerty;
}
@Override
@@ -217,202 +201,438 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
}
private boolean equals(KeyboardId other) {
- return other.mXml == this.mXml
- && other.mKeyboardMode == this.mKeyboardMode
- && other.mEnableShiftLock == this.mEnableShiftLock
- && other.mHasVoice == this.mHasVoice;
+ return other.mLocale.equals(this.mLocale)
+ && other.mOrientation == this.mOrientation
+ && other.mMode == this.mMode
+ && other.mXmlId == this.mXmlId
+ && other.mColorScheme == this.mColorScheme
+ && other.mHasSettingsKey == this.mHasSettingsKey
+ && other.mVoiceKeyEnabled == this.mVoiceKeyEnabled
+ && other.mHasVoiceKey == this.mHasVoiceKey
+ && other.mImeOptions == this.mImeOptions
+ && other.mEnableShiftLock == this.mEnableShiftLock;
}
@Override
public int hashCode() {
return mHashCode;
}
- }
- public void setVoiceMode(boolean enableVoice, boolean voiceOnPrimary) {
- if (enableVoice != mHasVoice || voiceOnPrimary != mVoiceOnPrimary) {
- mKeyboards.clear();
+ @Override
+ public String toString() {
+ return String.format("[%s %s %5s imeOptions=0x%08x xml=0x%08x %s%s%s%s%s]",
+ mLocale,
+ (mOrientation == 1 ? "port" : "land"),
+ modeName(mMode),
+ mImeOptions,
+ mXmlId,
+ colorSchemeName(mColorScheme),
+ (mHasSettingsKey ? " hasSettingsKey" : ""),
+ (mVoiceKeyEnabled ? " voiceKeyEnabled" : ""),
+ (mHasVoiceKey ? " hasVoiceKey" : ""),
+ (mEnableShiftLock ? " enableShiftLock" : ""));
+ }
+
+ private static String modeName(int mode) {
+ switch (mode) {
+ case MODE_TEXT: return "text";
+ case MODE_URL: return "url";
+ case MODE_EMAIL: return "email";
+ case MODE_IM: return "im";
+ case MODE_WEB: return "web";
+ case MODE_PHONE: return "phone";
+ case MODE_NUMBER: return "number";
+ }
+ return null;
+ }
+
+ private static String colorSchemeName(int colorScheme) {
+ switch (colorScheme) {
+ case BaseKeyboardView.COLOR_SCHEME_WHITE: return "white";
+ case BaseKeyboardView.COLOR_SCHEME_BLACK: return "black";
+ }
+ return null;
}
- mHasVoice = enableVoice;
- mVoiceOnPrimary = voiceOnPrimary;
- setKeyboardMode(mMode, mImeOptions, mHasVoice, mIsSymbols);
}
- private boolean hasVoiceButton(boolean isSymbols) {
- return mHasVoice && (isSymbols != mVoiceOnPrimary);
+ private boolean hasVoiceKey(boolean isSymbols) {
+ return mVoiceKeyEnabled && (isSymbols != mVoiceButtonOnPrimary);
}
- public void setKeyboardMode(int mode, int imeOptions, boolean enableVoice) {
+ public void loadKeyboard(int mode, int imeOptions, boolean voiceKeyEnabled,
+ boolean voiceButtonOnPrimary) {
mSymbolsModeState = SYMBOLS_MODE_STATE_NONE;
- mPreferSymbols = mode == MODE_SYMBOLS;
- if (mode == MODE_SYMBOLS) {
- mode = MODE_TEXT;
- }
try {
- setKeyboardMode(mode, imeOptions, enableVoice, mPreferSymbols);
+ loadKeyboardInternal(mode, imeOptions, voiceKeyEnabled, voiceButtonOnPrimary,
+ false);
} catch (RuntimeException e) {
- LatinImeLogger.logOnException(mode + "," + imeOptions + "," + mPreferSymbols, e);
+ Log.w(TAG, e);
+ LatinImeLogger.logOnException(mode + "," + imeOptions, e);
}
}
- private void setKeyboardMode(int mode, int imeOptions, boolean enableVoice, boolean isSymbols) {
+ private void loadKeyboardInternal(int mode, int imeOptions, boolean voiceButtonEnabled,
+ boolean voiceButtonOnPrimary, boolean isSymbols) {
if (mInputView == null) return;
+ mInputView.setPreviewEnabled(mInputMethodService.getPopupOn());
+
mMode = mode;
mImeOptions = imeOptions;
- if (enableVoice != mHasVoice) {
- // TODO clean up this unnecessary recursive call.
- setVoiceMode(enableVoice, mVoiceOnPrimary);
- }
+ mVoiceKeyEnabled = voiceButtonEnabled;
+ mVoiceButtonOnPrimary = voiceButtonOnPrimary;
mIsSymbols = isSymbols;
+ // Update the settings key state because number of enabled IMEs could have been changed
+ mHasSettingsKey = getSettingsKeyMode(mPrefs, mInputMethodService);
+ makeSymbolsKeyboardIds();
- mInputView.setPreviewEnabled(mInputMethodService.getPopupOn());
KeyboardId id = getKeyboardId(mode, imeOptions, isSymbols);
- LatinKeyboard keyboard = null;
- keyboard = getKeyboard(id);
-
- if (mode == MODE_PHONE) {
- mInputView.setPhoneKeyboard(keyboard);
- }
+ LatinKeyboard keyboard = getKeyboard(id);
mCurrentId = id;
mInputView.setKeyboard(keyboard);
- keyboard.setShifted(false);
- keyboard.setShiftLocked(keyboard.isShiftLocked());
- keyboard.setImeOptions(mInputMethodService.getResources(), mMode, imeOptions);
- keyboard.setColorOfSymbolIcons(mIsAutoCompletionActive, isBlackSym());
- // Update the settings key state because number of enabled IMEs could have been changed
- updateSettingsKeyState(PreferenceManager.getDefaultSharedPreferences(mInputMethodService));
}
private LatinKeyboard getKeyboard(KeyboardId id) {
- SoftReference<LatinKeyboard> ref = mKeyboards.get(id);
+ final SoftReference<LatinKeyboard> ref = mKeyboardCache.get(id);
LatinKeyboard keyboard = (ref == null) ? null : ref.get();
if (keyboard == null) {
- Resources orig = mInputMethodService.getResources();
- Configuration conf = orig.getConfiguration();
- Locale saveLocale = conf.locale;
- conf.locale = mInputLocale;
- orig.updateConfiguration(conf, null);
- keyboard = new LatinKeyboard(mInputMethodService, id.mXml, id.mKeyboardMode);
- keyboard.setVoiceMode(hasVoiceButton(id.mXml == R.xml.kbd_symbols
- || id.mXml == R.xml.kbd_symbols_black), mHasVoice);
- keyboard.setLanguageSwitcher(mLanguageSwitcher, mIsAutoCompletionActive, isBlackSym());
+ final Locale savedLocale = mSubtypeSwitcher.changeSystemLocale(
+ mSubtypeSwitcher.getInputLocale());
+
+ keyboard = new LatinKeyboard(mInputMethodService, id);
if (id.mEnableShiftLock) {
keyboard.enableShiftLock();
}
- mKeyboards.put(id, new SoftReference<LatinKeyboard>(keyboard));
- conf.locale = saveLocale;
- orig.updateConfiguration(conf, null);
+ mKeyboardCache.put(id, new SoftReference<LatinKeyboard>(keyboard));
+ if (DEBUG)
+ Log.d(TAG, "keyboard cache size=" + mKeyboardCache.size() + ": "
+ + ((ref == null) ? "LOAD" : "GCed") + " id=" + id);
+
+ mSubtypeSwitcher.changeSystemLocale(savedLocale);
+ } else if (DEBUG) {
+ Log.d(TAG, "keyboard cache size=" + mKeyboardCache.size() + ": HIT id=" + id);
}
+
+ keyboard.onAutoCompletionStateChanged(mIsAutoCompletionActive);
+ keyboard.setShifted(false);
return keyboard;
}
private KeyboardId getKeyboardId(int mode, int imeOptions, boolean isSymbols) {
- boolean hasVoice = hasVoiceButton(isSymbols);
- int charColorId = getCharColorId();
- // TODO: generalize for any KeyboardId
- int keyboardRowsResId = KBD_QWERTY[charColorId];
+ final boolean hasVoiceKey = hasVoiceKey(isSymbols);
+ final int charColorId = getColorScheme();
+ final int xmlId;
+ final boolean enableShiftLock;
+
if (isSymbols) {
if (mode == MODE_PHONE) {
- return new KeyboardId(KBD_PHONE_SYMBOLS[charColorId], hasVoice);
+ xmlId = R.xml.kbd_phone_symbols;
+ } else if (mode == MODE_NUMBER) {
+ // Note: MODE_NUMBER keyboard layout has no "switch alpha symbol" key.
+ xmlId = R.xml.kbd_number;
} else {
- return new KeyboardId(KBD_SYMBOLS[charColorId], mHasSettingsKey ?
- KEYBOARDMODE_SYMBOLS_WITH_SETTINGS_KEY : KEYBOARDMODE_SYMBOLS,
- false, hasVoice);
+ xmlId = R.xml.kbd_symbols;
+ }
+ enableShiftLock = false;
+ } else {
+ if (mode == MODE_PHONE) {
+ xmlId = R.xml.kbd_phone;
+ enableShiftLock = false;
+ } else if (mode == MODE_NUMBER) {
+ xmlId = R.xml.kbd_number;
+ enableShiftLock = false;
+ } else {
+ xmlId = R.xml.kbd_qwerty;
+ enableShiftLock = true;
}
}
- switch (mode) {
- case MODE_NONE:
- LatinImeLogger.logOnWarning(
- "getKeyboardId:" + mode + "," + imeOptions + "," + isSymbols);
- /* fall through */
- case MODE_TEXT:
- return new KeyboardId(keyboardRowsResId, mHasSettingsKey ?
- KEYBOARDMODE_NORMAL_WITH_SETTINGS_KEY : KEYBOARDMODE_NORMAL,
- true, hasVoice);
- case MODE_SYMBOLS:
- return new KeyboardId(KBD_SYMBOLS[charColorId], mHasSettingsKey ?
- KEYBOARDMODE_SYMBOLS_WITH_SETTINGS_KEY : KEYBOARDMODE_SYMBOLS,
- false, hasVoice);
- case MODE_PHONE:
- return new KeyboardId(KBD_PHONE[charColorId], hasVoice);
- case MODE_URL:
- return new KeyboardId(keyboardRowsResId, mHasSettingsKey ?
- KEYBOARDMODE_URL_WITH_SETTINGS_KEY : KEYBOARDMODE_URL, true, hasVoice);
- case MODE_EMAIL:
- return new KeyboardId(keyboardRowsResId, mHasSettingsKey ?
- KEYBOARDMODE_EMAIL_WITH_SETTINGS_KEY : KEYBOARDMODE_EMAIL, true, hasVoice);
- case MODE_IM:
- return new KeyboardId(keyboardRowsResId, mHasSettingsKey ?
- KEYBOARDMODE_IM_WITH_SETTINGS_KEY : KEYBOARDMODE_IM, true, hasVoice);
- case MODE_WEB:
- return new KeyboardId(keyboardRowsResId, mHasSettingsKey ?
- KEYBOARDMODE_WEB_WITH_SETTINGS_KEY : KEYBOARDMODE_WEB, true, hasVoice);
- }
- return null;
+ final int orientation = mInputMethodService.getResources().getConfiguration().orientation;
+ final Locale locale = mSubtypeSwitcher.getInputLocale();
+ return new KeyboardId(locale, orientation, mode, xmlId, charColorId,
+ mHasSettingsKey, mVoiceKeyEnabled, hasVoiceKey, imeOptions, enableShiftLock);
}
public int getKeyboardMode() {
return mMode;
}
-
+
public boolean isAlphabetMode() {
- if (mCurrentId == null) {
- return false;
+ return mCurrentId != null && mCurrentId.isAlphabetMode();
+ }
+
+ public boolean isInputViewShown() {
+ return mInputView != null && mInputView.isShown();
+ }
+
+ public boolean isKeyboardAvailable() {
+ if (mInputView != null)
+ return mInputView.getLatinKeyboard() != null;
+ return false;
+ }
+
+ private LatinKeyboard getLatinKeyboard() {
+ if (mInputView != null)
+ return mInputView.getLatinKeyboard();
+ return null;
+ }
+
+ public void setPreferredLetters(int[] frequencies) {
+ LatinKeyboard latinKeyboard = getLatinKeyboard();
+ if (latinKeyboard != null)
+ latinKeyboard.setPreferredLetters(frequencies);
+ }
+
+ public void keyReleased() {
+ LatinKeyboard latinKeyboard = getLatinKeyboard();
+ if (latinKeyboard != null)
+ latinKeyboard.keyReleased();
+ }
+
+ public boolean isShiftedOrShiftLocked() {
+ LatinKeyboard latinKeyboard = getLatinKeyboard();
+ if (latinKeyboard != null)
+ return latinKeyboard.isShiftedOrShiftLocked();
+ return false;
+ }
+
+ public boolean isShiftLocked() {
+ LatinKeyboard latinKeyboard = getLatinKeyboard();
+ if (latinKeyboard != null)
+ return latinKeyboard.isShiftLocked();
+ return false;
+ }
+
+ public boolean isAutomaticTemporaryUpperCase() {
+ LatinKeyboard latinKeyboard = getLatinKeyboard();
+ if (latinKeyboard != null)
+ return latinKeyboard.isAutomaticTemporaryUpperCase();
+ return false;
+ }
+
+ public boolean isManualTemporaryUpperCase() {
+ LatinKeyboard latinKeyboard = getLatinKeyboard();
+ if (latinKeyboard != null)
+ return latinKeyboard.isManualTemporaryUpperCase();
+ return false;
+ }
+
+ private void setManualTemporaryUpperCase(boolean shifted) {
+ LatinKeyboard latinKeyboard = getLatinKeyboard();
+ if (latinKeyboard != null) {
+ // On non-distinct multi touch panel device, we should also turn off the shift locked
+ // state when shift key is pressed to go to normal mode.
+ // On the other hand, on distinct multi touch panel device, turning off the shift locked
+ // state with shift key pressing is handled by onReleaseShift().
+ if (!hasDistinctMultitouch() && !shifted && latinKeyboard.isShiftLocked()) {
+ latinKeyboard.setShiftLocked(false);
+ }
+ if (latinKeyboard.setShifted(shifted)) {
+ mInputView.invalidateAllKeys();
+ }
}
- int currentMode = mCurrentId.mKeyboardMode;
- for (Integer mode : ALPHABET_MODES) {
- if (currentMode == mode) {
- return true;
+ }
+
+ private void setShiftLocked(boolean shiftLocked) {
+ LatinKeyboard latinKeyboard = getLatinKeyboard();
+ if (latinKeyboard != null && latinKeyboard.setShiftLocked(shiftLocked)) {
+ mInputView.invalidateAllKeys();
+ }
+ }
+
+ /**
+ * Toggle keyboard shift state triggered by user touch event.
+ */
+ public void toggleShift() {
+ mInputMethodService.mHandler.cancelUpdateShiftState();
+ if (DEBUG_STATE)
+ Log.d(TAG, "toggleShift:"
+ + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
+ + " shiftKeyState=" + mShiftKeyState);
+ if (isAlphabetMode()) {
+ setManualTemporaryUpperCase(!isShiftedOrShiftLocked());
+ } else {
+ toggleShiftInSymbol();
+ }
+ }
+
+ public void toggleCapsLock() {
+ mInputMethodService.mHandler.cancelUpdateShiftState();
+ if (DEBUG_STATE)
+ Log.d(TAG, "toggleCapsLock:"
+ + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
+ + " shiftKeyState=" + mShiftKeyState);
+ if (isAlphabetMode()) {
+ if (isShiftLocked()) {
+ // Shift key is long pressed while caps lock state, we will toggle back to normal
+ // state. And mark as if shift key is released.
+ setShiftLocked(false);
+ mShiftKeyState.onRelease();
+ } else {
+ setShiftLocked(true);
}
}
- return false;
}
- public void setShifted(boolean shifted) {
- if (mInputView != null) {
- mInputView.setShifted(shifted);
+ private void setAutomaticTemporaryUpperCase() {
+ LatinKeyboard latinKeyboard = getLatinKeyboard();
+ if (latinKeyboard != null) {
+ latinKeyboard.setAutomaticTemporaryUpperCase();
+ mInputView.invalidateAllKeys();
}
}
- public void setShiftLocked(boolean shiftLocked) {
- if (mInputView != null) {
- mInputView.setShiftLocked(shiftLocked);
+ /**
+ * Update keyboard shift state triggered by connected EditText status change.
+ */
+ public void updateShiftState() {
+ final ShiftKeyState shiftKeyState = mShiftKeyState;
+ if (DEBUG_STATE)
+ Log.d(TAG, "updateShiftState:"
+ + " autoCaps=" + mInputMethodService.getCurrentAutoCapsState()
+ + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
+ + " shiftKeyState=" + shiftKeyState);
+ if (isAlphabetMode()) {
+ if (!isShiftLocked() && !shiftKeyState.isIgnoring()) {
+ if (shiftKeyState.isReleasing() && mInputMethodService.getCurrentAutoCapsState()) {
+ // Only when shift key is releasing, automatic temporary upper case will be set.
+ setAutomaticTemporaryUpperCase();
+ } else {
+ setManualTemporaryUpperCase(shiftKeyState.isMomentary());
+ }
+ }
+ } else {
+ // In symbol keyboard mode, we should clear shift key state because only alphabet
+ // keyboard has shift key.
+ shiftKeyState.onRelease();
}
}
- public void toggleShift() {
+ public void changeKeyboardMode() {
+ if (DEBUG_STATE)
+ Log.d(TAG, "changeKeyboardMode:"
+ + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
+ + " shiftKeyState=" + mShiftKeyState);
+ toggleKeyboardMode();
+ if (isShiftLocked() && isAlphabetMode())
+ setShiftLocked(true);
+ updateShiftState();
+ }
+
+ public void onPressShift() {
+ if (!isKeyboardAvailable())
+ return;
+ ShiftKeyState shiftKeyState = mShiftKeyState;
+ if (DEBUG_STATE)
+ Log.d(TAG, "onPressShift:"
+ + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
+ + " shiftKeyState=" + shiftKeyState);
+ if (isAlphabetMode()) {
+ if (isShiftLocked()) {
+ // Shift key is pressed while caps lock state, we will treat this state as shifted
+ // caps lock state and mark as if shift key pressed while normal state.
+ shiftKeyState.onPress();
+ setManualTemporaryUpperCase(true);
+ } else if (isAutomaticTemporaryUpperCase()) {
+ // Shift key is pressed while automatic temporary upper case, we have to move to
+ // manual temporary upper case.
+ shiftKeyState.onPress();
+ setManualTemporaryUpperCase(true);
+ } else if (isShiftedOrShiftLocked()) {
+ // In manual upper case state, we just record shift key has been pressing while
+ // shifted state.
+ shiftKeyState.onPressOnShifted();
+ } else {
+ // In base layout, chording or manual temporary upper case mode is started.
+ shiftKeyState.onPress();
+ toggleShift();
+ }
+ } else {
+ // In symbol mode, just toggle symbol and symbol more keyboard.
+ shiftKeyState.onPress();
+ toggleShift();
+ }
+ }
+
+ public void onReleaseShift() {
+ if (!isKeyboardAvailable())
+ return;
+ ShiftKeyState shiftKeyState = mShiftKeyState;
+ if (DEBUG_STATE)
+ Log.d(TAG, "onReleaseShift:"
+ + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
+ + " shiftKeyState=" + shiftKeyState);
+ if (isAlphabetMode()) {
+ if (shiftKeyState.isMomentary()) {
+ // After chording input while normal state.
+ toggleShift();
+ } else if (isShiftLocked() && !shiftKeyState.isIgnoring()) {
+ // Shift has been pressed without chording while caps lock state.
+ toggleCapsLock();
+ } else if (isShiftedOrShiftLocked() && shiftKeyState.isPressingOnShifted()) {
+ // Shift has been pressed without chording while shifted state.
+ toggleShift();
+ }
+ }
+ shiftKeyState.onRelease();
+ }
+
+ public void onPressSymbol() {
+ if (DEBUG_STATE)
+ Log.d(TAG, "onReleaseShift:"
+ + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
+ + " symbolKeyState=" + mSymbolKeyState);
+ changeKeyboardMode();
+ mSymbolKeyState.onPress();
+ }
+
+ public void onReleaseSymbol() {
+ if (DEBUG_STATE)
+ Log.d(TAG, "onReleaseShift:"
+ + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
+ + " symbolKeyState=" + mSymbolKeyState);
+ if (mSymbolKeyState.isMomentary())
+ changeKeyboardMode();
+ mSymbolKeyState.onRelease();
+ }
+
+ public void onOtherKeyPressed() {
+ if (DEBUG_STATE)
+ Log.d(TAG, "onOtherKeyPressed:"
+ + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
+ + " shiftKeyState=" + mShiftKeyState
+ + " symbolKeyState=" + mSymbolKeyState);
+ mShiftKeyState.onOtherKeyPressed();
+ mSymbolKeyState.onOtherKeyPressed();
+ }
+
+ private void toggleShiftInSymbol() {
if (isAlphabetMode())
return;
+ final LatinKeyboard keyboard;
if (mCurrentId.equals(mSymbolsId) || !mCurrentId.equals(mSymbolsShiftedId)) {
- LatinKeyboard symbolsShiftedKeyboard = getKeyboard(mSymbolsShiftedId);
mCurrentId = mSymbolsShiftedId;
- mInputView.setKeyboard(symbolsShiftedKeyboard);
+ keyboard = getKeyboard(mCurrentId);
// Symbol shifted keyboard has an ALT key that has a caps lock style indicator. To
// enable the indicator, we need to call enableShiftLock() and setShiftLocked(true).
// Thus we can keep the ALT key's Key.on value true while LatinKey.onRelease() is
// called.
- symbolsShiftedKeyboard.enableShiftLock();
- symbolsShiftedKeyboard.setShiftLocked(true);
- symbolsShiftedKeyboard.setImeOptions(mInputMethodService.getResources(),
- mMode, mImeOptions);
+ keyboard.setShiftLocked(true);
} else {
- LatinKeyboard symbolsKeyboard = getKeyboard(mSymbolsId);
mCurrentId = mSymbolsId;
- mInputView.setKeyboard(symbolsKeyboard);
+ keyboard = getKeyboard(mCurrentId);
// Symbol keyboard has an ALT key that has a caps lock style indicator. To disable the
// indicator, we need to call enableShiftLock() and setShiftLocked(false).
- symbolsKeyboard.enableShiftLock();
- symbolsKeyboard.setShifted(false);
- symbolsKeyboard.setImeOptions(mInputMethodService.getResources(), mMode, mImeOptions);
+ keyboard.setShifted(false);
}
+ mInputView.setKeyboard(keyboard);
}
- public void toggleSymbols() {
- setKeyboardMode(mMode, mImeOptions, mHasVoice, !mIsSymbols);
- if (mIsSymbols && !mPreferSymbols) {
+ private void toggleKeyboardMode() {
+ loadKeyboardInternal(mMode, mImeOptions, mVoiceKeyEnabled, mVoiceButtonOnPrimary,
+ !mIsSymbols);
+ if (mIsSymbols) {
mSymbolsModeState = SYMBOLS_MODE_STATE_BEGIN;
} else {
mSymbolsModeState = SYMBOLS_MODE_STATE_NONE;
@@ -425,33 +645,34 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
/**
* Updates state machine to figure out when to automatically switch back to alpha mode.
- * Returns true if the keyboard needs to switch back
*/
- public boolean onKey(int key) {
- // Switch back to alpha mode if user types one or more non-space/enter characters
- // followed by a space/enter
+ public void onKey(int key) {
+ // Switch back to alpha mode if user types one or more non-space/enter
+ // characters followed by a space/enter
switch (mSymbolsModeState) {
- case SYMBOLS_MODE_STATE_BEGIN:
- if (key != LatinIME.KEYCODE_SPACE && key != LatinIME.KEYCODE_ENTER && key > 0) {
- mSymbolsModeState = SYMBOLS_MODE_STATE_SYMBOL;
- }
- break;
- case SYMBOLS_MODE_STATE_SYMBOL:
- if (key == LatinIME.KEYCODE_ENTER || key == LatinIME.KEYCODE_SPACE) return true;
- break;
+ case SYMBOLS_MODE_STATE_BEGIN:
+ if (key != LatinIME.KEYCODE_SPACE && key != LatinIME.KEYCODE_ENTER && key > 0) {
+ mSymbolsModeState = SYMBOLS_MODE_STATE_SYMBOL;
+ }
+ break;
+ case SYMBOLS_MODE_STATE_SYMBOL:
+ if (key == LatinIME.KEYCODE_ENTER || key == LatinIME.KEYCODE_SPACE) {
+ changeKeyboardMode();
+ }
+ break;
}
- return false;
}
public LatinKeyboardView getInputView() {
return mInputView;
}
- public void recreateInputView() {
- changeLatinKeyboardView(mLayoutId, true);
+ public LatinKeyboardView onCreateInputView() {
+ createInputViewInternal(mLayoutId, true);
+ return mInputView;
}
- private void changeLatinKeyboardView(int newLayout, boolean forceReset) {
+ private void createInputViewInternal(int newLayout, boolean forceReset) {
if (mLayoutId != newLayout || mInputView == null || forceReset) {
if (mInputView != null) {
mInputView.closing();
@@ -468,9 +689,11 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
).inflate(THEMES[newLayout], null);
tryGC = false;
} catch (OutOfMemoryError e) {
+ Log.w(TAG, "load keyboard failed: " + e);
tryGC = LatinIMEUtil.GCUtils.getInstance().tryGCOrWait(
mLayoutId + "," + newLayout, e);
} catch (InflateException e) {
+ Log.w(TAG, "load keyboard failed: " + e);
tryGC = LatinIMEUtil.GCUtils.getInstance().tryGCOrWait(
mLayoutId + "," + newLayout, e);
}
@@ -478,38 +701,37 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
mInputView.setOnKeyboardActionListener(mInputMethodService);
mLayoutId = newLayout;
}
+ }
+
+ private void postSetInputView() {
mInputMethodService.mHandler.post(new Runnable() {
+ @Override
public void run() {
if (mInputView != null) {
mInputMethodService.setInputView(mInputView);
}
mInputMethodService.updateInputViewShown();
- }});
+ }
+ });
}
+ @Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (PREF_KEYBOARD_LAYOUT.equals(key)) {
- changeLatinKeyboardView(
- Integer.valueOf(sharedPreferences.getString(key, DEFAULT_LAYOUT_ID)), false);
+ final int layoutId = Integer.valueOf(
+ sharedPreferences.getString(key, DEFAULT_LAYOUT_ID));
+ createInputViewInternal(layoutId, false);
+ postSetInputView();
} else if (LatinIMESettings.PREF_SETTINGS_KEY.equals(key)) {
- updateSettingsKeyState(sharedPreferences);
- recreateInputView();
- }
- }
-
- public boolean isBlackSym () {
- if (mInputView != null && mInputView.getSymbolColorScheme() == 1) {
- return true;
+ mHasSettingsKey = getSettingsKeyMode(sharedPreferences, mInputMethodService);
+ createInputViewInternal(mLayoutId, true);
+ postSetInputView();
}
- return false;
}
- private int getCharColorId () {
- if (isBlackSym()) {
- return CHAR_THEME_COLOR_BLACK;
- } else {
- return CHAR_THEME_COLOR_WHITE;
- }
+ private int getColorScheme() {
+ return (mInputView != null)
+ ? mInputView.getColorScheme() : BaseKeyboardView.COLOR_SCHEME_WHITE;
}
public void onAutoCompletionStateChanged(boolean isAutoCompletion) {
@@ -521,18 +743,23 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
}
}
- private void updateSettingsKeyState(SharedPreferences prefs) {
- Resources resources = mInputMethodService.getResources();
- final String settingsKeyMode = prefs.getString(LatinIMESettings.PREF_SETTINGS_KEY,
- resources.getString(DEFAULT_SETTINGS_KEY_MODE));
- // We show the settings key when 1) SETTINGS_KEY_MODE_ALWAYS_SHOW or
- // 2) SETTINGS_KEY_MODE_AUTO and there are two or more enabled IMEs on the system
- if (settingsKeyMode.equals(resources.getString(SETTINGS_KEY_MODE_ALWAYS_SHOW))
- || (settingsKeyMode.equals(resources.getString(SETTINGS_KEY_MODE_AUTO))
- && LatinIMEUtil.hasMultipleEnabledIMEs(mInputMethodService))) {
- mHasSettingsKey = true;
- } else {
- mHasSettingsKey = false;
+ private static boolean getSettingsKeyMode(SharedPreferences prefs, Context context) {
+ Resources resources = context.getResources();
+ final boolean showSettingsKeyOption = resources.getBoolean(
+ R.bool.config_enable_show_settings_key_option);
+ if (showSettingsKeyOption) {
+ final String settingsKeyMode = prefs.getString(LatinIMESettings.PREF_SETTINGS_KEY,
+ resources.getString(DEFAULT_SETTINGS_KEY_MODE));
+ // We show the settings key when 1) SETTINGS_KEY_MODE_ALWAYS_SHOW or
+ // 2) SETTINGS_KEY_MODE_AUTO and there are two or more enabled IMEs on the system
+ if (settingsKeyMode.equals(resources.getString(SETTINGS_KEY_MODE_ALWAYS_SHOW))
+ || (settingsKeyMode.equals(resources.getString(SETTINGS_KEY_MODE_AUTO))
+ && LatinIMEUtil.hasMultipleEnabledIMEsOrSubtypes(
+ ((InputMethodManager) context.getSystemService(
+ Context.INPUT_METHOD_SERVICE))))) {
+ return true;
+ }
}
+ return false;
}
}