Automaticaly snap back to the previous mode from sliding symbol input
Bug: 3280151 Change-Id: I48ea134639465d0cc178e524af8d7885d185957d
This commit is contained in:
parent
67a4ecacc7
commit
9e91472285
5 changed files with 94 additions and 25 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue