aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com/android/inputmethod/keyboard/PointerTracker.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/src/com/android/inputmethod/keyboard/PointerTracker.java')
-rw-r--r--java/src/com/android/inputmethod/keyboard/PointerTracker.java202
1 files changed, 137 insertions, 65 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index a1cac3f11..ee4ac950c 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -34,6 +34,7 @@ import com.android.inputmethod.latin.InputPointers;
import com.android.inputmethod.latin.LatinImeLogger;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.define.ProductionFlag;
+import com.android.inputmethod.latin.settings.Settings;
import com.android.inputmethod.latin.utils.CollectionUtils;
import com.android.inputmethod.latin.utils.CoordinateUtils;
import com.android.inputmethod.latin.utils.ResourceUtils;
@@ -63,7 +64,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
/**
* Get KeyboardActionListener object that is used to register key code and so on.
- * @return the KeyboardActionListner for this PointerTracker
+ * @return the KeyboardActionListner for this PointerTracke
*/
public KeyboardActionListener getKeyboardActionListener();
@@ -87,14 +88,14 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
public void dismissKeyPreview(PointerTracker tracker);
public void showSlidingKeyInputPreview(PointerTracker tracker);
public void dismissSlidingKeyInputPreview();
- public void showGestureTrail(PointerTracker tracker);
+ public void showGestureTrail(PointerTracker tracker, boolean showsFloatingPreviewText);
}
public interface TimerProxy {
public void startTypingStateTimer(Key typedKey);
public boolean isTypingState();
- public void startKeyRepeatTimer(PointerTracker tracker);
- public void startLongPressTimer(PointerTracker tracker);
+ public void startKeyRepeatTimer(PointerTracker tracker, int repeatCount, int delay);
+ public void startLongPressTimer(PointerTracker tracker, int delay);
public void cancelLongPressTimer();
public void startDoubleTapShiftKeyTimer();
public void cancelDoubleTapShiftKeyTimer();
@@ -110,9 +111,9 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
@Override
public boolean isTypingState() { return false; }
@Override
- public void startKeyRepeatTimer(PointerTracker tracker) {}
+ public void startKeyRepeatTimer(PointerTracker tracker, int repeatCount, int delay) {}
@Override
- public void startLongPressTimer(PointerTracker tracker) {}
+ public void startLongPressTimer(PointerTracker tracker, int delay) {}
@Override
public void cancelLongPressTimer() {}
@Override
@@ -137,6 +138,9 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
public final int mTouchNoiseThresholdTime;
public final int mTouchNoiseThresholdDistance;
public final int mSuppressKeyPreviewAfterBatchInputDuration;
+ public final int mKeyRepeatStartTimeout;
+ public final int mKeyRepeatInterval;
+ public final int mLongPressShiftLockTimeout;
public static final PointerTrackerParams DEFAULT = new PointerTrackerParams();
@@ -145,6 +149,9 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
mTouchNoiseThresholdTime = 0;
mTouchNoiseThresholdDistance = 0;
mSuppressKeyPreviewAfterBatchInputDuration = 0;
+ mKeyRepeatStartTimeout = 0;
+ mKeyRepeatInterval = 0;
+ mLongPressShiftLockTimeout = 0;
}
public PointerTrackerParams(final TypedArray mainKeyboardViewAttr) {
@@ -156,6 +163,12 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
R.styleable.MainKeyboardView_touchNoiseThresholdDistance, 0);
mSuppressKeyPreviewAfterBatchInputDuration = mainKeyboardViewAttr.getInt(
R.styleable.MainKeyboardView_suppressKeyPreviewAfterBatchInputDuration, 0);
+ mKeyRepeatStartTimeout = mainKeyboardViewAttr.getInt(
+ R.styleable.MainKeyboardView_keyRepeatStartTimeout, 0);
+ mKeyRepeatInterval = mainKeyboardViewAttr.getInt(
+ R.styleable.MainKeyboardView_keyRepeatInterval, 0);
+ mLongPressShiftLockTimeout = mainKeyboardViewAttr.getInt(
+ R.styleable.MainKeyboardView_longPressShiftLockTimeout, 0);
}
}
@@ -327,11 +340,14 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
// the more keys panel currently being shown. equals null if no panel is active.
private MoreKeysPanel mMoreKeysPanel;
+ private static final int MULTIPLIER_FOR_LONG_PRESS_TIMEOUT_IN_SLIDING_INPUT = 3;
// true if this pointer is in a sliding key input.
boolean mIsInSlidingKeyInput;
// true if this pointer is in a sliding key input from a modifier key,
// so that further modifier keys should be ignored.
boolean mIsInSlidingKeyInputFromModifier;
+ // if not a NOT_A_CODE, the key of this code is repeating
+ private int mCurrentRepeatingKeyCode = Constants.NOT_A_CODE;
// true if a sliding key input is allowed.
private boolean mIsAllowedSlidingKeyInput;
@@ -413,6 +429,10 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
return sPointerTrackerQueue.isAnyInSlidingKeyInput();
}
+ public static void cancelAllPointerTrackers() {
+ sPointerTrackerQueue.cancelAllPointerTrackers();
+ }
+
public static void setKeyboardActionListener(final KeyboardActionListener listener) {
final int trackersSize = sTrackers.size();
for (int i = 0; i < trackersSize; ++i) {
@@ -460,6 +480,10 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
mPointerId = id;
mGestureStrokeWithPreviewPoints = new GestureStrokeWithPreviewPoints(
id, sGestureStrokeParams, sGesturePreviewParams);
+ setKeyEventHandler(handler);
+ }
+
+ private void setKeyEventHandler(final KeyEventHandler handler) {
setKeyDetectorInner(handler.getKeyDetector());
mListener = handler.getKeyboardActionListener();
mDrawingProxy = handler.getDrawingProxy();
@@ -467,7 +491,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
}
// Returns true if keyboard has been changed by this callback.
- private boolean callListenerOnPressAndCheckKeyboardLayoutChange(final Key key) {
+ private boolean callListenerOnPressAndCheckKeyboardLayoutChange(final Key key,
+ final int repeatCount) {
// While gesture input is going on, this method should be a no-operation. But when gesture
// input has been canceled, <code>sInGesture</code> and <code>mIsDetectingGesture</code>
// are set to false. To keep this method is a no-operation,
@@ -477,17 +502,17 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
}
final boolean ignoreModifierKey = mIsInSlidingKeyInput && key.isModifier();
if (DEBUG_LISTENER) {
- Log.d(TAG, String.format("[%d] onPress : %s%s%s", mPointerId,
+ Log.d(TAG, String.format("[%d] onPress : %s%s%s%s", mPointerId,
KeyDetector.printableCode(key),
ignoreModifierKey ? " ignoreModifier" : "",
- key.isEnabled() ? "" : " disabled"));
+ key.isEnabled() ? "" : " disabled",
+ repeatCount > 0 ? " repeatCount=" + repeatCount : ""));
}
if (ignoreModifierKey) {
return false;
}
if (key.isEnabled()) {
- mListener.onPressKey(key.mCode, false /* isRepeatKey */,
- getActivePointerTrackerCount() == 1);
+ mListener.onPressKey(key.getCode(), repeatCount, getActivePointerTrackerCount() == 1);
final boolean keyboardLayoutHasBeenChanged = mKeyboardLayoutHasBeenChanged;
mKeyboardLayoutHasBeenChanged = false;
mTimerProxy.startTypingStateTimer(key);
@@ -598,10 +623,6 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
return mIsInSlidingKeyInput;
}
- public boolean isInSlidingKeyInputFromModifier() {
- return mIsInSlidingKeyInputFromModifier;
- }
-
public Key getKey() {
return mCurrentKey;
}
@@ -749,7 +770,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
return sPointerTrackerQueue.size();
}
- public boolean isOldestTrackerInQueue() {
+ private boolean isOldestTrackerInQueue() {
return sPointerTrackerQueue.getOldestElement() == this;
}
@@ -757,7 +778,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
if (sInGesture || !mGestureStrokeWithPreviewPoints.isStartOfAGesture()) {
return;
}
- if (key == null || !Character.isLetter(key.mCode)) {
+ if (key == null || !Character.isLetter(key.getCode())) {
return;
}
if (DEBUG_LISTENER) {
@@ -772,7 +793,9 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
dismissAllMoreKeysPanels();
}
mTimerProxy.cancelLongPressTimer();
- mDrawingProxy.showGestureTrail(this);
+ // A gesture floating preview text will be shown at the oldest pointer/finger on the screen.
+ mDrawingProxy.showGestureTrail(
+ this, isOldestTrackerInQueue() /* showsFloatingPreviewText */);
}
public void updateBatchInputByTimer(final long eventTime) {
@@ -788,7 +811,9 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
if (mIsTrackingForActionDisabled) {
return;
}
- mDrawingProxy.showGestureTrail(this);
+ // A gesture floating preview text will be shown at the oldest pointer/finger on the screen.
+ mDrawingProxy.showGestureTrail(
+ this, isOldestTrackerInQueue() /* showsFloatingPreviewText */);
}
private void updateBatchInput(final long eventTime) {
@@ -829,11 +854,13 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
if (mIsTrackingForActionDisabled) {
return;
}
- mDrawingProxy.showGestureTrail(this);
+ // A gesture floating preview text will be shown at the oldest pointer/finger on the screen.
+ mDrawingProxy.showGestureTrail(
+ this, isOldestTrackerInQueue() /* showsFloatingPreviewText */);
}
private void cancelBatchInput() {
- sPointerTrackerQueue.cancelAllPointerTracker();
+ cancelAllPointerTrackers();
mIsDetectingGesture = false;
if (!sInGesture) {
return;
@@ -845,8 +872,23 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
mListener.onCancelBatchInput();
}
- public void processMotionEvent(final int action, final int x, final int y, final long eventTime,
- final KeyEventHandler handler) {
+ public void processMotionEvent(final MotionEvent me, final KeyEventHandler handler) {
+ final int action = me.getActionMasked();
+ final long eventTime = me.getEventTime();
+ if (action == MotionEvent.ACTION_MOVE) {
+ final int pointerCount = me.getPointerCount();
+ for (int index = 0; index < pointerCount; index++) {
+ final int id = me.getPointerId(index);
+ final PointerTracker tracker = getPointerTracker(id, handler);
+ final int x = (int)me.getX(index);
+ final int y = (int)me.getY(index);
+ tracker.onMoveEvent(x, y, eventTime, me);
+ }
+ return;
+ }
+ final int index = me.getActionIndex();
+ final int x = (int)me.getX(index);
+ final int y = (int)me.getY(index);
switch (action) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
@@ -856,24 +898,18 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
case MotionEvent.ACTION_POINTER_UP:
onUpEvent(x, y, eventTime);
break;
- case MotionEvent.ACTION_MOVE:
- onMoveEvent(x, y, eventTime, null);
- break;
case MotionEvent.ACTION_CANCEL:
onCancelEvent(x, y, eventTime);
break;
}
}
- public void onDownEvent(final int x, final int y, final long eventTime,
+ private void onDownEvent(final int x, final int y, final long eventTime,
final KeyEventHandler handler) {
if (DEBUG_EVENT) {
printTouchEvent("onDownEvent:", x, y, eventTime);
}
- mDrawingProxy = handler.getDrawingProxy();
- mTimerProxy = handler.getTimerProxy();
- setKeyboardActionListener(handler.getKeyboardActionListener());
- setKeyDetectorInner(handler.getKeyDetector());
+ setKeyEventHandler(handler);
// Naive up-to-down noise filter.
final long deltaT = eventTime - mUpTime;
if (deltaT < sParams.mTouchNoiseThresholdTime) {
@@ -903,7 +939,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
if (!sShouldHandleGesture) {
return;
}
- // A gesture should start only from a non-modifier key.
+ // A gesture should start only from a non-modifier key. Note that the gesture detection is
+ // disabled when the key is repeating.
mIsDetectingGesture = (mKeyboard != null) && mKeyboard.mId.isAlphabetKeyboard()
&& key != null && !key.isModifier();
if (mIsDetectingGesture) {
@@ -933,7 +970,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
// This onPress call may have changed keyboard layout. Those cases are detected at
// {@link #setKeyboard}. In those cases, we should update key according to the new
// keyboard layout.
- if (callListenerOnPressAndCheckKeyboardLayoutChange(key)) {
+ if (callListenerOnPressAndCheckKeyboardLayoutChange(key, 0 /* repeatCount */)) {
key = onDownKey(x, y, eventTime);
}
@@ -983,7 +1020,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
}
}
- public void onMoveEvent(final int x, final int y, final long eventTime, final MotionEvent me) {
+ private void onMoveEvent(final int x, final int y, final long eventTime, final MotionEvent me) {
if (DEBUG_MOVE_EVENT) {
printTouchEvent("onMoveEvent:", x, y, eventTime);
}
@@ -1009,7 +1046,9 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
final int translatedY = mMoreKeysPanel.translateY(y);
mMoreKeysPanel.onMoveEvent(translatedX, translatedY, mPointerId, eventTime);
onMoveKey(x, y);
- mDrawingProxy.showSlidingKeyInputPreview(this);
+ if (mIsInSlidingKeyInputFromModifier) {
+ mDrawingProxy.showSlidingKeyInputPreview(this);
+ }
return;
}
onMoveEventInternal(x, y, eventTime);
@@ -1021,7 +1060,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
// at {@link #setKeyboard}. In those cases, we should update key according
// to the new keyboard layout.
Key key = newKey;
- if (callListenerOnPressAndCheckKeyboardLayoutChange(key)) {
+ if (callListenerOnPressAndCheckKeyboardLayoutChange(key, 0 /* repeatCount */)) {
key = onMoveKey(x, y);
}
onMoveToNewKey(key, x, y);
@@ -1039,8 +1078,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
+ " phantom sudden move event (distance=%d) is translated to "
+ "up[%d,%d,%s]/down[%d,%d,%s] events", mPointerId,
getDistance(x, y, lastX, lastY),
- lastX, lastY, Constants.printableCode(oldKey.mCode),
- x, y, Constants.printableCode(key.mCode)));
+ lastX, lastY, Constants.printableCode(oldKey.getCode()),
+ x, y, Constants.printableCode(key.getCode())));
}
// TODO: This should be moved to outside of this nested if-clause?
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
@@ -1062,8 +1101,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
+ " bogus down-move-up event (raidus=%.2f key diagonal) is "
+ " translated to up[%d,%d,%s]/down[%d,%d,%s] events",
mPointerId, radiusRatio,
- lastX, lastY, Constants.printableCode(oldKey.mCode),
- x, y, Constants.printableCode(key.mCode)));
+ lastX, lastY, Constants.printableCode(oldKey.getCode()),
+ x, y, Constants.printableCode(key.getCode())));
}
onUpEventInternal(x, y, eventTime);
onDownEventInternal(x, y, eventTime);
@@ -1071,7 +1110,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
private void processSildeOutFromOldKey(final Key oldKey) {
setReleasedKeyGraphics(oldKey);
- callListenerOnRelease(oldKey, oldKey.mCode, true /* withSliding */);
+ callListenerOnRelease(oldKey, oldKey.getCode(), true /* withSliding */);
startSlidingKeyInput(oldKey);
mTimerProxy.cancelKeyTimers();
}
@@ -1164,10 +1203,12 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
slideOutFromOldKey(oldKey, x, y);
}
}
- mDrawingProxy.showSlidingKeyInputPreview(this);
+ if (mIsInSlidingKeyInputFromModifier) {
+ mDrawingProxy.showSlidingKeyInputPreview(this);
+ }
}
- public void onUpEvent(final int x, final int y, final long eventTime) {
+ private void onUpEvent(final int x, final int y, final long eventTime) {
if (DEBUG_EVENT) {
printTouchEvent("onUpEvent :", x, y, eventTime);
}
@@ -1209,6 +1250,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
mIsDetectingGesture = false;
final Key currentKey = mCurrentKey;
mCurrentKey = null;
+ final int currentRepeatingKeyCode = mCurrentRepeatingKeyCode;
+ mCurrentRepeatingKeyCode = Constants.NOT_A_CODE;
// Release the last pressed key.
setReleasedKeyGraphics(currentKey);
@@ -1225,7 +1268,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
if (sInGesture) {
if (currentKey != null) {
- callListenerOnRelease(currentKey, currentKey.mCode, true /* withSliding */);
+ callListenerOnRelease(currentKey, currentKey.getCode(), true /* withSliding */);
}
mayEndBatchInput(eventTime);
return;
@@ -1234,8 +1277,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
if (mIsTrackingForActionDisabled) {
return;
}
- if (currentKey != null && currentKey.isRepeatable() && !isInSlidingKeyInput) {
- // Repeatable key has been registered in {@link #onDownEventInternal(int,int,long)}.
+ if (currentKey != null && currentKey.isRepeatable()
+ && (currentKey.getCode() == currentRepeatingKeyCode) && !isInSlidingKeyInput) {
return;
}
detectAndSendKey(currentKey, mKeyX, mKeyY, eventTime);
@@ -1244,12 +1287,12 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
}
}
- public void onShowMoreKeysPanel(final int translatedX, final int translatedY,
- final MoreKeysPanel panel) {
+ public void onShowMoreKeysPanel(final MoreKeysPanel panel) {
setReleasedKeyGraphics(mCurrentKey);
- final long eventTime = SystemClock.uptimeMillis();
+ final int translatedX = panel.translateX(mLastX);
+ final int translatedY = panel.translateY(mLastY);
+ panel.onDownEvent(translatedX, translatedY, mPointerId, SystemClock.uptimeMillis());
mMoreKeysPanel = panel;
- mMoreKeysPanel.onDownEvent(translatedX, translatedY, mPointerId, eventTime);
}
@Override
@@ -1267,13 +1310,13 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
sPointerTrackerQueue.remove(this);
}
- public void onCancelEvent(final int x, final int y, final long eventTime) {
+ private void onCancelEvent(final int x, final int y, final long eventTime) {
if (DEBUG_EVENT) {
printTouchEvent("onCancelEvt:", x, y, eventTime);
}
cancelBatchInput();
- sPointerTrackerQueue.cancelAllPointerTracker();
+ cancelAllPointerTrackers();
sPointerTrackerQueue.releaseAllPointers(eventTime);
onCancelEventInternal();
}
@@ -1288,16 +1331,6 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
}
}
- private void startRepeatKey(final Key key) {
- if (sInGesture) return;
- if (key == null) return;
- if (!key.isRepeatable()) return;
- // Don't start key repeat when we are in sliding input mode.
- if (mIsInSlidingKeyInput) return;
- detectAndSendKey(key, key.mX, key.mY, SystemClock.uptimeMillis());
- mTimerProxy.startKeyRepeatTimer(this);
- }
-
private boolean isMajorEnoughMoveToBeOnNewKey(final int x, final int y, final long eventTime,
final Key newKey) {
if (mKeyDetector == null) {
@@ -1348,8 +1381,23 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
// doesn't have its more keys. (e.g. spacebar, globe key)
// We always need to start the long press timer if the key has its more keys regardless of
// whether or not we are in the sliding input mode.
- if (mIsInSlidingKeyInput && key.mMoreKeys == null) return;
- mTimerProxy.startLongPressTimer(this);
+ if (mIsInSlidingKeyInput && key.getMoreKeys() == null) return;
+ final int delay;
+ switch (key.getCode()) {
+ case Constants.CODE_SHIFT:
+ delay = sParams.mLongPressShiftLockTimeout;
+ break;
+ default:
+ final int longpressTimeout = Settings.getInstance().getCurrent().mKeyLongpressTimeout;
+ if (mIsInSlidingKeyInputFromModifier) {
+ // We use longer timeout for sliding finger input started from the modifier key.
+ delay = longpressTimeout * MULTIPLIER_FOR_LONG_PRESS_TIMEOUT_IN_SLIDING_INPUT;
+ } else {
+ delay = longpressTimeout;
+ }
+ break;
+ }
+ mTimerProxy.startLongPressTimer(this, delay);
}
private void detectAndSendKey(final Key key, final int x, final int y, final long eventTime) {
@@ -1358,11 +1406,35 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
return;
}
- final int code = key.mCode;
+ final int code = key.getCode();
callListenerOnCodeInput(key, code, x, y, eventTime);
callListenerOnRelease(key, code, false /* withSliding */);
}
+ private void startRepeatKey(final Key key) {
+ if (sInGesture) return;
+ if (key == null) return;
+ if (!key.isRepeatable()) return;
+ // Don't start key repeat when we are in sliding input mode.
+ if (mIsInSlidingKeyInput) return;
+ final int startRepeatCount = 1;
+ mTimerProxy.startKeyRepeatTimer(this, startRepeatCount, sParams.mKeyRepeatStartTimeout);
+ }
+
+ public void onKeyRepeat(final int code, final int repeatCount) {
+ final Key key = getKey();
+ if (key == null || key.getCode() != code) {
+ mCurrentRepeatingKeyCode = Constants.NOT_A_CODE;
+ return;
+ }
+ mCurrentRepeatingKeyCode = code;
+ mIsDetectingGesture = false;
+ final int nextRepeatCount = repeatCount + 1;
+ mTimerProxy.startKeyRepeatTimer(this, nextRepeatCount, sParams.mKeyRepeatInterval);
+ callListenerOnPressAndCheckKeyboardLayoutChange(key, repeatCount);
+ callListenerOnCodeInput(key, code, mKeyX, mKeyY, SystemClock.uptimeMillis());
+ }
+
private void printTouchEvent(final String title, final int x, final int y,
final long eventTime) {
final Key key = mKeyDetector.detectHitKey(x, y);