From b3f789799a2983a9c97288686f11dfab369243c0 Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Thu, 22 Nov 2012 15:39:28 +0900 Subject: [PATCH] Cancel gesture typing by sliding out from keyboard Bug: 7594165 Change-Id: I7849d763e49b57716e8418fb8b6f90eca3a5d2ec --- .../keyboard/KeyboardActionListener.java | 4 ++ .../inputmethod/keyboard/PointerTracker.java | 55 ++++++++++++------- .../keyboard/internal/GestureStroke.java | 25 ++++++++- .../GestureStrokeWithPreviewPoints.java | 10 ++-- .../internal/PointerTrackerQueue.java | 10 ++++ .../keyboard/internal/PreviewPlacerView.java | 6 +- .../android/inputmethod/latin/LatinIME.java | 11 ++++ .../internal/PointerTrackerQueueTests.java | 3 + 8 files changed, 93 insertions(+), 31 deletions(-) diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java index b612f0927..14da9ebe6 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java @@ -80,6 +80,8 @@ public interface KeyboardActionListener { */ public void onEndBatchInput(InputPointers batchPointers); + public void onCancelBatchInput(); + /** * Called when user released a finger outside any key. */ @@ -107,6 +109,8 @@ public interface KeyboardActionListener { @Override public void onEndBatchInput(InputPointers batchPointers) {} @Override + public void onCancelBatchInput() {} + @Override public void onCancelInput() {} @Override public boolean onCustomRequest(int requestCode) { diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index c86805232..c8052af6a 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -305,8 +305,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element { // true if keyboard layout has been changed. private boolean mKeyboardLayoutHasBeenChanged; - // true if event is already translated to a key action. - private boolean mKeyAlreadyProcessed; + // true if this pointer is no longer tracking touch event. + private boolean mIsTrackingCanceled; // true if this pointer has been long-pressed and is showing a more keys panel. private boolean mIsShowingMoreKeysPanel; @@ -517,7 +517,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { mKeyboard = keyDetector.getKeyboard(); final int keyWidth = mKeyboard.mMostCommonKeyWidth; final int keyHeight = mKeyboard.mMostCommonKeyHeight; - mGestureStrokeWithPreviewPoints.setKeyboardGeometry(keyWidth); + mGestureStrokeWithPreviewPoints.setKeyboardGeometry(keyWidth, mKeyboard.mOccupiedHeight); final Key newKey = mKeyDetector.detectHitKey(mKeyX, mKeyY); if (newKey != mCurrentKey) { if (mDrawingProxy != null) { @@ -730,13 +730,15 @@ public final class PointerTracker implements PointerTrackerQueue.Element { synchronized (sAggregratedPointers) { mGestureStrokeWithPreviewPoints.appendAllBatchPoints(sAggregratedPointers); if (getActivePointerTrackerCount() == 1) { - if (DEBUG_LISTENER) { - Log.d(TAG, String.format("[%d] onEndBatchInput : batchPoints=%d", - mPointerId, sAggregratedPointers.getPointerSize())); - } sInGesture = false; sTimeRecorder.onEndBatchInput(eventTime); - mListener.onEndBatchInput(sAggregratedPointers); + if (!mIsTrackingCanceled) { + if (DEBUG_LISTENER) { + Log.d(TAG, String.format("[%d] onEndBatchInput : batchPoints=%d", + mPointerId, sAggregratedPointers.getPointerSize())); + } + mListener.onEndBatchInput(sAggregratedPointers); + } } } mDrawingProxy.showGesturePreviewTrail(this, isOldestTrackerInQueue(this)); @@ -784,7 +786,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { if (ProductionFlag.IS_EXPERIMENTAL) { ResearchLogger.pointerTracker_onDownEvent(deltaT, distance * distance); } - mKeyAlreadyProcessed = true; + cancelTracking(); return; } } @@ -821,7 +823,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { || (key != null && key.isModifier()) || mKeyDetector.alwaysAllowsSlidingInput(); mKeyboardLayoutHasBeenChanged = false; - mKeyAlreadyProcessed = false; + mIsTrackingCanceled = false; resetSlidingKeyInput(); if (key != null) { // This onPress call may have changed keyboard layout. Those cases are detected at @@ -853,7 +855,17 @@ public final class PointerTracker implements PointerTrackerQueue.Element { final boolean isMajorEvent, final Key key) { final int gestureTime = (int)(eventTime - sGestureFirstDownTime); if (mIsDetectingGesture) { - mGestureStrokeWithPreviewPoints.addPoint(x, y, gestureTime, isMajorEvent); + final boolean onValidArea = mGestureStrokeWithPreviewPoints.addPointOnKeyboard( + x, y, gestureTime, isMajorEvent); + if (!onValidArea) { + sPointerTrackerQueue.cancelAllPointerTracker(); + if (DEBUG_LISTENER) { + Log.d(TAG, String.format("[%d] onCancelBatchInput: batchPoints=%d", + mPointerId, sAggregratedPointers.getPointerSize())); + } + mListener.onCancelBatchInput(); + return; + } mayStartBatchInput(key); if (sInGesture) { mayUpdateBatchInput(eventTime, key); @@ -865,7 +877,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { if (DEBUG_MOVE_EVENT) { printTouchEvent("onMoveEvent:", x, y, eventTime); } - if (mKeyAlreadyProcessed) { + if (mIsTrackingCanceled) { return; } @@ -979,11 +991,11 @@ public final class PointerTracker implements PointerTrackerQueue.Element { + " detected sliding finger while multi touching", mPointerId)); } onUpEvent(x, y, eventTime); - mKeyAlreadyProcessed = true; + cancelTracking(); setReleasedKeyGraphics(oldKey); } else { if (!mIsDetectingGesture) { - mKeyAlreadyProcessed = true; + cancelTracking(); } setReleasedKeyGraphics(oldKey); } @@ -997,7 +1009,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { onMoveToNewKey(null, x, y); } else { if (!mIsDetectingGesture) { - mKeyAlreadyProcessed = true; + cancelTracking(); } } } @@ -1060,7 +1072,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { printTouchEvent("onPhntEvent:", getLastX(), getLastY(), eventTime); } onUpEventInternal(eventTime); - mKeyAlreadyProcessed = true; + cancelTracking(); } private void onUpEventInternal(final long eventTime) { @@ -1084,7 +1096,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { return; } - if (mKeyAlreadyProcessed) { + if (mIsTrackingCanceled) { return; } if (currentKey != null && !currentKey.isRepeatable()) { @@ -1098,8 +1110,13 @@ public final class PointerTracker implements PointerTrackerQueue.Element { onDownEvent(x, y, SystemClock.uptimeMillis(), handler); } + @Override + public void cancelTracking() { + mIsTrackingCanceled = true; + } + public void onLongPressed() { - mKeyAlreadyProcessed = true; + cancelTracking(); setReleasedKeyGraphics(mCurrentKey); sPointerTrackerQueue.remove(this); } @@ -1202,6 +1219,6 @@ public final class PointerTracker implements PointerTrackerQueue.Element { final Key key = mKeyDetector.detectHitKey(x, y); final String code = KeyDetector.printableCode(key); Log.d(TAG, String.format("[%d]%s%s %4d %4d %5d %s", mPointerId, - (mKeyAlreadyProcessed ? "-" : " "), title, x, y, eventTime, code)); + (mIsTrackingCanceled ? "-" : " "), title, x, y, eventTime, code)); } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java index f8244dd5b..aab14e968 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java @@ -27,6 +27,10 @@ public class GestureStroke { private static final boolean DEBUG = false; private static final boolean DEBUG_SPEED = false; + // The height of extra area above the keyboard to draw gesture trails. + // Proportional to the keyboard height. + public static final float EXTRA_GESTURE_TRAIL_AREA_ABOVE_KEYBOARD_RATIO = 0.25f; + public static final int DEFAULT_CAPACITY = 128; private final int mPointerId; @@ -37,6 +41,8 @@ public class GestureStroke { private final GestureStrokeParams mParams; private int mKeyWidth; // pixel + private int mMinYCoordinate; // pixel + private int mMaxYCoordinate; // pixel // Static threshold for starting gesture detection private int mDetectFastMoveSpeedThreshold; // pixel /sec private int mDetectFastMoveTime; @@ -135,8 +141,10 @@ public class GestureStroke { mParams = params; } - public void setKeyboardGeometry(final int keyWidth) { + public void setKeyboardGeometry(final int keyWidth, final int keyboardHeight) { mKeyWidth = keyWidth; + mMinYCoordinate = -(int)(keyboardHeight * EXTRA_GESTURE_TRAIL_AREA_ABOVE_KEYBOARD_RATIO); + mMaxYCoordinate = keyboardHeight - 1; // TODO: Find an appropriate base metric for these length. Maybe diagonal length of the key? mDetectFastMoveSpeedThreshold = (int)(keyWidth * mParams.mDetectFastMoveSpeedThreshold); mGestureDynamicDistanceThresholdFrom = @@ -167,7 +175,7 @@ public class GestureStroke { elapsedTimeAfterTyping, mAfterFastTyping ? " afterFastTyping" : "")); } final int elapsedTimeFromFirstDown = (int)(downTime - gestureFirstDownTime); - addPoint(x, y, elapsedTimeFromFirstDown, true /* isMajorEvent */); + addPointOnKeyboard(x, y, elapsedTimeFromFirstDown, true /* isMajorEvent */); } private int getGestureDynamicDistanceThreshold(final int deltaTime) { @@ -277,7 +285,17 @@ public class GestureStroke { return dist; } - public void addPoint(final int x, final int y, final int time, final boolean isMajorEvent) { + /** + * Add a touch event as a gesture point. Returns true if the touch event is on the valid + * gesture area. + * @param x the x-coordinate of the touch event + * @param y the y-coordinate of the touch event + * @param time the elapsed time in millisecond from the first gesture down + * @param isMajorEvent false if this is a historical move event + * @return true if the touch event is on the valid gesture area + */ + public boolean addPointOnKeyboard(final int x, final int y, final int time, + final boolean isMajorEvent) { final int size = mEventTimes.getLength(); if (size <= 0) { // Down event @@ -293,6 +311,7 @@ public class GestureStroke { updateIncrementalRecognitionSize(x, y, time); updateMajorEvent(x, y, time); } + return y >= mMinYCoordinate && y < mMaxYCoordinate; } private void updateIncrementalRecognitionSize(final int x, final int y, final int time) { diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java index 8192c9076..7ab7e9aad 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java @@ -56,8 +56,8 @@ public final class GestureStrokeWithPreviewPoints extends GestureStroke { } @Override - public void setKeyboardGeometry(final int keyWidth) { - super.setKeyboardGeometry(keyWidth); + public void setKeyboardGeometry(final int keyWidth, final int keyboardHeight) { + super.setKeyboardGeometry(keyWidth, keyboardHeight); final float sampleLength = keyWidth * MIN_PREVIEW_SAMPLE_LENGTH_RATIO_TO_KEY_WIDTH; mMinPreviewSampleLengthSquare = (int)(sampleLength * sampleLength); } @@ -69,8 +69,9 @@ public final class GestureStrokeWithPreviewPoints extends GestureStroke { } @Override - public void addPoint(final int x, final int y, final int time, final boolean isMajorEvent) { - super.addPoint(x, y, time, isMajorEvent); + public boolean addPointOnKeyboard(final int x, final int y, final int time, + final boolean isMajorEvent) { + final boolean onValidArea = super.addPointOnKeyboard(x, y, time, isMajorEvent); if (isMajorEvent || needsSampling(x, y)) { mPreviewEventTimes.add(time); mPreviewXCoordinates.add(x); @@ -78,6 +79,7 @@ public final class GestureStrokeWithPreviewPoints extends GestureStroke { mLastX = x; mLastY = y; } + return onValidArea; } public void appendPreviewStroke(final ResizableIntArray eventTimes, diff --git a/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java b/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java index a52f202aa..00fc885e8 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java +++ b/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java @@ -30,6 +30,7 @@ public final class PointerTrackerQueue { public boolean isModifier(); public boolean isInSlidingKeyInput(); public void onPhantomUpEvent(long eventTime); + public void cancelTracking(); } private static final int INITIAL_CAPACITY = 10; @@ -182,6 +183,15 @@ public final class PointerTrackerQueue { return false; } + public synchronized void cancelAllPointerTracker() { + final ArrayList expandableArray = mExpandableArrayOfActivePointers; + final int arraySize = mArraySize; + for (int index = 0; index < arraySize; index++) { + final Element element = expandableArray.get(index); + element.cancelTracking(); + } + } + @Override public synchronized String toString() { final StringBuilder sb = new StringBuilder(); diff --git a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java index 776ac0204..0d44ecdff 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java +++ b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java @@ -40,10 +40,6 @@ import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.StaticInnerHandlerWrapper; public final class PreviewPlacerView extends RelativeLayout { - // The height of extra area above the keyboard to draw gesture trails. - // Proportional to the keyboard height. - private static final float EXTRA_GESTURE_TRAIL_AREA_ABOVE_KEYBOARD_RATIO = 0.25f; - private final int mGestureFloatingPreviewTextColor; private final int mGestureFloatingPreviewTextOffset; private final int mGestureFloatingPreviewColor; @@ -175,7 +171,7 @@ public final class PreviewPlacerView extends RelativeLayout { public void setKeyboardViewGeometry(final int x, final int y, final int w, final int h) { mKeyboardViewOriginX = x; mKeyboardViewOriginY = y; - mOffscreenOffsetY = (int)(h * EXTRA_GESTURE_TRAIL_AREA_ABOVE_KEYBOARD_RATIO); + mOffscreenOffsetY = (int)(h * GestureStroke.EXTRA_GESTURE_TRAIL_AREA_ABOVE_KEYBOARD_RATIO); mOffscreenWidth = w; mOffscreenHeight = mOffscreenOffsetY + h; } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index e3508ac44..dc3ad4ff0 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1528,6 +1528,12 @@ public final class LatinIME extends InputMethodService implements KeyboardAction .sendToTarget(); } + public void onCancelBatchInput(final LatinIME latinIme) { + mInBatchInput = false; + latinIme.mHandler.showGesturePreviewAndSuggestionStrip( + SuggestedWords.EMPTY, true /* dismissGestureFloatingPreviewText */); + } + // Run in the UI thread. public synchronized SuggestedWords onEndBatchInput(final InputPointers batchPointers, final LatinIME latinIme) { @@ -1613,6 +1619,11 @@ public final class LatinIME extends InputMethodService implements KeyboardAction mKeyboardSwitcher.onCancelInput(); } + @Override + public void onCancelBatchInput() { + BatchInputUpdater.getInstance().onCancelBatchInput(this); + } + private void handleBackspace(final int spaceState) { // In many cases, we may have to put the keyboard in auto-shift state again. However // we want to wait a few milliseconds before doing it to avoid the keyboard flashing diff --git a/tests/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueueTests.java b/tests/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueueTests.java index 8fed28f9e..2c3e3a514 100644 --- a/tests/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueueTests.java +++ b/tests/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueueTests.java @@ -48,6 +48,9 @@ public class PointerTrackerQueueTests extends AndroidTestCase { mPhantomUpEventTime = eventTime + sPhantomUpCount; } + @Override + public void cancelTracking() {} + @Override public String toString() { return Integer.toString(mId);