Merge "UI test automation cannot get the root node and gets null children."
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index 54c62ee..e3f5b96 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -58,9 +58,14 @@
 
     private final AccessibilityNodePrefetcher mPrefetcher;
 
+    private final long mMyLooperThreadId;
+
+    private final int mMyProcessId;
+
     public AccessibilityInteractionController(ViewRootImpl viewRootImpl) {
-        // mView is never null - the caller has already checked.
-        Looper looper = viewRootImpl.mView.mContext.getMainLooper();
+        Looper looper =  viewRootImpl.mHandler.getLooper();
+        mMyLooperThreadId = looper.getThread().getId();
+        mMyProcessId = Process.myPid();
         mHandler = new PrivateHandler(looper);
         mViewRootImpl = viewRootImpl;
         mPrefetcher = new AccessibilityNodePrefetcher();
@@ -137,8 +142,7 @@
         // thread in this process, set the message as a static reference so
         // after this call completes the same thread but in the interrogating
         // client can handle the message to generate the result.
-        if (interrogatingPid == Process.myPid()
-                && interrogatingTid == Looper.getMainLooper().getThread().getId()) {
+        if (interrogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) {
             AccessibilityInteractionClient.getInstanceForThread(
                     interrogatingTid).setSameThreadMessage(message);
         } else {
@@ -169,7 +173,7 @@
             } else {
                 root = findViewByAccessibilityId(accessibilityViewId);
             }
-            if (root != null && isDisplayedOnScreen(root)) {
+            if (root != null && root.isDisplayedOnScreen()) {
                 mPrefetcher.prefetchAccessibilityNodeInfos(root, virtualDescendantId, flags, infos);
             }
         } finally {
@@ -199,8 +203,7 @@
         // thread in this process, set the message as a static reference so
         // after this call completes the same thread but in the interrogating
         // client can handle the message to generate the result.
-        if (interrogatingPid == Process.myPid()
-                && interrogatingTid == Looper.getMainLooper().getThread().getId()) {
+        if (interrogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) {
             AccessibilityInteractionClient.getInstanceForThread(
                     interrogatingTid).setSameThreadMessage(message);
         } else {
@@ -232,7 +235,7 @@
             }
             if (root != null) {
                 View target = root.findViewById(viewId);
-                if (target != null && isDisplayedOnScreen(target)) {
+                if (target != null && target.isDisplayedOnScreen()) {
                     info = target.createAccessibilityNodeInfo();
                 }
             }
@@ -263,8 +266,7 @@
         // thread in this process, set the message as a static reference so
         // after this call completes the same thread but in the interrogating
         // client can handle the message to generate the result.
-        if (interrogatingPid == Process.myPid()
-                && interrogatingTid == Looper.getMainLooper().getThread().getId()) {
+        if (interrogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) {
             AccessibilityInteractionClient.getInstanceForThread(
                     interrogatingTid).setSameThreadMessage(message);
         } else {
@@ -295,7 +297,7 @@
             } else {
                 root = mViewRootImpl.mView;
             }
-            if (root != null && isDisplayedOnScreen(root)) {
+            if (root != null && root.isDisplayedOnScreen()) {
                 AccessibilityNodeProvider provider = root.getAccessibilityNodeProvider();
                 if (provider != null) {
                     infos = provider.findAccessibilityNodeInfosByText(text,
@@ -312,7 +314,7 @@
                         final int viewCount = foundViews.size();
                         for (int i = 0; i < viewCount; i++) {
                             View foundView = foundViews.get(i);
-                            if (isDisplayedOnScreen(foundView)) {
+                            if (foundView.isDisplayedOnScreen()) {
                                 provider = foundView.getAccessibilityNodeProvider();
                                 if (provider != null) {
                                     List<AccessibilityNodeInfo> infosFromProvider =
@@ -356,8 +358,7 @@
         // thread in this process, set the message as a static reference so
         // after this call completes the same thread but in the interrogating
         // client can handle the message to generate the result.
-        if (interogatingPid == Process.myPid()
-                && interrogatingTid == Looper.getMainLooper().getThread().getId()) {
+        if (interogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) {
             AccessibilityInteractionClient.getInstanceForThread(
                     interrogatingTid).setSameThreadMessage(message);
         } else {
@@ -388,7 +389,7 @@
             } else {
                 root = mViewRootImpl.mView;
             }
-            if (root != null && isDisplayedOnScreen(root)) {
+            if (root != null && root.isDisplayedOnScreen()) {
                 switch (focusType) {
                     case AccessibilityNodeInfo.FOCUS_ACCESSIBILITY: {
                         View host = mViewRootImpl.mAccessibilityFocusedHost;
@@ -409,7 +410,7 @@
                     case AccessibilityNodeInfo.FOCUS_INPUT: {
                         // Input focus cannot go to virtual views.
                         View target = root.findFocus();
-                        if (target != null && isDisplayedOnScreen(target)) {
+                        if (target != null && target.isDisplayedOnScreen()) {
                             focused = target.createAccessibilityNodeInfo();
                         }
                     } break;
@@ -444,8 +445,7 @@
         // thread in this process, set the message as a static reference so
         // after this call completes the same thread but in the interrogating
         // client can handle the message to generate the result.
-        if (interogatingPid == Process.myPid()
-                && interrogatingTid == Looper.getMainLooper().getThread().getId()) {
+        if (interogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) {
             AccessibilityInteractionClient.getInstanceForThread(
                     interrogatingTid).setSameThreadMessage(message);
         } else {
@@ -476,7 +476,7 @@
             } else {
                 root = mViewRootImpl.mView;
             }
-            if (root != null && isDisplayedOnScreen(root)) {
+            if (root != null && root.isDisplayedOnScreen()) {
                 if ((direction & View.FOCUS_ACCESSIBILITY) ==  View.FOCUS_ACCESSIBILITY) {
                     AccessibilityNodeProvider provider = root.getAccessibilityNodeProvider();
                     if (provider != null) {
@@ -530,8 +530,7 @@
         // thread in this process, set the message as a static reference so
         // after this call completes the same thread but in the interrogating
         // client can handle the message to generate the result.
-        if (interogatingPid == Process.myPid()
-                && interrogatingTid == Looper.getMainLooper().getThread().getId()) {
+        if (interogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) {
             AccessibilityInteractionClient.getInstanceForThread(
                     interrogatingTid).setSameThreadMessage(message);
         } else {
@@ -562,7 +561,7 @@
             } else {
                 target = mViewRootImpl.mView;
             }
-            if (target != null && isDisplayedOnScreen(target)) {
+            if (target != null && target.isDisplayedOnScreen()) {
                 AccessibilityNodeProvider provider = target.getAccessibilityNodeProvider();
                 if (provider != null) {
                     succeeded = provider.performAccessibilityAction(action, virtualDescendantId);
@@ -586,31 +585,13 @@
             return null;
         }
         View foundView = root.findViewByAccessibilityId(accessibilityId);
-        if (foundView != null && !isDisplayedOnScreen(foundView)) {
+        if (foundView != null && !foundView.isDisplayedOnScreen()) {
             return null;
         }
         return foundView;
     }
 
     /**
-     * Computes whether a view is visible on the screen.
-     *
-     * @param view The view to check.
-     * @return Whether the view is visible on the screen.
-     */
-    private boolean isDisplayedOnScreen(View view) {
-        // The first two checks are made also made by isShown() which
-        // however traverses the tree up to the parent to catch that.
-        // Therefore, we do some fail fast check to minimize the up
-        // tree traversal.
-        return (view.mAttachInfo != null
-                && view.mAttachInfo.mWindowVisibility == View.VISIBLE
-                && view.getAlpha() > 0
-                && view.isShown()
-                && view.getGlobalVisibleRect(mViewRootImpl.mTempRect));
-    }
-
-    /**
      * This class encapsulates a prefetching strategy for the accessibility APIs for
      * querying window content. It is responsible to prefetch a batch of
      * AccessibilityNodeInfos in addition to the one for a requested node.
@@ -684,7 +665,7 @@
                     }
                     View child = children.getChildAt(i);
                     if (child.getAccessibilityViewId() != current.getAccessibilityViewId()
-                            &&  isDisplayedOnScreen(child)) {
+                            &&  child.isDisplayedOnScreen()) {
                         AccessibilityNodeInfo info = null;
                         AccessibilityNodeProvider provider = child.getAccessibilityNodeProvider();
                         if (provider == null) {
@@ -718,7 +699,7 @@
                     return;
                 }
                 View child = children.getChildAt(i);
-                if ( isDisplayedOnScreen(child)) {
+                if (child.isDisplayedOnScreen()) {
                     AccessibilityNodeProvider provider = child.getAccessibilityNodeProvider();
                     if (provider == null) {
                         AccessibilityNodeInfo info = child.createAccessibilityNodeInfo();
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index ab3413e..ce02113 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4680,6 +4680,23 @@
     }
 
     /**
+     * Computes whether this view is visible on the screen.
+     *
+     * @return Whether the view is visible on the screen.
+     */
+    boolean isDisplayedOnScreen() {
+        // The first two checks are made also made by isShown() which
+        // however traverses the tree up to the parent to catch that.
+        // Therefore, we do some fail fast check to minimize the up
+        // tree traversal.
+        return (mAttachInfo != null
+                && mAttachInfo.mWindowVisibility == View.VISIBLE
+                && getAlpha() > 0
+                && isShown()
+                && getGlobalVisibleRect(mAttachInfo.mTmpInvalRect));
+    }
+
+    /**
      * Sets a delegate for implementing accessibility support via compositon as
      * opposed to inheritance. The delegate's primary use is for implementing
      * backwards compatible widgets. For more details see {@link AccessibilityDelegate}.
@@ -6301,9 +6318,9 @@
     boolean includeForAccessibility() {
         if (mAttachInfo != null) {
             if (!mAttachInfo.mIncludeNotImportantViews) {
-                return isImportantForAccessibility();
+                return isImportantForAccessibility() && isDisplayedOnScreen();
             } else {
-                return true;
+                return isDisplayedOnScreen();
             }
         }
         return false;