Skip to content

Commit bac7ef0

Browse files
sganovAndroid (Google) Code Review
authored andcommitted
Merge "UI test automation cannot get the root node and gets null children."
2 parents 7728c68 + 749e796 commit bac7ef0

File tree

2 files changed

+43
-45
lines changed

2 files changed

+43
-45
lines changed

core/java/android/view/AccessibilityInteractionController.java

Lines changed: 24 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,14 @@ final class AccessibilityInteractionController {
5858

5959
private final AccessibilityNodePrefetcher mPrefetcher;
6060

61+
private final long mMyLooperThreadId;
62+
63+
private final int mMyProcessId;
64+
6165
public AccessibilityInteractionController(ViewRootImpl viewRootImpl) {
62-
// mView is never null - the caller has already checked.
63-
Looper looper = viewRootImpl.mView.mContext.getMainLooper();
66+
Looper looper = viewRootImpl.mHandler.getLooper();
67+
mMyLooperThreadId = looper.getThread().getId();
68+
mMyProcessId = Process.myPid();
6469
mHandler = new PrivateHandler(looper);
6570
mViewRootImpl = viewRootImpl;
6671
mPrefetcher = new AccessibilityNodePrefetcher();
@@ -137,8 +142,7 @@ public void findAccessibilityNodeInfoByAccessibilityIdClientThread(
137142
// thread in this process, set the message as a static reference so
138143
// after this call completes the same thread but in the interrogating
139144
// client can handle the message to generate the result.
140-
if (interrogatingPid == Process.myPid()
141-
&& interrogatingTid == Looper.getMainLooper().getThread().getId()) {
145+
if (interrogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) {
142146
AccessibilityInteractionClient.getInstanceForThread(
143147
interrogatingTid).setSameThreadMessage(message);
144148
} else {
@@ -169,7 +173,7 @@ private void findAccessibilityNodeInfoByAccessibilityIdUiThread(Message message)
169173
} else {
170174
root = findViewByAccessibilityId(accessibilityViewId);
171175
}
172-
if (root != null && isDisplayedOnScreen(root)) {
176+
if (root != null && root.isDisplayedOnScreen()) {
173177
mPrefetcher.prefetchAccessibilityNodeInfos(root, virtualDescendantId, flags, infos);
174178
}
175179
} finally {
@@ -199,8 +203,7 @@ public void findAccessibilityNodeInfoByViewIdClientThread(long accessibilityNode
199203
// thread in this process, set the message as a static reference so
200204
// after this call completes the same thread but in the interrogating
201205
// client can handle the message to generate the result.
202-
if (interrogatingPid == Process.myPid()
203-
&& interrogatingTid == Looper.getMainLooper().getThread().getId()) {
206+
if (interrogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) {
204207
AccessibilityInteractionClient.getInstanceForThread(
205208
interrogatingTid).setSameThreadMessage(message);
206209
} else {
@@ -232,7 +235,7 @@ private void findAccessibilityNodeInfoByViewIdUiThread(Message message) {
232235
}
233236
if (root != null) {
234237
View target = root.findViewById(viewId);
235-
if (target != null && isDisplayedOnScreen(target)) {
238+
if (target != null && target.isDisplayedOnScreen()) {
236239
info = target.createAccessibilityNodeInfo();
237240
}
238241
}
@@ -263,8 +266,7 @@ public void findAccessibilityNodeInfosByTextClientThread(long accessibilityNodeI
263266
// thread in this process, set the message as a static reference so
264267
// after this call completes the same thread but in the interrogating
265268
// client can handle the message to generate the result.
266-
if (interrogatingPid == Process.myPid()
267-
&& interrogatingTid == Looper.getMainLooper().getThread().getId()) {
269+
if (interrogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) {
268270
AccessibilityInteractionClient.getInstanceForThread(
269271
interrogatingTid).setSameThreadMessage(message);
270272
} else {
@@ -295,7 +297,7 @@ private void findAccessibilityNodeInfosByTextUiThread(Message message) {
295297
} else {
296298
root = mViewRootImpl.mView;
297299
}
298-
if (root != null && isDisplayedOnScreen(root)) {
300+
if (root != null && root.isDisplayedOnScreen()) {
299301
AccessibilityNodeProvider provider = root.getAccessibilityNodeProvider();
300302
if (provider != null) {
301303
infos = provider.findAccessibilityNodeInfosByText(text,
@@ -312,7 +314,7 @@ private void findAccessibilityNodeInfosByTextUiThread(Message message) {
312314
final int viewCount = foundViews.size();
313315
for (int i = 0; i < viewCount; i++) {
314316
View foundView = foundViews.get(i);
315-
if (isDisplayedOnScreen(foundView)) {
317+
if (foundView.isDisplayedOnScreen()) {
316318
provider = foundView.getAccessibilityNodeProvider();
317319
if (provider != null) {
318320
List<AccessibilityNodeInfo> infosFromProvider =
@@ -356,8 +358,7 @@ public void findFocusClientThread(long accessibilityNodeId, int interactionId, i
356358
// thread in this process, set the message as a static reference so
357359
// after this call completes the same thread but in the interrogating
358360
// client can handle the message to generate the result.
359-
if (interogatingPid == Process.myPid()
360-
&& interrogatingTid == Looper.getMainLooper().getThread().getId()) {
361+
if (interogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) {
361362
AccessibilityInteractionClient.getInstanceForThread(
362363
interrogatingTid).setSameThreadMessage(message);
363364
} else {
@@ -388,7 +389,7 @@ private void findFocusUiThread(Message message) {
388389
} else {
389390
root = mViewRootImpl.mView;
390391
}
391-
if (root != null && isDisplayedOnScreen(root)) {
392+
if (root != null && root.isDisplayedOnScreen()) {
392393
switch (focusType) {
393394
case AccessibilityNodeInfo.FOCUS_ACCESSIBILITY: {
394395
View host = mViewRootImpl.mAccessibilityFocusedHost;
@@ -409,7 +410,7 @@ private void findFocusUiThread(Message message) {
409410
case AccessibilityNodeInfo.FOCUS_INPUT: {
410411
// Input focus cannot go to virtual views.
411412
View target = root.findFocus();
412-
if (target != null && isDisplayedOnScreen(target)) {
413+
if (target != null && target.isDisplayedOnScreen()) {
413414
focused = target.createAccessibilityNodeInfo();
414415
}
415416
} break;
@@ -444,8 +445,7 @@ public void focusSearchClientThread(long accessibilityNodeId, int interactionId,
444445
// thread in this process, set the message as a static reference so
445446
// after this call completes the same thread but in the interrogating
446447
// client can handle the message to generate the result.
447-
if (interogatingPid == Process.myPid()
448-
&& interrogatingTid == Looper.getMainLooper().getThread().getId()) {
448+
if (interogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) {
449449
AccessibilityInteractionClient.getInstanceForThread(
450450
interrogatingTid).setSameThreadMessage(message);
451451
} else {
@@ -476,7 +476,7 @@ private void focusSearchUiThread(Message message) {
476476
} else {
477477
root = mViewRootImpl.mView;
478478
}
479-
if (root != null && isDisplayedOnScreen(root)) {
479+
if (root != null && root.isDisplayedOnScreen()) {
480480
if ((direction & View.FOCUS_ACCESSIBILITY) == View.FOCUS_ACCESSIBILITY) {
481481
AccessibilityNodeProvider provider = root.getAccessibilityNodeProvider();
482482
if (provider != null) {
@@ -530,8 +530,7 @@ public void performAccessibilityActionClientThread(long accessibilityNodeId, int
530530
// thread in this process, set the message as a static reference so
531531
// after this call completes the same thread but in the interrogating
532532
// client can handle the message to generate the result.
533-
if (interogatingPid == Process.myPid()
534-
&& interrogatingTid == Looper.getMainLooper().getThread().getId()) {
533+
if (interogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) {
535534
AccessibilityInteractionClient.getInstanceForThread(
536535
interrogatingTid).setSameThreadMessage(message);
537536
} else {
@@ -562,7 +561,7 @@ private void perfromAccessibilityActionUiThread(Message message) {
562561
} else {
563562
target = mViewRootImpl.mView;
564563
}
565-
if (target != null && isDisplayedOnScreen(target)) {
564+
if (target != null && target.isDisplayedOnScreen()) {
566565
AccessibilityNodeProvider provider = target.getAccessibilityNodeProvider();
567566
if (provider != null) {
568567
succeeded = provider.performAccessibilityAction(action, virtualDescendantId);
@@ -586,30 +585,12 @@ private View findViewByAccessibilityId(int accessibilityId) {
586585
return null;
587586
}
588587
View foundView = root.findViewByAccessibilityId(accessibilityId);
589-
if (foundView != null && !isDisplayedOnScreen(foundView)) {
588+
if (foundView != null && !foundView.isDisplayedOnScreen()) {
590589
return null;
591590
}
592591
return foundView;
593592
}
594593

595-
/**
596-
* Computes whether a view is visible on the screen.
597-
*
598-
* @param view The view to check.
599-
* @return Whether the view is visible on the screen.
600-
*/
601-
private boolean isDisplayedOnScreen(View view) {
602-
// The first two checks are made also made by isShown() which
603-
// however traverses the tree up to the parent to catch that.
604-
// Therefore, we do some fail fast check to minimize the up
605-
// tree traversal.
606-
return (view.mAttachInfo != null
607-
&& view.mAttachInfo.mWindowVisibility == View.VISIBLE
608-
&& view.getAlpha() > 0
609-
&& view.isShown()
610-
&& view.getGlobalVisibleRect(mViewRootImpl.mTempRect));
611-
}
612-
613594
/**
614595
* This class encapsulates a prefetching strategy for the accessibility APIs for
615596
* querying window content. It is responsible to prefetch a batch of
@@ -684,7 +665,7 @@ private void prefetchSiblingsOfRealNode(View current,
684665
}
685666
View child = children.getChildAt(i);
686667
if (child.getAccessibilityViewId() != current.getAccessibilityViewId()
687-
&& isDisplayedOnScreen(child)) {
668+
&& child.isDisplayedOnScreen()) {
688669
AccessibilityNodeInfo info = null;
689670
AccessibilityNodeProvider provider = child.getAccessibilityNodeProvider();
690671
if (provider == null) {
@@ -718,7 +699,7 @@ private void prefetchDescendantsOfRealNode(View root,
718699
return;
719700
}
720701
View child = children.getChildAt(i);
721-
if ( isDisplayedOnScreen(child)) {
702+
if (child.isDisplayedOnScreen()) {
722703
AccessibilityNodeProvider provider = child.getAccessibilityNodeProvider();
723704
if (provider == null) {
724705
AccessibilityNodeInfo info = child.createAccessibilityNodeInfo();

core/java/android/view/View.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4679,6 +4679,23 @@ void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
46794679
}
46804680
}
46814681

4682+
/**
4683+
* Computes whether this view is visible on the screen.
4684+
*
4685+
* @return Whether the view is visible on the screen.
4686+
*/
4687+
boolean isDisplayedOnScreen() {
4688+
// The first two checks are made also made by isShown() which
4689+
// however traverses the tree up to the parent to catch that.
4690+
// Therefore, we do some fail fast check to minimize the up
4691+
// tree traversal.
4692+
return (mAttachInfo != null
4693+
&& mAttachInfo.mWindowVisibility == View.VISIBLE
4694+
&& getAlpha() > 0
4695+
&& isShown()
4696+
&& getGlobalVisibleRect(mAttachInfo.mTmpInvalRect));
4697+
}
4698+
46824699
/**
46834700
* Sets a delegate for implementing accessibility support via compositon as
46844701
* opposed to inheritance. The delegate's primary use is for implementing
@@ -6301,9 +6318,9 @@ public void addChildrenForAccessibility(ArrayList<View> children) {
63016318
boolean includeForAccessibility() {
63026319
if (mAttachInfo != null) {
63036320
if (!mAttachInfo.mIncludeNotImportantViews) {
6304-
return isImportantForAccessibility();
6321+
return isImportantForAccessibility() && isDisplayedOnScreen();
63056322
} else {
6306-
return true;
6323+
return isDisplayedOnScreen();
63076324
}
63086325
}
63096326
return false;

0 commit comments

Comments
 (0)