From eb68036798f53763768e4ab37c7bfab9a2f36025 Mon Sep 17 00:00:00 2001
From: "Tadashi G. Takaoka" <takaoka@google.com>
Date: Mon, 13 Sep 2010 19:26:23 +0900
Subject: [PATCH] Add keyHysteresisDistance xml attribute

This change also introduces MiniKeyboardKeyDetector and
mini_keyboad_slide_allowance parameter to tune the key detection
behavior.

Bug: 2993769
Change-Id: I1932b0a382e172cb77b9e098ae182049c834dfe0
---
 java/res/layout/keyboard_popup.xml            |  2 +
 java/res/values-land/dimens.xml               |  5 +-
 java/res/values/attrs.xml                     |  6 +-
 java/res/values/dimens.xml                    |  4 +-
 java/res/values/styles.xml                    |  2 +-
 .../latin/LatinKeyboardBaseView.java          | 25 ++++----
 .../latin/MiniKeyboardKeyDetector.java        | 59 +++++++++++++++++++
 .../inputmethod/latin/PointerTracker.java     | 13 ++--
 8 files changed, 89 insertions(+), 27 deletions(-)
 create mode 100644 java/src/com/android/inputmethod/latin/MiniKeyboardKeyDetector.java

diff --git a/java/res/layout/keyboard_popup.xml b/java/res/layout/keyboard_popup.xml
index 1005e7e11a..9a52e2cbd4 100644
--- a/java/res/layout/keyboard_popup.xml
+++ b/java/res/layout/keyboard_popup.xml
@@ -33,5 +33,7 @@
             android:background="@drawable/keyboard_dark_background"
 
             latin:keyBackground="@drawable/btn_keyboard_key_gingerbread_popup"
+            latin:keyHysteresisDistance="0dip"
+            latin:verticalCorrection="-20dip"
             />
 </LinearLayout>
diff --git a/java/res/values-land/dimens.xml b/java/res/values-land/dimens.xml
index 43951552e5..4f87b79d27 100644
--- a/java/res/values-land/dimens.xml
+++ b/java/res/values-land/dimens.xml
@@ -22,4 +22,7 @@
     <dimen name="key_height">47dip</dimen>
     <dimen name="candidate_strip_height">38dip</dimen>
     <dimen name="spacebar_vertical_correction">2dip</dimen>
-</resources>
\ No newline at end of file
+    <!-- Amount of allowance for selecting keys in a mini popup keyboard by sliding finger. -->
+    <!-- key_height * 1.7 -->
+    <dimen name="mini_keyboard_slide_allowance">79.9dip</dimen>
+</resources>
diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml
index a8eaab9a34..995373e845 100644
--- a/java/res/values/attrs.xml
+++ b/java/res/values/attrs.xml
@@ -43,12 +43,12 @@
         <!-- Height of the key press feedback popup. -->
         <attr name="keyPreviewHeight" format="dimension" />
 
+        <!-- Hysteresis distance for key debouncing -->
+        <attr name="keyHysteresisDistance" format="dimension" />
+
         <!-- Amount to offset the touch Y coordinate by, for bias correction. -->
         <attr name="verticalCorrection" format="dimension" />
 
-        <!-- Amount of allowance for selecting keys in a mini popup keyboard by sliding finger. -->
-        <attr name="miniKeyboardSlideAllowance" format="dimension" />
-
         <!-- Layout resource for popup keyboards. -->
         <attr name="popupLayout" format="reference" />
 
diff --git a/java/res/values/dimens.xml b/java/res/values/dimens.xml
index 39dce9db0e..af8b381105 100644
--- a/java/res/values/dimens.xml
+++ b/java/res/values/dimens.xml
@@ -27,5 +27,7 @@
          will not go into extract (fullscreen) mode. -->
     <dimen name="max_height_for_fullscreen">2.5in</dimen>
     <dimen name="key_text_size">22sp</dimen>
-    <dimen name="key_debounce_hysteresis_distance">0.05in</dimen>
+    <!-- Amount of allowance for selecting keys in a mini popup keyboard by sliding finger. -->
+    <!-- key_height * 1.7 -->
+    <dimen name="mini_keyboard_slide_allowance">91.8dip</dimen>
 </resources>
diff --git a/java/res/values/styles.xml b/java/res/values/styles.xml
index 48f0d5e542..258082eb66 100644
--- a/java/res/values/styles.xml
+++ b/java/res/values/styles.xml
@@ -26,8 +26,8 @@
         <item name="keyPreviewHeight">80dip</item>
         <item name="labelTextSize">14sp</item>
         <item name="popupLayout">@layout/keyboard_popup</item>
+        <item name="keyHysteresisDistance">0.05in</item>
         <item name="verticalCorrection">-10dip</item>
-        <item name="miniKeyboardSlideAllowance">40dip</item>
         <item name="shadowColor">#BB000000</item>
         <item name="shadowRadius">2.75</item>
         <item name="backgroundDimAmount">0.5</item>
diff --git a/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java b/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java
index 610d954233..a78e2b8691 100644
--- a/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java
+++ b/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java
@@ -170,6 +170,7 @@ public class LatinKeyboardBaseView extends View implements PointerTracker.UIProx
     private float mShadowRadius;
     private Drawable mKeyBackground;
     private float mBackgroundDimAmount;
+    private float mKeyHysteresisDistance;
     private float mVerticalCorrection;
     private int mPreviewOffset;
     private int mPreviewHeight;
@@ -200,14 +201,13 @@ public class LatinKeyboardBaseView extends View implements PointerTracker.UIProx
     private int mMiniKeyboardOriginY;
     private long mMiniKeyboardPopupTime;
     private int[] mWindowOffset;
-    private float mMiniKeyboardSlideAllowance;
+    private final float mMiniKeyboardSlideAllowance;
 
     /** Listener for {@link OnKeyboardActionListener}. */
     private OnKeyboardActionListener mKeyboardActionListener;
 
     private final ArrayList<PointerTracker> mPointerTrackers = new ArrayList<PointerTracker>();
     private final PointerQueue mPointerQueue = new PointerQueue();
-    private final float mDebounceHysteresis;
     private final boolean mHasDistinctMultitouch;
     private int mOldPointerCount = 1;
 
@@ -386,12 +386,12 @@ public class LatinKeyboardBaseView extends View implements PointerTracker.UIProx
             case R.styleable.LatinKeyboardBaseView_keyBackground:
                 mKeyBackground = a.getDrawable(attr);
                 break;
+            case R.styleable.LatinKeyboardBaseView_keyHysteresisDistance:
+                mKeyHysteresisDistance = a.getDimensionPixelOffset(attr, 0);
+                break;
             case R.styleable.LatinKeyboardBaseView_verticalCorrection:
                 mVerticalCorrection = a.getDimensionPixelOffset(attr, 0);
                 break;
-            case R.styleable.LatinKeyboardBaseView_miniKeyboardSlideAllowance:
-                mMiniKeyboardSlideAllowance = a.getDimensionPixelOffset(attr, 0);
-                break;
             case R.styleable.LatinKeyboardBaseView_keyPreviewLayout:
                 previewLayout = a.getResourceId(attr, 0);
                 break;
@@ -473,7 +473,7 @@ public class LatinKeyboardBaseView extends View implements PointerTracker.UIProx
         mSwipeThreshold = (int) (500 * res.getDisplayMetrics().density);
         // TODO: Refer frameworks/base/core/res/res/values/config.xml
         mDisambiguateSwipe = res.getBoolean(R.bool.config_swipeDisambiguation);
-        mDebounceHysteresis = res.getDimension(R.dimen.key_debounce_hysteresis_distance);
+        mMiniKeyboardSlideAllowance = res.getDimension(R.dimen.mini_keyboard_slide_allowance);
 
         GestureDetector.SimpleOnGestureListener listener =
                 new GestureDetector.SimpleOnGestureListener() {
@@ -556,7 +556,7 @@ public class LatinKeyboardBaseView extends View implements PointerTracker.UIProx
         mKeys = mKeyDetector.setKeyboard(keyboard, -getPaddingLeft(),
                 -getPaddingTop() + mVerticalCorrection);
         for (PointerTracker tracker : mPointerTrackers) {
-            tracker.setKeyboard(mKeys, mDebounceHysteresis);
+            tracker.setKeyboard(mKeys, mKeyHysteresisDistance);
         }
         requestLayout();
         // Hint to reallocate the buffer if the size changed
@@ -1025,6 +1025,8 @@ public class LatinKeyboardBaseView extends View implements PointerTracker.UIProx
                 mKeyboardActionListener.onRelease(primaryCode);
             }
         });
+        // Override default ProximityKeyDetector.
+        miniKeyboard.mKeyDetector = new MiniKeyboardKeyDetector(mMiniKeyboardSlideAllowance);
 
         Keyboard keyboard;
         if (popupKey.popupCharacters != null) {
@@ -1120,12 +1122,7 @@ public class LatinKeyboardBaseView extends View implements PointerTracker.UIProx
 
     private MotionEvent generateMiniKeyboardMotionEvent(int action, int x, int y, long eventTime) {
         return MotionEvent.obtain(mMiniKeyboardPopupTime, eventTime, action,
-                x - mMiniKeyboardOriginX,
-                // TODO: Currently just taking care of "below" of the keys in a mini popup keyboard
-                // for key detection by sliding finger.  Need to take care of left, right, and
-                // upper of "edge" keys.
-                y - mMiniKeyboardOriginY - (int)mMiniKeyboardSlideAllowance,
-                0);
+                    x - mMiniKeyboardOriginX, y - mMiniKeyboardOriginY, 0);
     }
 
     private PointerTracker getPointerTracker(final int id) {
@@ -1138,7 +1135,7 @@ public class LatinKeyboardBaseView extends View implements PointerTracker.UIProx
             final PointerTracker tracker =
                 new PointerTracker(i, mHandler, mKeyDetector, this, mHasDistinctMultitouch);
             if (keys != null)
-                tracker.setKeyboard(keys, mDebounceHysteresis);
+                tracker.setKeyboard(keys, mKeyHysteresisDistance);
             if (listener != null)
                 tracker.setOnKeyboardActionListener(listener);
             pointers.add(tracker);
diff --git a/java/src/com/android/inputmethod/latin/MiniKeyboardKeyDetector.java b/java/src/com/android/inputmethod/latin/MiniKeyboardKeyDetector.java
new file mode 100644
index 0000000000..709d082bed
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/MiniKeyboardKeyDetector.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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;
+
+import android.inputmethodservice.Keyboard.Key;
+
+class MiniKeyboardKeyDetector extends KeyDetector {
+    private static final int MAX_NEARBY_KEYS = 1;
+
+    private final int mSlideAllowanceSquare;
+    private final int mSlideAllowanceSquareTop;
+
+    public MiniKeyboardKeyDetector(float slideAllowance) {
+        super();
+        mSlideAllowanceSquare = (int)(slideAllowance * slideAllowance);
+        // Top slide allowance is slightly longer (sqrt(2) times) than other edges.
+        mSlideAllowanceSquareTop = mSlideAllowanceSquare * 2;
+    }
+
+    @Override
+    protected int getMaxNearbyKeys() {
+        return MAX_NEARBY_KEYS;
+    }
+
+    @Override
+    public int getKeyIndexAndNearbyCodes(int x, int y, int[] allKeys) {
+        final Key[] keys = getKeys();
+        final int touchX = getTouchX(x);
+        final int touchY = getTouchY(y);
+        int closestKey = LatinKeyboardBaseView.NOT_A_KEY;
+        int closestKeyDist = (y < 0) ? mSlideAllowanceSquareTop : mSlideAllowanceSquare;
+        final int keyCount = keys.length;
+        for (int i = 0; i < keyCount; i++) {
+            final Key key = keys[i];
+            int dist = key.squaredDistanceFrom(touchX, touchY);
+            if (dist < closestKeyDist) {
+                closestKey = i;
+                closestKeyDist = dist;
+            }
+        }
+        if (allKeys != null && closestKey != LatinKeyboardBaseView.NOT_A_KEY)
+            allKeys[0] = closestKey;
+        return closestKey;
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/PointerTracker.java b/java/src/com/android/inputmethod/latin/PointerTracker.java
index e10c9b8623..958e57618d 100644
--- a/java/src/com/android/inputmethod/latin/PointerTracker.java
+++ b/java/src/com/android/inputmethod/latin/PointerTracker.java
@@ -55,7 +55,7 @@ public class PointerTracker {
     private final boolean mHasDistinctMultitouch;
 
     private Key[] mKeys;
-    private int mKeyDebounceThresholdSquared = -1;
+    private int mKeyHysteresisDistanceSquared = -1;
 
     private int mCurrentKey = NOT_A_KEY;
     private int mStartX;
@@ -106,11 +106,11 @@ public class PointerTracker {
         mListener = listener;
     }
 
-    public void setKeyboard(Key[] keys, float hysteresisPixel) {
-        if (keys == null || hysteresisPixel < 1.0f)
+    public void setKeyboard(Key[] keys, float keyHysteresisDistance) {
+        if (keys == null || keyHysteresisDistance < 0)
             throw new IllegalArgumentException();
         mKeys = keys;
-        mKeyDebounceThresholdSquared = (int)(hysteresisPixel * hysteresisPixel);
+        mKeyHysteresisDistanceSquared = (int)(keyHysteresisDistance * keyHysteresisDistance);
         // Update current key index because keyboard layout has been changed.
         mCurrentKey = mKeyDetector.getKeyIndexAndNearbyCodes(mStartX, mStartY, null);
     }
@@ -335,13 +335,12 @@ public class PointerTracker {
     }
 
     private boolean isMinorMoveBounce(int x, int y, int newKey, int curKey) {
-        if (mKeys == null || mKeyDebounceThresholdSquared < 0)
+        if (mKeys == null || mKeyHysteresisDistanceSquared < 0)
             throw new IllegalStateException("keyboard and/or hysteresis not set");
         if (newKey == curKey) {
             return true;
         } else if (isValidKeyIndex(curKey)) {
-            return getSquareDistanceToKeyEdge(x, y, mKeys[curKey])
-                    < mKeyDebounceThresholdSquared;
+            return getSquareDistanceToKeyEdge(x, y, mKeys[curKey]) < mKeyHysteresisDistanceSquared;
         } else {
             return false;
         }
-- 
GitLab