From 80bcb9963259994cfb6497a19709198414aa860a Mon Sep 17 00:00:00 2001
From: "Tadashi G. Takaoka" <takaoka@google.com>
Date: Fri, 5 Oct 2012 12:12:54 +0900
Subject: [PATCH] Move gesture detection and recognition paramters to resources

Bug: 7032858
Change-Id: I66570a5e21cdeede1eba420c597f440ab61aa941
---
 java/res/values/attrs.xml                     |  17 +++
 java/res/values/config.xml                    |  17 +++
 java/res/values/styles.xml                    |  11 ++
 .../inputmethod/keyboard/PointerTracker.java  |  14 +-
 .../keyboard/internal/GestureStroke.java      | 132 ++++++++++++------
 .../GestureStrokeWithPreviewPoints.java       |   4 +-
 6 files changed, 149 insertions(+), 46 deletions(-)

diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml
index 7e8c77e136..88b4da3aee 100644
--- a/java/res/values/attrs.xml
+++ b/java/res/values/attrs.xml
@@ -127,6 +127,23 @@
         <attr name="ignoreAltCodeKeyTimeout" format="integer" />
         <!-- More keys keyboard will shown at touched point. -->
         <attr name="showMoreKeysKeyboardAtTouchedPoint" format="boolean" />
+        <!-- Static threshold for gesture after fast typing (msec) -->
+        <attr name="gestureStaticTimeThresholdAfterFastTyping" format="integer" />
+        <!-- Static threshold for starting gesture detection (keyWidth%/sec) -->
+        <attr name="gestureDetectFastMoveSpeedThreshold" format="fraction" />
+        <!-- Dynamic threshold for gesture after fast typing (msec) -->
+        <attr name="gestureDynamicThresholdDecayDuration" format="integer" />
+        <!-- Time based threshold values for gesture detection (msec) -->
+        <attr name="gestureDynamicTimeThresholdFrom" format="integer" />
+        <attr name="gestureDynamicTimeThresholdTo" format="integer" />
+        <!-- Distance based threshold values for gesture detection (keyWidth%/sec) -->
+        <attr name="gestureDynamicDistanceThresholdFrom" format="fraction" />
+        <attr name="gestureDynamicDistanceThresholdTo" format="fraction" />
+        <!-- Parameter for gesture sampling (keyWidth%/sec) -->
+        <attr name="gestureSamplingMinimumDistance" format="fraction" />
+        <!-- Parameters for gesture recognition (msec) and (keyWidth%/sec) -->
+        <attr name="gestureRecognitionMinimumTime" format="integer" />
+        <attr name="gestureRecognitionSpeedThreshold" format="fraction" />
     </declare-styleable>
 
     <declare-styleable name="SuggestionStripView">
diff --git a/java/res/values/config.xml b/java/res/values/config.xml
index 8e2d43e4e0..da9a734015 100644
--- a/java/res/values/config.xml
+++ b/java/res/values/config.xml
@@ -69,6 +69,23 @@
     <!-- Showing more keys keyboard, just above the touched point if true, aligned to the key if
          false -->
     <bool name="config_show_more_keys_keyboard_at_touched_point">false</bool>
+    <!-- Static threshold for gesture after fast typing (msec) -->
+    <integer name="config_gesture_static_time_threshold_after_fast_typing">350</integer>
+    <!-- Static threshold for starting gesture detection (keyWidth%/sec) -->
+    <fraction name="config_gesture_detect_fast_move_speed_threshold">150%</fraction>
+    <!-- Dynamic threshold for gesture after fast typing (msec) -->
+    <integer name="config_gesture_dynamic_threshold_decay_duration">450</integer>
+    <!-- Time based threshold values for gesture detection (msec) -->
+    <integer name="config_gesture_dynamic_time_threshold_from">300</integer>
+    <integer name="config_gesture_dynamic_time_threshold_to">20</integer>
+    <!-- Distance based threshold values for gesture detection (keyWidth%/sec) -->
+    <fraction name="config_gesture_dynamic_distance_threshold_from">600%</fraction>
+    <fraction name="config_gesture_dynamic_distance_threshold_to">35%</fraction>
+    <!-- Parameter for gesture sampling (keyWidth%/sec) -->
+    <fraction name="config_gesture_sampling_minimum_distance">16.6666%</fraction>
+    <!-- Parameters for gesture recognition (msec) and (keyWidth%/sec) -->
+    <integer name="config_gesture_recognition_minimum_time">100</integer>
+    <fraction name="config_gesture_recognition_speed_threshold">550%</fraction>
     <!--
         Configuration for auto correction
      -->
diff --git a/java/res/values/styles.xml b/java/res/values/styles.xml
index 9d3d716071..96d8c905b6 100644
--- a/java/res/values/styles.xml
+++ b/java/res/values/styles.xml
@@ -94,6 +94,17 @@
         <item name="languageOnSpacebarFadeoutAnimator">@anim/language_on_spacebar_fadeout</item>
         <item name="altCodeKeyWhileTypingFadeoutAnimator">@anim/alt_code_key_while_typing_fadeout</item>
         <item name="altCodeKeyWhileTypingFadeinAnimator">@anim/alt_code_key_while_typing_fadein</item>
+        <!-- Common attributes of MainKeyboardView for gesture typing detection and recognition -->
+        <item name="gestureStaticTimeThresholdAfterFastTyping">@integer/config_gesture_static_time_threshold_after_fast_typing</item>
+        <item name="gestureDetectFastMoveSpeedThreshold">@fraction/config_gesture_detect_fast_move_speed_threshold</item>
+        <item name="gestureDynamicThresholdDecayDuration">@integer/config_gesture_dynamic_threshold_decay_duration</item>
+        <item name="gestureDynamicTimeThresholdFrom">@integer/config_gesture_dynamic_time_threshold_from</item>
+        <item name="gestureDynamicTimeThresholdTo">@integer/config_gesture_dynamic_time_threshold_to</item>
+        <item name="gestureDynamicDistanceThresholdFrom">@fraction/config_gesture_dynamic_distance_threshold_from</item>
+        <item name="gestureDynamicDistanceThresholdTo">@fraction/config_gesture_dynamic_distance_threshold_to</item>
+        <item name="gestureSamplingMinimumDistance">@fraction/config_gesture_sampling_minimum_distance</item>
+        <item name="gestureRecognitionMinimumTime">@integer/config_gesture_recognition_minimum_time</item>
+        <item name="gestureRecognitionSpeedThreshold">@fraction/config_gesture_recognition_speed_threshold</item>
     </style>
     <style
         name="MainKeyboardView"
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index ad7d0a39f0..fb623ea77f 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -23,6 +23,7 @@ import android.view.MotionEvent;
 
 import com.android.inputmethod.accessibility.AccessibilityUtils;
 import com.android.inputmethod.keyboard.internal.GestureStroke;
+import com.android.inputmethod.keyboard.internal.GestureStroke.GestureStrokeParams;
 import com.android.inputmethod.keyboard.internal.GestureStrokeWithPreviewPoints;
 import com.android.inputmethod.keyboard.internal.PointerTrackerQueue;
 import com.android.inputmethod.latin.CollectionUtils;
@@ -135,7 +136,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
             mTouchNoiseThresholdDistanceSquared = 0;
         }
 
-        public PointerTrackerParams(TypedArray mainKeyboardViewAttr) {
+        public PointerTrackerParams(final TypedArray mainKeyboardViewAttr) {
             mSlidingKeyInputEnabled = mainKeyboardViewAttr.getBoolean(
                     R.styleable.MainKeyboardView_slidingKeyInputEnable, false);
             mTouchNoiseThresholdTime = mainKeyboardViewAttr.getInt(
@@ -150,6 +151,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
 
     // Parameters for pointer handling.
     private static PointerTrackerParams sParams;
+    private static GestureStrokeParams sGestureStrokeParams;
     private static boolean sNeedsPhantomSuddenMoveEventHack;
 
     private static final ArrayList<PointerTracker> sTrackers = CollectionUtils.newArrayList();
@@ -222,10 +224,12 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
         }
         sNeedsPhantomSuddenMoveEventHack = needsPhantomSuddenMoveEventHack;
         sParams = PointerTrackerParams.DEFAULT;
+        sGestureStrokeParams = GestureStrokeParams.DEFAULT;
     }
 
     public static void setParameters(final TypedArray mainKeyboardViewAttr) {
         sParams = new PointerTrackerParams(mainKeyboardViewAttr);
+        sGestureStrokeParams = new GestureStrokeParams(mainKeyboardViewAttr);
     }
 
     private static void updateGestureHandlingMode() {
@@ -296,7 +300,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
             throw new NullPointerException();
         }
         mPointerId = id;
-        mGestureStrokeWithPreviewPoints = new GestureStrokeWithPreviewPoints(id);
+        mGestureStrokeWithPreviewPoints = new GestureStrokeWithPreviewPoints(
+                id, sGestureStrokeParams);
         setKeyDetectorInner(handler.getKeyDetector());
         mListener = handler.getKeyboardActionListener();
         mDrawingProxy = handler.getDrawingProxy();
@@ -587,10 +592,11 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
     private void mayUpdateBatchInput(final long eventTime, final Key key) {
         if (key != null) {
             synchronized (sAggregratedPointers) {
-                mGestureStrokeWithPreviewPoints.appendIncrementalBatchPoints(sAggregratedPointers);
+                final GestureStroke stroke = mGestureStrokeWithPreviewPoints;
+                stroke.appendIncrementalBatchPoints(sAggregratedPointers);
                 final int size = sAggregratedPointers.getPointerSize();
                 if (size > sLastRecognitionPointSize
-                        && GestureStroke.hasRecognitionTimePast(eventTime, sLastRecognitionTime)) {
+                        && stroke.hasRecognitionTimePast(eventTime, sLastRecognitionTime)) {
                     sLastRecognitionPointSize = size;
                     sLastRecognitionTime = eventTime;
                     if (DEBUG_LISTENER) {
diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java
index c0e92df323..9b1a20159d 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java
@@ -14,10 +14,13 @@
 
 package com.android.inputmethod.keyboard.internal;
 
+import android.content.res.TypedArray;
 import android.util.Log;
 
 import com.android.inputmethod.latin.InputPointers;
+import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.ResizableIntArray;
+import com.android.inputmethod.latin.ResourceUtils;
 
 public class GestureStroke {
     private static final String TAG = GestureStroke.class.getSimpleName();
@@ -31,6 +34,8 @@ public class GestureStroke {
     private final ResizableIntArray mXCoordinates = new ResizableIntArray(DEFAULT_CAPACITY);
     private final ResizableIntArray mYCoordinates = new ResizableIntArray(DEFAULT_CAPACITY);
 
+    private final GestureStrokeParams mParams;
+
     private int mKeyWidth; // pixel
     // Static threshold for starting gesture detection
     private int mDetectFastMoveSpeedThreshold; // pixel /sec
@@ -51,53 +56,100 @@ public class GestureStroke {
     private int mIncrementalRecognitionSize;
     private int mLastIncrementalBatchSize;
 
-    // TODO: Move some of these to resource.
-
-    // Static threshold for gesture after fast typing
-    public static final int GESTURE_STATIC_TIME_THRESHOLD_AFTER_FAST_TYPING = 350; // msec
-
-    // Static threshold for starting gesture detection
-    private static final float DETECT_FAST_MOVE_SPEED_THRESHOLD = 1.5f; // keyWidth / sec
+    public static final class GestureStrokeParams {
+        // Static threshold for gesture after fast typing
+        public final int mStaticTimeThresholdAfterFastTyping; // msec
+        // Static threshold for starting gesture detection
+        public final float mDetectFastMoveSpeedThreshold; // keyWidth/sec
+        // Dynamic threshold for gesture after fast typing
+        public final int mDynamicThresholdDecayDuration; // msec
+        // Time based threshold values
+        public final int mDynamicTimeThresholdFrom; // msec
+        public final int mDynamicTimeThresholdTo; // msec
+        // Distance based threshold values
+        public final float mDynamicDistanceThresholdFrom; // keyWidth
+        public final float mDynamicDistanceThresholdTo; // keyWidth
+        // Parameters for gesture sampling
+        public final float mSamplingMinimumDistance; // keyWidth
+        // Parameters for gesture recognition
+        public final int mRecognitionMinimumTime; // msec
+        public final float mRecognitionSpeedThreshold; // keyWidth/sec
 
-    // Dynamic threshold for gesture after fast typing
-    private static final int GESTURE_DYNAMIC_THRESHOLD_DECAY_DURATION = 450; // msec
-    // Time based threshold values
-    private static final int GESTURE_DYNAMIC_TIME_THRESHOLD_FROM = 300; // msec
-    private static final int GESTURE_DYNAMIC_TIME_THRESHOLD_TO = 20; // msec
-    // Distance based threshold values
-    private static final float GESTURE_DYNAMIC_DISTANCE_THRESHOLD_FROM = 6.0f; // keyWidth
-    private static final float GESTURE_DYNAMIC_DISTANCE_THRESHOLD_TO = 0.35f; // keyWidth
+        // Default GestureStroke parameters for test.
+        public static final GestureStrokeParams FOR_TEST = new GestureStrokeParams();
+        public static final GestureStrokeParams DEFAULT = FOR_TEST;
 
-    // Parameters for gesture sampling
-    private static final float GESTURE_SAMPLING_MINIMUM_DISTANCE = 1.0f / 6.0f; // keyWidth
+        private GestureStrokeParams() {
+            // These parameter values are default and intended for testing.
+            mStaticTimeThresholdAfterFastTyping = 350; // msec
+            mDetectFastMoveSpeedThreshold = 1.5f; // keyWidth / sec
+            mDynamicThresholdDecayDuration = 450; // msec
+            mDynamicTimeThresholdFrom = 300; // msec
+            mDynamicTimeThresholdTo = 20; // msec
+            mDynamicDistanceThresholdFrom = 6.0f; // keyWidth
+            mDynamicDistanceThresholdTo = 0.35f; // keyWidth
+            // The following parameters' change will affect the result of regression test.
+            mSamplingMinimumDistance = 1.0f / 6.0f; // keyWidth
+            mRecognitionMinimumTime = 100; // msec
+            mRecognitionSpeedThreshold = 5.5f; // keyWidth / sec
+        }
 
-    // Parameters for gesture recognition
-    private static final int GESTURE_RECOGNITION_MINIMUM_TIME = 100; // msec
-    private static final float GESTURE_RECOGNITION_SPEED_THRESHOLD = 5.5f; // keyWidth / sec
+        public GestureStrokeParams(final TypedArray mainKeyboardViewAttr) {
+            mStaticTimeThresholdAfterFastTyping = mainKeyboardViewAttr.getInt(
+                    R.styleable.MainKeyboardView_gestureStaticTimeThresholdAfterFastTyping,
+                    DEFAULT.mStaticTimeThresholdAfterFastTyping);
+            mDetectFastMoveSpeedThreshold = ResourceUtils.getFraction(mainKeyboardViewAttr,
+                    R.styleable.MainKeyboardView_gestureDetectFastMoveSpeedThreshold,
+                    DEFAULT.mDetectFastMoveSpeedThreshold);
+            mDynamicThresholdDecayDuration = mainKeyboardViewAttr.getInt(
+                    R.styleable.MainKeyboardView_gestureDynamicThresholdDecayDuration,
+                    DEFAULT.mDynamicThresholdDecayDuration);
+            mDynamicTimeThresholdFrom = mainKeyboardViewAttr.getInt(
+                    R.styleable.MainKeyboardView_gestureDynamicTimeThresholdFrom,
+                    DEFAULT.mDynamicTimeThresholdFrom);
+            mDynamicTimeThresholdTo = mainKeyboardViewAttr.getInt(
+                    R.styleable.MainKeyboardView_gestureDynamicTimeThresholdTo,
+                    DEFAULT.mDynamicTimeThresholdTo);
+            mDynamicDistanceThresholdFrom = ResourceUtils.getFraction(mainKeyboardViewAttr,
+                    R.styleable.MainKeyboardView_gestureDynamicDistanceThresholdFrom,
+                    DEFAULT.mDynamicDistanceThresholdFrom);
+            mDynamicDistanceThresholdTo = ResourceUtils.getFraction(mainKeyboardViewAttr,
+                    R.styleable.MainKeyboardView_gestureDynamicDistanceThresholdTo,
+                    DEFAULT.mDynamicDistanceThresholdTo);
+            mSamplingMinimumDistance = ResourceUtils.getFraction(mainKeyboardViewAttr,
+                    R.styleable.MainKeyboardView_gestureSamplingMinimumDistance,
+                    DEFAULT.mSamplingMinimumDistance);
+            mRecognitionMinimumTime = mainKeyboardViewAttr.getInt(
+                    R.styleable.MainKeyboardView_gestureRecognitionMinimumTime,
+                    DEFAULT.mRecognitionMinimumTime);
+            mRecognitionSpeedThreshold = ResourceUtils.getFraction(mainKeyboardViewAttr,
+                    R.styleable.MainKeyboardView_gestureRecognitionSpeedThreshold,
+                    DEFAULT.mRecognitionSpeedThreshold);
+        }
+    }
 
     private static final int MSEC_PER_SEC = 1000;
 
-    public GestureStroke(final int pointerId) {
+    public GestureStroke(final int pointerId, final GestureStrokeParams params) {
         mPointerId = pointerId;
+        mParams = params;
     }
 
     public void setKeyboardGeometry(final int keyWidth) {
         mKeyWidth = keyWidth;
         // TODO: Find an appropriate base metric for these length. Maybe diagonal length of the key?
-        mDetectFastMoveSpeedThreshold = (int)(keyWidth * DETECT_FAST_MOVE_SPEED_THRESHOLD);
+        mDetectFastMoveSpeedThreshold = (int)(keyWidth * mParams.mDetectFastMoveSpeedThreshold);
         mGestureDynamicDistanceThresholdFrom =
-                (int)(keyWidth * GESTURE_DYNAMIC_DISTANCE_THRESHOLD_FROM);
-        mGestureDynamicDistanceThresholdTo =
-                (int)(keyWidth * GESTURE_DYNAMIC_DISTANCE_THRESHOLD_TO);
-        mGestureSamplingMinimumDistance = (int)(keyWidth * GESTURE_SAMPLING_MINIMUM_DISTANCE);
-        mGestureRecognitionSpeedThreshold =
-                (int)(keyWidth * GESTURE_RECOGNITION_SPEED_THRESHOLD);
+                (int)(keyWidth * mParams.mDynamicDistanceThresholdFrom);
+        mGestureDynamicDistanceThresholdTo = (int)(keyWidth * mParams.mDynamicDistanceThresholdTo);
+        mGestureSamplingMinimumDistance = (int)(keyWidth * mParams.mSamplingMinimumDistance);
+        mGestureRecognitionSpeedThreshold = (int)(keyWidth * mParams.mRecognitionSpeedThreshold);
         if (DEBUG) {
             Log.d(TAG, String.format(
                     "[%d] setKeyboardGeometry: keyWidth=%3d tT=%3d >> %3d tD=%3d >> %3d",
                     mPointerId, keyWidth,
-                    GESTURE_DYNAMIC_TIME_THRESHOLD_FROM,
-                    GESTURE_DYNAMIC_TIME_THRESHOLD_TO,
+                    mParams.mDynamicTimeThresholdFrom,
+                    mParams.mDynamicTimeThresholdTo,
                     mGestureDynamicDistanceThresholdFrom,
                     mGestureDynamicDistanceThresholdTo));
         }
@@ -107,7 +159,7 @@ public class GestureStroke {
             final long gestureFirstDownTime, final long lastTypingTime) {
         reset();
         final long elapsedTimeAfterTyping = downTime - lastTypingTime;
-        if (elapsedTimeAfterTyping < GESTURE_STATIC_TIME_THRESHOLD_AFTER_FAST_TYPING) {
+        if (elapsedTimeAfterTyping < mParams.mStaticTimeThresholdAfterFastTyping) {
             mAfterFastTyping = true;
         }
         if (DEBUG) {
@@ -119,23 +171,23 @@ public class GestureStroke {
     }
 
     private int getGestureDynamicDistanceThreshold(final int deltaTime) {
-        if (!mAfterFastTyping || deltaTime >= GESTURE_DYNAMIC_THRESHOLD_DECAY_DURATION) {
+        if (!mAfterFastTyping || deltaTime >= mParams.mDynamicThresholdDecayDuration) {
             return mGestureDynamicDistanceThresholdTo;
         }
         final int decayedThreshold =
                 (mGestureDynamicDistanceThresholdFrom - mGestureDynamicDistanceThresholdTo)
-                * deltaTime / GESTURE_DYNAMIC_THRESHOLD_DECAY_DURATION;
+                * deltaTime / mParams.mDynamicThresholdDecayDuration;
         return mGestureDynamicDistanceThresholdFrom - decayedThreshold;
     }
 
     private int getGestureDynamicTimeThreshold(final int deltaTime) {
-        if (!mAfterFastTyping || deltaTime >= GESTURE_DYNAMIC_THRESHOLD_DECAY_DURATION) {
-            return GESTURE_DYNAMIC_TIME_THRESHOLD_TO;
+        if (!mAfterFastTyping || deltaTime >= mParams.mDynamicThresholdDecayDuration) {
+            return mParams.mDynamicTimeThresholdTo;
         }
         final int decayedThreshold =
-                (GESTURE_DYNAMIC_TIME_THRESHOLD_FROM - GESTURE_DYNAMIC_TIME_THRESHOLD_TO)
-                * deltaTime / GESTURE_DYNAMIC_THRESHOLD_DECAY_DURATION;
-        return GESTURE_DYNAMIC_TIME_THRESHOLD_FROM - decayedThreshold;
+                (mParams.mDynamicTimeThresholdFrom - mParams.mDynamicTimeThresholdTo)
+                * deltaTime / mParams.mDynamicThresholdDecayDuration;
+        return mParams.mDynamicTimeThresholdFrom - decayedThreshold;
     }
 
     public boolean isStartOfAGesture() {
@@ -249,9 +301,9 @@ public class GestureStroke {
         }
     }
 
-    public static final boolean hasRecognitionTimePast(
+    public final boolean hasRecognitionTimePast(
             final long currentTime, final long lastRecognitionTime) {
-        return currentTime > lastRecognitionTime + GESTURE_RECOGNITION_MINIMUM_TIME;
+        return currentTime > lastRecognitionTime + mParams.mRecognitionMinimumTime;
     }
 
     public void appendAllBatchPoints(final InputPointers out) {
diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java
index 05e0a2ec3b..8192c9076b 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java
@@ -33,8 +33,8 @@ public final class GestureStrokeWithPreviewPoints extends GestureStroke {
     // TODO: Move this to resource.
     private static final float MIN_PREVIEW_SAMPLE_LENGTH_RATIO_TO_KEY_WIDTH = 0.1f;
 
-    public GestureStrokeWithPreviewPoints(final int pointerId) {
-        super(pointerId);
+    public GestureStrokeWithPreviewPoints(final int pointerId, final GestureStrokeParams params) {
+        super(pointerId, params);
     }
 
     @Override
-- 
GitLab