Improving accessibility focus traversal.

1. Now the views considered during the accessibility focus search
   are the ones that would get accessibility focus when thovered
   over. This way the user will get the same items i.e. feedback
   if he touch explores the screen and uses focus traversal. This
   is imperative for a good user experience.

2. Updated which focusables are considered when searching for access
   focus in ViewGroup. Generally accessibility focus ignores focus
   before/after descendants.

3. Implemented focus search strategy in AbsListView that will traverse
   the items of the current list (and the stuff withing one item
   before moving to the next) before continuing the search if
   forward and backward accessibility focus direction.

4. View focus search stops at root namespace. This is not the right
   way to prevent some stuff that is not supposed to get a focus in
   a container for a specific state. Actually the addFocusables
   for that container has to be overriden. Further this approach
   leads to focus getting stuck. The accessibility focus ignores
   root names space since we want to traverse the entire screen.

5. Fixed an bug in AccessibilityInteractionController which was not
   starting to search from the root of a virtual node tree.

6. Fixed a couple of bugs in FocusFinder where it was possible to
   get index out of bounds exception if the focusables list is empty.

bug:5932640

Change-Id: Ic3bdd11767a7d40fbb21f35dcd79a4746af784d4
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 35a6879..42fd63f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -6029,8 +6029,7 @@
             return;
         }
         if ((focusableMode & FOCUSABLES_ACCESSIBILITY) == FOCUSABLES_ACCESSIBILITY) {
-            if (AccessibilityManager.getInstance(mContext).isEnabled()
-                    && includeForAccessibility()) {
+            if (canTakeAccessibilityFocusFromHover()) {
                 views.add(this);
                 return;
             }
@@ -6183,57 +6182,28 @@
         }
     }
 
-    /**
-     * Find the best view to take accessibility focus from a hover.
-     * This function finds the deepest actionable view and if that
-     * fails ask the parent to take accessibility focus from hover.
-     *
-     * @param x The X hovered location in this view coorditantes.
-     * @param y The Y hovered location in this view coorditantes.
-     * @return Whether the request was handled.
-     *
-     * @hide
-     */
-    public boolean requestAccessibilityFocusFromHover(float x, float y) {
-        if (onRequestAccessibilityFocusFromHover(x, y)) {
-            return true;
-        }
-        ViewParent parent = mParent;
-        if (parent instanceof View) {
-            View parentView = (View) parent;
-
-            float[] position = mAttachInfo.mTmpTransformLocation;
-            position[0] = x;
-            position[1] = y;
-
-            // Compensate for the transformation of the current matrix.
-            if (!hasIdentityMatrix()) {
-                getMatrix().mapPoints(position);
+    private void requestAccessibilityFocusFromHover() {
+        if (includeForAccessibility() && isActionableForAccessibility()) {
+            requestAccessibilityFocus();
+        } else {
+            if (mParent != null) {
+                View nextFocus = mParent.findViewToTakeAccessibilityFocusFromHover(this, this);
+                if (nextFocus != null) {
+                    nextFocus.requestAccessibilityFocus();
+                }
             }
-
-            // Compensate for the parent scroll and the offset
-            // of this view stop from the parent top.
-            position[0] += mLeft - parentView.mScrollX;
-            position[1] += mTop - parentView.mScrollY;
-
-            return parentView.requestAccessibilityFocusFromHover(position[0], position[1]);
         }
-        return false;
     }
 
     /**
-     * Requests to give this View focus from hover.
-     *
-     * @param x The X hovered location in this view coorditantes.
-     * @param y The Y hovered location in this view coorditantes.
-     * @return Whether the request was handled.
-     *
      * @hide
      */
-    public boolean onRequestAccessibilityFocusFromHover(float x, float y) {
-        if (includeForAccessibility()
-                && (isActionableForAccessibility() || hasListenersForAccessibility())) {
-            return requestAccessibilityFocus();
+    public boolean canTakeAccessibilityFocusFromHover() {
+        if (includeForAccessibility() && isActionableForAccessibility()) {
+            return true;
+        }
+        if (mParent != null) {
+            return (mParent.findViewToTakeAccessibilityFocusFromHover(this, this) == this);
         }
         return false;
     }
@@ -6495,14 +6465,15 @@
      * important for accessibility are regarded.
      *
      * @return Whether to regard the view for accessibility.
+     *
+     * @hide
      */
-    boolean includeForAccessibility() {
+    public boolean includeForAccessibility() {
         if (mAttachInfo != null) {
             if (!mAttachInfo.mIncludeNotImportantViews) {
                 return isImportantForAccessibility();
-            } else {
-                return true;
             }
+            return true;
         }
         return false;
     }
@@ -6513,8 +6484,10 @@
      * accessiiblity.
      *
      * @return True if the view is actionable for accessibility.
+     *
+     * @hide
      */
-    private boolean isActionableForAccessibility() {
+    public boolean isActionableForAccessibility() {
         return (isClickable() || isLongClickable() || isFocusable());
     }
 
@@ -7687,7 +7660,7 @@
                     && pointInView(event.getX(), event.getY())) {
                 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER);
                 mSendingHoverAccessibilityEvents = true;
-                requestAccessibilityFocusFromHover((int) event.getX(), (int) event.getY());
+                requestAccessibilityFocusFromHover();
             }
         } else {
             if (action == MotionEvent.ACTION_HOVER_EXIT