diff options
Diffstat (limited to 'java/src/com/android/inputmethod/keyboard/internal/BatchInputArbiter.java')
-rw-r--r-- | java/src/com/android/inputmethod/keyboard/internal/BatchInputArbiter.java | 181 |
1 files changed, 181 insertions, 0 deletions
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; + } +} |