Implement "lift-to-type" interaction. Fix event text.

Bug: 6456970
Change-Id: Idd6b84fc7a730a1e78d9c1157e3b5f22e5d49fc4
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java b/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java
index d7cd8e2..955cb4c 100644
--- a/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java
+++ b/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java
@@ -90,6 +90,7 @@
         final AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
         event.setPackageName(mKeyboardView.getContext().getPackageName());
         event.setClassName(key.getClass().getName());
+        event.setContentDescription(keyDescription);
         event.setEnabled(true);
 
         final AccessibilityRecordCompat record = new AccessibilityRecordCompat(event);
@@ -158,12 +159,12 @@
             info = AccessibilityNodeInfoCompat.obtain();
             info.setPackageName(mKeyboardView.getContext().getPackageName());
             info.setClassName(key.getClass().getName());
+            info.setContentDescription(keyDescription);
             info.setBoundsInParent(boundsInParent);
             info.setBoundsInScreen(boundsInScreen);
             info.setParent(mKeyboardView);
             info.setSource(mKeyboardView, virtualViewId);
             info.setBoundsInScreen(boundsInScreen);
-            info.setText(keyDescription);
             info.setEnabled(true);
         }
 
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java
index ba814e3..34817ba 100644
--- a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java
+++ b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java
@@ -23,6 +23,7 @@
 import android.support.v4.view.accessibility.AccessibilityEventCompat;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewConfiguration;
 import android.view.accessibility.AccessibilityEvent;
 
 import com.android.inputmethod.keyboard.Key;
@@ -41,6 +42,12 @@
 
     private Key mLastHoverKey = null;
 
+    /**
+     * Inset in pixels to look for keys when the user's finger exits the
+     * keyboard area. See {@link ViewConfiguration#getScaledEdgeSlop()}.
+     */
+    private int mEdgeSlop;
+
     public static void init(InputMethodService inputMethod) {
         sInstance.initInternal(inputMethod);
     }
@@ -55,6 +62,7 @@
 
     private void initInternal(InputMethodService inputMethod) {
         mInputMethod = inputMethod;
+        mEdgeSlop = ViewConfiguration.get(inputMethod).getScaledEdgeSlop();
     }
 
     /**
@@ -108,8 +116,14 @@
         mLastHoverKey = key;
 
         switch (event.getAction()) {
-        case MotionEvent.ACTION_HOVER_ENTER:
         case MotionEvent.ACTION_HOVER_EXIT:
+            // Make sure we're not getting an EXIT event because the user slid
+            // off the keyboard area, then force a key press.
+            if (pointInView(x, y)) {
+                tracker.onRegisterKey(key);
+            }
+            //$FALL-THROUGH$
+        case MotionEvent.ACTION_HOVER_ENTER:
             return onHoverKey(key, event);
         case MotionEvent.ACTION_HOVER_MOVE:
             if (key != previousKey) {
@@ -123,6 +137,20 @@
     }
 
     /**
+     * Utility method to determine whether the given point, in local
+     * coordinates, is inside the view, where the area of the view is contracted
+     * by the edge slop factor.
+     *
+     * @param localX The local x-coordinate.
+     * @param localY The local y-coordinate.
+     */
+    private boolean pointInView(int localX, int localY) {
+        return (localX >= mEdgeSlop) && (localY >= mEdgeSlop)
+                && (localX < (mView.getWidth() - mEdgeSlop))
+                && (localY < (mView.getHeight() - mEdgeSlop));
+    }
+
+    /**
      * Simulates a transition between two {@link Key}s by sending a HOVER_EXIT
      * on the previous key, a HOVER_ENTER on the current key, and a HOVER_MOVE
      * on the current key.
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
index aeca839..337ae9c 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
@@ -140,7 +140,7 @@
             final PointerTracker tracker = (PointerTracker) msg.obj;
             switch (msg.what) {
             case MSG_REPEAT_KEY:
-                tracker.onRepeatKey(tracker.getKey());
+                tracker.onRegisterKey(tracker.getKey());
                 startKeyRepeatTimer(tracker, mParams.mKeyRepeatInterval);
                 break;
             case MSG_LONGPRESS_KEY:
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index c62c3dd..6ad854d 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -714,7 +714,7 @@
 
     private void startRepeatKey(Key key) {
         if (key != null && key.isRepeatable()) {
-            onRepeatKey(key);
+            onRegisterKey(key);
             mTimerProxy.startKeyRepeatTimer(this);
             mIsRepeatableKey = true;
         } else {
@@ -722,7 +722,7 @@
         }
     }
 
-    public void onRepeatKey(Key key) {
+    public void onRegisterKey(Key key) {
         if (key != null) {
             detectAndSendKey(key, key.mX, key.mY);
             if (!key.altCodeWhileTyping() && !key.isModifier()) {