Use onHoverEvent instead of dispatchHoverEvent

This CL also refactors KeyboardAccessibilityDelegate a bit to be able
to override on hovering methods that handle enter, move, and exit on a
key.

Bug: 12491371
Change-Id: I3c7e81ccb8729ae6e466c654efde0c18ed734bdf
diff --git a/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityDelegate.java b/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityDelegate.java
index ed175f5..f0749a4 100644
--- a/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityDelegate.java
+++ b/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityDelegate.java
@@ -37,7 +37,7 @@
     protected final KeyDetector mKeyDetector;
     private Keyboard mKeyboard;
     private KeyboardAccessibilityNodeProvider mAccessibilityNodeProvider;
-    private Key mLastHoverKey;
+    private Key mCurrentHoverKey;
 
     public KeyboardAccessibilityDelegate(final KV keyboardView, final KeyDetector keyDetector) {
         super();
@@ -117,14 +117,14 @@
      * Receives hover events when touch exploration is turned on in SDK versions ICS and higher.
      *
      * @param event The hover event.
-     * @return {@code true} if the event is handled
+     * @return {@code true} if the event is handled.
      */
-    public boolean dispatchHoverEvent(final MotionEvent event) {
+    public boolean onHoverEvent(final MotionEvent event) {
         final int x = (int) event.getX();
         final int y = (int) event.getY();
-        final Key previousKey = mLastHoverKey;
+        final Key previousKey = mCurrentHoverKey;
         final Key key = mKeyDetector.detectHitKey(x, y);
-        mLastHoverKey = key;
+        mCurrentHoverKey = key;
 
         switch (event.getAction()) {
         case MotionEvent.ACTION_HOVER_EXIT:
@@ -133,17 +133,30 @@
             if (key != null) {
                 final long downTime = simulateKeyPress(key);
                 simulateKeyRelease(key, downTime);
+                onHoverExitKey(key);
             }
-            //$FALL-THROUGH$
+            mCurrentHoverKey = null;
+            break;
         case MotionEvent.ACTION_HOVER_ENTER:
-            return onHoverKey(key, event);
+            if (key != null) {
+                onHoverEnterKey(key);
+            }
+            break;
         case MotionEvent.ACTION_HOVER_MOVE:
             if (key != previousKey) {
-                return onTransitionKey(key, previousKey, event);
+                if (previousKey != null) {
+                    onHoverExitKey(previousKey);
+                }
+                if (key != null) {
+                    onHoverEnterKey(key);
+                }
             }
-            return onHoverKey(key, event);
+            if (key != null) {
+                onHoverMoveKey(key);
+            }
+            break;
         }
-        return false;
+        return true;
     }
 
     /**
@@ -151,6 +164,7 @@
      * This avoids the complexity of trackers and listeners within the keyboard.
      *
      * @param key The key to press.
+     * @return the event time of the simulated key press.
      */
     private long simulateKeyPress(final Key key) {
         final int x = key.getHitBox().centerX();
@@ -168,6 +182,7 @@
      * This avoids the complexity of trackers and listeners within the keyboard.
      *
      * @param key The key to release.
+     * @param downTime the event time of the key press.
      */
     private void simulateKeyRelease(final Key key, final long downTime) {
         final int x = key.getHitBox().centerX();
@@ -179,54 +194,30 @@
     }
 
     /**
-     * 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.
+     * Handles a hover enter event on a key.
      *
-     * @param currentKey The currently hovered key.
-     * @param previousKey The previously hovered key.
-     * @param event The event that triggered the transition.
-     * @return {@code true} if the event was handled.
+     * @param key The currently hovered key.
      */
-    private boolean onTransitionKey(final Key currentKey, final Key previousKey,
-            final MotionEvent event) {
-        final int savedAction = event.getAction();
-        event.setAction(MotionEvent.ACTION_HOVER_EXIT);
-        onHoverKey(previousKey, event);
-        event.setAction(MotionEvent.ACTION_HOVER_ENTER);
-        onHoverKey(currentKey, event);
-        event.setAction(MotionEvent.ACTION_HOVER_MOVE);
-        final boolean handled = onHoverKey(currentKey, event);
-        event.setAction(savedAction);
-        return handled;
+    protected void onHoverEnterKey(final Key key) {
+        final KeyboardAccessibilityNodeProvider provider = getAccessibilityNodeProvider();
+        provider.sendAccessibilityEventForKey(key, AccessibilityEventCompat.TYPE_VIEW_HOVER_ENTER);
+        provider.performActionForKey(key, AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS);
     }
 
     /**
-     * Handles a hover event on a key. If {@link Key} extended View, this would be analogous to
-     * calling View.onHoverEvent(MotionEvent).
+     * Handles a hover move event on a key.
      *
      * @param key The currently hovered key.
-     * @param event The hover event.
-     * @return {@code true} if the event was handled.
      */
-    private boolean onHoverKey(final Key key, final MotionEvent event) {
-        // Null keys can't receive events.
-        if (key == null) {
-            return false;
-        }
-        final KeyboardAccessibilityNodeProvider provider = getAccessibilityNodeProvider();
+    protected void onHoverMoveKey(final Key key) { }
 
-        switch (event.getAction()) {
-        case MotionEvent.ACTION_HOVER_ENTER:
-            provider.sendAccessibilityEventForKey(
-                    key, AccessibilityEventCompat.TYPE_VIEW_HOVER_ENTER);
-            provider.performActionForKey(
-                    key, AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS);
-            break;
-        case MotionEvent.ACTION_HOVER_EXIT:
-            provider.sendAccessibilityEventForKey(
-                    key, AccessibilityEventCompat.TYPE_VIEW_HOVER_EXIT);
-            break;
-        }
-        return true;
+    /**
+     * Handles a hover exit event on a key.
+     *
+     * @param key The currently hovered key.
+     */
+    protected void onHoverExitKey(final Key key) {
+        final KeyboardAccessibilityNodeProvider provider = getAccessibilityNodeProvider();
+        provider.sendAccessibilityEventForKey(key, AccessibilityEventCompat.TYPE_VIEW_HOVER_EXIT);
     }
 }
diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
index 22c6b6e..f291a7e 100644
--- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
@@ -763,19 +763,14 @@
     }
 
     /**
-     * Receives hover events from the input framework.
-     *
-     * @param event The motion event to be dispatched.
-     * @return {@code true} if the event was handled by the view, {@code false}
-     *         otherwise
+     * {@inheritDoc}
      */
     @Override
-    public boolean dispatchHoverEvent(final MotionEvent event) {
-        if (!AccessibilityUtils.getInstance().isTouchExplorationEnabled()) {
-            // Reflection doesn't support calling superclass methods.
-            return false;
+    public boolean onHoverEvent(final MotionEvent event) {
+        if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) {
+            return mAccessibilityDelegate.onHoverEvent(event);
         }
-        return mAccessibilityDelegate.dispatchHoverEvent(event);
+        return super.onHoverEvent(event);
     }
 
     public void updateShortcutKey(final boolean available) {
diff --git a/java/src/com/android/inputmethod/keyboard/emoji/EmojiPageKeyboardView.java b/java/src/com/android/inputmethod/keyboard/emoji/EmojiPageKeyboardView.java
index 4d74ea9..0166802 100644
--- a/java/src/com/android/inputmethod/keyboard/emoji/EmojiPageKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/emoji/EmojiPageKeyboardView.java
@@ -83,13 +83,15 @@
         mKeyDetector.setKeyboard(keyboard, 0 /* correctionX */, 0 /* correctionY */);
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
-    public boolean dispatchHoverEvent(final MotionEvent event) {
-        if (!AccessibilityUtils.getInstance().isTouchExplorationEnabled()) {
-            // Reflection doesn't support calling superclass methods.
-            return false;
+    public boolean onHoverEvent(final MotionEvent event) {
+        if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) {
+            return mAccessibilityDelegate.onHoverEvent(event);
         }
-        return mAccessibilityDelegate.dispatchHoverEvent(event);
+        return super.onHoverEvent(event);
     }
 
     /**