Include invisible parent layouts in assistStructure
Currently, a ViewGroup's visibility is not taken into account when being
added to AssistStructure. This results in Autofill Provider mistaking
the visibility of some nodes because it sees that their parents are
visible, when in fact, the parents who are invisible was filtered out of
the assistStructure.
For a particular CUJ, this issue has amplified the problem like the
following.
The activity had two containers for sign in - the invisible one on top
and the visible one on the bottom. When the assistStructure was passed
to AWG, it consisted of both sets of signin edittexts without the parent
containers. AWG, thinking both sets of forms are visible, picked the
first set of form for SaveInfo. When the Framework received the
FillResponse from AWG, it checked whether the views inside the SaveInfo
are visible, and finding that none of them are visible, destroyed the
session. This resulted in autofill being broken and causing weird
behaviors for the app's signin page.
Other alternate solutions that were considered include passing multiple
credentials to SaveInfo and omitting invisible components entirely in AssistStructure. However,
these would either mess up multi-page save logic or is not a
reliable fix (framework does not refresh assiststructure on individual
view visibility change). Including invisible ViewGroups into
AssistStructure can resolve the issue by letting the Autofill providers
filter on children nodes that are inside invisible layouts.
Bug: 291795358
Test: atest android.autofillservice.cts.dropdown.LoginActivityTest, atest CtsAutoFillServiceTestCases
Change-Id: I87372235971a3d07ddf464d0e793929c8fb65441
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 85d7c10..1ef6ab7 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3752,7 +3752,15 @@
&& !child.isActivityDeniedForAutofillForUnimportantView())
|| (shouldIncludeAllChildrenViewWithAutofillTypeNotNone(afm)
&& child.getAutofillType() != AUTOFILL_TYPE_NONE)
- || shouldIncludeAllChildrenViews(afm)){
+ || shouldIncludeAllChildrenViews(afm)
+ || (child instanceof ViewGroup && child.getVisibility() != View.VISIBLE)) {
+ // If the child is a ViewGroup object and its visibility is not visible, include
+ // it as part of the assist structure. The children of these invisible ViewGroup
+ // objects are parsed and included in the assist structure. When the Autofill
+ // Provider determines the visibility of these children, it looks at their
+ // visibility as well as their parent's visibility. Omitting invisible parents
+ // will lead to the Autofill Provider incorrectly assuming that these children
+ // of invisible parents are actually visible.
list.add(child);
} else if (child instanceof ViewGroup) {
((ViewGroup) child).populateChildrenForAutofill(list, flags);