UI test automation cannot get the root node and gets null children.

1. The AccessibilityInteractionController was using an incorrect
   looper i.e. not the UI thread looper which was causing getting
   the root node to fail.

2. The AccessibilityNodeInfo was populated by a ViewGroup with the
   children for accessibility without checking whether these children
   are really displayed.

bug:6362875

Change-Id: I7906d89571eb9d57d10f971639f88632926dd077
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;