aboutsummaryrefslogtreecommitdiffstats
path: root/java/src
diff options
context:
space:
mode:
Diffstat (limited to 'java/src')
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardId.java9
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java312
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java325
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java8
4 files changed, 353 insertions, 301 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
index 840857778..ecc821a4b 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
@@ -16,6 +16,7 @@
package com.android.inputmethod.keyboard;
+import android.text.TextUtils;
import android.view.inputmethod.EditorInfo;
import com.android.inputmethod.compat.EditorInfoCompatUtils;
@@ -177,6 +178,14 @@ public class KeyboardId {
);
}
+ public static boolean equivalentEditorInfoForKeyboard(EditorInfo a, EditorInfo b) {
+ if (a == null && b == null) return true;
+ if (a == null || b == null) return false;
+ return a.inputType == b.inputType
+ && a.imeOptions == b.imeOptions
+ && TextUtils.equals(a.privateImeOptions, b.privateImeOptions);
+ }
+
public static String modeName(int mode) {
switch (mode) {
case MODE_TEXT: return "text";
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 32aabf928..d38f25496 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -20,7 +20,6 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.ContextThemeWrapper;
@@ -44,7 +43,8 @@ import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Locale;
-public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceChangeListener {
+public class KeyboardSwitcher implements KeyboardState.SwitchActions,
+ SharedPreferences.OnSharedPreferenceChangeListener {
private static final String TAG = KeyboardSwitcher.class.getSimpleName();
private static final boolean DEBUG_CACHE = LatinImeLogger.sDBG;
public static final boolean DEBUG_STATE = false;
@@ -81,80 +81,15 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
private final HashMap<KeyboardId, SoftReference<LatinKeyboard>> mKeyboardCache =
new HashMap<KeyboardId, SoftReference<LatinKeyboard>>();
- private KeyboardLayoutState mSavedKeyboardState = new KeyboardLayoutState();
-
/** mIsAutoCorrectionActive indicates that auto corrected word will be input instead of
* what user actually typed. */
private boolean mIsAutoCorrectionActive;
- // TODO: Encapsulate these state handling to separate class and combine with ShiftKeyState
- // and ModifierKeyState into KeyboardState.
- private static final int SWITCH_STATE_ALPHA = 0;
- private static final int SWITCH_STATE_SYMBOL_BEGIN = 1;
- private static final int SWITCH_STATE_SYMBOL = 2;
- // The following states are used only on the distinct multi-touch panel devices.
- private static final int SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL = 3;
- private static final int SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE = 4;
- private static final int SWITCH_STATE_CHORDING_ALPHA = 5;
- private static final int SWITCH_STATE_CHORDING_SYMBOL = 6;
- private int mSwitchState = SWITCH_STATE_ALPHA;
-
- private String mLayoutSwitchBackSymbols;
-
private int mThemeIndex = -1;
private Context mThemeContext;
private static final KeyboardSwitcher sInstance = new KeyboardSwitcher();
- private class KeyboardLayoutState {
- private boolean mIsValid;
- private boolean mIsAlphabetMode;
- private boolean mIsShiftLocked;
- private boolean mIsShifted;
-
- public void save() {
- if (mCurrentId == null) {
- return;
- }
- mIsAlphabetMode = isAlphabetMode();
- if (mIsAlphabetMode) {
- mIsShiftLocked = mState.isShiftLocked();
- mIsShifted = !mIsShiftLocked && mState.isShiftedOrShiftLocked();
- } else {
- mIsShiftLocked = false;
- mIsShifted = mCurrentId.equals(mSymbolsShiftedKeyboardId);
- }
- mIsValid = true;
- }
-
- public KeyboardId getKeyboardId() {
- if (!mIsValid) return mMainKeyboardId;
-
- if (mIsAlphabetMode) {
- return mMainKeyboardId;
- } else {
- return mIsShifted ? mSymbolsShiftedKeyboardId : mSymbolsKeyboardId;
- }
- }
-
- public void restore() {
- if (!mIsValid) return;
- mIsValid = false;
-
- if (mIsAlphabetMode) {
- final boolean isAlphabetMode = isAlphabetMode();
- final boolean isShiftLocked = isAlphabetMode && mState.isShiftLocked();
- final boolean isShifted = !isShiftLocked && mState.isShiftedOrShiftLocked();
- if (mIsShiftLocked != isShiftLocked) {
- toggleCapsLock();
- } else if (mIsShifted != isShifted) {
- onPressShift(false);
- onReleaseShift(false);
- }
- }
- }
- }
-
public static KeyboardSwitcher getInstance() {
return sInstance;
}
@@ -173,7 +108,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
mResources = ims.getResources();
mPrefs = prefs;
mSubtypeSwitcher = SubtypeSwitcher.getInstance();
- mState = new KeyboardState();
+ mState = new KeyboardState(this);
setContextThemeWrapper(ims, getKeyboardThemeIndex(ims, prefs));
prefs.registerOnSharedPreferenceChangeListener(this);
}
@@ -205,9 +140,9 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
mMainKeyboardId = getKeyboardId(editorInfo, false, false, settingsValues);
mSymbolsKeyboardId = getKeyboardId(editorInfo, true, false, settingsValues);
mSymbolsShiftedKeyboardId = getKeyboardId(editorInfo, true, true, settingsValues);
- mLayoutSwitchBackSymbols = mResources.getString(R.string.layout_switch_back_symbols);
- setKeyboard(getKeyboard(mSavedKeyboardState.getKeyboardId()));
- mSavedKeyboardState.restore();
+ mState.onLoadKeyboard(mResources.getString(R.string.layout_switch_back_symbols));
+ mPrevMainKeyboardWasShiftLocked = false;
+ mState.onRestoreKeyboardState();
} catch (RuntimeException e) {
Log.w(TAG, "loading keyboard failed: " + mMainKeyboardId, e);
LatinImeLogger.logOnException(mMainKeyboardId.toString(), e);
@@ -215,7 +150,9 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
}
public void saveKeyboardState() {
- mSavedKeyboardState.save();
+ if (mCurrentId != null) {
+ mState.onSaveKeyboardState(isAlphabetMode(), isSymbolShifted());
+ }
}
public void onFinishInputView() {
@@ -231,7 +168,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
mKeyboardView.setKeyboard(keyboard);
mCurrentInputView.setKeyboardGeometry(keyboard.mTopPadding);
mCurrentId = keyboard.mId;
- mSwitchState = getSwitchState();
+ mState.onSetKeyboard(isAlphabetMode());
updateShiftLockState(keyboard);
mKeyboardView.setKeyPreviewPopupEnabled(
Settings.Values.isKeyPreviewPopupEnabled(mPrefs, mResources),
@@ -242,10 +179,6 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
updateShiftState();
}
- private int getSwitchState() {
- return isAlphabetMode() ? SWITCH_STATE_ALPHA : SWITCH_STATE_SYMBOL_BEGIN;
- }
-
private void updateShiftLockState(Keyboard keyboard) {
if (mCurrentId.equals(mSymbolsShiftedKeyboardId)) {
// Symbol keyboard may have an ALT key that has a caps lock style indicator (a.k.a.
@@ -381,7 +314,10 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
return mState.isManualTemporaryUpperCase();
}
- private void setShifted(int shiftMode) {
+ // Implements {@link KeyboardState.SwitchActions}.
+ @Override
+ public void setShifted(int shiftMode) {
+ mInputMethodService.mHandler.cancelUpdateShiftState();
LatinKeyboard latinKeyboard = getLatinKeyboard();
if (latinKeyboard == null)
return;
@@ -404,20 +340,28 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
mKeyboardView.invalidateAllKeys();
}
- private void setShiftLocked(boolean shiftLocked) {
+ // Implements {@link KeyboardState.SwitchActions}.
+ @Override
+ public void setShiftLocked(boolean shiftLocked) {
+ mInputMethodService.mHandler.cancelUpdateShiftState();
LatinKeyboard latinKeyboard = getLatinKeyboard();
if (latinKeyboard == null)
return;
mState.setShiftLocked(shiftLocked);
latinKeyboard.setShiftLocked(shiftLocked);
mKeyboardView.invalidateAllKeys();
+ if (!shiftLocked) {
+ // To be able to turn off caps lock by "double tap" on shift key, we should ignore
+ // the second tap of the "double tap" from now for a while because we just have
+ // already turned off caps lock above.
+ mKeyboardView.startIgnoringDoubleTap();
+ }
}
/**
* Toggle keyboard shift state triggered by user touch event.
*/
public void toggleShift() {
- mInputMethodService.mHandler.cancelUpdateShiftState();
if (DEBUG_STATE) {
Log.d(TAG, "toggleShift: " + mState);
}
@@ -429,16 +373,16 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
}
public void toggleCapsLock() {
- mInputMethodService.mHandler.cancelUpdateShiftState();
if (DEBUG_STATE) {
Log.d(TAG, "toggleCapsLock: " + mState);
}
if (isAlphabetMode()) {
if (mState.isShiftLocked()) {
+ setShiftLocked(false);
+ // TODO: Remove this.
// 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);
- mState.onToggleCapsLock();
+ mState.onReleaseCapsLock();
} else {
setShiftLocked(true);
}
@@ -452,12 +396,6 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
toggleAlphabetAndSymbols();
}
- private void startIgnoringDoubleTap() {
- if (mKeyboardView != null) {
- mKeyboardView.startIgnoringDoubleTap();
- }
- }
-
/**
* Update keyboard shift state triggered by connected EditText status change.
*/
@@ -466,19 +404,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
Log.d(TAG, "updateShiftState: " + mState
+ " autoCaps=" + mInputMethodService.getCurrentAutoCapsState());
}
- final boolean isAlphabetMode = isAlphabetMode();
- final boolean isShiftLocked = mState.isShiftLocked();
- if (isAlphabetMode) {
- if (!isShiftLocked && !mState.isShiftKeyIgnoring()) {
- if (mState.isShiftKeyReleasing() && mInputMethodService.getCurrentAutoCapsState()) {
- // Only when shift key is releasing, automatic temporary upper case will be set.
- setShifted(AUTOMATIC_SHIFT);
- } else {
- setShifted(mState.isShiftKeyMomentary() ? MANUAL_SHIFT : UNSHIFT);
- }
- }
- }
- mState.onUpdateShiftState(isAlphabetMode);
+ mState.onUpdateShiftState(isAlphabetMode(), mInputMethodService.getCurrentAutoCapsState());
}
public void onPressShift(boolean withSliding) {
@@ -487,33 +413,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
if (DEBUG_STATE) {
Log.d(TAG, "onPressShift: " + mState + " sliding=" + withSliding);
}
- final boolean isAlphabetMode = isAlphabetMode();
- final boolean isShiftLocked = mState.isShiftLocked();
- final boolean isAutomaticTemporaryUpperCase = mState.isAutomaticTemporaryUpperCase();
- final boolean isShiftedOrShiftLocked = mState.isShiftedOrShiftLocked();
- 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.
- setShifted(MANUAL_SHIFT);
- } else if (isAutomaticTemporaryUpperCase) {
- // Shift key is pressed while automatic temporary upper case, we have to move to
- // manual temporary upper case.
- setShifted(MANUAL_SHIFT);
- } else if (isShiftedOrShiftLocked) {
- // In manual upper case state, we just record shift key has been pressing while
- // shifted state.
- } else {
- // In base layout, chording or manual temporary upper case mode is started.
- toggleShift();
- }
- } else {
- // In symbol mode, just toggle symbol and symbol more keyboard.
- toggleShiftInSymbols();
- mSwitchState = SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE;
- }
- mState.onPressShift(isAlphabetMode, isShiftLocked, isAutomaticTemporaryUpperCase,
- isShiftedOrShiftLocked);
+ mState.onPressShift(isAlphabetMode(), isSymbolShifted());
}
public void onReleaseShift(boolean withSliding) {
@@ -522,65 +422,21 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
if (DEBUG_STATE) {
Log.d(TAG, "onReleaseShift: " + mState + " sliding=" + withSliding);
}
- final boolean isAlphabetMode = isAlphabetMode();
- final boolean isShiftLocked = mState.isShiftLocked();
- final boolean isShiftLockShifted = mState.isShiftLockShifted();
- final boolean isShiftedOrShiftLocked = mState.isShiftedOrShiftLocked();
- final boolean isManualTemporaryUpperCaseFromAuto =
- mState.isManualTemporaryUpperCaseFromAuto();
- if (isAlphabetMode) {
- if (mState.isShiftKeyMomentary()) {
- // After chording input while normal state.
- toggleShift();
- } else if (isShiftLocked && !isShiftLockShifted && (mState.isShiftKeyPressing()
- || mState.isShiftKeyPressingOnShifted()) && !withSliding) {
- // Shift has been long pressed, ignore this release.
- } else if (isShiftLocked && !mState.isShiftKeyIgnoring() && !withSliding) {
- // Shift has been pressed without chording while caps lock state.
- toggleCapsLock();
- // To be able to turn off caps lock by "double tap" on shift key, we should ignore
- // the second tap of the "double tap" from now for a while because we just have
- // already turned off caps lock above.
- startIgnoringDoubleTap();
- } else if (isShiftedOrShiftLocked && mState.isShiftKeyPressingOnShifted()
- && !withSliding) {
- // Shift has been pressed without chording while shifted state.
- toggleShift();
- } else if (isManualTemporaryUpperCaseFromAuto && mState.isShiftKeyPressing()
- && !withSliding) {
- // Shift has been pressed without chording while manual temporary upper case
- // transited from automatic temporary upper case.
- toggleShift();
- }
- } else {
- // In symbol mode, snap back to the previous keyboard mode if the user chords the shift
- // key and another key, then releases the shift key.
- if (mSwitchState == SWITCH_STATE_CHORDING_SYMBOL) {
- toggleShiftInSymbols();
- }
- }
- mState.onReleaseShift();
+ mState.onReleaseShift(isAlphabetMode(), isSymbolShifted(), withSliding);
}
public void onPressSymbol() {
if (DEBUG_STATE) {
Log.d(TAG, "onPressSymbol: " + mState);
}
- toggleAlphabetAndSymbols();
- mState.onPressSymbol();
- mSwitchState = SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL;
+ mState.onPressSymbol(isAlphabetMode());
}
public void onReleaseSymbol() {
if (DEBUG_STATE) {
Log.d(TAG, "onReleaseSymbol: " + mState);
- }
- // Snap back to the previous keyboard mode if the user chords the mode change key and
- // another key, then releases the mode change key.
- if (mSwitchState == SWITCH_STATE_CHORDING_ALPHA) {
- toggleAlphabetAndSymbols();
}
- mState.onReleaseSymbol();
+ mState.onReleaseSymbol(isAlphabetMode());
}
public void onOtherKeyPressed() {
@@ -591,29 +447,28 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
}
public void onCancelInput() {
- // Snap back to the previous keyboard mode if the user cancels sliding input.
- if (isSinglePointer()) {
- if (mSwitchState == SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL) {
- toggleAlphabetAndSymbols();
- } else if (mSwitchState == SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE) {
- toggleShiftInSymbols();
- }
- }
+ mState.onCancelInput(isAlphabetMode(), isSymbolShifted(), isSinglePointer());
}
+ // TODO: Move this variable to KeyboardState.
private boolean mPrevMainKeyboardWasShiftLocked;
- private void setSymbolsKeyboard() {
+ // Implements {@link KeyboardState.SwitchActions}.
+ @Override
+ public void setSymbolsKeyboard() {
mPrevMainKeyboardWasShiftLocked = mState.isShiftLocked();
setKeyboard(getKeyboard(mSymbolsKeyboardId));
}
- private void setAlphabetKeyboard() {
+ // Implements {@link KeyboardState.SwitchActions}.
+ @Override
+ public void setAlphabetKeyboard() {
setKeyboard(getKeyboard(mMainKeyboardId));
setShiftLocked(mPrevMainKeyboardWasShiftLocked);
mPrevMainKeyboardWasShiftLocked = false;
}
+ // TODO: Remove this method and merge into toggleKeyboardMode().
private void toggleAlphabetAndSymbols() {
if (isAlphabetMode()) {
setSymbolsKeyboard();
@@ -626,10 +481,13 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
return mCurrentId != null && mCurrentId.equals(mSymbolsShiftedKeyboardId);
}
- private void setSymbolsShiftedKeyboard() {
+ // Implements {@link KeyboardState.SwitchActions}.
+ @Override
+ public void setSymbolsShiftedKeyboard() {
setKeyboard(getKeyboard(mSymbolsShiftedKeyboardId));
}
+ // TODO: Remove this method and merge into toggleShift().
private void toggleShiftInSymbols() {
if (isSymbolShifted()) {
setSymbolsKeyboard();
@@ -639,8 +497,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
}
public boolean isInMomentarySwitchState() {
- return mSwitchState == SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL
- || mSwitchState == SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE;
+ return mState.isInMomentarySwitchState();
}
public boolean isVibrateAndSoundFeedbackRequired() {
@@ -655,84 +512,15 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
return mKeyboardView != null && mKeyboardView.hasDistinctMultitouch();
}
- private static boolean isSpaceCharacter(int c) {
- return c == Keyboard.CODE_SPACE || c == Keyboard.CODE_ENTER;
- }
-
- private boolean isLayoutSwitchBackCharacter(int c) {
- if (TextUtils.isEmpty(mLayoutSwitchBackSymbols)) return false;
- if (mLayoutSwitchBackSymbols.indexOf(c) >= 0) return true;
- return false;
- }
-
/**
* Updates state machine to figure out when to automatically snap back to the previous mode.
*/
- public void onKey(int code) {
+ public void onCodeInput(int code) {
if (DEBUG_STATE) {
- Log.d(TAG, "onKey: code=" + code + " switchState=" + mSwitchState
- + " isSinglePointer=" + isSinglePointer());
- }
- switch (mSwitchState) {
- case SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL:
- // Only distinct multi touch devices can be in this state.
- // On non-distinct multi touch devices, mode change key is handled by
- // {@link LatinIME#onCodeInput}, not by {@link LatinIME#onPress} and
- // {@link LatinIME#onRelease}. So, on such devices, {@link #mSwitchState} starts
- // from {@link #SWITCH_STATE_SYMBOL_BEGIN}, or {@link #SWITCH_STATE_ALPHA}, not from
- // {@link #SWITCH_STATE_MOMENTARY}.
- if (code == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
- // Detected only the mode change key has been pressed, and then released.
- if (mCurrentId.equals(mMainKeyboardId)) {
- mSwitchState = SWITCH_STATE_ALPHA;
- } else {
- mSwitchState = SWITCH_STATE_SYMBOL_BEGIN;
- }
- } else if (isSinglePointer()) {
- // Snap back to the previous keyboard mode if the user pressed the mode change key
- // and slid to other key, then released the finger.
- // If the user cancels the sliding input, snapping back to the previous keyboard
- // mode is handled by {@link #onCancelInput}.
- toggleAlphabetAndSymbols();
- } else {
- // Chording input is being started. The keyboard mode will be snapped back to the
- // previous mode in {@link onReleaseSymbol} when the mode change key is released.
- mSwitchState = SWITCH_STATE_CHORDING_ALPHA;
- }
- break;
- case SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE:
- if (code == Keyboard.CODE_SHIFT) {
- // Detected only the shift key has been pressed on symbol layout, and then released.
- mSwitchState = SWITCH_STATE_SYMBOL_BEGIN;
- } else if (isSinglePointer()) {
- // Snap back to the previous keyboard mode if the user pressed the shift key on
- // symbol mode and slid to other key, then released the finger.
- toggleShiftInSymbols();
- mSwitchState = SWITCH_STATE_SYMBOL;
- } else {
- // Chording input is being started. The keyboard mode will be snapped back to the
- // previous mode in {@link onReleaseShift} when the shift key is released.
- mSwitchState = SWITCH_STATE_CHORDING_SYMBOL;
- }
- break;
- case SWITCH_STATE_SYMBOL_BEGIN:
- if (!isSpaceCharacter(code) && code >= 0) {
- mSwitchState = SWITCH_STATE_SYMBOL;
- }
- // Snap back to alpha keyboard mode immediately if user types a quote character.
- if (isLayoutSwitchBackCharacter(code)) {
- setAlphabetKeyboard();
- }
- break;
- case SWITCH_STATE_SYMBOL:
- case SWITCH_STATE_CHORDING_SYMBOL:
- // Snap back to alpha keyboard mode if user types one or more non-space/enter
- // characters followed by a space/enter or a quote character.
- if (isSpaceCharacter(code) || isLayoutSwitchBackCharacter(code)) {
- setAlphabetKeyboard();
- }
- break;
+ Log.d(TAG, "onCodeInput: code=" + code + " isSinglePointer=" + isSinglePointer()
+ + " " + mState);
}
+ mState.onCodeInput(isAlphabetMode(), isSymbolShifted(), code, isSinglePointer());
}
public LatinKeyboardView getKeyboardView() {
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
index fd7e77863..ee5ef9164 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
@@ -16,15 +16,116 @@
package com.android.inputmethod.keyboard.internal;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.inputmethod.keyboard.Keyboard;
+
// TODO: Add unit tests
public class KeyboardState {
+ private static final String TAG = KeyboardState.class.getSimpleName();
+ private static final boolean DEBUG_STATE = false;
+
+ public interface SwitchActions {
+ public void setAlphabetKeyboard();
+ public static final int UNSHIFT = 0;
+ public static final int MANUAL_SHIFT = 1;
+ public static final int AUTOMATIC_SHIFT = 2;
+ public void setShifted(int shiftMode);
+ public void setShiftLocked(boolean shiftLocked);
+ public void setSymbolsKeyboard();
+ public void setSymbolsShiftedKeyboard();
+ }
+
private KeyboardShiftState mKeyboardShiftState = new KeyboardShiftState();
- // TODO: Combine these key state objects with auto mode switch state.
private ShiftKeyState mShiftKeyState = new ShiftKeyState("Shift");
private ModifierKeyState mSymbolKeyState = new ModifierKeyState("Symbol");
- public KeyboardState() {
+ private static final int SWITCH_STATE_ALPHA = 0;
+ private static final int SWITCH_STATE_SYMBOL_BEGIN = 1;
+ private static final int SWITCH_STATE_SYMBOL = 2;
+ // The following states are used only on the distinct multi-touch panel devices.
+ private static final int SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL = 3;
+ private static final int SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE = 4;
+ private static final int SWITCH_STATE_CHORDING_ALPHA = 5;
+ private static final int SWITCH_STATE_CHORDING_SYMBOL = 6;
+ private int mSwitchState = SWITCH_STATE_ALPHA;
+
+ private String mLayoutSwitchBackSymbols;
+
+ private final SwitchActions mSwitchActions;
+
+ private final SavedKeyboardState mSavedKeyboardState = new SavedKeyboardState();
+
+ private static class SavedKeyboardState {
+ public boolean mIsValid;
+ public boolean mIsAlphabetMode;
+ public boolean mIsShiftLocked;
+ public boolean mIsShifted;
+ }
+
+ public KeyboardState(SwitchActions switchActions) {
+ mSwitchActions = switchActions;
+ }
+
+ public void onLoadKeyboard(String layoutSwitchBackSymbols) {
+ mLayoutSwitchBackSymbols = layoutSwitchBackSymbols;
+ mKeyboardShiftState.setShifted(false);
+ mKeyboardShiftState.setShiftLocked(false);
+ mShiftKeyState.onRelease();
+ mSymbolKeyState.onRelease();
+ }
+
+ // TODO: Get rid of isAlphabetMode and isSymbolShifted arguments.
+ public void onSaveKeyboardState(boolean isAlphabetMode, boolean isSymbolShifted) {
+ final SavedKeyboardState state = mSavedKeyboardState;
+ state.mIsAlphabetMode = isAlphabetMode;
+ if (isAlphabetMode) {
+ state.mIsShiftLocked = isShiftLocked();
+ state.mIsShifted = !state.mIsShiftLocked && isShiftedOrShiftLocked();
+ } else {
+ state.mIsShiftLocked = false;
+ state.mIsShifted = isSymbolShifted;
+ }
+ state.mIsValid = true;
+ if (DEBUG_STATE) {
+ Log.d(TAG, "save: alphabet=" + state.mIsAlphabetMode
+ + " shiftLocked=" + state.mIsShiftLocked + " shift=" + state.mIsShifted);
+ }
+ }
+
+ public void onRestoreKeyboardState() {
+ final SavedKeyboardState state = mSavedKeyboardState;
+ if (DEBUG_STATE) {
+ Log.d(TAG, "restore: valid=" + state.mIsValid + " alphabet=" + state.mIsAlphabetMode
+ + " shiftLocked=" + state.mIsShiftLocked + " shift=" + state.mIsShifted);
+ }
+ if (!state.mIsValid || state.mIsAlphabetMode) {
+ mSwitchActions.setAlphabetKeyboard();
+ } else {
+ if (state.mIsShifted) {
+ mSwitchActions.setSymbolsShiftedKeyboard();
+ } else {
+ mSwitchActions.setSymbolsKeyboard();
+ }
+ }
+
+ if (!state.mIsValid) return;
+ state.mIsValid = false;
+
+ if (state.mIsAlphabetMode) {
+ mSwitchActions.setShiftLocked(state.mIsShiftLocked);
+ if (!state.mIsShiftLocked) {
+ mSwitchActions.setShifted(
+ state.mIsShifted ? SwitchActions.MANUAL_SHIFT : SwitchActions.UNSHIFT);
+ }
+ }
+ }
+
+ // TODO: Get rid of this method
+ public void onSetKeyboard(boolean isAlphabetMode) {
+ mSwitchState = isAlphabetMode ? SWITCH_STATE_ALPHA : SWITCH_STATE_SYMBOL_BEGIN;
}
public boolean isShiftLocked() {
@@ -66,40 +167,40 @@ public class KeyboardState {
mKeyboardShiftState.setAutomaticTemporaryUpperCase();
}
- // TODO: Get rid of this method
- public boolean isShiftKeyIgnoring() {
- return mShiftKeyState.isIgnoring();
- }
-
- // TODO: Get rid of this method
- public boolean isShiftKeyReleasing() {
- return mShiftKeyState.isReleasing();
- }
-
- // TODO: Get rid of this method
- public boolean isShiftKeyMomentary() {
- return mShiftKeyState.isMomentary();
- }
-
- // TODO: Get rid of this method
- public boolean isShiftKeyPressing() {
- return mShiftKeyState.isPressing();
+ private void toggleAlphabetAndSymbols(boolean isAlphabetMode) {
+ if (isAlphabetMode) {
+ mSwitchActions.setSymbolsKeyboard();
+ } else {
+ mSwitchActions.setAlphabetKeyboard();
+ }
}
- // TODO: Get rid of this method
- public boolean isShiftKeyPressingOnShifted() {
- return mShiftKeyState.isPressingOnShifted();
+ private void toggleShiftInSymbols(boolean isSymbolShifted) {
+ if (isSymbolShifted) {
+ mSwitchActions.setSymbolsKeyboard();
+ } else {
+ mSwitchActions.setSymbolsShiftedKeyboard();
+ }
}
- public void onToggleCapsLock() {
+ public void onReleaseCapsLock() {
mShiftKeyState.onRelease();
}
- public void onPressSymbol() {
+ // TODO: Get rid of isAlphabetMode argument.
+ public void onPressSymbol(boolean isAlphabetMode) {
+ toggleAlphabetAndSymbols(isAlphabetMode);
mSymbolKeyState.onPress();
+ mSwitchState = SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL;
}
- public void onReleaseSymbol() {
+ // TODO: Get rid of isAlphabetMode argument.
+ public void onReleaseSymbol(boolean isAlphabetMode) {
+ // Snap back to the previous keyboard mode if the user chords the mode change key and
+ // another key, then releases the mode change key.
+ if (mSwitchState == SWITCH_STATE_CHORDING_ALPHA) {
+ toggleAlphabetAndSymbols(isAlphabetMode);
+ }
mSymbolKeyState.onRelease();
}
@@ -108,48 +209,200 @@ public class KeyboardState {
mSymbolKeyState.onOtherKeyPressed();
}
- public void onUpdateShiftState(boolean isAlphabetMode) {
- if (!isAlphabetMode) {
+ // TODO: Get rid of isAlphabetMode argument.
+ public void onUpdateShiftState(boolean isAlphabetMode, boolean autoCaps) {
+ if (isAlphabetMode) {
+ if (!isShiftLocked() && !mShiftKeyState.isIgnoring()) {
+ if (mShiftKeyState.isReleasing() && autoCaps) {
+ // Only when shift key is releasing, automatic temporary upper case will be set.
+ mSwitchActions.setShifted(SwitchActions.AUTOMATIC_SHIFT);
+ } else {
+ mSwitchActions.setShifted(mShiftKeyState.isMomentary()
+ ? SwitchActions.MANUAL_SHIFT : SwitchActions.UNSHIFT);
+ }
+ }
+ } else {
// In symbol keyboard mode, we should clear shift key state because only alphabet
// keyboard has shift key.
mSymbolKeyState.onRelease();
}
}
- // TODO: Get rid of these boolean arguments.
- public void onPressShift(boolean isAlphabetMode, boolean isShiftLocked,
- boolean isAutomaticTemporaryUpperCase, boolean isShiftedOrShiftLocked) {
+ // TODO: Get rid of isAlphabetMode and isSymbolShifted arguments.
+ public void onPressShift(boolean isAlphabetMode, boolean isSymbolShifted) {
if (isAlphabetMode) {
- if (isShiftLocked) {
+ 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.
+ mSwitchActions.setShifted(SwitchActions.MANUAL_SHIFT);
mShiftKeyState.onPress();
- } else if (isAutomaticTemporaryUpperCase) {
+ } else if (isAutomaticTemporaryUpperCase()) {
// Shift key is pressed while automatic temporary upper case, we have to move to
// manual temporary upper case.
+ mSwitchActions.setShifted(SwitchActions.MANUAL_SHIFT);
mShiftKeyState.onPress();
- } else if (isShiftedOrShiftLocked) {
+ } else if (isShiftedOrShiftLocked()) {
// In manual upper case state, we just record shift key has been pressing while
// shifted state.
mShiftKeyState.onPressOnShifted();
} else {
// In base layout, chording or manual temporary upper case mode is started.
+ mSwitchActions.setShifted(SwitchActions.MANUAL_SHIFT);
mShiftKeyState.onPress();
}
} else {
// In symbol mode, just toggle symbol and symbol more keyboard.
+ toggleShiftInSymbols(isSymbolShifted);
+ mSwitchState = SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE;
mShiftKeyState.onPress();
}
}
- public void onReleaseShift() {
+ // TODO: Get rid of isAlphabetMode and isSymbolShifted arguments.
+ public void onReleaseShift(boolean isAlphabetMode, boolean isSymbolShifted,
+ boolean withSliding) {
+ if (isAlphabetMode) {
+ final boolean isShiftLocked = isShiftLocked();
+ if (mShiftKeyState.isMomentary()) {
+ // After chording input while normal state.
+ mSwitchActions.setShifted(SwitchActions.UNSHIFT);
+ } else if (isShiftLocked && !isShiftLockShifted() && (mShiftKeyState.isPressing()
+ || mShiftKeyState.isPressingOnShifted()) && !withSliding) {
+ // Shift has been long pressed, ignore this release.
+ } else if (isShiftLocked && !mShiftKeyState.isIgnoring() && !withSliding) {
+ // Shift has been pressed without chording while caps lock state.
+ mSwitchActions.setShiftLocked(false);
+ } else if (isShiftedOrShiftLocked() && mShiftKeyState.isPressingOnShifted()
+ && !withSliding) {
+ // Shift has been pressed without chording while shifted state.
+ mSwitchActions.setShifted(SwitchActions.UNSHIFT);
+ } else if (isManualTemporaryUpperCaseFromAuto() && mShiftKeyState.isPressing()
+ && !withSliding) {
+ // Shift has been pressed without chording while manual temporary upper case
+ // transited from automatic temporary upper case.
+ mSwitchActions.setShifted(SwitchActions.UNSHIFT);
+ }
+ } else {
+ // In symbol mode, snap back to the previous keyboard mode if the user chords the shift
+ // key and another key, then releases the shift key.
+ if (mSwitchState == SWITCH_STATE_CHORDING_SYMBOL) {
+ toggleShiftInSymbols(isSymbolShifted);
+ }
+ }
mShiftKeyState.onRelease();
}
+ // TODO: Get rid of isAlphabetMode and isSymbolShifted arguments.
+ public void onCancelInput(boolean isAlphabetMode, boolean isSymbolShifted,
+ boolean isSinglePointer) {
+ // Snap back to the previous keyboard mode if the user cancels sliding input.
+ if (isSinglePointer) {
+ if (mSwitchState == SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL) {
+ toggleAlphabetAndSymbols(isAlphabetMode);
+ } else if (mSwitchState == SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE) {
+ toggleShiftInSymbols(isSymbolShifted);
+ }
+ }
+ }
+
+ public boolean isInMomentarySwitchState() {
+ return mSwitchState == SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL
+ || mSwitchState == SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE;
+ }
+
+ private static boolean isSpaceCharacter(int c) {
+ return c == Keyboard.CODE_SPACE || c == Keyboard.CODE_ENTER;
+ }
+
+ private boolean isLayoutSwitchBackCharacter(int c) {
+ if (TextUtils.isEmpty(mLayoutSwitchBackSymbols)) return false;
+ if (mLayoutSwitchBackSymbols.indexOf(c) >= 0) return true;
+ return false;
+ }
+
+ // TODO: Get rid of isAlphabetMode and isSymbolShifted arguments.
+ public void onCodeInput(boolean isAlphabetMode, boolean isSymbolShifted, int code,
+ boolean isSinglePointer) {
+ switch (mSwitchState) {
+ case SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL:
+ // Only distinct multi touch devices can be in this state.
+ // On non-distinct multi touch devices, mode change key is handled by
+ // {@link LatinIME#onCodeInput}, not by {@link LatinIME#onPress} and
+ // {@link LatinIME#onRelease}. So, on such devices, {@link #mSwitchState} starts
+ // from {@link #SWITCH_STATE_SYMBOL_BEGIN}, or {@link #SWITCH_STATE_ALPHA}, not from
+ // {@link #SWITCH_STATE_MOMENTARY}.
+ if (code == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
+ // Detected only the mode change key has been pressed, and then released.
+ if (isAlphabetMode) {
+ mSwitchState = SWITCH_STATE_ALPHA;
+ } else {
+ mSwitchState = SWITCH_STATE_SYMBOL_BEGIN;
+ }
+ } else if (isSinglePointer) {
+ // Snap back to the previous keyboard mode if the user pressed the mode change key
+ // and slid to other key, then released the finger.
+ // If the user cancels the sliding input, snapping back to the previous keyboard
+ // mode is handled by {@link #onCancelInput}.
+ toggleAlphabetAndSymbols(isAlphabetMode);
+ } else {
+ // Chording input is being started. The keyboard mode will be snapped back to the
+ // previous mode in {@link onReleaseSymbol} when the mode change key is released.
+ mSwitchState = SWITCH_STATE_CHORDING_ALPHA;
+ }
+ break;
+ case SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE:
+ if (code == Keyboard.CODE_SHIFT) {
+ // Detected only the shift key has been pressed on symbol layout, and then released.
+ mSwitchState = SWITCH_STATE_SYMBOL_BEGIN;
+ } else if (isSinglePointer) {
+ // Snap back to the previous keyboard mode if the user pressed the shift key on
+ // symbol mode and slid to other key, then released the finger.
+ toggleShiftInSymbols(isSymbolShifted);
+ mSwitchState = SWITCH_STATE_SYMBOL;
+ } else {
+ // Chording input is being started. The keyboard mode will be snapped back to the
+ // previous mode in {@link onReleaseShift} when the shift key is released.
+ mSwitchState = SWITCH_STATE_CHORDING_SYMBOL;
+ }
+ break;
+ case SWITCH_STATE_SYMBOL_BEGIN:
+ if (!isSpaceCharacter(code) && code >= 0) {
+ mSwitchState = SWITCH_STATE_SYMBOL;
+ }
+ // Snap back to alpha keyboard mode immediately if user types a quote character.
+ if (isLayoutSwitchBackCharacter(code)) {
+ mSwitchActions.setAlphabetKeyboard();
+ }
+ break;
+ case SWITCH_STATE_SYMBOL:
+ case SWITCH_STATE_CHORDING_SYMBOL:
+ // Snap back to alpha keyboard mode if user types one or more non-space/enter
+ // characters followed by a space/enter or a quote character.
+ if (isSpaceCharacter(code) || isLayoutSwitchBackCharacter(code)) {
+ mSwitchActions.setAlphabetKeyboard();
+ }
+ break;
+ }
+ }
+
+ private static String switchStateToString(int switchState) {
+ switch (switchState) {
+ case SWITCH_STATE_ALPHA: return "ALPHA";
+ case SWITCH_STATE_SYMBOL_BEGIN: return "SYMBOL-BEGIN";
+ case SWITCH_STATE_SYMBOL: return "SYMBOL";
+ case SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL: return "MOMENTARY-ALPHA-SYMBOL";
+ case SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE: return "MOMENTARY-SYMBOL-MORE";
+ case SWITCH_STATE_CHORDING_ALPHA: return "CHORDING-ALPHA";
+ case SWITCH_STATE_CHORDING_SYMBOL: return "CHORDING-SYMBOL";
+ default: return null;
+ }
+ }
+
@Override
public String toString() {
return "[keyboard=" + mKeyboardShiftState
+ " shift=" + mShiftKeyState
- + " symbol=" + mSymbolKeyState + "]";
+ + " symbol=" + mSymbolKeyState
+ + " switch=" + switchStateToString(mSwitchState) + "]";
}
}
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 5f446a5c4..ab41b1018 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -62,6 +62,7 @@ import com.android.inputmethod.deprecated.VoiceProxy;
import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.keyboard.KeyboardActionListener;
+import com.android.inputmethod.keyboard.KeyboardId;
import com.android.inputmethod.keyboard.KeyboardSwitcher;
import com.android.inputmethod.keyboard.KeyboardView;
import com.android.inputmethod.keyboard.LatinKeyboard;
@@ -442,7 +443,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
}
public void onStartInputView(EditorInfo editorInfo, boolean restarting) {
- if (hasMessages(MSG_PENDING_IMS_CALLBACK) && editorInfo == mAppliedEditorInfo) {
+ if (hasMessages(MSG_PENDING_IMS_CALLBACK)
+ && KeyboardId.equivalentEditorInfoForKeyboard(editorInfo, mAppliedEditorInfo)) {
// Typically this is the second onStartInputView after orientation changed.
resetPendingImsCallback();
} else {
@@ -1372,7 +1374,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
mExpectingUpdateSelection = true;
break;
}
- switcher.onKey(primaryCode);
+ switcher.onCodeInput(primaryCode);
// Reset after any single keystroke
mEnteredText = null;
}
@@ -1388,7 +1390,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
ic.commitText(text, 1);
ic.endBatchEdit();
mKeyboardSwitcher.updateShiftState();
- mKeyboardSwitcher.onKey(Keyboard.CODE_DUMMY);
+ mKeyboardSwitcher.onCodeInput(Keyboard.CODE_DUMMY);
mSpaceState = SPACE_STATE_NONE;
mEnteredText = text;
}