Tweak hover for better accessibility and compatibility.
Bug: 5087943

Change-Id: I5533c18ec042b8d9cb590d8d3b22ce4a391c910d
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 2213188..b17e9f0 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -5300,12 +5300,6 @@
                     || action == MotionEvent.ACTION_HOVER_MOVE
                     || action == MotionEvent.ACTION_HOVER_EXIT) {
                 if (dispatchHoverEvent(event)) {
-                    // For compatibility with existing applications that handled HOVER_MOVE
-                    // events in onGenericMotionEvent, dispatch the event there.  The
-                    // onHoverEvent method did not exist at the time.
-                    if (action == MotionEvent.ACTION_HOVER_MOVE) {
-                        dispatchGenericMotionEventInternal(event);
-                    }
                     return true;
                 }
             } else if (dispatchGenericPointerEvent(event)) {
@@ -5353,21 +5347,6 @@
      * @return True if the event was handled by the view, false otherwise.
      */
     protected boolean dispatchHoverEvent(MotionEvent event) {
-        switch (event.getAction()) {
-            case MotionEvent.ACTION_HOVER_ENTER:
-                if (!hasHoveredChild() && !mSendingHoverAccessibilityEvents) {
-                    mSendingHoverAccessibilityEvents = true;
-                    sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER);
-                }
-                break;
-            case MotionEvent.ACTION_HOVER_EXIT:
-                if (mSendingHoverAccessibilityEvents) {
-                    mSendingHoverAccessibilityEvents = false;
-                    sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
-                }
-                break;
-        }
-
         //noinspection SimplifiableIfStatement
         if (mOnHoverListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
                 && mOnHoverListener.onHover(this, event)) {
@@ -6008,7 +5987,8 @@
      * </p><p>
      * The default implementation calls {@link #setHovered} to update the hovered state
      * of the view when a hover enter or hover exit event is received, if the view
-     * is enabled and is clickable.
+     * is enabled and is clickable.  The default implementation also sends hover
+     * accessibility events.
      * </p>
      *
      * @param event The motion event that describes the hover.
@@ -6019,6 +5999,21 @@
      * @see #onHoverChanged
      */
     public boolean onHoverEvent(MotionEvent event) {
+        switch (event.getAction()) {
+            case MotionEvent.ACTION_HOVER_ENTER:
+                if (!hasHoveredChild() && !mSendingHoverAccessibilityEvents) {
+                    mSendingHoverAccessibilityEvents = true;
+                    sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER);
+                }
+                break;
+            case MotionEvent.ACTION_HOVER_EXIT:
+                if (mSendingHoverAccessibilityEvents) {
+                    mSendingHoverAccessibilityEvents = false;
+                    sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
+                }
+                break;
+        }
+
         if (isHoverable()) {
             switch (event.getAction()) {
                 case MotionEvent.ACTION_HOVER_ENTER:
@@ -6028,6 +6023,15 @@
                     setHovered(false);
                     break;
             }
+
+            // Dispatch the event to onGenericMotionEvent before returning true.
+            // This is to provide compatibility with existing applications that
+            // handled HOVER_MOVE events in onGenericMotionEvent and that would
+            // break because of the new default handling for hoverable views
+            // in onHoverEvent.
+            // Note that onGenericMotionEvent will be called by default when
+            // onHoverEvent returns false (refer to dispatchGenericMotionEvent).
+            dispatchGenericMotionEventInternal(event);
             return true;
         }
         return false;