aboutsummaryrefslogtreecommitdiffstats
path: root/java/src
diff options
context:
space:
mode:
authorTadashi G. Takaoka <takaoka@google.com>2012-07-18 14:27:51 +0900
committerTadashi G. Takaoka <takaoka@google.com>2012-07-18 17:32:17 +0900
commitf39fccbd0fd63647c52e8eabcb60df69f97492b5 (patch)
tree8d5a4202d5169731cf2bfde44688226677316376 /java/src
parent3ec31f4971c3db7ef73488859609870d15f5dc69 (diff)
downloadlatinime-f39fccbd0fd63647c52e8eabcb60df69f97492b5.tar.gz
latinime-f39fccbd0fd63647c52e8eabcb60df69f97492b5.tar.xz
latinime-f39fccbd0fd63647c52e8eabcb60df69f97492b5.zip
Make GestureStroke as top level class
And make PointerTracker object has GestureStroke object. Change-Id: Ibf5cfd593c4f13468368e01acb847589b0ab12e7
Diffstat (limited to 'java/src')
-rw-r--r--java/src/com/android/inputmethod/keyboard/PointerTracker.java45
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java149
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/GestureTracker.java188
3 files changed, 199 insertions, 183 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index 733d3b09b..437bbf06b 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -22,8 +22,10 @@ import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;
+import com.android.inputmethod.keyboard.internal.GestureStroke;
import com.android.inputmethod.keyboard.internal.GestureTracker;
import com.android.inputmethod.keyboard.internal.PointerTrackerQueue;
+import com.android.inputmethod.latin.InputPointers;
import com.android.inputmethod.latin.LatinImeLogger;
import com.android.inputmethod.latin.ResearchLogger;
import com.android.inputmethod.latin.define.ProductionFlag;
@@ -165,6 +167,8 @@ public class PointerTracker {
// Gesture tracker singleton instance
private static final GestureTracker sGestureTracker = GestureTracker.getInstance();
+ private final GestureStroke mGestureStroke;
+
public static void init(boolean hasDistinctMultitouch,
boolean needsPhantomSuddenMoveEventHack) {
if (hasDistinctMultitouch) {
@@ -222,10 +226,43 @@ public class PointerTracker {
}
}
- public PointerTracker(int id, KeyEventHandler handler) {
+ // The working and returning object of the following methods,
+ // {@link #getIncrementalBatchPoints()} and {@link #getAllBatchPoints()}.
+ private static final InputPointers mAggregatedPointers = new InputPointers();
+
+ // TODO: This method is called only from GestureTracker and should address the thread-safty
+ // issue soon.
+ public static InputPointers getIncrementalBatchPoints() {
+ final InputPointers pointers = mAggregatedPointers;
+ pointers.reset();
+ for (final PointerTracker tracker : sTrackers) {
+ tracker.getGestureStroke().appendIncrementalBatchPoints(pointers);
+ }
+ return pointers;
+ }
+
+ // TODO: This method is called only from GestureTracker and should address the thread-safety
+ // issue soon.
+ public static InputPointers getAllBatchPoints() {
+ final InputPointers pointers = mAggregatedPointers;
+ pointers.reset();
+ for (final PointerTracker tracker : sTrackers) {
+ tracker.getGestureStroke().appendAllBatchPoints(pointers);
+ }
+ return pointers;
+ }
+
+ public static void clearBatchInputPoints() {
+ for (final PointerTracker tracker : sTrackers) {
+ tracker.getGestureStroke().reset();
+ }
+ }
+
+ private PointerTracker(int id, KeyEventHandler handler) {
if (handler == null)
throw new NullPointerException();
mPointerId = id;
+ mGestureStroke = new GestureStroke(id);
setKeyDetectorInner(handler.getKeyDetector());
mListener = handler.getKeyboardActionListener();
mDrawingProxy = handler.getDrawingProxy();
@@ -237,6 +274,10 @@ public class PointerTracker {
return mKeyPreviewText;
}
+ public GestureStroke getGestureStroke() {
+ return mGestureStroke;
+ }
+
// Returns true if keyboard has been changed by this callback.
private boolean callListenerOnPressAndCheckKeyboardLayoutChange(Key key) {
if (sGestureTracker.isInGesture()) {
@@ -328,6 +369,8 @@ public class PointerTracker {
private void setKeyDetectorInner(KeyDetector keyDetector) {
mKeyDetector = keyDetector;
mKeyboard = keyDetector.getKeyboard();
+ mGestureStroke.setGestureSampleLength(
+ mKeyboard.mMostCommonKeyWidth, mKeyboard.mMostCommonKeyHeight);
final Key newKey = mKeyDetector.detectHitKey(mKeyX, mKeyY);
if (newKey != mCurrentKey) {
if (mDrawingProxy != null) {
diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java
new file mode 100644
index 000000000..14e99487d
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2012 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 android.util.FloatMath;
+
+import com.android.inputmethod.latin.InputPointers;
+
+public class GestureStroke {
+ private final int mPointerId;
+ private final InputPointers mInputPointers = new InputPointers();
+ private float mLength;
+ private float mAngle;
+ private int mIncrementalRecognitionPoint;
+ private boolean mHasSharpCorner;
+ private long mLastPointTime;
+ private int mLastPointX;
+ private int mLastPointY;
+
+ private int mMinGestureLength;
+ private int mMinGestureSampleLength;
+
+ // TODO: Tune these parameters.
+ private static final float MIN_GESTURE_DETECTION_RATIO_TO_KEY_WIDTH = 1.0f / 4.0f;
+ private static final float MIN_GESTURE_SAMPLING_RATIO_TO_KEY_HEIGHT = 1.0f / 6.0f;
+ private static final int MIN_GESTURE_DURATION = 100; // msec
+ private static final float GESTURE_RECOG_SPEED_THRESHOLD = 0.4f; // dip/msec
+ private static final float GESTURE_RECOG_CURVATURE_THRESHOLD = (float)(Math.PI / 4.0f);
+
+ private static final float DOUBLE_PI = (float)(2 * Math.PI);
+
+ public GestureStroke(int pointerId) {
+ mPointerId = pointerId;
+ reset();
+ }
+
+ public void setGestureSampleLength(final int keyWidth, final int keyHeight) {
+ mMinGestureLength = (int)(keyWidth * MIN_GESTURE_DETECTION_RATIO_TO_KEY_WIDTH);
+ mMinGestureSampleLength = (int)(keyHeight * MIN_GESTURE_SAMPLING_RATIO_TO_KEY_HEIGHT);
+ }
+
+ public boolean isStartOfAGesture(int downDuration) {
+ return downDuration > MIN_GESTURE_DURATION && mLength > mMinGestureLength;
+ }
+
+ public void reset() {
+ mLength = 0;
+ mAngle = 0;
+ mIncrementalRecognitionPoint = 0;
+ mHasSharpCorner = false;
+ mLastPointTime = 0;
+ mInputPointers.reset();
+ }
+
+ private void updateLastPoint(final int x, final int y, final int time) {
+ mLastPointTime = time;
+ mLastPointX = x;
+ mLastPointY = y;
+ }
+
+ public void addPoint(final int x, final int y, final int time, final boolean isHistorical) {
+ final int size = mInputPointers.getPointerSize();
+ if (size == 0) {
+ mInputPointers.addPointer(x, y, mPointerId, time);
+ if (!isHistorical) {
+ updateLastPoint(x, y, time);
+ }
+ return;
+ }
+
+ final int[] xCoords = mInputPointers.getXCoordinates();
+ final int[] yCoords = mInputPointers.getYCoordinates();
+ final int lastX = xCoords[size - 1];
+ final int lastY = yCoords[size - 1];
+ final float dist = getDistance(lastX, lastY, x, y);
+ if (dist > mMinGestureSampleLength) {
+ mInputPointers.addPointer(x, y, mPointerId, time);
+ mLength += dist;
+ final float angle = getAngle(lastX, lastY, x, y);
+ if (size > 1) {
+ float curvature = getAngleDiff(angle, mAngle);
+ if (curvature > GESTURE_RECOG_CURVATURE_THRESHOLD) {
+ if (size > mIncrementalRecognitionPoint) {
+ mIncrementalRecognitionPoint = size;
+ }
+ mHasSharpCorner = true;
+ }
+ if (!mHasSharpCorner) {
+ mIncrementalRecognitionPoint = size;
+ }
+ }
+ mAngle = angle;
+ }
+
+ if (!isHistorical) {
+ final int duration = (int)(time - mLastPointTime);
+ if (mLastPointTime != 0 && duration > 0) {
+ final float speed = getDistance(mLastPointX, mLastPointY, x, y) / duration;
+ if (speed < GESTURE_RECOG_SPEED_THRESHOLD) {
+ mIncrementalRecognitionPoint = size;
+ }
+ }
+ updateLastPoint(x, y, time);
+ }
+ }
+
+ public void appendAllBatchPoints(final InputPointers out) {
+ out.append(mInputPointers, 0, mInputPointers.getPointerSize());
+ }
+
+ public void appendIncrementalBatchPoints(final InputPointers out) {
+ out.append(mInputPointers, 0, mIncrementalRecognitionPoint);
+ }
+
+ private static float getDistance(final int p1x, final int p1y,
+ final int p2x, final int p2y) {
+ final float dx = p1x - p2x;
+ final float dy = p1y - p2y;
+ // TODO: Optimize out this {@link FloatMath#sqrt(float)} call.
+ return FloatMath.sqrt(dx * dx + dy * dy);
+ }
+
+ private static float getAngle(final int p1x, final int p1y, final int p2x, final int p2y) {
+ final int dx = p1x - p2x;
+ final int dy = p1y - p2y;
+ if (dx == 0 && dy == 0) return 0;
+ return (float)Math.atan2(dy, dx);
+ }
+
+ private static float getAngleDiff(final float a1, final float a2) {
+ final float diff = Math.abs(a1 - a2);
+ if (diff > Math.PI) {
+ return DOUBLE_PI - diff;
+ }
+ return diff;
+ }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureTracker.java b/java/src/com/android/inputmethod/keyboard/internal/GestureTracker.java
index dfd697a7a..0f14dcef4 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/GestureTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/GestureTracker.java
@@ -15,7 +15,6 @@
package com.android.inputmethod.keyboard.internal;
import android.util.Log;
-import android.util.SparseArray;
import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.keyboard.Keyboard;
@@ -35,12 +34,6 @@ public class GestureTracker {
private static final GestureTracker sInstance = new GestureTracker();
private static final int MIN_RECOGNITION_TIME = 100;
- private static final int MIN_GESTURE_DURATION = 200;
-
- private static final float GESTURE_RECOG_SPEED_THRESHOLD = 0.4f;
- private static final float SQUARED_GESTURE_RECOG_SPEED_THRESHOLD =
- GESTURE_RECOG_SPEED_THRESHOLD * GESTURE_RECOG_SPEED_THRESHOLD;
- private static final float GESTURE_RECOG_CURVATURE_THRESHOLD = (float) (Math.PI / 4);
private boolean mIsAlphabetKeyboard;
private boolean mIsPossibleGesture = false;
@@ -49,8 +42,6 @@ public class GestureTracker {
private KeyboardActionListener mListener;
private SuggestedWords mSuggestions;
- private final SparseArray<GestureStroke> mGestureStrokes = new SparseArray<GestureStroke>();
-
private int mLastRecognitionPointSize = 0;
private long mLastRecognitionTime = 0;
@@ -67,8 +58,6 @@ public class GestureTracker {
public void setKeyboard(Keyboard keyboard) {
mIsAlphabetKeyboard = keyboard.mId.isAlphabetKeyboard();
- GestureStroke.setGestureSampleLength(keyboard.mMostCommonKeyWidth / 2,
- keyboard.mMostCommonKeyHeight / 6);
}
private void startBatchInput() {
@@ -107,7 +96,7 @@ public class GestureTracker {
// A gesture should start only from the letter key.
if (GESTURE_ON && mIsAlphabetKeyboard && key != null && Keyboard.isLetterCode(key.mCode)) {
mIsPossibleGesture = true;
- addPointToStroke(x, y, 0, tracker.mPointerId, false);
+ tracker.getGestureStroke().addPoint(x, y, 0, false);
}
}
@@ -115,15 +104,15 @@ public class GestureTracker {
boolean isHistorical, Key key) {
final int gestureTime = (int)(eventTime - tracker.getDownTime());
if (GESTURE_ON && mIsPossibleGesture) {
- final GestureStroke stroke = addPointToStroke(x, y, gestureTime, tracker.mPointerId,
- isHistorical);
+ final GestureStroke stroke = tracker.getGestureStroke();
+ stroke.addPoint(x, y, gestureTime, isHistorical);
if (!isInGesture() && stroke.isStartOfAGesture(gestureTime)) {
startBatchInput();
}
}
if (key != null && isInGesture()) {
- final InputPointers batchPoints = getIncrementalBatchPoints();
+ final InputPointers batchPoints = PointerTracker.getIncrementalBatchPoints();
if (updateBatchInputRecognitionState(eventTime, batchPoints.getPointerSize())) {
if (DEBUG_LISTENER) {
Log.d(TAG, "onUpdateBatchInput: batchPoints=" + batchPoints.getPointerSize());
@@ -135,7 +124,7 @@ public class GestureTracker {
public void onUpEvent(PointerTracker tracker, int x, int y, long eventTime) {
if (isInGesture()) {
- final InputPointers batchPoints = getAllBatchPoints();
+ final InputPointers batchPoints = PointerTracker.getAllBatchPoints();
if (DEBUG_LISTENER) {
Log.d(TAG, "onUpdateBatchInput: batchPoints=" + batchPoints.getPointerSize());
}
@@ -143,49 +132,8 @@ public class GestureTracker {
}
}
- private GestureStroke addPointToStroke(int x, int y, int time, int pointerId,
- boolean isHistorical) {
- GestureStroke stroke = mGestureStrokes.get(pointerId);
- if (stroke == null) {
- stroke = new GestureStroke(pointerId);
- mGestureStrokes.put(pointerId, stroke);
- }
- stroke.addPoint(x, y, time, isHistorical);
- return stroke;
- }
-
- // The working and return object of the following methods, {@link #getIncrementalBatchPoints()}
- // and {@link #getAllBatchPoints()}.
- private final InputPointers mAggregatedPointers = new InputPointers();
-
- private InputPointers getIncrementalBatchPoints() {
- final InputPointers pointers = mAggregatedPointers;
- pointers.reset();
- final int strokeSize = mGestureStrokes.size();
- for (int index = 0; index < strokeSize; index++) {
- final GestureStroke stroke = mGestureStrokes.valueAt(index);
- stroke.appendIncrementalBatchPoints(pointers);
- }
- return pointers;
- }
-
- private InputPointers getAllBatchPoints() {
- final InputPointers pointers = mAggregatedPointers;
- pointers.reset();
- final int strokeSize = mGestureStrokes.size();
- for (int index = 0; index < strokeSize; index++) {
- final GestureStroke stroke = mGestureStrokes.valueAt(index);
- stroke.appendAllBatchPoints(pointers);
- }
- return pointers;
- }
-
private void clearBatchInputPoints() {
- final int strokeSize = mGestureStrokes.size();
- for (int index = 0; index < strokeSize; index++) {
- final GestureStroke stroke = mGestureStrokes.valueAt(index);
- stroke.reset();
- }
+ PointerTracker.clearBatchInputPoints();
mLastRecognitionPointSize = 0;
mLastRecognitionTime = 0;
}
@@ -199,128 +147,4 @@ public class GestureTracker {
}
return false;
}
-
- private static class GestureStroke {
- private final int mPointerId;
- private final InputPointers mInputPointers = new InputPointers();
- private float mLength;
- private float mAngle;
- private int mIncrementalRecognitionPoint;
- private boolean mHasSharpCorner;
- private long mLastPointTime;
- private int mLastPointX;
- private int mLastPointY;
-
- private static int sMinGestureLength;
- private static int sSquaredGestureSampleLength;
-
- private static final float DOUBLE_PI = (float)(2 * Math.PI);
-
- public static void setGestureSampleLength(final int minGestureLength,
- final int sampleLength) {
- sMinGestureLength = minGestureLength;
- sSquaredGestureSampleLength = sampleLength * sampleLength;
- }
-
- public GestureStroke(int pointerId) {
- mPointerId = pointerId;
- reset();
- }
-
- public boolean isStartOfAGesture(int downDuration) {
- return downDuration > MIN_GESTURE_DURATION / 2 && mLength > sMinGestureLength / 2;
- }
-
- public void reset() {
- mLength = 0;
- mAngle = 0;
- mIncrementalRecognitionPoint = 0;
- mHasSharpCorner = false;
- mLastPointTime = 0;
- mInputPointers.reset();
- }
-
- private void updateLastPoint(final int x, final int y, final int time) {
- mLastPointTime = time;
- mLastPointX = x;
- mLastPointY = y;
- }
-
- public void addPoint(final int x, final int y, final int time, final boolean isHistorical) {
- final int size = mInputPointers.getPointerSize();
- if (size == 0) {
- mInputPointers.addPointer(x, y, mPointerId, time);
- if (!isHistorical) {
- updateLastPoint(x, y, time);
- }
- return;
- }
-
- final int[] xCoords = mInputPointers.getXCoordinates();
- final int[] yCoords = mInputPointers.getYCoordinates();
- final int lastX = xCoords[size - 1];
- final int lastY = yCoords[size - 1];
- final float dist = squaredDistance(lastX, lastY, x, y);
- if (dist > sSquaredGestureSampleLength) {
- mInputPointers.addPointer(x, y, mPointerId, time);
- mLength += dist;
- final float angle = angle(lastX, lastY, x, y);
- if (size > 1) {
- float curvature = getAngleDiff(angle, mAngle);
- if (curvature > GESTURE_RECOG_CURVATURE_THRESHOLD) {
- if (size > mIncrementalRecognitionPoint) {
- mIncrementalRecognitionPoint = size;
- }
- mHasSharpCorner = true;
- }
- if (!mHasSharpCorner) {
- mIncrementalRecognitionPoint = size;
- }
- }
- mAngle = angle;
- }
-
- if (!isHistorical) {
- final int duration = (int)(time - mLastPointTime);
- if (mLastPointTime != 0 && duration > 0) {
- final int squaredDuration = duration * duration;
- final float squaredSpeed =
- squaredDistance(mLastPointX, mLastPointY, x, y) / squaredDuration;
- if (squaredSpeed < SQUARED_GESTURE_RECOG_SPEED_THRESHOLD) {
- mIncrementalRecognitionPoint = size;
- }
- }
- updateLastPoint(x, y, time);
- }
- }
-
- private float getAngleDiff(float a1, float a2) {
- final float diff = Math.abs(a1 - a2);
- if (diff > Math.PI) {
- return DOUBLE_PI - diff;
- }
- return diff;
- }
-
- public void appendAllBatchPoints(InputPointers out) {
- out.append(mInputPointers, 0, mInputPointers.getPointerSize());
- }
-
- public void appendIncrementalBatchPoints(InputPointers out) {
- out.append(mInputPointers, 0, mIncrementalRecognitionPoint);
- }
- }
-
- static float squaredDistance(int p1x, int p1y, int p2x, int p2y) {
- final float dx = p1x - p2x;
- final float dy = p1y - p2y;
- return dx * dx + dy * dy;
- }
-
- static float angle(int p1x, int p1y, int p2x, int p2y) {
- final int dx = p1x - p2x;
- final int dy = p1y - p2y;
- if (dx == 0 && dy == 0) return 0;
- return (float)Math.atan2(dy, dx);
- }
}