Don't focus on the recyclerview via rotate

Fixes: 160924453
Test: maual test and atest CarRotaryControllerRoboTests
Change-Id: I61ae6ad4158e85972991effc94ed98af92d41257
diff --git a/src/com/android/car/rotary/Navigator.java b/src/com/android/car/rotary/Navigator.java
index 56c5dd7..81a53d0 100644
--- a/src/com/android/car/rotary/Navigator.java
+++ b/src/com/android/car/rotary/Navigator.java
@@ -318,17 +318,18 @@
             @NonNull AccessibilityNodeInfo sourceNode, int direction, int rotationCount) {
         int advancedCount = 0;
         AccessibilityNodeInfo currentFocusArea = getAncestorFocusArea(sourceNode);
-        AccessibilityNodeInfo targetNode = copyNode(sourceNode);
-        for (int i = 0; i < rotationCount; i++) {
-            AccessibilityNodeInfo nextTargetNode = targetNode.focusSearch(direction);
-            AccessibilityNodeInfo targetFocusArea =
-                    nextTargetNode == null ? null : getAncestorFocusArea(nextTargetNode);
+        AccessibilityNodeInfo candidate = copyNode(sourceNode);
+        AccessibilityNodeInfo target = null;
+        while (advancedCount < rotationCount) {
+            AccessibilityNodeInfo nextCandidate = candidate.focusSearch(direction);
+            AccessibilityNodeInfo candidateFocusArea =
+                    nextCandidate == null ? null : getAncestorFocusArea(nextCandidate);
 
-            // Only advance to nextTargetNode if it's in the same focus area and it isn't a
+            // Only advance to nextCandidate if it's in the same focus area and it isn't a
             // FocusParkingView. The second condition prevents wrap-around when there is only one
             // focus area in the window, including when the root node is treated as a focus area.
-            if (nextTargetNode != null && currentFocusArea.equals(targetFocusArea)
-                    && !Utils.isFocusParkingView(nextTargetNode)) {
+            if (nextCandidate != null && currentFocusArea.equals(candidateFocusArea)
+                    && !Utils.isFocusParkingView(nextCandidate)) {
                 // We need to skip nextTargetNode if:
                 // 1. it can't perform focus action (focusSearch() may return a node with zero
                 //    width and height),
@@ -336,21 +337,20 @@
                 //    the container because we want to focus on its element directly. We don't skip
                 //    a scrollable container without descendants that can take focus because we want
                 //    to focus on it, thus we can scroll it when the rotary controller is rotated.
-                if (!Utils.canPerformFocus(nextTargetNode)
-                        || (Utils.isScrollableContainer(nextTargetNode)
-                            && Utils.descendantCanTakeFocus(nextTargetNode))) {
-                    Utils.recycleNode(targetNode);
-                    Utils.recycleNode(targetFocusArea);
-                    targetNode = nextTargetNode;
-                    --i;
+                if (!Utils.canPerformFocus(nextCandidate)
+                        || (Utils.isScrollableContainer(nextCandidate)
+                        && Utils.descendantCanTakeFocus(nextCandidate))) {
+                    Utils.recycleNode(candidate);
+                    Utils.recycleNode(candidateFocusArea);
+                    candidate = nextCandidate;
                     continue;
                 }
                 // If we're navigating through a scrolling view that can scroll in the specified
                 // direction and the next view is off-screen, don't advance to it. (We'll scroll
-                // instead.)
+                // the remaining count instead.)
                 Rect nextTargetBounds = new Rect();
-                nextTargetNode.getBoundsInScreen(nextTargetBounds);
-                AccessibilityNodeInfo scrollableContainer = findScrollableContainer(targetNode);
+                nextCandidate.getBoundsInScreen(nextTargetBounds);
+                AccessibilityNodeInfo scrollableContainer = findScrollableContainer(candidate);
                 AccessibilityNodeInfo.AccessibilityAction scrollAction =
                         direction == View.FOCUS_FORWARD
                                 ? ACTION_SCROLL_FORWARD
@@ -361,29 +361,33 @@
                     scrollableContainer.getBoundsInScreen(scrollBounds);
                     boolean intersects = nextTargetBounds.intersect(scrollBounds);
                     if (!intersects) {
-                        Utils.recycleNode(nextTargetNode);
-                        Utils.recycleNode(targetFocusArea);
+                        Utils.recycleNode(nextCandidate);
+                        Utils.recycleNode(candidateFocusArea);
                         break;
                     }
                 }
                 Utils.recycleNode(scrollableContainer);
 
-                Utils.recycleNode(targetNode);
-                Utils.recycleNode(targetFocusArea);
-                targetNode = nextTargetNode;
+                Utils.recycleNode(candidate);
+                Utils.recycleNode(candidateFocusArea);
+                candidate = nextCandidate;
+                Utils.recycleNode(target);
+                target = copyNode(candidate);
                 advancedCount++;
             } else {
-                Utils.recycleNode(nextTargetNode);
-                Utils.recycleNode(targetFocusArea);
+                Utils.recycleNode(nextCandidate);
+                Utils.recycleNode(candidateFocusArea);
                 break;
             }
         }
-        Utils.recycleNode(currentFocusArea);
-        if (sourceNode.equals(targetNode)) {
-            targetNode.recycle();
+        currentFocusArea.recycle();
+        candidate.recycle();
+        if (sourceNode.equals(target)) {
+            L.e("Wrap-around on the same node");
+            target.recycle();
             return null;
         }
-        return new FindRotateTargetResult(targetNode, advancedCount);
+        return target == null ? null : new FindRotateTargetResult(target, advancedCount);
     }
 
     /**
diff --git a/tests/robotests/src/com/android/car/rotary/NavigatorTest.java b/tests/robotests/src/com/android/car/rotary/NavigatorTest.java
index 650bba7..c89482f 100644
--- a/tests/robotests/src/com/android/car/rotary/NavigatorTest.java
+++ b/tests/robotests/src/com/android/car/rotary/NavigatorTest.java
@@ -270,6 +270,39 @@
     }
 
     /**
+     * Tests {@link Navigator#findRotateTarget} in the following node tree:
+     * <pre>
+     *                     root
+     *                    /    \
+     *                  /       \
+     *    focusParkingView    scrollableContainer
+     *                               /    \
+     *                              /      \
+     *                      focusable1    focusable2
+     * </pre>
+     */
+    @Test
+    public void testFindRotateTargetSkipScrollableContainer2() {
+        AccessibilityNodeInfo root = mNodeBuilder.build();
+        AccessibilityNodeInfo focusParkingView = mNodeBuilder.setParent(root).setFpv().build();
+        AccessibilityNodeInfo scrollableContainer = mNodeBuilder
+                .setParent(root)
+                .setScrollableContainer()
+                .build();
+        AccessibilityNodeInfo focusable1 = mNodeBuilder.setParent(scrollableContainer).build();
+        AccessibilityNodeInfo focusable2 = mNodeBuilder.setParent(scrollableContainer).build();
+
+        int direction = View.FOCUS_BACKWARD;
+        when(focusable2.focusSearch(direction)).thenReturn(focusable1);
+        when(focusable1.focusSearch(direction)).thenReturn(scrollableContainer);
+        when(scrollableContainer.focusSearch(direction)).thenReturn(focusParkingView);
+
+        FindRotateTargetResult target = mNavigator.findRotateTarget(focusable2, direction, 2);
+        assertThat(target.node).isSameAs(focusable1);
+        assertThat(target.advancedCount).isEqualTo(1);
+    }
+
+    /**
      * Tests {@link Navigator#findRotateTarget} in the following layout:
      * <pre>
      *     ============ focus area ============