Merge Android 14 QPR2 to AOSP main
Bug: 319669529
Merged-In: I5d00a84ec17b7b0d39efde52fcf610044fbfbb99
Change-Id: I1c09ab77fef36b75ed28166895dd59bfb9256460
diff --git a/src/com/android/car/rotary/Navigator.java b/src/com/android/car/rotary/Navigator.java
index c417958..ccaf357 100644
--- a/src/com/android/car/rotary/Navigator.java
+++ b/src/com/android/car/rotary/Navigator.java
@@ -317,7 +317,7 @@
@NonNull AccessibilityNodeInfo root) {
AccessibilityNodeInfo surfaceView = null;
if (!isClientNode(root)) {
- AccessibilityNodeInfo focusedNode = root.findFocus(FOCUS_INPUT);
+ AccessibilityNodeInfo focusedNode = Utils.findFocusWithRetry(root);
if (focusedNode != null && Utils.isSurfaceView(focusedNode)) {
// The focused node represents a SurfaceView. In this case the root node is actually
// a client node but Navigator doesn't know that because SurfaceViewHelper doesn't
diff --git a/src/com/android/car/rotary/RotaryService.java b/src/com/android/car/rotary/RotaryService.java
index 7b506a1..899f4a3 100644
--- a/src/com/android/car/rotary/RotaryService.java
+++ b/src/com/android/car/rotary/RotaryService.java
@@ -1645,6 +1645,7 @@
// what FocusArea to nudge to. In this case, we'll find a target FocusArea using geometry.
AccessibilityNodeInfo targetFocusArea =
mNavigator.findNudgeTargetFocusArea(windows, mFocusedNode, mFocusArea, direction);
+ L.d("Found targetFocusArea: " + targetFocusArea);
if (targetFocusArea == null) {
L.d("Failed to find nearest FocusArea for nudge");
@@ -1975,6 +1976,7 @@
int direction = clockwise ? View.FOCUS_FORWARD : View.FOCUS_BACKWARD;
Navigator.FindRotateTargetResult result =
mNavigator.findRotateTarget(mFocusedNode, direction, rotationCount);
+ L.d("Found rotation result: " + result);
if (result != null) {
if (performFocusAction(result.node)) {
remainingRotationCount -= result.advancedCount;
@@ -1983,6 +1985,7 @@
} else {
L.w("Failed to find rotate target from " + mFocusedNode);
}
+ L.d("mFocusedNode: " + mFocusedNode);
// If navigation didn't consume all of rotationCount and the focused node either is a
// scrollable container or is a descendant of one, scroll it. The former happens when no
@@ -1992,7 +1995,7 @@
// is only supported in the focused window because injected events always go to the focused
// window. We don't bother checking whether the scrollable container can currently scroll
// because there's nothing else to do if it can't.
- if (remainingRotationCount > 0 && isInFocusedWindow(mFocusedNode)) {
+ if (mFocusedNode != null && remainingRotationCount > 0 && isInFocusedWindow(mFocusedNode)) {
AccessibilityNodeInfo scrollableContainer =
mNavigator.findScrollableContainer(mFocusedNode);
if (scrollableContainer != null) {
diff --git a/src/com/android/car/rotary/Utils.java b/src/com/android/car/rotary/Utils.java
index 27f7028..c78a40e 100644
--- a/src/com/android/car/rotary/Utils.java
+++ b/src/com/android/car/rotary/Utils.java
@@ -77,6 +77,8 @@
@VisibleForTesting
static final String SURFACE_VIEW_CLASS_NAME = SurfaceView.class.getName();
+ private static final int FIND_FOCUS_MAX_TRY_COUNT = 3;
+
private Utils() {
}
@@ -451,4 +453,22 @@
}
return false;
}
+
+ /** Retries several times to find the focused node. See b/301318227. */
+ @Nullable
+ static AccessibilityNodeInfo findFocusWithRetry(@NonNull AccessibilityNodeInfo root) {
+ AccessibilityNodeInfo focusedNode;
+ for (int i = 0; i < FIND_FOCUS_MAX_TRY_COUNT; i++) {
+ focusedNode = root.findFocus(FOCUS_INPUT);
+ L.v("findFocus():" + focusedNode);
+ focusedNode = Utils.refreshNode(focusedNode);
+ if (focusedNode != null && focusedNode.isFocused()) {
+ return focusedNode;
+ }
+ Utils.recycleNode(focusedNode);
+ L.w("Retry findFocus()");
+ }
+ L.e("Failed to find focused node in " + root);
+ return null;
+ }
}
diff --git a/tests/unit/src/com/android/car/rotary/RotaryServiceTest.java b/tests/unit/src/com/android/car/rotary/RotaryServiceTest.java
index 7730eea..b1a26f7 100644
--- a/tests/unit/src/com/android/car/rotary/RotaryServiceTest.java
+++ b/tests/unit/src/com/android/car/rotary/RotaryServiceTest.java
@@ -1102,6 +1102,8 @@
mRotaryService.onKeyEvents(validDisplayId, Collections.singletonList(nudgeUpEventActionUp));
// It should initialize the focus.
+ Button appDefaultFocus = activity.findViewById(R.id.app_default_focus);
+ assertThat(appDefaultFocus.isFocused()).isTrue();
AccessibilityNodeInfo appDefaultFocusNode = createNode("app_default_focus");
assertThat(mRotaryService.getFocusedNode()).isEqualTo(appDefaultFocusNode);
}