diff options
Diffstat (limited to 'java/src')
9 files changed, 356 insertions, 148 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index d4e3e2928..5e02926de 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -22,12 +22,13 @@ import android.os.SystemClock; import android.util.Log; import android.view.MotionEvent; +import com.android.inputmethod.keyboard.internal.BatchInputArbiter; +import com.android.inputmethod.keyboard.internal.BatchInputArbiter.BatchInputArbiterListener; import com.android.inputmethod.keyboard.internal.BogusMoveEventDetector; import com.android.inputmethod.keyboard.internal.GestureEnabler; import com.android.inputmethod.keyboard.internal.GestureStrokeDrawingParams; import com.android.inputmethod.keyboard.internal.GestureStrokeDrawingPoints; import com.android.inputmethod.keyboard.internal.GestureStrokeRecognitionParams; -import com.android.inputmethod.keyboard.internal.GestureStrokeRecognitionPoints; import com.android.inputmethod.keyboard.internal.PointerTrackerQueue; import com.android.inputmethod.keyboard.internal.TypingTimeRecorder; import com.android.inputmethod.latin.Constants; @@ -43,7 +44,8 @@ import com.android.inputmethod.research.ResearchLogger; import java.util.ArrayList; -public final class PointerTracker implements PointerTrackerQueue.Element { +public final class PointerTracker implements PointerTrackerQueue.Element, + BatchInputArbiterListener { private static final String TAG = PointerTracker.class.getSimpleName(); private static final boolean DEBUG_EVENT = false; private static final boolean DEBUG_MOVE_EVENT = false; @@ -160,12 +162,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { private boolean mIsDetectingGesture = false; // per PointerTracker. private static boolean sInGesture = false; - private static long sGestureFirstDownTime; private static TypingTimeRecorder sTypingTimeRecorder; - private static final InputPointers sAggregatedPointers = new InputPointers( - GestureStrokeRecognitionPoints.DEFAULT_CAPACITY); - private static int sLastRecognitionPointSize = 0; // synchronized using sAggregatedPointers - private static long sLastRecognitionTime = 0; // synchronized using sAggregatedPointers // The position and time at which first down event occurred. private long mDownTime; @@ -203,7 +200,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { // true if dragging finger is allowed. private boolean mIsAllowedDraggingFinger; - private final GestureStrokeRecognitionPoints mGestureStrokeRecognitionPoints; + private final BatchInputArbiter mBatchInputArbiter; private final GestureStrokeDrawingPoints mGestureStrokeDrawingPoints; // TODO: Add PointerTrackerFactory singleton and move some class static methods into it. @@ -287,8 +284,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { private PointerTracker(final int id) { mPointerId = id; - mGestureStrokeRecognitionPoints = new GestureStrokeRecognitionPoints( - id, sGestureStrokeRecognitionParams); + mBatchInputArbiter = new BatchInputArbiter(id, sGestureStrokeRecognitionParams); mGestureStrokeDrawingPoints = new GestureStrokeDrawingPoints(sGestureStrokeDrawingParams); } @@ -410,7 +406,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { mKeyboardLayoutHasBeenChanged = true; final int keyWidth = mKeyboard.mMostCommonKeyWidth; final int keyHeight = mKeyboard.mMostCommonKeyHeight; - mGestureStrokeRecognitionPoints.setKeyboardGeometry(keyWidth, mKeyboard.mOccupiedHeight); + mBatchInputArbiter.setKeyboardGeometry(keyWidth, mKeyboard.mOccupiedHeight); final Key newKey = mKeyDetector.detectHitKey(mKeyX, mKeyY); if (newKey != mCurrentKey) { if (sDrawingProxy != null) { @@ -578,26 +574,15 @@ public final class PointerTracker implements PointerTrackerQueue.Element { return sPointerTrackerQueue.getOldestElement() == this; } - /** - * Determines whether the batch input has started or not. - * @return true if the batch input has started successfully. - */ - private boolean mayStartBatchInput() { - if (!mGestureStrokeRecognitionPoints.isStartOfAGesture()) { - return false; - } + // Implements {@link BatchInputArbiterListener}. + @Override + public void onStartBatchInput() { if (DEBUG_LISTENER) { Log.d(TAG, String.format("[%d] onStartBatchInput", mPointerId)); } - synchronized (sAggregatedPointers) { - sAggregatedPointers.reset(); - sLastRecognitionPointSize = 0; - sLastRecognitionTime = 0; - sListener.onStartBatchInput(); - dismissAllMoreKeysPanels(); - sTimerProxy.cancelLongPressTimerOf(this); - } - return true; + sListener.onStartBatchInput(); + dismissAllMoreKeysPanels(); + sTimerProxy.cancelLongPressTimerOf(this); } private void showGestureTrail() { @@ -610,55 +595,38 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } public void updateBatchInputByTimer(final long syntheticMoveEventTime) { - final int gestureTime = (int)(syntheticMoveEventTime - sGestureFirstDownTime); - mGestureStrokeRecognitionPoints.duplicateLastPointWith(gestureTime); - updateBatchInput(syntheticMoveEventTime); - } - - private void updateBatchInput(final long moveEventTime) { - synchronized (sAggregatedPointers) { - final GestureStrokeRecognitionPoints stroke = mGestureStrokeRecognitionPoints; - stroke.appendIncrementalBatchPoints(sAggregatedPointers); - final int size = sAggregatedPointers.getPointerSize(); - if (size > sLastRecognitionPointSize - && stroke.hasRecognitionTimePast(moveEventTime, sLastRecognitionTime)) { - if (DEBUG_LISTENER) { - Log.d(TAG, String.format("[%d] onUpdateBatchInput: batchPoints=%d", mPointerId, - size)); - } - sTimerProxy.startUpdateBatchInputTimer(this); - sListener.onUpdateBatchInput(sAggregatedPointers); - // The listener may change the size of the pointers (when auto-committing - // for example), so we need to get the size from the pointers again. - sLastRecognitionPointSize = sAggregatedPointers.getPointerSize(); - sLastRecognitionTime = moveEventTime; - } + mBatchInputArbiter.updateBatchInputByTimer(syntheticMoveEventTime, this); + } + + // Implements {@link BatchInputArbiterListener}. + @Override + public void onUpdateBatchInput(final InputPointers aggregatedPointers, final long eventTime) { + if (DEBUG_LISTENER) { + Log.d(TAG, String.format("[%d] onUpdateBatchInput: batchPoints=%d", mPointerId, + aggregatedPointers.getPointerSize())); } + sListener.onUpdateBatchInput(aggregatedPointers); } - /** - * Determines whether the batch input has ended successfully or continues. - * @param upEventTime the event time of this pointer up. - * @return true if the batch input has ended successfully, false if it continues. - */ - private boolean mayEndBatchInput(final long upEventTime) { - boolean hasEndBatchInputSuccessfully = false; - synchronized (sAggregatedPointers) { - mGestureStrokeRecognitionPoints.appendAllBatchPoints(sAggregatedPointers); - if (getActivePointerTrackerCount() == 1) { - hasEndBatchInputSuccessfully = true; - sTypingTimeRecorder.onEndBatchInput(upEventTime); - sTimerProxy.cancelAllUpdateBatchInputTimers(); - if (!mIsTrackingForActionDisabled) { - if (DEBUG_LISTENER) { - Log.d(TAG, String.format("[%d] onEndBatchInput : batchPoints=%d", - mPointerId, sAggregatedPointers.getPointerSize())); - } - sListener.onEndBatchInput(sAggregatedPointers); - } - } + // Implements {@link BatchInputArbiterListener}. + @Override + public void onStartUpdateBatchInputTimer() { + sTimerProxy.startUpdateBatchInputTimer(this); + } + + // Implements {@link BatchInputArbiterListener}. + @Override + public void onEndBatchInput(final InputPointers aggregatedPointers, final long eventTime) { + sTypingTimeRecorder.onEndBatchInput(eventTime); + sTimerProxy.cancelAllUpdateBatchInputTimers(); + if (mIsTrackingForActionDisabled) { + return; + } + if (DEBUG_LISTENER) { + Log.d(TAG, String.format("[%d] onEndBatchInput : batchPoints=%d", + mPointerId, aggregatedPointers.getPointerSize())); } - return hasEndBatchInputSuccessfully; + sListener.onEndBatchInput(aggregatedPointers); } private void cancelBatchInput() { @@ -753,15 +721,10 @@ public final class PointerTracker implements PointerTrackerQueue.Element { mIsDetectingGesture = (mKeyboard != null) && mKeyboard.mId.isAlphabetKeyboard() && key != null && !key.isModifier(); if (mIsDetectingGesture) { - if (getActivePointerTrackerCount() == 1) { - sGestureFirstDownTime = eventTime; - } - final int elapsedTimeSinceFirstDown = (int)(eventTime - sGestureFirstDownTime); - final int elapsedTimeSinceLastTyping = (int)( - eventTime - sTypingTimeRecorder.getLastLetterTypingTime()); - mGestureStrokeRecognitionPoints.onDownEvent(x, y, elapsedTimeSinceFirstDown, - elapsedTimeSinceLastTyping); - mGestureStrokeDrawingPoints.onDownEvent(x, y, elapsedTimeSinceFirstDown); + mBatchInputArbiter.addDownEventPoint(x, y, eventTime, + sTypingTimeRecorder.getLastLetterTypingTime(), getActivePointerTrackerCount()); + mGestureStrokeDrawingPoints.onDownEvent( + x, y, mBatchInputArbiter.getElapsedTimeSinceFirstDown(eventTime)); } } @@ -820,31 +783,27 @@ public final class PointerTracker implements PointerTrackerQueue.Element { if (!mIsDetectingGesture) { return; } - final int beforeLength = mGestureStrokeRecognitionPoints.getLength(); - final int elapsedTimeSinceFirstDown = (int)(eventTime - sGestureFirstDownTime); - final boolean onValidArea = mGestureStrokeRecognitionPoints.addPointOnKeyboard( - x, y, elapsedTimeSinceFirstDown, isMajorEvent); - if (mGestureStrokeRecognitionPoints.getLength() > beforeLength) { - sTimerProxy.startUpdateBatchInputTimer(this); - } + final boolean onValidArea = mBatchInputArbiter.addMoveEventPoint( + x, y, eventTime, isMajorEvent, this); // If the move event goes out from valid batch input area, cancel batch input. if (!onValidArea) { cancelBatchInput(); return; } - mGestureStrokeDrawingPoints.onMoveEvent(x, y, elapsedTimeSinceFirstDown); + mGestureStrokeDrawingPoints.onMoveEvent( + x, y, mBatchInputArbiter.getElapsedTimeSinceFirstDown(eventTime)); // If the MoreKeysPanel is showing then do not attempt to enter gesture mode. However, // the gestured touch points are still being recorded in case the panel is dismissed. if (isShowingMoreKeysPanel()) { return; } if (!sInGesture && key != null && Character.isLetter(key.getCode()) - && mayStartBatchInput()) { + && mBatchInputArbiter.mayStartBatchInput(this)) { sInGesture = true; } if (sInGesture) { if (key != null) { - updateBatchInput(eventTime); + mBatchInputArbiter.updateBatchInput(eventTime, this); } showGestureTrail(); } @@ -1097,7 +1056,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element { if (currentKey != null) { callListenerOnRelease(currentKey, currentKey.getCode(), true /* withSliding */); } - if (mayEndBatchInput(eventTime)) { + if (mBatchInputArbiter.mayEndBatchInput( + eventTime, getActivePointerTrackerCount(), this)) { sInGesture = false; } showGestureTrail(); diff --git a/java/src/com/android/inputmethod/keyboard/internal/BatchInputArbiter.java b/java/src/com/android/inputmethod/keyboard/internal/BatchInputArbiter.java new file mode 100644 index 000000000..cd9875955 --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/internal/BatchInputArbiter.java @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.inputmethod.keyboard.internal; + +import com.android.inputmethod.latin.Constants; +import com.android.inputmethod.latin.InputPointers; + +/** + * This class arbitrates batch input. + * An instance of this class holds a {@link GestureStrokeRecognitionPoints}. + * And it arbitrates multiple strokes gestured by multiple fingers and aggregates those gesture + * points into one batch input. + */ +public class BatchInputArbiter { + public interface BatchInputArbiterListener { + public void onStartBatchInput(); + public void onUpdateBatchInput( + final InputPointers aggregatedPointers, final long moveEventTime); + public void onStartUpdateBatchInputTimer(); + public void onEndBatchInput(final InputPointers aggregatedPointers, final long upEventTime); + } + + // The starting time of the first stroke of a gesture input. + private static long sGestureFirstDownTime; + // The {@link InputPointers} that includes all events of a gesture input. + private static final InputPointers sAggregatedPointers = new InputPointers( + Constants.DEFAULT_GESTURE_POINTS_CAPACITY); + private static int sLastRecognitionPointSize = 0; // synchronized using sAggregatedPointers + private static long sLastRecognitionTime = 0; // synchronized using sAggregatedPointers + + private final GestureStrokeRecognitionPoints mRecognitionPoints; + + public BatchInputArbiter(final int pointerId, final GestureStrokeRecognitionParams params) { + mRecognitionPoints = new GestureStrokeRecognitionPoints(pointerId, params); + } + + public void setKeyboardGeometry(final int keyWidth, final int keyboardHeight) { + mRecognitionPoints.setKeyboardGeometry(keyWidth, keyboardHeight); + } + + /** + * Calculate elapsed time since the first gesture down. + * @param eventTime the time of this event. + * @return the elapsed time in millisecond from the first gesture down. + */ + public int getElapsedTimeSinceFirstDown(final long eventTime) { + return (int)(eventTime - sGestureFirstDownTime); + } + + /** + * Add a down event point. + * @param x the x-coordinate of this down event. + * @param y the y-coordinate of this down event. + * @param downEventTime the time of this down event. + * @param lastLetterTypingTime the last typing input time. + * @param activePointerCount the number of active pointers when this pointer down event occurs. + */ + public void addDownEventPoint(final int x, final int y, final long downEventTime, + final long lastLetterTypingTime, final int activePointerCount) { + if (activePointerCount == 1) { + sGestureFirstDownTime = downEventTime; + } + final int elapsedTimeSinceFirstDown = getElapsedTimeSinceFirstDown(downEventTime); + final int elapsedTimeSinceLastTyping = (int)(downEventTime - lastLetterTypingTime); + mRecognitionPoints.addDownEventPoint( + x, y, elapsedTimeSinceFirstDown, elapsedTimeSinceLastTyping); + } + + /** + * Add a move event point. + * @param x the x-coordinate of this move event. + * @param y the y-coordinate of this move event. + * @param moveEventTime the time of this move event. + * @param isMajorEvent false if this is a historical move event. + * @param listener {@link BatchInputArbiterListener#onStartUpdateBatchInputTimer()} of this + * <code>listener</code> may be called if enough move points have been added. + * @return true if this move event occurs on the valid gesture area. + */ + public boolean addMoveEventPoint(final int x, final int y, final long moveEventTime, + final boolean isMajorEvent, final BatchInputArbiterListener listener) { + final int beforeLength = mRecognitionPoints.getLength(); + final boolean onValidArea = mRecognitionPoints.addEventPoint( + x, y, getElapsedTimeSinceFirstDown(moveEventTime), isMajorEvent); + if (mRecognitionPoints.getLength() > beforeLength) { + listener.onStartUpdateBatchInputTimer(); + } + return onValidArea; + } + + /** + * Determine whether the batch input has started or not. + * @param listener {@link BatchInputArbiterListener#onStartBatchInput()} of this + * <code>listener</code> will be called when the batch input has started successfully. + * @return true if the batch input has started successfully. + */ + public boolean mayStartBatchInput(final BatchInputArbiterListener listener) { + if (!mRecognitionPoints.isStartOfAGesture()) { + return false; + } + synchronized (sAggregatedPointers) { + sAggregatedPointers.reset(); + sLastRecognitionPointSize = 0; + sLastRecognitionTime = 0; + listener.onStartBatchInput(); + } + return true; + } + + /** + * Add synthetic move event point. After adding the point, + * {@link #updateBatchInput(long,BatchInputArbiterListener)} will be called internally. + * @param syntheticMoveEventTime the synthetic move event time. + * @param listener the listener to be passed to + * {@link #updateBatchInput(long,BatchInputArbiterListener)}. + */ + public void updateBatchInputByTimer(final long syntheticMoveEventTime, + final BatchInputArbiterListener listener) { + mRecognitionPoints.duplicateLastPointWith( + getElapsedTimeSinceFirstDown(syntheticMoveEventTime)); + updateBatchInput(syntheticMoveEventTime, listener); + } + + /** + * Determine whether we have enough gesture points to lookup dictionary. + * @param moveEventTime the time of this move event. + * @param listener {@link BatchInputArbiterListener#onUpdateBatchInput(InputPointers,long)} of + * this <code>listener</code> will be called when enough event points we have. Also + * {@link BatchInputArbiterListener#onStartUpdateBatchInputTimer()} will be called to have + * possible future synthetic move event. + */ + public void updateBatchInput(final long moveEventTime, + final BatchInputArbiterListener listener) { + synchronized (sAggregatedPointers) { + mRecognitionPoints.appendIncrementalBatchPoints(sAggregatedPointers); + final int size = sAggregatedPointers.getPointerSize(); + if (size > sLastRecognitionPointSize && mRecognitionPoints.hasRecognitionTimePast( + moveEventTime, sLastRecognitionTime)) { + listener.onUpdateBatchInput(sAggregatedPointers, moveEventTime); + listener.onStartUpdateBatchInputTimer(); + // The listener may change the size of the pointers (when auto-committing + // for example), so we need to get the size from the pointers again. + sLastRecognitionPointSize = sAggregatedPointers.getPointerSize(); + sLastRecognitionTime = moveEventTime; + } + } + } + + /** + * Determine whether the batch input has ended successfully or continues. + * @param upEventTime the time of this up event. + * @param activePointerCount the number of active pointers when this pointer up event occurs. + * @param listener {@link BatchInputArbiterListener#onEndBatchInput(InputPointers,long)} of this + * <code>listener</code> will be called when the batch input has started successfully. + * @return true if the batch input has ended successfully. + */ + public boolean mayEndBatchInput(final long upEventTime, final int activePointerCount, + final BatchInputArbiterListener listener) { + synchronized (sAggregatedPointers) { + mRecognitionPoints.appendAllBatchPoints(sAggregatedPointers); + if (activePointerCount == 1) { + listener.onEndBatchInput(sAggregatedPointers, upEventTime); + return true; + } + } + return false; + } +} diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeRecognitionPoints.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeRecognitionPoints.java index 5d4f5e826..e49e538aa 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeRecognitionPoints.java +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeRecognitionPoints.java @@ -18,14 +18,15 @@ package com.android.inputmethod.keyboard.internal; import android.util.Log; +import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.InputPointers; import com.android.inputmethod.latin.utils.ResizableIntArray; /** * This class holds event points to recognize a gesture stroke. - * TODO: Should be final and package private class. + * TODO: Should be package private class. */ -public class GestureStrokeRecognitionPoints { +public final class GestureStrokeRecognitionPoints { private static final String TAG = GestureStrokeRecognitionPoints.class.getSimpleName(); private static final boolean DEBUG = false; private static final boolean DEBUG_SPEED = false; @@ -34,12 +35,13 @@ public class GestureStrokeRecognitionPoints { // 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; - private final ResizableIntArray mEventTimes = new ResizableIntArray(DEFAULT_CAPACITY); - private final ResizableIntArray mXCoordinates = new ResizableIntArray(DEFAULT_CAPACITY); - private final ResizableIntArray mYCoordinates = new ResizableIntArray(DEFAULT_CAPACITY); + private final ResizableIntArray mEventTimes = new ResizableIntArray( + Constants.DEFAULT_GESTURE_POINTS_CAPACITY); + private final ResizableIntArray mXCoordinates = new ResizableIntArray( + Constants.DEFAULT_GESTURE_POINTS_CAPACITY); + private final ResizableIntArray mYCoordinates = new ResizableIntArray( + Constants.DEFAULT_GESTURE_POINTS_CAPACITY); private final GestureStrokeRecognitionParams mRecognitionParams; @@ -67,12 +69,14 @@ public class GestureStrokeRecognitionPoints { private static final int MSEC_PER_SEC = 1000; + // TODO: Make this package private public GestureStrokeRecognitionPoints(final int pointerId, final GestureStrokeRecognitionParams recognitionParams) { mPointerId = pointerId; mRecognitionParams = recognitionParams; } + // TODO: Make this package private public void setKeyboardGeometry(final int keyWidth, final int keyboardHeight) { mKeyWidth = keyWidth; mMinYCoordinate = -(int)(keyboardHeight * EXTRA_GESTURE_TRAIL_AREA_ABOVE_KEYBOARD_RATIO); @@ -99,11 +103,13 @@ public class GestureStrokeRecognitionPoints { } } + // TODO: Make this package private public int getLength() { return mEventTimes.getLength(); } - public void onDownEvent(final int x, final int y, final int elapsedTimeSinceFirstDown, + // TODO: Make this package private + public void addDownEventPoint(final int x, final int y, final int elapsedTimeSinceFirstDown, final int elapsedTimeSinceLastTyping) { reset(); if (elapsedTimeSinceLastTyping < mRecognitionParams.mStaticTimeThresholdAfterFastTyping) { @@ -113,7 +119,9 @@ public class GestureStrokeRecognitionPoints { Log.d(TAG, String.format("[%d] onDownEvent: dT=%3d%s", mPointerId, elapsedTimeSinceLastTyping, mAfterFastTyping ? " afterFastTyping" : "")); } - addPointOnKeyboard(x, y, elapsedTimeSinceFirstDown, true /* isMajorEvent */); + // Call {@link #addEventPoint(int,int,int,boolean)} to record this down event point as a + // major event point. + addEventPoint(x, y, elapsedTimeSinceFirstDown, true /* isMajorEvent */); } private int getGestureDynamicDistanceThreshold(final int deltaTime) { @@ -137,6 +145,7 @@ public class GestureStrokeRecognitionPoints { return mRecognitionParams.mDynamicTimeThresholdFrom - decayedThreshold; } + // TODO: Make this package private public final boolean isStartOfAGesture() { if (!hasDetectedFastMove()) { return false; @@ -167,6 +176,7 @@ public class GestureStrokeRecognitionPoints { return isStartOfAGesture; } + // TODO: Make this package private public void duplicateLastPointWith(final int time) { final int lastIndex = getLength() - 1; if (lastIndex >= 0) { @@ -250,19 +260,20 @@ public class GestureStrokeRecognitionPoints { } /** - * 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 + * Add an event point to this gesture stroke recognition points. Returns true if the event + * point is on the valid gesture area. + * @param x the x-coordinate of the event point + * @param y the y-coordinate of the event point * @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 + * @return true if the event point is on the valid gesture area */ - public boolean addPointOnKeyboard(final int x, final int y, final int time, + // TODO: Make this package private + public boolean addEventPoint(final int x, final int y, final int time, final boolean isMajorEvent) { final int size = getLength(); if (size <= 0) { - // Down event + // The first event of this stroke (a.k.a. down event). appendPoint(x, y, time); updateMajorEvent(x, y, time); } else { @@ -291,15 +302,18 @@ public class GestureStrokeRecognitionPoints { } } + // TODO: Make this package private public final boolean hasRecognitionTimePast( final long currentTime, final long lastRecognitionTime) { return currentTime > lastRecognitionTime + mRecognitionParams.mRecognitionMinimumTime; } + // TODO: Make this package private public final void appendAllBatchPoints(final InputPointers out) { appendBatchPoints(out, getLength()); } + // TODO: Make this package private public final void appendIncrementalBatchPoints(final InputPointers out) { appendBatchPoints(out, mIncrementalRecognitionSize); } diff --git a/java/src/com/android/inputmethod/latin/Constants.java b/java/src/com/android/inputmethod/latin/Constants.java index fbd6ef4e9..00b54f593 100644 --- a/java/src/com/android/inputmethod/latin/Constants.java +++ b/java/src/com/android/inputmethod/latin/Constants.java @@ -257,6 +257,13 @@ public final class Constants { public static final int SCREEN_METRICS_LARGE_TABLET = 2; public static final int SCREEN_METRICS_SMALL_TABLET = 3; + /** + * Default capacity of gesture points container. + * This constant is used by {@link BatchInputArbiter} and etc. to preallocate regions that + * contain gesture event points. + */ + public static final int DEFAULT_GESTURE_POINTS_CAPACITY = 128; + private Constants() { // This utility class is not publicly instantiable. } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 68ed23897..d8fb4f2be 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1147,7 +1147,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen @Override public boolean onEvaluateFullscreenMode() { - // Reread resource value here, because this method is called by framework anytime as needed. + // Reread resource value here, because this method is called by the framework as needed. final boolean isFullscreenModeAllowed = Settings.readUseFullscreenMode(getResources()); if (super.onEvaluateFullscreenMode() && isFullscreenModeAllowed) { // TODO: Remove this hack. Actually we should not really assume NO_EXTRACT_UI @@ -1272,7 +1272,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen @Override public void onCancelBatchInput() { - mInputLogic.onCancelBatchInput(mInputUpdater); + mInputLogic.onCancelBatchInput(mHandler, mInputUpdater); } // TODO[IL]: Make this a package-private standalone class in inputlogic/ and remove all @@ -1310,17 +1310,15 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen return true; } - // Run in the UI thread. + // Run on the UI thread. public void onStartBatchInput() { synchronized (mLock) { mHandler.removeMessages(MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP); mInBatchInput = true; - mLatinIme.mHandler.showGesturePreviewAndSuggestionStrip( - SuggestedWords.EMPTY, false /* dismissGestureFloatingPreviewText */); } } - // Run in the Handler thread. + // Run on the Handler thread. private void updateBatchInput(final InputPointers batchPointers, final int sequenceNumber) { synchronized (mLock) { if (!mInBatchInput) { @@ -1339,7 +1337,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } } - // Run in the UI thread. + // Run on the UI thread. public void onUpdateBatchInput(final InputPointers batchPointers, final int sequenceNumber) { if (mHandler.hasMessages(MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP)) { @@ -1352,12 +1350,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen public void onCancelBatchInput() { synchronized (mLock) { mInBatchInput = false; - mLatinIme.mHandler.showGesturePreviewAndSuggestionStrip( - SuggestedWords.EMPTY, true /* dismissGestureFloatingPreviewText */); } } - // Run in the UI thread. + // Run on the UI thread. public void onEndBatchInput(final InputPointers batchPointers) { synchronized(mLock) { getSuggestedWordsGestureLocked(batchPointers, SuggestedWords.NOT_A_SEQUENCE_NUMBER, @@ -1407,7 +1403,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } } - // This method must run in UI Thread. + // This method must run on the UI Thread. private void showGesturePreviewAndSuggestionStrip(final SuggestedWords suggestedWords, final boolean dismissGestureFloatingPreviewText) { showSuggestionStrip(suggestedWords); @@ -1418,7 +1414,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } } - // This method must run in UI Thread. + // This method must run on the UI Thread. public void onEndBatchInputAsyncInternal(final SuggestedWords suggestedWords) { final String batchInputText = suggestedWords.isEmpty() ? null : suggestedWords.getWord(0); if (TextUtils.isEmpty(batchInputText)) { @@ -1615,19 +1611,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen false /* isPrediction */); } - private void setAutoCorrection(final SuggestedWords suggestedWords, final String typedWord) { - if (suggestedWords.isEmpty()) return; - final String autoCorrection; - if (suggestedWords.mWillAutoCorrect) { - autoCorrection = suggestedWords.getWord(SuggestedWords.INDEX_OF_AUTO_CORRECTION); - } else { - // We can't use suggestedWords.getWord(SuggestedWords.INDEX_OF_TYPED_WORD) - // because it may differ from mWordComposer.mTypedWord. - autoCorrection = typedWord; - } - mInputLogic.mWordComposer.setAutoCorrection(autoCorrection); - } - private void showSuggestionStripWithTypedWord(final SuggestedWords suggestedWords, final String typedWord) { if (suggestedWords.isEmpty()) { @@ -1636,10 +1619,17 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen clearSuggestionStrip(); return; } - setAutoCorrection(suggestedWords, typedWord); - final boolean isAutoCorrection = suggestedWords.willAutoCorrect(); - setSuggestedWords(suggestedWords, isAutoCorrection); - setAutoCorrectionIndicator(isAutoCorrection); + final String autoCorrection; + if (suggestedWords.mWillAutoCorrect) { + autoCorrection = suggestedWords.getWord(SuggestedWords.INDEX_OF_AUTO_CORRECTION); + } else { + // We can't use suggestedWords.getWord(SuggestedWords.INDEX_OF_TYPED_WORD) + // because it may differ from mWordComposer.mTypedWord. + autoCorrection = typedWord; + } + mInputLogic.mWordComposer.setAutoCorrection(autoCorrection); + setSuggestedWords(suggestedWords, suggestedWords.mWillAutoCorrect); + setAutoCorrectionIndicator(suggestedWords.mWillAutoCorrect); setSuggestionStripShown(isSuggestionsStripVisible()); // An auto-correction is available, cache it in accessibility code so // we can be speak it if the user touches a key that will insert it. diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java index 97c89dd4e..f9de89c80 100644 --- a/java/src/com/android/inputmethod/latin/SuggestedWords.java +++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java @@ -104,10 +104,6 @@ public final class SuggestedWords { return debugString; } - public boolean willAutoCorrect() { - return mWillAutoCorrect; - } - @Override public String toString() { // Pretty-print method to help debug @@ -150,7 +146,7 @@ public final class SuggestedWords { for (int index = 1; index < previousSize; index++) { final SuggestedWordInfo prevWordInfo = previousSuggestions.getInfo(index); final String prevWord = prevWordInfo.mWord; - // Filter out duplicate suggestion. + // Filter out duplicate suggestions. if (!alreadySeen.contains(prevWord)) { suggestionsList.add(prevWordInfo); alreadySeen.add(prevWord); diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java index 0686ff641..4a4abd7d2 100644 --- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java @@ -68,6 +68,8 @@ public final class InputLogic { // TODO : Remove this member when we can. private final LatinIME mLatinIME; + private InputLogicHandler mInputLogicHandler; + // TODO : make all these fields private as soon as possible. // Current space state of the input method. This can be any of the above constants. public int mSpaceState; @@ -102,6 +104,7 @@ public final class InputLogic { mWordComposer = new WordComposer(); mEventInterpreter = new EventInterpreter(latinIME); mConnection = new RichInputConnection(latinIME); + mInputLogicHandler = null; } /** @@ -116,12 +119,15 @@ public final class InputLogic { * @param restarting whether input is starting in the same field as before. */ public void startInput(final boolean restarting) { + mInputLogicHandler = new InputLogicHandler(); } /** * Clean up the input logic after input is finished. */ public void finishInput() { + mInputLogicHandler.destroy(); + mInputLogicHandler = null; } /** @@ -297,6 +303,8 @@ public final class InputLogic { final KeyboardSwitcher keyboardSwitcher, final LatinIME.UIHandler handler, final LatinIME.InputUpdater inputUpdater) { inputUpdater.onStartBatchInput(); + handler.showGesturePreviewAndSuggestionStrip( + SuggestedWords.EMPTY, false /* dismissGestureFloatingPreviewText */); handler.cancelUpdateSuggestionStrip(); mConnection.beginBatchEdit(); if (mWordComposer.isComposingWord()) { @@ -397,9 +405,12 @@ public final class InputLogic { inputUpdater.onEndBatchInput(batchPointers); } - // TODO: remove this argument - public void onCancelBatchInput(final LatinIME.InputUpdater inputUpdater) { + // TODO: remove these arguments + public void onCancelBatchInput(final LatinIME.UIHandler handler, + final LatinIME.InputUpdater inputUpdater) { inputUpdater.onCancelBatchInput(); + handler.showGesturePreviewAndSuggestionStrip( + SuggestedWords.EMPTY, true /* dismissGestureFloatingPreviewText */); } /** diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java new file mode 100644 index 000000000..d611e4bf8 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.inputmethod.latin.inputlogic; + +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Message; + +/** + * A helper to manage deferred tasks for the input logic. + */ +// TODO: Make this package private +public class InputLogicHandler implements Handler.Callback { + final Handler mNonUIThreadHandler; + + public InputLogicHandler() { + final HandlerThread handlerThread = new HandlerThread( + InputLogicHandler.class.getSimpleName()); + handlerThread.start(); + mNonUIThreadHandler = new Handler(handlerThread.getLooper(), this); + } + + public void destroy() { + mNonUIThreadHandler.getLooper().quit(); + } + + /** + * Handle a message. + * @see android.os.Handler.Callback#handleMessage(android.os.Message) + */ + @Override + public boolean handleMessage(final Message msg) { + return true; + } +} diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java index 72281e62c..f836e61cb 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java +++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java @@ -208,7 +208,7 @@ final class SuggestionStripLayoutHelper { } final String word = suggestedWords.getWord(indexInSuggestedWords); final boolean isAutoCorrect = indexInSuggestedWords == 1 - && suggestedWords.willAutoCorrect(); + && suggestedWords.mWillAutoCorrect; final boolean isTypedWordValid = indexInSuggestedWords == 0 && suggestedWords.mTypedWordValid; if (!isAutoCorrect && !isTypedWordValid) { @@ -232,7 +232,7 @@ final class SuggestionStripLayoutHelper { final SuggestedWords suggestedWords) { final int indexToDisplayMostImportantSuggestion; final int indexToDisplaySecondMostImportantSuggestion; - if (suggestedWords.willAutoCorrect()) { + if (suggestedWords.mWillAutoCorrect) { indexToDisplayMostImportantSuggestion = SuggestedWords.INDEX_OF_AUTO_CORRECTION; indexToDisplaySecondMostImportantSuggestion = SuggestedWords.INDEX_OF_TYPED_WORD; } else { @@ -257,7 +257,7 @@ final class SuggestionStripLayoutHelper { final boolean isSuggested = (indexInSuggestedWords != SuggestedWords.INDEX_OF_TYPED_WORD); final int color; - if (positionInStrip == mCenterPositionInStrip && suggestedWords.willAutoCorrect()) { + if (positionInStrip == mCenterPositionInStrip && suggestedWords.mWillAutoCorrect) { color = mColorAutoCorrect; } else if (positionInStrip == mCenterPositionInStrip && suggestedWords.mTypedWordValid) { color = mColorValidTypedWord; |