feat(hierarchy): an element reports whether it masks what is typed into it

ios reads it off SecureTextField, which the companion already sent and
nothing read; web reads input[type=password]. Android cannot: the native
tree mapper drops the password attribute before the sidecar sees it, so
the fact is three-valued and null there rather than a false that would
read as "not secure".
This commit is contained in:
pj committed 2026-08-18 17:16:55 +05:30
1 parent 5f1f50c2fb
commit b1e95739ad
11 files changed
+186 -5

No files matched your search

+19 -1
View File
@@ -72,10 +72,20 @@ type Element struct {
Focused bool `json:"focused,omitempty"`
Selected bool `json:"selected,omitempty"`
Editable bool `json:"editable,omitempty"`
Secure bool `json:"secure,omitempty"`
Bounds Bounds `json:"bounds"`
Attributes map[string]string `json:"attrs,omitempty"`
}
// SecureReported reports whether the producer stated this element's secure
// fact at all. Android never does, so an element without it is unknown rather
// than known not to be a secure entry, and a caller deciding what may be
// written down has to tell those two apart.
func (e *Element) SecureReported() bool {
_, reported := e.Attributes["secure"]
return reported
}
// Node is one node in the hierarchy tree.
type Node struct {
Element
@@ -194,6 +204,7 @@ type treeNodeJSON struct {
Checked flagJSON `json:"checked"`
Selected flagJSON `json:"selected"`
Editable flagJSON `json:"editable"`
Secure flagJSON `json:"secure"`
}
// flagJSON is one boolean field of a node. A value that is not a boolean
@@ -223,7 +234,7 @@ func (f *flagJSON) UnmarshalJSON(data []byte) error {
func (n *treeNodeJSON) unreadableFlags() int {
count := 0
for _, flag := range []flagJSON{n.Clickable, n.Enabled, n.Focused, n.Checked, n.Selected, n.Editable} {
for _, flag := range []flagJSON{n.Clickable, n.Enabled, n.Focused, n.Checked, n.Selected, n.Editable, n.Secure} {
if flag.unreadable {
count++
}
@@ -305,6 +316,7 @@ var selectorKeys = []string{
"placeholderValue",
"resource-id",
"scrollable",
"secure",
"selected",
"tag",
"testID",
@@ -583,6 +595,9 @@ func elementFromNode(node *treeNodeJSON) *Element {
if node.Selected.set {
element.Selected = node.Selected.value
}
if node.Secure.set {
element.Secure = node.Secure.value
}
if node.Editable.set {
element.Editable = node.Editable.value
} else {
@@ -613,6 +628,9 @@ func elementFromNode(node *treeNodeJSON) *Element {
if node.Selected.set {
element.Attributes["selected"] = strconv.FormatBool(node.Selected.value)
}
if node.Secure.set {
element.Attributes["secure"] = strconv.FormatBool(node.Secure.value)
}
element.Attributes["editable"] = strconv.FormatBool(element.Editable)
return element