Refresh AccessibilityNodeInfo and wait for the nodes become stable.

Root cause:
The AccessibilityOverlayTest was flaky because:
- We didn’t refresh the accessibility node to be used as the baseline
- The node infos are not stable yet when we compare the expected and the actual

Bug: 296132856
Test: atest CtsAccessibilityServiceTestCases:android.accessibilityservice.cts.AccessibilityOverlayTest#testA11yServiceShowsWindowEmbeddedOverlayWithoutCallback_shouldAppearAndDisappear --iteration 100
Test: atest AccessibilityOverlayTest
Change-Id: I14c0dbf20b974b59035beb2b9f4a2d812ccb8d25
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityOverlayTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityOverlayTest.java
index 92482d9b..1c84ac2 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityOverlayTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityOverlayTest.java
@@ -75,6 +75,7 @@
 import java.util.concurrent.Executors;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 import java.util.function.Function;
 import java.util.function.IntConsumer;
 import java.util.function.Predicate;
@@ -220,6 +221,7 @@
     private void doOverlayWindowTest(Executor executor, ResultCapturingCallback callback)
             throws Exception {
         // Show an activity on screen.
+        final StringBuilder timeoutExceptionRecords = new StringBuilder();
         final Activity activity =
                 launchActivityOnSpecifiedDisplayAndWaitForItToBeOnscreen(
                         sInstrumentation,
@@ -237,6 +239,7 @@
             final SurfaceControl sc = viewHost.getSurfacePackage().getSurfaceControl();
             final SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
             transaction.setVisibility(sc, true).apply();
+            transaction.close();
 
             // Create an accessibility overlay hosting a FrameLayout with the same size
             // as the activity's root node bounds.
@@ -282,38 +285,54 @@
                             mService.attachAccessibilityOverlayToWindow(
                                     activityRootNode.getWindowId(), sc, executor, callback),
                     (event) -> {
+                        // Wait until the overlay window is added
                         final AccessibilityWindowInfo overlayWindow =
                                 ActivityLaunchUtils.findWindowByTitle(sUiAutomation, overlayTitle);
-                        if (overlayWindow == null) {
+                        if (overlayWindow == null || overlayWindow.getType()
+                                != AccessibilityWindowInfo.TYPE_ACCESSIBILITY_OVERLAY) {
                             return false;
                         }
-                        if (overlayWindow.getType()
-                                == AccessibilityWindowInfo.TYPE_ACCESSIBILITY_OVERLAY) {
-                            final AccessibilityNodeInfo overlayButtonNode =
-                                    overlayWindow
-                                            .getRoot()
-                                            .findAccessibilityNodeInfosByText(buttonText)
-                                            .get(0);
-                            final Rect expected = new Rect();
-                            final Rect actual = new Rect();
+                        // Refresh the activity's button node to ensure the AccessibilityNodeInfo
+                        // is the latest
+                        activityNodeToDrawOver.refresh();
 
-                            // The overlay button should have the same window-space and screen-space
-                            // bounds as the view in the activity, as configured above.
-                            activityNodeToDrawOver.getBoundsInWindow(expected);
-                            overlayButtonNode.getBoundsInWindow(actual);
-                            assertThat(actual.isEmpty()).isFalse();
-                            assertThat(actual).isEqualTo(expected);
-                            activityNodeToDrawOver.getBoundsInScreen(expected);
-                            overlayButtonNode.getBoundsInScreen(actual);
-                            assertThat(actual.isEmpty()).isFalse();
-                            assertThat(actual).isEqualTo(expected);
-                            return true;
-                        }
-                        return false;
+                        // Wait until overlay is drawn on correct location
+                        final AccessibilityNodeInfo overlayButtonNode = overlayWindow
+                                .getRoot()
+                                .findAccessibilityNodeInfosByText(buttonText)
+                                .get(0);
+                        final Rect expectedBoundsInWindow = new Rect();
+                        final Rect actualBoundsInWindow = new Rect();
+                        activityNodeToDrawOver.getBoundsInWindow(expectedBoundsInWindow);
+                        overlayButtonNode.getBoundsInWindow(actualBoundsInWindow);
+
+                        final Rect expectedBoundsInScreen = new Rect();
+                        final Rect actualBoundsInScreen = new Rect();
+                        activityNodeToDrawOver.getBoundsInScreen(expectedBoundsInScreen);
+                        overlayButtonNode.getBoundsInScreen(actualBoundsInScreen);
+
+                        // Stores the related information including event, bounds
+                        // as a timeout exception record.
+                        timeoutExceptionRecords.append(String.format("""
+                                        { Received event: %s }
+                                        Expected bounds in window: %s, actual bounds in window: %s
+                                        Expected bounds in screen: %s, actual bounds in screen: %s
+                                        """,
+                                event, expectedBoundsInWindow, actualBoundsInWindow,
+                                expectedBoundsInScreen, actualBoundsInScreen));
+
+                        // The overlay button should have the same window-space and screen-space
+                        // bounds as the view in the activity, as configured above.
+                        return actualBoundsInWindow.equals(expectedBoundsInWindow)
+                                && actualBoundsInScreen.equals(expectedBoundsInScreen);
                     },
                     AsyncUtils.DEFAULT_TIMEOUT_MS);
+
             checkTrustedOverlayExists(overlayTitle);
             removeOverlayAndCheck(sc, overlayTitle);
+        } catch (TimeoutException timeout) {
+            throw new TimeoutException(timeout.getMessage() + "\n\nTimeout exception records : \n"
+                    + timeoutExceptionRecords);
         } finally {
             if (activity != null) {
                 activity.finish();