Merge "Only generate private symbols that are needed."
diff --git a/core/java/android/accessibilityservice/UiTestAutomationBridge.java b/core/java/android/accessibilityservice/UiTestAutomationBridge.java
index 9d48efc..616b796 100644
--- a/core/java/android/accessibilityservice/UiTestAutomationBridge.java
+++ b/core/java/android/accessibilityservice/UiTestAutomationBridge.java
@@ -63,6 +63,8 @@
 
     private AccessibilityEvent mLastEvent;
 
+    private AccessibilityEvent mLastWindowStateChangeEvent;
+
     private volatile boolean mWaitingForEventDelivery;
 
     private volatile boolean mUnprocessedEventAvailable;
@@ -138,12 +140,22 @@
             public void onAccessibilityEvent(AccessibilityEvent event) {
                 synchronized (mLock) {
                     while (true) {
+                        mLastEvent = AccessibilityEvent.obtain(event);
+
+                        final int eventType = event.getEventType();
+                        if (eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
+                                || eventType == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED) {
+                            if (mLastWindowStateChangeEvent != null) {
+                                mLastWindowStateChangeEvent.recycle();
+                            }
+                            mLastWindowStateChangeEvent = mLastEvent;
+                        }
+
                         if (!mWaitingForEventDelivery) {
                             break;
                         }
                         if (!mUnprocessedEventAvailable) {
                             mUnprocessedEventAvailable = true;
-                            mLastEvent = AccessibilityEvent.obtain(event);
                             mLock.notifyAll();
                             break;
                         }
@@ -409,6 +421,20 @@
                 accessibilityWindowId, accessibilityNodeId, action);
     }
 
+    /**
+     * Gets the root {@link AccessibilityNodeInfo} in the active window.
+     *
+     * @return The root info.
+     */
+    public AccessibilityNodeInfo getRootAccessibilityNodeInfoInActiveWindow() {
+        synchronized (mLock) {
+            if (mLastWindowStateChangeEvent != null) {
+                return mLastWindowStateChangeEvent.getSource();
+            }
+        }
+        return null;
+    }
+
     private void ensureValidConnection(int connectionId) {
         if (connectionId == AccessibilityInteractionClient.NO_ID) {
             throw new IllegalStateException("UiAutomationService not connected."
diff --git a/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java b/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java
index fa48093..2fb4237 100644
--- a/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java
+++ b/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java
@@ -430,4 +430,35 @@
             }
         }
     }
+
+    @LargeTest
+    public void testGetRootAccessibilityNodeInfoInActiveWindow() throws Exception {
+        final long startTimeMillis = SystemClock.uptimeMillis();
+        try {
+            // get the root via the designated API
+            AccessibilityNodeInfo fetched = mUiTestAutomationBridge
+                    .getRootAccessibilityNodeInfoInActiveWindow();
+            assertNotNull(fetched);
+
+            // get the root via traversal
+            AccessibilityNodeInfo expected = mUiTestAutomationBridge
+                    .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.root);
+            while (true) {
+                AccessibilityNodeInfo parent = expected.getParent();
+                if (parent == null) {
+                    break;
+                }
+                expected = parent;
+            }
+            assertNotNull(expected);
+
+            assertEquals("The node with id \"root\" should be the root.", expected, fetched);
+        } finally {
+            if (DEBUG) {
+                final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+                Log.i(LOG_TAG, "testGetRootAccessibilityNodeInfoInActiveWindow: "
+                        + elapsedTimeMillis + "ms");
+            }
+        }
+    }
 }