json.put("autofillId", wrap(node.getAutofillId())); json.put("autofillOptions", wrap(node.getAutofillOptions())); json.put("autofillType", wrap(node.getAutofillType())); json.put("autofillValue", wrap(node.getAutofillValue())); json.put("checkable", wrap(node.isCheckable()));
/** * Uses heuristics to infer an autofill hint from a {@code string}. * * @return standard autofill hint, or {@code null} when it could not be inferred. */ @Nullable protected String inferHint(ViewNode node, @Nullable String actualHint) { if (actualHint == null) return null; String hint = actualHint.toLowerCase(); if (hint.contains("label") || hint.contains("container")) { Log.v(TAG, "Ignoring 'label/container' hint: " + hint); return null; } if (hint.contains("password")) return View.AUTOFILL_HINT_PASSWORD; if (hint.contains("username") || (hint.contains("login") && hint.contains("id"))) return View.AUTOFILL_HINT_USERNAME; if (hint.contains("email")) return View.AUTOFILL_HINT_EMAIL_ADDRESS; if (hint.contains("name")) return View.AUTOFILL_HINT_NAME; if (hint.contains("phone")) return View.AUTOFILL_HINT_PHONE; // When everything else fails, return the full string - this is helpful to help app // developers visualize when autofill is triggered when it shouldn't (for example, in a // chat conversation window), so they can mark the root view of such activities with // android:importantForAutofill=noExcludeDescendants if (node.isEnabled() && node.getAutofillType() != View.AUTOFILL_TYPE_NONE) { Log.v(TAG, "Falling back to " + actualHint); return actualHint; } return null; }
builder.append(prefix).append("afType: ").append(getAutofillTypeAsString(node.getAutofillType())) .append("\tafValue:") .append(getAutofillValueAndTypeAsString(node.getAutofillValue()))
builder.append(prefix).append("afType: ").append(getTypeAsString(node.getAutofillType())) .append("\tafValue:") .append(getAutofillValueAndTypeAsString(node.getAutofillValue()))
return; int autofillType = viewNode.getAutofillType(); switch (autofillType) { case View.AUTOFILL_TYPE_LIST:
private void parseViewNode(AssistStructure.ViewNode node) { String[] hints = node.getAutofillHints(); if (hints != null && hints.length > 0) { if (Arrays.stream(hints).anyMatch(View.AUTOFILL_HINT_USERNAME::equals)) result.username.add(node.getAutofillId()); else if (Arrays.stream(hints).anyMatch(View.AUTOFILL_HINT_EMAIL_ADDRESS::equals)) result.email.add(node.getAutofillId()); else if (Arrays.stream(hints).anyMatch(View.AUTOFILL_HINT_PASSWORD::equals)) result.password.add(node.getAutofillId()); else Log.d(TAG, "unsupported hints"); } else if (node.getAutofillType() == View.AUTOFILL_TYPE_TEXT) { int inputType = node.getInputType(); if ((inputType & InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS) > 0) result.email.add(node.getAutofillId()); else if ((inputType & InputType.TYPE_TEXT_VARIATION_PASSWORD) > 0) result.password.add(node.getAutofillId()); else if (result.password.isEmpty()) usernameCandidate = node.getAutofillId(); } for (int i=0; i<node.getChildCount(); ++i) parseViewNode(node.getChildAt(i)); }