Automaticaly snap back to the previous mode from sliding symbol input

Bug: 3280151

Change-Id: I48ea134639465d0cc178e524af8d7885d185957d
main
Tadashi G. Takaoka 2010-12-17 16:56:15 +09:00
parent 67a4ecacc7
commit 9e91472285
5 changed files with 94 additions and 25 deletions

View File

@ -89,6 +89,10 @@ public class KeyboardId {
return mXmlId == R.xml.kbd_qwerty;
}
public boolean isSymbolsKeyboard() {
return mXmlId == R.xml.kbd_symbols;
}
public boolean isPhoneKeyboard() {
return mMode == MODE_PHONE;
}

View File

@ -51,10 +51,6 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
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;
@ -79,7 +75,14 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
private boolean mIsAutoCorrectionActive;
private boolean mVoiceKeyEnabled;
private boolean mVoiceButtonOnPrimary;
private int mSymbolsModeState = SYMBOLS_MODE_STATE_NONE;
private static final int AUTO_MODE_SWITCH_STATE_ALPHA = 0;
private static final int AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN = 1;
private static final int AUTO_MODE_SWITCH_STATE_SYMBOL = 2;
// The following states are used only on the distinct multi-touch panel devices.
private static final int AUTO_MODE_SWITCH_STATE_MOMENTARY = 3;
private static final int AUTO_MODE_SWITCH_STATE_CHORDING = 4;
private int mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_ALPHA;
// Indicates whether or not we have the settings key
private boolean mHasSettingsKey;
@ -146,10 +149,9 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
public void loadKeyboard(int mode, int imeOptions, boolean voiceKeyEnabled,
boolean voiceButtonOnPrimary) {
mSymbolsModeState = SYMBOLS_MODE_STATE_NONE;
mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_ALPHA;
try {
loadKeyboardInternal(mode, imeOptions, voiceKeyEnabled, voiceButtonOnPrimary,
false);
loadKeyboardInternal(mode, imeOptions, voiceKeyEnabled, voiceButtonOnPrimary, false);
} catch (RuntimeException e) {
Log.w(TAG, e);
LatinImeLogger.logOnException(mode + "," + imeOptions, e);
@ -467,19 +469,22 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
public void onPressSymbol() {
if (DEBUG_STATE)
Log.d(TAG, "onReleaseShift:"
Log.d(TAG, "onPressSymbol:"
+ " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
+ " symbolKeyState=" + mSymbolKeyState);
changeKeyboardMode();
mSymbolKeyState.onPress();
mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_MOMENTARY;
}
public void onReleaseSymbol() {
if (DEBUG_STATE)
Log.d(TAG, "onReleaseShift:"
Log.d(TAG, "onReleaseSymbol:"
+ " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
+ " symbolKeyState=" + mSymbolKeyState);
if (mSymbolKeyState.isMomentary())
// Snap back to the previous keyboard mode if the user chords the mode change key and
// other key, then released the mode change key.
if (mAutoModeSwitchState == AUTO_MODE_SWITCH_STATE_CHORDING)
changeKeyboardMode();
mSymbolKeyState.onRelease();
}
@ -516,13 +521,21 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
mInputView.setKeyboard(keyboard);
}
public boolean isInMomentaryAutoModeSwitchState() {
return mAutoModeSwitchState == AUTO_MODE_SWITCH_STATE_MOMENTARY;
}
private int getPointerCount() {
return mInputView == null ? 0 : mInputView.getPointerCount();
}
private void toggleKeyboardMode() {
loadKeyboardInternal(mMode, mImeOptions, mVoiceKeyEnabled, mVoiceButtonOnPrimary,
!mIsSymbols);
if (mIsSymbols) {
mSymbolsModeState = SYMBOLS_MODE_STATE_BEGIN;
mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN;
} else {
mSymbolsModeState = SYMBOLS_MODE_STATE_NONE;
mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_ALPHA;
}
}
@ -531,18 +544,45 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
}
/**
* Updates state machine to figure out when to automatically switch back to alpha mode.
* Updates state machine to figure out when to automatically snap back to the previous mode.
*/
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 != Keyboard.CODE_SPACE && key != Keyboard.CODE_ENTER && key > 0) {
mSymbolsModeState = SYMBOLS_MODE_STATE_SYMBOL;
if (DEBUG_STATE)
Log.d(TAG, "onKey: code=" + key + " autoModeSwitchState=" + mAutoModeSwitchState
+ " pointers=" + getPointerCount());
switch (mAutoModeSwitchState) {
case AUTO_MODE_SWITCH_STATE_MOMENTARY:
// Only distinct multi touch devices can be in this state.
// On non-distinct multi touch devices, mode change key is handled by {@link onKey},
// not by {@link onPress} and {@link onRelease}. So, on such devices,
// {@link mAutoModeSwitchState} starts from {@link AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN},
// or {@link AUTO_MODE_SWITCH_STATE_ALPHA}, not from
// {@link AUTO_MODE_SWITCH_STATE_MOMENTARY}.
if (key == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
// Detected only the mode change key has been pressed, and then released.
if (mIsSymbols) {
mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN;
} else {
mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_ALPHA;
}
} else if (getPointerCount() == 1) {
// Snap back to the previous keyboard mode if the user pressed the mode change key
// and slid to other key, then released the finger.
changeKeyboardMode();
} 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.
mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_CHORDING;
}
break;
case SYMBOLS_MODE_STATE_SYMBOL:
case AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN:
if (key != Keyboard.CODE_SPACE && key != Keyboard.CODE_ENTER && key > 0) {
mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_SYMBOL;
}
break;
case AUTO_MODE_SWITCH_STATE_SYMBOL:
// Snap back to alpha keyboard mode if user types one or more non-space/enter
// characters followed by a space/enter.
if (key == Keyboard.CODE_ENTER || key == Keyboard.CODE_SPACE) {
changeKeyboardMode();
}

View File

@ -1308,15 +1308,21 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
return pointers.get(id);
}
public int getPointerCount() {
return mOldPointerCount;
}
@Override
public boolean onTouchEvent(MotionEvent me) {
final int pointerCount = me.getPointerCount();
final int action = me.getActionMasked();
final int pointerCount = me.getPointerCount();
final int oldPointerCount = mOldPointerCount;
mOldPointerCount = pointerCount;
// TODO: cleanup this code into a multi-touch to single-touch event converter class?
// If the device does not have distinct multi-touch support panel, ignore all multi-touch
// events except a transition from/to single-touch.
if (!mHasDistinctMultitouch && pointerCount > 1 && mOldPointerCount > 1) {
if (!mHasDistinctMultitouch && pointerCount > 1 && oldPointerCount > 1) {
return true;
}
@ -1372,7 +1378,6 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
if (!mHasDistinctMultitouch) {
// Use only main (id=0) pointer tracker.
PointerTracker tracker = getPointerTracker(0);
int oldPointerCount = mOldPointerCount;
if (pointerCount == 1 && oldPointerCount == 2) {
// Multi-touch to single touch transition.
// Send a down event for the latest pointer.
@ -1387,7 +1392,6 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
Log.w(TAG, "Unknown touch panel behavior: pointer count is " + pointerCount
+ " (old " + oldPointerCount + ")");
}
mOldPointerCount = pointerCount;
return true;
}

View File

@ -55,6 +55,10 @@ public class ModifierKeyState {
Log.d(TAG, mName + ".onOtherKeyPressed: " + toString(oldState) + " > " + this);
}
public boolean isPressing() {
return mState == PRESSING;
}
public boolean isReleasing() {
return mState == RELEASING;
}

View File

@ -50,6 +50,7 @@ public class PointerTracker {
private final UIHandler mHandler;
private final KeyDetector mKeyDetector;
private KeyboardActionListener mListener;
private final KeyboardSwitcher mKeyboardSwitcher;
private final boolean mHasDistinctMultitouch;
private final boolean mConfigSlidingKeyInputEnabled;
@ -175,6 +176,7 @@ public class PointerTracker {
mProxy = proxy;
mHandler = handler;
mKeyDetector = keyDetector;
mKeyboardSwitcher = KeyboardSwitcher.getInstance();
mKeyState = new KeyState(keyDetector);
mHasDistinctMultitouch = proxy.hasDistinctMultitouch();
mConfigSlidingKeyInputEnabled = res.getBoolean(R.bool.config_sliding_key_input_enabled);
@ -318,13 +320,22 @@ public class PointerTracker {
final Key oldKey = getKey(keyState.getKeyIndex());
if (isValidKeyIndex(keyIndex)) {
if (oldKey == null) {
// The pointer has been slid in to the new key, but the finger was not on any keys.
// In this case, we must call onPress() to notify that the new key is being pressed.
if (mListener != null)
mListener.onPress(getKey(keyIndex).mCodes[0]);
keyState.onMoveToNewKey(keyIndex, x, y);
startLongPressTimer(keyIndex);
} else if (!isMinorMoveBounce(x, y, keyIndex)) {
// The pointer has been slid in to the new key from the previous key, we must call
// onRelease() first to notify that the previous key has been released, then call
// onPress() to notify that the new key is being pressed.
if (mListener != null)
mListener.onRelease(oldKey.mCodes[0]);
if (mIsAllowedSlidingKeyInput) {
resetMultiTap();
if (mListener != null)
mListener.onPress(getKey(keyIndex).mCodes[0]);
keyState.onMoveToNewKey(keyIndex, x, y);
startLongPressTimer(keyIndex);
} else {
@ -334,7 +345,10 @@ public class PointerTracker {
}
}
} else {
// TODO: we should check isMinorMoveDebounce() first.
if (oldKey != null) {
// The pointer has been slid out from the previous key, we must call onRelease() to
// notify that the previous key has been released.
if (mListener != null)
mListener.onRelease(oldKey.mCodes[0]);
if (mIsAllowedSlidingKeyInput) {
@ -449,6 +463,9 @@ public class PointerTracker {
Key key = getKey(keyIndex);
if (key.mCodes[0] == Keyboard.CODE_SHIFT) {
mHandler.startLongPressShiftTimer(mLongPressShiftKeyTimeout, keyIndex, this);
} else if (mKeyboardSwitcher.isInMomentaryAutoModeSwitchState()) {
// We use longer timeout for sliding finger input started from the symbols mode key.
mHandler.startLongPressTimer(mLongPressKeyTimeout * 2, keyIndex, this);
} else {
mHandler.startLongPressTimer(mLongPressKeyTimeout, keyIndex, this);
}