下面列出了android.support.v4.view.accessibility.AccessibilityNodeInfoCompat#ACTION_ACCESSIBILITY_FOCUS 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/**
* Performs the specified accessibility action for the given key.
*
* @param key The on which to perform the action.
* @param action The action to perform.
* @return The result of performing the action, or false if the action is not supported.
*/
boolean performActionForKey(final Key key, final int action) {
switch (action) {
case AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS:
mAccessibilityFocusedView = getVirtualViewIdOf(key);
sendAccessibilityEventForKey(
key, AccessibilityEventCompat.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
return true;
case AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS:
mAccessibilityFocusedView = UNDEFINED;
sendAccessibilityEventForKey(
key, AccessibilityEventCompat.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
return true;
case AccessibilityNodeInfoCompat.ACTION_CLICK:
sendAccessibilityEventForKey(key, AccessibilityEvent.TYPE_VIEW_CLICKED);
mDelegate.performClickOn(key);
return true;
case AccessibilityNodeInfoCompat.ACTION_LONG_CLICK:
sendAccessibilityEventForKey(key, AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
mDelegate.performLongClickOn(key);
return true;
default:
return false;
}
}
private boolean performActionForChild(int virtualViewId, int action, Bundle arguments) {
switch (action) {
case AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS:
case AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS:
return manageFocusForChild(virtualViewId, action, arguments);
default:
return onPerformActionForVirtualView(virtualViewId, action, arguments);
}
}
private boolean manageFocusForChild(int virtualViewId, int action, Bundle arguments) {
switch (action) {
case AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS:
return requestAccessibilityFocus(virtualViewId);
case AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS:
return clearAccessibilityFocus(virtualViewId);
default:
return false;
}
}
private boolean performActionForChild(int virtualViewId, int action, Bundle arguments) {
switch (action) {
case AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS:
case AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS:
return manageFocusForChild(virtualViewId, action, arguments);
default:
return onPerformActionForVirtualView(virtualViewId, action, arguments);
}
}
private boolean manageFocusForChild(int virtualViewId, int action, Bundle arguments) {
switch (action) {
case AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS:
return requestAccessibilityFocus(virtualViewId);
case AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS:
return clearAccessibilityFocus(virtualViewId);
default:
return false;
}
}
@Override
public boolean performAction(int virtualViewId, int action, Bundle arguments) {
if (virtualViewId == View.NO_ID) {
return ViewCompat.performAccessibilityAction(mParentView, action, arguments);
}
final T item = getItemForId(virtualViewId);
if (item == null) {
return false;
}
boolean handled = false;
switch (action) {
case AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS:
if (mFocusedItemId != virtualViewId) {
mFocusedItemId = virtualViewId;
sendEventForItem(item, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
handled = true;
}
break;
case AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS:
if (mFocusedItemId == virtualViewId) {
mFocusedItemId = INVALID_ID;
sendEventForItem(item, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
handled = true;
}
break;
}
handled |= performActionForItem(item, action, arguments);
return handled;
}
private boolean performActionForChild(int virtualViewId, int action, Bundle arguments) {
switch (action) {
case AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS:
case AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS:
return manageFocusForChild(virtualViewId, action, arguments);
default:
return onPerformActionForVirtualView(virtualViewId, action, arguments);
}
}
private boolean manageFocusForChild(int virtualViewId, int action, Bundle arguments) {
switch (action) {
case AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS:
return requestAccessibilityFocus(virtualViewId);
case AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS:
return clearAccessibilityFocus(virtualViewId);
default:
return false;
}
}
private boolean performActionForChild(int virtualViewId, int action, Bundle arguments) {
switch (action) {
case AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS:
case AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS:
return manageFocusForChild(virtualViewId, action, arguments);
default:
return onPerformActionForVirtualView(virtualViewId, action, arguments);
}
}
private boolean manageFocusForChild(int virtualViewId, int action, Bundle arguments) {
switch (action) {
case AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS:
return requestAccessibilityFocus(virtualViewId);
case AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS:
return clearAccessibilityFocus(virtualViewId);
default:
return false;
}
}
@Override
public boolean performAction(int virtualViewId, int action, Bundle arguments) {
boolean handled = false;
switch (action) {
case AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS:
// Only handle the FOCUS action if it's placing focus on
// a different view that was previously focused.
if (mFocusedVirtualViewId != virtualViewId) {
mFocusedVirtualViewId = virtualViewId;
mHost.invalidate();
sendEventForVirtualViewId(virtualViewId,
AccessibilityEventCompat.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
handled = true;
}
break;
case AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS:
if (mFocusedVirtualViewId == virtualViewId) {
mFocusedVirtualViewId = INVALID_ID;
}
// Since we're managing focus at the parent level, we are
// likely to receive a FOCUS action before a CLEAR_FOCUS
// action. We'll give the benefit of the doubt to the
// framework and always handle FOCUS_CLEARED.
mHost.invalidate();
sendEventForVirtualViewId(virtualViewId,
AccessibilityEventCompat.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
handled = true;
break;
default:
// Let the node provider handle focus for the root node, but
// the root node should handle everything else by itself.
if (virtualViewId == View.NO_ID) {
return ViewCompat.performAccessibilityAction(mHost, action, arguments);
}
}
// Since the client implementation may want to do something special
// when a FOCUS event occurs, let them handle all events.
handled |= performActionForVirtualViewId(virtualViewId, action, arguments);
return handled;
}
/**
* Gets a description of the properties of a node.
*/
public static CharSequence nodeDebugDescription(AccessibilityNodeInfoCompat node) {
StringBuilder sb = new StringBuilder();
sb.append(node.getWindowId());
if (node.getClassName() != null) {
appendSimpleName(sb, node.getClassName());
} else {
sb.append("??");
}
if (!node.isVisibleToUser()) {
sb.append(":invisible");
}
if (node.getText() != null) {
sb.append(":");
sb.append(node.getText().toString().trim());
}
if (node.getContentDescription() != null) {
sb.append(":");
sb.append(node.getContentDescription().toString().trim());
}
int actions = node.getActions();
if (actions != 0) {
sb.append(":");
if ((actions & AccessibilityNodeInfoCompat.ACTION_FOCUS) != 0) {
sb.append("F");
}
if ((actions & AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS) != 0) {
sb.append("A");
}
if ((actions & AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS) != 0) {
sb.append("a");
}
if ((actions & AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD) != 0) {
sb.append("-");
}
if ((actions & AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD) != 0) {
sb.append("+");
}
}
if (node.isCheckable()) {
sb.append(":");
if (node.isChecked()) {
sb.append("(X)");
} else {
sb.append("( )");
}
}
if (node.isFocusable()) {
sb.append(":focusable");
}
if (node.isFocused()) {
sb.append(":focused");
}
if (node.isSelected()) {
sb.append(":selected");
}
if (node.isClickable()) {
sb.append(":clickable");
}
if (node.isLongClickable()) {
sb.append(":longClickable");
}
if (node.isAccessibilityFocused()) {
sb.append(":accessibilityFocused");
}
if (!node.isEnabled()) {
sb.append(":disabled");
}
return sb.toString();
}
@Nullable
public static String getActions(View view) {
AccessibilityNodeInfoCompat node = createNodeInfoFromView(view);
try {
final StringBuilder actionLabels = new StringBuilder();
final String separator = ", ";
for (AccessibilityActionCompat action : node.getActionList()) {
if (actionLabels.length() > 0) {
actionLabels.append(separator);
}
switch (action.getId()) {
case AccessibilityNodeInfoCompat.ACTION_FOCUS:
actionLabels.append("focus");
break;
case AccessibilityNodeInfoCompat.ACTION_CLEAR_FOCUS:
actionLabels.append("clear-focus");
break;
case AccessibilityNodeInfoCompat.ACTION_SELECT:
actionLabels.append("select");
break;
case AccessibilityNodeInfoCompat.ACTION_CLEAR_SELECTION:
actionLabels.append("clear-selection");
break;
case AccessibilityNodeInfoCompat.ACTION_CLICK:
actionLabels.append("click");
break;
case AccessibilityNodeInfoCompat.ACTION_LONG_CLICK:
actionLabels.append("long-click");
break;
case AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS:
actionLabels.append("accessibility-focus");
break;
case AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS:
actionLabels.append("clear-accessibility-focus");
break;
case AccessibilityNodeInfoCompat.ACTION_NEXT_AT_MOVEMENT_GRANULARITY:
actionLabels.append("next-at-movement-granularity");
break;
case AccessibilityNodeInfoCompat.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY:
actionLabels.append("previous-at-movement-granularity");
break;
case AccessibilityNodeInfoCompat.ACTION_NEXT_HTML_ELEMENT:
actionLabels.append("next-html-element");
break;
case AccessibilityNodeInfoCompat.ACTION_PREVIOUS_HTML_ELEMENT:
actionLabels.append("previous-html-element");
break;
case AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD:
actionLabels.append("scroll-forward");
break;
case AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD:
actionLabels.append("scroll-backward");
break;
case AccessibilityNodeInfoCompat.ACTION_CUT:
actionLabels.append("cut");
break;
case AccessibilityNodeInfoCompat.ACTION_COPY:
actionLabels.append("copy");
break;
case AccessibilityNodeInfoCompat.ACTION_PASTE:
actionLabels.append("paste");
break;
case AccessibilityNodeInfoCompat.ACTION_SET_SELECTION:
actionLabels.append("set-selection");
break;
default:
CharSequence label = action.getLabel();
if (label != null) {
actionLabels.append(label);
} else {
actionLabels.append("unknown");
}
break;
}
}
return actionLabels.length() > 0 ? actionLabels.toString() : null;
} finally {
node.recycle();
}
}
/**
* Constructs and returns an {@link AccessibilityNodeInfoCompat} for the
* specified item. Automatically manages accessibility focus actions.
* <p>
* Allows the implementing class to specify most node properties, but
* overrides the following:
* <ul>
* <li>{@link AccessibilityNodeInfoCompat#setPackageName}
* <li>{@link AccessibilityNodeInfoCompat#setClassName}
* <li>{@link AccessibilityNodeInfoCompat#setParent(View)}
* <li>{@link AccessibilityNodeInfoCompat#setSource(View, int)}
* <li>{@link AccessibilityNodeInfoCompat#setVisibleToUser}
* <li>{@link AccessibilityNodeInfoCompat#setBoundsInScreen(Rect)}
* </ul>
* <p>
* Uses the bounds of the parent view and the parent-relative bounding
* rectangle specified by
* {@link AccessibilityNodeInfoCompat#getBoundsInParent} to automatically
* update the following properties:
* <ul>
* <li>{@link AccessibilityNodeInfoCompat#setVisibleToUser}
* <li>{@link AccessibilityNodeInfoCompat#setBoundsInParent}
* </ul>
*
* @param virtualViewId The virtual view id for item for which to construct
* a node.
* @return An {@link AccessibilityNodeInfoCompat} for the specified item.
*/
private AccessibilityNodeInfoCompat createNodeForChild(int virtualViewId) {
final AccessibilityNodeInfoCompat node = AccessibilityNodeInfoCompat.obtain();
// Ensure the client has good defaults.
node.setEnabled(true);
node.setClassName(DEFAULT_CLASS_NAME);
// Allow the client to populate the node.
onPopulateNodeForVirtualView(virtualViewId, node);
// Make sure the developer is following the rules.
if ((node.getText() == null) && (node.getContentDescription() == null)) {
throw new RuntimeException("Callbacks must add text or a content description in "
+ "populateNodeForVirtualViewId()");
}
node.getBoundsInParent(mTempParentRect);
if (mTempParentRect.isEmpty()) {
throw new RuntimeException("Callbacks must set parent bounds in "
+ "populateNodeForVirtualViewId()");
}
final int actions = node.getActions();
if ((actions & AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS) != 0) {
throw new RuntimeException("Callbacks must not add ACTION_ACCESSIBILITY_FOCUS in "
+ "populateNodeForVirtualViewId()");
}
if ((actions & AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS) != 0) {
throw new RuntimeException("Callbacks must not add ACTION_CLEAR_ACCESSIBILITY_FOCUS in "
+ "populateNodeForVirtualViewId()");
}
// Don't allow the client to override these properties.
node.setPackageName(mView.getContext().getPackageName());
node.setSource(mView, virtualViewId);
node.setParent(mView);
// Manage internal accessibility focus state.
if (mFocusedVirtualViewId == virtualViewId) {
node.setAccessibilityFocused(true);
node.addAction(AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
} else {
node.setAccessibilityFocused(false);
node.addAction(AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS);
}
// Set the visibility based on the parent bound.
if (intersectVisibleToUser(mTempParentRect)) {
node.setVisibleToUser(true);
node.setBoundsInParent(mTempParentRect);
}
// Calculate screen-relative bound.
mView.getLocationOnScreen(mTempGlobalRect);
final int offsetX = mTempGlobalRect[0];
final int offsetY = mTempGlobalRect[1];
mTempScreenRect.set(mTempParentRect);
mTempScreenRect.offset(offsetX, offsetY);
node.setBoundsInScreen(mTempScreenRect);
return node;
}
/**
* Constructs and returns an {@link AccessibilityNodeInfoCompat} for the
* specified item. Automatically manages accessibility focus actions.
* <p>
* Allows the implementing class to specify most node properties, but
* overrides the following:
* <ul>
* <li>{@link AccessibilityNodeInfoCompat#setPackageName}
* <li>{@link AccessibilityNodeInfoCompat#setClassName}
* <li>{@link AccessibilityNodeInfoCompat#setParent(View)}
* <li>{@link AccessibilityNodeInfoCompat#setSource(View, int)}
* <li>{@link AccessibilityNodeInfoCompat#setVisibleToUser}
* <li>{@link AccessibilityNodeInfoCompat#setBoundsInScreen(Rect)}
* </ul>
* <p>
* Uses the bounds of the parent view and the parent-relative bounding
* rectangle specified by
* {@link AccessibilityNodeInfoCompat#getBoundsInParent} to automatically
* update the following properties:
* <ul>
* <li>{@link AccessibilityNodeInfoCompat#setVisibleToUser}
* <li>{@link AccessibilityNodeInfoCompat#setBoundsInParent}
* </ul>
*
* @param virtualViewId The virtual view id for item for which to construct
* a node.
* @return An {@link AccessibilityNodeInfoCompat} for the specified item.
*/
private AccessibilityNodeInfoCompat createNodeForChild(int virtualViewId) {
final AccessibilityNodeInfoCompat node = AccessibilityNodeInfoCompat.obtain();
// Ensure the client has good defaults.
node.setEnabled(true);
node.setClassName(DEFAULT_CLASS_NAME);
// Allow the client to populate the node.
onPopulateNodeForVirtualView(virtualViewId, node);
// Make sure the developer is following the rules.
if ((node.getText() == null) && (node.getContentDescription() == null)) {
throw new RuntimeException("Callbacks must add text or a content description in "
+ "populateNodeForVirtualViewId()");
}
node.getBoundsInParent(mTempParentRect);
if (mTempParentRect.isEmpty()) {
throw new RuntimeException("Callbacks must set parent bounds in "
+ "populateNodeForVirtualViewId()");
}
final int actions = node.getActions();
if ((actions & AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS) != 0) {
throw new RuntimeException("Callbacks must not add ACTION_ACCESSIBILITY_FOCUS in "
+ "populateNodeForVirtualViewId()");
}
if ((actions & AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS) != 0) {
throw new RuntimeException("Callbacks must not add ACTION_CLEAR_ACCESSIBILITY_FOCUS in "
+ "populateNodeForVirtualViewId()");
}
// Don't allow the client to override these properties.
node.setPackageName(mView.getContext().getPackageName());
node.setSource(mView, virtualViewId);
node.setParent(mView);
// Manage internal accessibility focus state.
if (mFocusedVirtualViewId == virtualViewId) {
node.setAccessibilityFocused(true);
node.addAction(AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
} else {
node.setAccessibilityFocused(false);
node.addAction(AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS);
}
// Set the visibility based on the parent bound.
if (intersectVisibleToUser(mTempParentRect)) {
node.setVisibleToUser(true);
node.setBoundsInParent(mTempParentRect);
}
// Calculate screen-relative bound.
mView.getLocationOnScreen(mTempGlobalRect);
final int offsetX = mTempGlobalRect[0];
final int offsetY = mTempGlobalRect[1];
mTempScreenRect.set(mTempParentRect);
mTempScreenRect.offset(offsetX, offsetY);
node.setBoundsInScreen(mTempScreenRect);
return node;
}
/**
* Constructs and returns an {@link AccessibilityNodeInfoCompat} for the
* specified item. Automatically manages accessibility focus actions.
* <p>
* Allows the implementing class to specify most node properties, but
* overrides the following:
* <ul>
* <li>{@link AccessibilityNodeInfoCompat#setPackageName}
* <li>{@link AccessibilityNodeInfoCompat#setClassName}
* <li>{@link AccessibilityNodeInfoCompat#setParent(View)}
* <li>{@link AccessibilityNodeInfoCompat#setSource(View, int)}
* <li>{@link AccessibilityNodeInfoCompat#setVisibleToUser}
* <li>{@link AccessibilityNodeInfoCompat#setBoundsInScreen(Rect)}
* </ul>
* <p>
* Uses the bounds of the parent view and the parent-relative bounding
* rectangle specified by
* {@link AccessibilityNodeInfoCompat#getBoundsInParent} to automatically
* update the following properties:
* <ul>
* <li>{@link AccessibilityNodeInfoCompat#setVisibleToUser}
* <li>{@link AccessibilityNodeInfoCompat#setBoundsInParent}
* </ul>
*
* @param virtualViewId The virtual view id for item for which to construct
* a node.
* @return An {@link AccessibilityNodeInfoCompat} for the specified item.
*/
private AccessibilityNodeInfoCompat createNodeForChild(int virtualViewId) {
final AccessibilityNodeInfoCompat node = AccessibilityNodeInfoCompat.obtain();
// Ensure the client has good defaults.
node.setEnabled(true);
node.setClassName(DEFAULT_CLASS_NAME);
// Allow the client to populate the node.
onPopulateNodeForVirtualView(virtualViewId, node);
// Make sure the developer is following the rules.
if ((node.getText() == null) && (node.getContentDescription() == null)) {
throw new RuntimeException("Callbacks must add text or a content description in "
+ "populateNodeForVirtualViewId()");
}
node.getBoundsInParent(mTempParentRect);
if (mTempParentRect.isEmpty()) {
throw new RuntimeException("Callbacks must set parent bounds in "
+ "populateNodeForVirtualViewId()");
}
final int actions = node.getActions();
if ((actions & AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS) != 0) {
throw new RuntimeException("Callbacks must not add ACTION_ACCESSIBILITY_FOCUS in "
+ "populateNodeForVirtualViewId()");
}
if ((actions & AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS) != 0) {
throw new RuntimeException("Callbacks must not add ACTION_CLEAR_ACCESSIBILITY_FOCUS in "
+ "populateNodeForVirtualViewId()");
}
// Don't allow the client to override these properties.
node.setPackageName(mView.getContext().getPackageName());
node.setSource(mView, virtualViewId);
node.setParent(mView);
// Manage internal accessibility focus state.
if (mFocusedVirtualViewId == virtualViewId) {
node.setAccessibilityFocused(true);
node.addAction(AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
} else {
node.setAccessibilityFocused(false);
node.addAction(AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS);
}
// Set the visibility based on the parent bound.
if (intersectVisibleToUser(mTempParentRect)) {
node.setVisibleToUser(true);
node.setBoundsInParent(mTempParentRect);
}
// Calculate screen-relative bound.
mView.getLocationOnScreen(mTempGlobalRect);
final int offsetX = mTempGlobalRect[0];
final int offsetY = mTempGlobalRect[1];
mTempScreenRect.set(mTempParentRect);
mTempScreenRect.offset(offsetX, offsetY);
node.setBoundsInScreen(mTempScreenRect);
return node;
}
/**
* Constructs and returns an {@link AccessibilityNodeInfoCompat} for the
* specified item. Automatically manages accessibility focus actions.
* <p>
* Allows the implementing class to specify most node properties, but
* overrides the following:
* <ul>
* <li>{@link AccessibilityNodeInfoCompat#setPackageName}
* <li>{@link AccessibilityNodeInfoCompat#setClassName}
* <li>{@link AccessibilityNodeInfoCompat#setParent(View)}
* <li>{@link AccessibilityNodeInfoCompat#setSource(View, int)}
* <li>{@link AccessibilityNodeInfoCompat#setVisibleToUser}
* <li>{@link AccessibilityNodeInfoCompat#setBoundsInScreen(Rect)}
* </ul>
* <p>
* Uses the bounds of the parent view and the parent-relative bounding
* rectangle specified by
* {@link AccessibilityNodeInfoCompat#getBoundsInParent} to automatically
* update the following properties:
* <ul>
* <li>{@link AccessibilityNodeInfoCompat#setVisibleToUser}
* <li>{@link AccessibilityNodeInfoCompat#setBoundsInParent}
* </ul>
*
* @param virtualViewId The virtual view id for item for which to construct
* a node.
* @return An {@link AccessibilityNodeInfoCompat} for the specified item.
*/
private AccessibilityNodeInfoCompat createNodeForChild(int virtualViewId) {
final AccessibilityNodeInfoCompat node = AccessibilityNodeInfoCompat.obtain();
// Ensure the client has good defaults.
node.setEnabled(true);
node.setClassName(DEFAULT_CLASS_NAME);
// Allow the client to populate the node.
onPopulateNodeForVirtualView(virtualViewId, node);
// Make sure the developer is following the rules.
if ((node.getText() == null) && (node.getContentDescription() == null)) {
throw new RuntimeException("Callbacks must add text or a content description in "
+ "populateNodeForVirtualViewId()");
}
node.getBoundsInParent(mTempParentRect);
if (mTempParentRect.isEmpty()) {
throw new RuntimeException("Callbacks must set parent bounds in "
+ "populateNodeForVirtualViewId()");
}
final int actions = node.getActions();
if ((actions & AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS) != 0) {
throw new RuntimeException("Callbacks must not add ACTION_ACCESSIBILITY_FOCUS in "
+ "populateNodeForVirtualViewId()");
}
if ((actions & AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS) != 0) {
throw new RuntimeException("Callbacks must not add ACTION_CLEAR_ACCESSIBILITY_FOCUS in "
+ "populateNodeForVirtualViewId()");
}
// Don't allow the client to override these properties.
node.setPackageName(mView.getContext().getPackageName());
node.setSource(mView, virtualViewId);
node.setParent(mView);
// Manage internal accessibility focus state.
if (mFocusedVirtualViewId == virtualViewId) {
node.setAccessibilityFocused(true);
node.addAction(AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
} else {
node.setAccessibilityFocused(false);
node.addAction(AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS);
}
// Set the visibility based on the parent bound.
if (intersectVisibleToUser(mTempParentRect)) {
node.setVisibleToUser(true);
node.setBoundsInParent(mTempParentRect);
}
// Calculate screen-relative bound.
mView.getLocationOnScreen(mTempGlobalRect);
final int offsetX = mTempGlobalRect[0];
final int offsetY = mTempGlobalRect[1];
mTempScreenRect.set(mTempParentRect);
mTempScreenRect.offset(offsetX, offsetY);
node.setBoundsInScreen(mTempScreenRect);
return node;
}