下面列出了怎么用android.view.ViewStructure的API类实例代码及写法,或者点击链接到github查看源代码。
private void onProvideAutoFillStructureForAssistOrAutofill(ViewStructure structure) {
CharSequence switchText = isChecked() ? mTextOn : mTextOff;
if (!TextUtils.isEmpty(switchText)) {
CharSequence oldText = structure.getText();
if (TextUtils.isEmpty(oldText)) {
structure.setText(switchText);
} else {
StringBuilder newText = new StringBuilder();
newText.append(oldText).append(' ').append(switchText);
structure.setText(newText);
}
// The style of the label text is provided via the base TextView class. This is more
// relevant than the style of the (optional) on/off text on the switch button itself,
// so ignore the size/color/style stored this.mTextPaint.
}
}
@Override
public void dispatchProvideAutofillStructure(@NonNull ViewStructure structure, int flags) {
if (originalHint == null || editText == null) {
super.dispatchProvideAutofillStructure(structure, flags);
return;
}
// Temporarily sets child's hint to its original value so it is properly set in the
// child's ViewStructure.
boolean wasProvidingHint = isProvidingHint;
// Ensures a child TextInputEditText does not retrieve its hint from this TextInputLayout.
isProvidingHint = false;
final CharSequence hint = editText.getHint();
editText.setHint(originalHint);
try {
super.dispatchProvideAutofillStructure(structure, flags);
} finally {
editText.setHint(hint);
isProvidingHint = wasProvidingHint;
}
}
@TargetApi(Build.VERSION_CODES.M)
public void onProvideVirtualStructure(
final ViewStructure structure, final boolean ignoreScrollOffset) {
// Do not collect accessibility tree in incognito mode
if (getWebContents().isIncognito()) {
structure.setChildCount(0);
return;
}
structure.setChildCount(1);
final ViewStructure viewRoot = structure.asyncNewChild(0);
getWebContents().requestAccessibilitySnapshot(new AccessibilitySnapshotCallback() {
@Override
public void onAccessibilitySnapshot(AccessibilitySnapshotNode root) {
viewRoot.setClassName("");
viewRoot.setHint(mProductVersion);
if (root == null) {
viewRoot.asyncCommit();
return;
}
createVirtualStructure(viewRoot, root, ignoreScrollOffset);
}
});
}
@Override
public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) {
// Build a ViewStructure that will get passed to the AutofillService by the framework
// when it is time to find autofill suggestions.
structure.setClassName(getClass().getName());
int childrenSize = mVirtualViews.size();
if (DEBUG) {
Log.d(TAG, "onProvideAutofillVirtualStructure(): flags = " + flags + ", items = "
+ childrenSize + ", extras: " + bundleToString(structure.getExtras()));
}
int index = structure.addChildCount(childrenSize);
// Traverse through the view hierarchy, including virtual child views. For each view, we
// need to set the relevant autofill metadata and add it to the ViewStructure.
for (int i = 0; i < childrenSize; i++) {
Item item = mVirtualViews.valueAt(i);
if (DEBUG) {
Log.d(TAG, "Adding new child at index " + index + ": " + item);
}
ViewStructure child = structure.newChild(index);
child.setAutofillId(structure.getAutofillId(), item.id);
child.setAutofillHints(item.hints);
child.setAutofillType(item.type);
child.setAutofillValue(item.getAutofillValue());
child.setDataIsSensitive(!item.sanitized);
child.setFocused(item.focused);
child.setVisibility(View.VISIBLE);
child.setDimens(item.line.mBounds.left, item.line.mBounds.top, 0, 0,
item.line.mBounds.width(), item.line.mBounds.height());
child.setId(item.id, getContext().getPackageName(), null, item.idEntry);
child.setClassName(item.getClassName());
child.setDimens(item.line.mBounds.left, item.line.mBounds.top, 0, 0,
item.line.mBounds.width(), item.line.mBounds.height());
index++;
}
}
@Override
public ViewStructure asyncNewChild(int index) {
synchronized (mAssist) {
ViewNode node = new ViewNode();
mNode.mChildren[index] = node;
ViewNodeBuilder builder = new ViewNodeBuilder(mAssist, node, true);
mAssist.mPendingAsyncChildren.add(builder);
return builder;
}
}
@Override
public void dispatchProvideAutofillStructure(ViewStructure structure, int flags) {
// This view is self-sufficient for autofill, so it needs to call
// onProvideAutoFillStructure() to fill itself, but it does not need to call
// dispatchProvideAutoFillStructure() to fill its children.
structure.setAutofillId(getAutofillId());
onProvideAutofillStructure(structure, flags);
}
@Override
public void dispatchProvideAutofillStructure(ViewStructure structure, int flags) {
// This view is self-sufficient for autofill, so it needs to call
// onProvideAutoFillStructure() to fill itself, but it does not need to call
// dispatchProvideAutoFillStructure() to fill its children.
structure.setAutofillId(getAutofillId());
onProvideAutofillStructure(structure, flags);
}
/**
* {@inheritDoc}
*
* <p>It also sets the autofill options in the structure; when overridden, it should set it as
* well, either explicitly by calling {@link ViewStructure#setAutofillOptions(CharSequence[])}
* or implicitly by calling {@code super.onProvideAutofillStructure(structure, flags)}.
*/
@Override
public void onProvideAutofillStructure(ViewStructure structure, int flags) {
super.onProvideAutofillStructure(structure, flags);
final Adapter adapter = getAdapter();
if (adapter == null) return;
final CharSequence[] options = adapter.getAutofillOptions();
if (options != null) {
structure.setAutofillOptions(options);
}
}
@Override
public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) {
// Build a ViewStructure that will get passed to the AutofillService by the framework
// when it is time to find autofill suggestions.
structure.setClassName(getClass().getName());
int childrenSize = mVirtualViews.size();
if (DEBUG) {
Log.d(TAG, "onProvideAutofillVirtualStructure(): flags = " + flags + ", items = "
+ childrenSize + ", extras: " + bundleToString(structure.getExtras()));
}
int index = structure.addChildCount(childrenSize);
// Traverse through the view hierarchy, including virtual child views. For each view, we
// need to set the relevant autofill metadata and add it to the ViewStructure.
for (int i = 0; i < childrenSize; i++) {
Item item = mVirtualViews.valueAt(i);
if (DEBUG) {
Log.d(TAG, "Adding new child at index " + index + ": " + item);
}
ViewStructure child = structure.newChild(index);
child.setAutofillId(structure.getAutofillId(), item.id);
child.setAutofillHints(item.hints);
child.setAutofillType(item.type);
child.setAutofillValue(item.getAutofillValue());
child.setDataIsSensitive(!item.sanitized);
child.setFocused(item.focused);
child.setVisibility(View.VISIBLE);
child.setDimens(item.line.mBounds.left, item.line.mBounds.top, 0, 0,
item.line.mBounds.width(), item.line.mBounds.height());
child.setId(item.id, getContext().getPackageName(), null, item.idEntry);
child.setClassName(item.getClassName());
child.setDimens(item.line.mBounds.left, item.line.mBounds.top, 0, 0,
item.line.mBounds.width(), item.line.mBounds.height());
index++;
}
}
@TargetApi(Build.VERSION_CODES.O)
@Override
public void dispatchProvideAutofillStructure(ViewStructure structure, int flags) {
// This view is self-sufficient for autofill, so it needs to call
// onProvideAutoFillStructure() to fill itself, but it does not need to call
// dispatchProvideAutoFillStructure() to fill its children.
structure.setAutofillId(getAutofillId());
onProvideAutofillStructure(structure, flags);
}
@Override
public void onProvideVirtualStructure(ViewStructure structure) {
mProvider.getViewDelegate().onProvideVirtualStructure(structure);
}
@Override
public ViewStructure newChild(int index) {
ViewNode node = new ViewNode();
mNode.mChildren[index] = node;
return new ViewNodeBuilder(mAssist, node, false);
}
@Override
public void onProvideStructure(ViewStructure structure) {
super.onProvideStructure(structure);
onProvideAutoFillStructureForAssistOrAutofill(structure);
}
@Override
public void onProvideAutofillStructure(ViewStructure structure, int flags) {
super.onProvideAutofillStructure(structure, flags);
onProvideAutoFillStructureForAssistOrAutofill(structure);
}
@Override
public void onProvideAutofillStructure(ViewStructure structure, int flags) {
super.onProvideAutofillStructure(structure, flags);
structure.setDataIsSensitive(mCheckedId != mInitialCheckedId);
}
@Override
public void onProvideAutofillStructure(ViewStructure structure, int flags) {
super.onProvideAutofillStructure(structure, flags);
structure.setDataIsSensitive(!mCheckedFromResource);
}
@TargetApi(Build.VERSION_CODES.O)
@Override
public void onProvideAutofillStructure(ViewStructure structure, int flags) {
super.onProvideAutofillStructure(structure, flags);
nestedRadioGroupManager.onProvideAutofillStructure(structure);
}
@TargetApi(Build.VERSION_CODES.O)
@Override
public void onProvideAutofillStructure(ViewStructure structure, int flags) {
super.onProvideAutofillStructure(structure, flags);
nestedRadioGroupManager.onProvideAutofillStructure(structure);
}
@TargetApi(Build.VERSION_CODES.O)
@Override
public void onProvideAutofillStructure(ViewStructure structure, int flags) {
super.onProvideAutofillStructure(structure, flags);
nestedRadioGroupManager.onProvideAutofillStructure(structure);
}
@TargetApi(Build.VERSION_CODES.O)
@Override
public void onProvideAutofillStructure(ViewStructure structure, int flags) {
super.onProvideAutofillStructure(structure, flags);
nestedRadioGroupManager.onProvideAutofillStructure(structure);
}
@TargetApi(Build.VERSION_CODES.O)
public void onProvideAutofillStructure(ViewStructure structure) {
structure.setDataIsSensitive(checkedId != initialCheckedId);
}
@Override
public void onProvideStructure(ViewStructure structure) {
super.onProvideStructure(structure);
}
@Override
public void onProvideAutofillStructure(ViewStructure structure, int flags) {
super.onProvideAutofillStructure(structure, flags);
}
@Override
public ViewStructure newChild(int index) {
final ViewStructureImpl child = new ViewStructureImpl();
children[index] = child;
return child;
}
@Override
public ViewStructure asyncNewChild(int index) {
return newChild(index);
}
@Override
public void onProvideVirtualStructure(final ViewStructure structure) {
mContentViewCore.onProvideVirtualStructure(structure, false);
}
@TargetApi(Build.VERSION_CODES.M)
private void createVirtualStructure(ViewStructure viewNode, AccessibilitySnapshotNode node,
final boolean ignoreScrollOffset) {
viewNode.setClassName(node.className);
if (node.hasSelection) {
viewNode.setText(node.text, node.startSelection, node.endSelection);
} else {
viewNode.setText(node.text);
}
int left = (int) mRenderCoordinates.fromLocalCssToPix(node.x);
int top = (int) mRenderCoordinates.fromLocalCssToPix(node.y);
int width = (int) mRenderCoordinates.fromLocalCssToPix(node.width);
int height = (int) mRenderCoordinates.fromLocalCssToPix(node.height);
Rect boundsInParent = new Rect(left, top, left + width, top + height);
if (node.isRootNode) {
// Offset of the web content relative to the View.
boundsInParent.offset(0, (int) mRenderCoordinates.getContentOffsetYPix());
if (!ignoreScrollOffset) {
boundsInParent.offset(-(int) mRenderCoordinates.getScrollXPix(),
-(int) mRenderCoordinates.getScrollYPix());
}
}
viewNode.setDimens(boundsInParent.left, boundsInParent.top, 0, 0, width, height);
viewNode.setChildCount(node.children.size());
if (node.hasStyle) {
// The text size should be in physical pixels, not CSS pixels.
float textSize = mRenderCoordinates.fromLocalCssToPix(node.textSize);
int style = (node.bold ? ViewNode.TEXT_STYLE_BOLD : 0)
| (node.italic ? ViewNode.TEXT_STYLE_ITALIC : 0)
| (node.underline ? ViewNode.TEXT_STYLE_UNDERLINE : 0)
| (node.lineThrough ? ViewNode.TEXT_STYLE_STRIKE_THRU : 0);
viewNode.setTextStyle(textSize, node.color, node.bgcolor, style);
}
for (int i = 0; i < node.children.size(); i++) {
createVirtualStructure(viewNode.asyncNewChild(i), node.children.get(i), true);
}
viewNode.asyncCommit();
}
/**
* {@inheritDoc}
*
* <p>The {@link ViewStructure} traditionally represents a {@link View}, while for web pages
* it represent HTML nodes. Hence, it's necessary to "map" the HTML properties in a way that is
* understood by the {@link android.service.autofill.AutofillService} implementations:
*
* <ol>
* <li>Only the HTML nodes inside a {@code FORM} are generated.
* <li>The source of the HTML is set using {@link ViewStructure#setWebDomain(String)} in the
* node representing the WebView.
* <li>If a web page has multiple {@code FORM}s, only the data for the current form is
* represented—if the user taps a field from another form, then the current autofill
* context is canceled (by calling {@link android.view.autofill.AutofillManager#cancel()} and
* a new context is created for that {@code FORM}.
* <li>Similarly, if the page has {@code IFRAME} nodes, they are not initially represented in
* the view structure until the user taps a field from a {@code FORM} inside the
* {@code IFRAME}, in which case it would be treated the same way as multiple forms described
* above, except that the {@link ViewStructure#setWebDomain(String) web domain} of the
* {@code FORM} contains the {@code src} attribute from the {@code IFRAME} node.
* <li>The W3C autofill field ({@code autocomplete} tag attribute) maps to
* {@link ViewStructure#setAutofillHints(String[])}.
* <li>If the view is editable, the {@link ViewStructure#setAutofillType(int)} and
* {@link ViewStructure#setAutofillValue(AutofillValue)} must be set.
* <li>The {@code placeholder} attribute maps to {@link ViewStructure#setHint(CharSequence)}.
* <li>Other HTML attributes can be represented through
* {@link ViewStructure#setHtmlInfo(android.view.ViewStructure.HtmlInfo)}.
* </ol>
*
* <p>If the WebView implementation can determine that the value of a field was set statically
* (for example, not through Javascript), it should also call
* {@code structure.setDataIsSensitive(false)}.
*
* <p>For example, an HTML form with 2 fields for username and password:
*
* <pre class="prettyprint">
* <label>Username:</label>
* <input type="text" name="username" id="user" value="Type your username" autocomplete="username" placeholder="Email or username">
* <label>Password:</label>
* <input type="password" name="password" id="pass" autocomplete="current-password" placeholder="Password">
* </pre>
*
* <p>Would map to:
*
* <pre class="prettyprint">
* int index = structure.addChildCount(2);
* ViewStructure username = structure.newChild(index);
* username.setAutofillId(structure.getAutofillId(), 1); // id 1 - first child
* username.setAutofillHints("username");
* username.setHtmlInfo(username.newHtmlInfoBuilder("input")
* .addAttribute("type", "text")
* .addAttribute("name", "username")
* .addAttribute("label", "Username:")
* .build());
* username.setHint("Email or username");
* username.setAutofillType(View.AUTOFILL_TYPE_TEXT);
* username.setAutofillValue(AutofillValue.forText("Type your username"));
* // Value of the field is not sensitive because it was created statically and not changed.
* username.setDataIsSensitive(false);
*
* ViewStructure password = structure.newChild(index + 1);
* username.setAutofillId(structure, 2); // id 2 - second child
* password.setAutofillHints("current-password");
* password.setHtmlInfo(password.newHtmlInfoBuilder("input")
* .addAttribute("type", "password")
* .addAttribute("name", "password")
* .addAttribute("label", "Password:")
* .build());
* password.setHint("Password");
* password.setAutofillType(View.AUTOFILL_TYPE_TEXT);
* </pre>
*/
@Override
public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) {
mProvider.getViewDelegate().onProvideAutofillVirtualStructure(structure, flags);
}
public void setAutofillId(ViewStructure parent, int virtualId) {}