Example usage for android.support.v4.view.accessibility AccessibilityNodeInfoCompat setContentDescription

List of usage examples for android.support.v4.view.accessibility AccessibilityNodeInfoCompat setContentDescription

Introduction

In this page you can find the example usage for android.support.v4.view.accessibility AccessibilityNodeInfoCompat setContentDescription.

Prototype

public void setContentDescription(CharSequence contentDescription) 

Source Link

Document

Sets the content description of this node.

Usage

From source file:com.facebook.react.uimanager.AccessibilityDelegateUtil.java

public static void setDelegate(final View view) {
    // if a view already has an accessibility delegate, replacing it could cause problems,
    // so leave it alone.
    if (!ViewCompat.hasAccessibilityDelegate(view)) {
        ViewCompat.setAccessibilityDelegate(view, new AccessibilityDelegateCompat() {
            @Override// www.  ja  v  a  2  s .  c o  m
            public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
                super.onInitializeAccessibilityNodeInfo(host, info);
                String accessibilityHint = (String) view.getTag(R.id.accessibility_hint);
                AccessibilityRole accessibilityRole = (AccessibilityRole) view.getTag(R.id.accessibility_role);
                if (accessibilityRole == null) {
                    accessibilityRole = AccessibilityRole.NONE;
                }
                setRole(info, accessibilityRole, view.getContext());
                if (!(accessibilityHint == null)) {
                    String contentDescription = (String) info.getContentDescription();
                    if (contentDescription != null) {
                        contentDescription = contentDescription + ", " + accessibilityHint;
                        info.setContentDescription(contentDescription);
                    } else {
                        info.setContentDescription(accessibilityHint);
                    }
                }
            }
        });
    }
}

From source file:com.android.launcher3.accessibility.DragAndDropAccessibilityDelegate.java

@Override
protected void onPopulateNodeForVirtualView(int id, AccessibilityNodeInfoCompat node) {
    if (id == INVALID_ID) {
        throw new IllegalArgumentException("Invalid virtual view id");
    }/* w w  w  .j av a  2s. c  o  m*/

    node.setContentDescription(getLocationDescriptionForIconDrop(id));
    node.setBoundsInParent(getItemBounds(id));

    node.addAction(AccessibilityNodeInfoCompat.ACTION_CLICK);
    node.setClickable(true);
    node.setFocusable(true);
}

From source file:org.connectbot.views.CheckableMenuItem.java

public CheckableMenuItem(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);

    mRootView = inflate(context, R.layout.view_checkablemenuitem, this);

    mTitle = (TextView) mRootView.findViewById(R.id.title);
    mSummary = (TextView) mRootView.findViewById(R.id.summary);
    mSwitch = (SwitchCompat) findViewById(R.id.checkbox_switch);

    setFocusable(true);// www . j a va2s .  co m

    mAccessHelper = new ExploreByTouchHelper(this) {
        private final Rect mTmpRect = new Rect();

        @Override
        protected int getVirtualViewAt(float x, float y) {
            return HOST_ID;
        }

        @Override
        protected void getVisibleVirtualViews(List<Integer> virtualViewIds) {
        }

        @Override
        protected void onPopulateEventForVirtualView(int virtualViewId, AccessibilityEvent event) {
            if (virtualViewId != HOST_ID) {
                // TODO(kroot): remove this when the bug is fixed.
                event.setContentDescription(PLACEHOLDER_STRING);
                return;
            }

            event.setContentDescription(mTitle.getText() + " " + mSummary.getText());
            event.setClassName(ACCESSIBILITY_EVENT_CLASS_NAME);
            event.setChecked(isChecked());
        }

        @Override
        protected void onPopulateNodeForVirtualView(int virtualViewId, AccessibilityNodeInfoCompat node) {
            if (virtualViewId != HOST_ID) {
                // TODO(kroot): remove this when the bug is fixed.
                node.setBoundsInParent(mPlaceHolderRect);
                node.setContentDescription(PLACEHOLDER_STRING);
                return;
            }

            mTmpRect.set(0, 0, CheckableMenuItem.this.getWidth(), CheckableMenuItem.this.getHeight());
            node.setBoundsInParent(mTmpRect);

            node.addAction(AccessibilityNodeInfoCompat.ACTION_CLICK);
            node.setClassName(ACCESSIBILITY_EVENT_CLASS_NAME);
            node.setCheckable(true);
            node.setChecked(isChecked());

            node.addChild(mTitle);
            node.addChild(mSummary);
        }

        @Override
        protected boolean onPerformActionForVirtualView(int virtualViewId, int action, Bundle arguments) {
            if (virtualViewId != HOST_ID) {
                return false;
            }

            if (action == AccessibilityNodeInfoCompat.ACTION_CLICK) {
                mSwitch.toggle();
                sendAccessibilityEvent(mRootView, AccessibilityEventCompat.CONTENT_CHANGE_TYPE_UNDEFINED);
                return true;
            }

            return false;
        }
    };
    ViewCompat.setAccessibilityDelegate(mRootView, mAccessHelper);

    setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mSwitch.toggle();
        }
    });

    if (attrs != null) {
        TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.CheckableMenuItem, 0, 0);

        @DrawableRes
        int iconRes = typedArray.getResourceId(R.styleable.CheckableMenuItem_android_icon, 0);
        @StringRes
        int titleRes = typedArray.getResourceId(R.styleable.CheckableMenuItem_android_title, 0);
        @StringRes
        int summaryRes = typedArray.getResourceId(R.styleable.CheckableMenuItem_summary, 0);

        typedArray.recycle();

        ImageView icon = (ImageView) mRootView.findViewById(R.id.icon);
        mTitle.setText(titleRes);
        if (iconRes != 0) {
            Resources resources = context.getResources();
            Resources.Theme theme = context.getTheme();
            Drawable iconDrawable = VectorDrawableCompat.create(resources, iconRes, theme);

            icon.setImageDrawable(iconDrawable);
        }
        if (summaryRes != 0) {
            mSummary.setText(summaryRes);
        }
    }
}

From source file:com.yyl.inputmethod.accessibility.AccessibilityEntityProvider.java

/**
 * Returns an {@link AccessibilityNodeInfoCompat} representing a virtual
 * view, i.e. a descendant of the host View, with the given <code>virtualViewId</code> or
 * the host View itself if <code>virtualViewId</code> equals to {@link View#NO_ID}.
 * <p>//from   w w w.j ava  2s.c  o m
 * A virtual descendant is an imaginary View that is reported as a part of
 * the view hierarchy for accessibility purposes. This enables custom views
 * that draw complex content to report them selves as a tree of virtual
 * views, thus conveying their logical structure.
 * </p>
 * <p>
 * The implementer is responsible for obtaining an accessibility node info
 * from the pool of reusable instances and setting the desired properties of
 * the node info before returning it.
 * </p>
 *
 * @param virtualViewId A client defined virtual view id.
 * @return A populated {@link AccessibilityNodeInfoCompat} for a virtual descendant or the host
 * View.
 * @see AccessibilityNodeInfoCompat
 */
@Override
public AccessibilityNodeInfoCompat createAccessibilityNodeInfo(final int virtualViewId) {
    if (virtualViewId == UNDEFINED) {
        return null;
    }
    if (virtualViewId == View.NO_ID) {
        // We are requested to create an AccessibilityNodeInfo describing
        // this View, i.e. the root of the virtual sub-tree.
        final AccessibilityNodeInfoCompat rootInfo = AccessibilityNodeInfoCompat.obtain(mKeyboardView);
        ViewCompat.onInitializeAccessibilityNodeInfo(mKeyboardView, rootInfo);

        // Add the virtual children of the root View.
        final Keyboard keyboard = mKeyboardView.getKeyboard();
        final Key[] keys = keyboard.mKeys;
        for (Key key : keys) {
            final int childVirtualViewId = generateVirtualViewIdForKey(key);
            rootInfo.addChild(mKeyboardView, childVirtualViewId);
        }
        return rootInfo;
    }

    // Find the view that corresponds to the given id.
    final Key key = mVirtualViewIdToKey.get(virtualViewId);
    if (key == null) {
        Log.e(TAG, "Invalid virtual view ID: " + virtualViewId);
        return null;
    }
    final String keyDescription = getKeyDescription(key);
    final Rect boundsInParent = key.mHitBox;

    // Calculate the key's in-screen bounds.
    mTempBoundsInScreen.set(boundsInParent);
    mTempBoundsInScreen.offset(CoordinateUtils.x(mParentLocation), CoordinateUtils.y(mParentLocation));
    final Rect boundsInScreen = mTempBoundsInScreen;

    // Obtain and initialize an AccessibilityNodeInfo with information about the virtual view.
    final AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
    info.setPackageName(mKeyboardView.getContext().getPackageName());
    info.setClassName(key.getClass().getName());
    info.setContentDescription(keyDescription);
    info.setBoundsInParent(boundsInParent);
    info.setBoundsInScreen(boundsInScreen);
    info.setParent(mKeyboardView);
    info.setSource(mKeyboardView, virtualViewId);
    info.setBoundsInScreen(boundsInScreen);
    info.setEnabled(true);
    info.setVisibleToUser(true);

    if (mAccessibilityFocusedView == virtualViewId) {
        info.addAction(AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
    } else {
        info.addAction(AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS);
    }
    return info;
}

From source file:com.onyx.latinime.accessibility.AccessibilityEntityProvider.java

/**
 * Returns an {@link AccessibilityNodeInfoCompat} representing a virtual
 * view, i.e. a descendant of the host View, with the given <code>virtualViewId</code> or
 * the host View itself if <code>virtualViewId</code> equals to {@link View#NO_ID}.
 * <p>/*from   ww w .j  a  v  a  2 s . c  o  m*/
 * A virtual descendant is an imaginary View that is reported as a part of
 * the view hierarchy for accessibility purposes. This enables custom views
 * that draw complex content to report them selves as a tree of virtual
 * views, thus conveying their logical structure.
 * </p>
 * <p>
 * The implementer is responsible for obtaining an accessibility node info
 * from the pool of reusable instances and setting the desired properties of
 * the node info before returning it.
 * </p>
 *
 * @param virtualViewId A client defined virtual view id.
 * @return A populated {@link AccessibilityNodeInfoCompat} for a virtual descendant or the host
 * View.
 * @see AccessibilityNodeInfoCompat
 */
@Override
public AccessibilityNodeInfoCompat createAccessibilityNodeInfo(final int virtualViewId) {
    if (virtualViewId == UNDEFINED) {
        return null;
    }
    if (virtualViewId == View.NO_ID) {
        // We are requested to create an AccessibilityNodeInfo describing
        // this View, i.e. the root of the virtual sub-tree.
        final AccessibilityNodeInfoCompat rootInfo = AccessibilityNodeInfoCompat.obtain(mKeyboardView);
        ViewCompat.onInitializeAccessibilityNodeInfo(mKeyboardView, rootInfo);

        // Add the virtual children of the root View.
        final Keyboard keyboard = mKeyboardView.getKeyboard();
        final Key[] keys = keyboard.getKeys();
        for (Key key : keys) {
            final int childVirtualViewId = generateVirtualViewIdForKey(key);
            rootInfo.addChild(mKeyboardView, childVirtualViewId);
        }
        return rootInfo;
    }

    // Find the view that corresponds to the given id.
    final Key key = mVirtualViewIdToKey.get(virtualViewId);
    if (key == null) {
        Log.e(TAG, "Invalid virtual view ID: " + virtualViewId);
        return null;
    }
    final String keyDescription = getKeyDescription(key);
    final Rect boundsInParent = key.getHitBox();

    // Calculate the key's in-screen bounds.
    mTempBoundsInScreen.set(boundsInParent);
    mTempBoundsInScreen.offset(CoordinateUtils.x(mParentLocation), CoordinateUtils.y(mParentLocation));
    final Rect boundsInScreen = mTempBoundsInScreen;

    // Obtain and initialize an AccessibilityNodeInfo with information about the virtual view.
    final AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
    info.setPackageName(mKeyboardView.getContext().getPackageName());
    info.setClassName(key.getClass().getName());
    info.setContentDescription(keyDescription);
    info.setBoundsInParent(boundsInParent);
    info.setBoundsInScreen(boundsInScreen);
    info.setParent(mKeyboardView);
    info.setSource(mKeyboardView, virtualViewId);
    info.setBoundsInScreen(boundsInScreen);
    info.setEnabled(true);
    info.setVisibleToUser(true);

    if (mAccessibilityFocusedView == virtualViewId) {
        info.addAction(AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
    } else {
        info.addAction(AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS);
    }
    return info;
}

From source file:com.android.inputmethod.accessibility.KeyboardAccessibilityNodeProvider.java

/**
 * Returns an {@link AccessibilityNodeInfoCompat} representing a virtual
 * view, i.e. a descendant of the host View, with the given <code>virtualViewId</code> or
 * the host View itself if <code>virtualViewId</code> equals to {@link View#NO_ID}.
 * <p>/*from  w w  w.  java  2s . co m*/
 * A virtual descendant is an imaginary View that is reported as a part of
 * the view hierarchy for accessibility purposes. This enables custom views
 * that draw complex content to report them selves as a tree of virtual
 * views, thus conveying their logical structure.
 * </p>
 * <p>
 * The implementer is responsible for obtaining an accessibility node info
 * from the pool of reusable instances and setting the desired properties of
 * the node info before returning it.
 * </p>
 *
 * @param virtualViewId A client defined virtual view id.
 * @return A populated {@link AccessibilityNodeInfoCompat} for a virtual descendant or the host
 * View.
 * @see AccessibilityNodeInfoCompat
 */
@Override
public AccessibilityNodeInfoCompat createAccessibilityNodeInfo(final int virtualViewId) {
    if (virtualViewId == UNDEFINED) {
        return null;
    }
    if (virtualViewId == View.NO_ID) {
        // We are requested to create an AccessibilityNodeInfo describing
        // this View, i.e. the root of the virtual sub-tree.
        final AccessibilityNodeInfoCompat rootInfo = AccessibilityNodeInfoCompat.obtain(mKeyboardView);
        ViewCompat.onInitializeAccessibilityNodeInfo(mKeyboardView, rootInfo);
        updateParentLocation();

        // Add the virtual children of the root View.
        final List<Key> sortedKeys = mKeyboard.getSortedKeys();
        final int size = sortedKeys.size();
        for (int index = 0; index < size; index++) {
            final Key key = sortedKeys.get(index);
            if (key.isSpacer()) {
                continue;
            }
            // Use an index of the sorted keys list as a virtual view id.
            rootInfo.addChild(mKeyboardView, index);
        }
        return rootInfo;
    }

    // Find the key that corresponds to the given virtual view id.
    final Key key = getKeyOf(virtualViewId);
    if (key == null) {
        Log.e(TAG, "Invalid virtual view ID: " + virtualViewId);
        return null;
    }
    final String keyDescription = getKeyDescription(key);
    final Rect boundsInParent = key.getHitBox();

    // Calculate the key's in-screen bounds.
    mTempBoundsInScreen.set(boundsInParent);
    mTempBoundsInScreen.offset(CoordinateUtils.x(mParentLocation), CoordinateUtils.y(mParentLocation));
    final Rect boundsInScreen = mTempBoundsInScreen;

    // Obtain and initialize an AccessibilityNodeInfo with information about the virtual view.
    final AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
    info.setPackageName(mKeyboardView.getContext().getPackageName());
    info.setClassName(key.getClass().getName());
    info.setContentDescription(keyDescription);
    info.setBoundsInParent(boundsInParent);
    info.setBoundsInScreen(boundsInScreen);
    info.setParent(mKeyboardView);
    info.setSource(mKeyboardView, virtualViewId);
    info.setEnabled(key.isEnabled());
    info.setVisibleToUser(true);
    // Don't add ACTION_CLICK and ACTION_LONG_CLOCK actions while hovering on the key.
    // See {@link #onHoverEnterTo(Key)} and {@link #onHoverExitFrom(Key)}.
    if (virtualViewId != mHoveringNodeId) {
        info.addAction(AccessibilityNodeInfoCompat.ACTION_CLICK);
        if (key.isLongPressEnabled()) {
            info.addAction(AccessibilityNodeInfoCompat.ACTION_LONG_CLICK);
        }
    }

    if (mAccessibilityFocusedView == virtualViewId) {
        info.addAction(AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
    } else {
        info.addAction(AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS);
    }
    return info;
}

From source file:com.facebook.litho.ComponentAccessibilityDelegate.java

@Override
protected void onPopulateNodeForVirtualView(int virtualViewId, AccessibilityNodeInfoCompat node) {
    final MountItem mountItem = getAccessibleMountItem(mView);
    if (mountItem == null) {
        Log.e(TAG, "No accessible mount item found for view: " + mView);

        // ExploreByTouchHelper insists that we set something.
        node.setContentDescription("");
        node.setBoundsInParent(getDefaultBounds());
        return;//from   w ww.java  2s  .co m
    }

    final Drawable drawable = (Drawable) mountItem.getContent();
    final Rect bounds = drawable.getBounds();

    final Component<?> component = mountItem.getComponent();
    final ComponentLifecycle lifecycle = component.getLifecycle();

    node.setClassName(lifecycle.getClass().getName());

    if (virtualViewId >= lifecycle.getExtraAccessibilityNodesCount(component)) {
        Log.e(TAG, "Received unrecognized virtual view id: " + virtualViewId);

        // ExploreByTouchHelper insists that we set something.
        node.setContentDescription("");
        node.setBoundsInParent(getDefaultBounds());
        return;
    }

    lifecycle.onPopulateExtraAccessibilityNode(node, virtualViewId, bounds.left, bounds.top, component);
}

From source file:com.android.settings.localepicker.LocaleLinearLayoutManager.java

@Override
public void onInitializeAccessibilityNodeInfoForItem(RecyclerView.Recycler recycler, RecyclerView.State state,
        View host, AccessibilityNodeInfoCompat info) {

    super.onInitializeAccessibilityNodeInfoForItem(recycler, state, host, info);

    final int itemCount = this.getItemCount();
    final int position = this.getPosition(host);
    final LocaleDragCell dragCell = (LocaleDragCell) host;

    // We want the description to be something not localizable, so that any TTS engine for
    // any language can handle it. And we want the position to be part of it.
    // So we use something like "2, French (France)"
    final String description = (position + 1) + ", " + dragCell.getCheckbox().getContentDescription();
    info.setContentDescription(description);

    if (mAdapter.isRemoveMode()) { // We don't move things around in remove mode
        return;/*from w  w w.j a  va2  s.c om*/
    }

    // The order in which we add the actions is important for the circular selection menu.
    // With the current order the "up" action will be (more or less) up, and "down" more
    // or less down ("more or less" because we have 5 actions)
    if (position > 0) { // it is not the first one
        info.addAction(mActionMoveUp);
        info.addAction(mActionMoveTop);
    }
    if (position + 1 < itemCount) { // it is not the last one
        info.addAction(mActionMoveDown);
        info.addAction(mActionMoveBottom);
    }
    if (itemCount > 1) {
        info.addAction(mActionRemove);
    }
}

From source file:com.facebook.litho.widget.TextSpec.java

@OnPopulateExtraAccessibilityNode
static void onPopulateExtraAccessibilityNode(AccessibilityNodeInfoCompat node, int extraNodeIndex,
        int componentBoundsLeft, int componentBoundsTop, @Prop(resType = STRING) CharSequence text,
        @FromBoundsDefined Layout textLayout, @FromBoundsDefined ClickableSpan[] clickableSpans) {
    final Spanned spanned = (Spanned) text;

    final ClickableSpan span = clickableSpans[extraNodeIndex];
    final int start = spanned.getSpanStart(span);
    final int end = spanned.getSpanEnd(span);
    final int startLine = textLayout.getLineForOffset(start);
    final int endLine = textLayout.getLineForOffset(end);

    // The bounds for multi-line strings should *only* include the first line.  This is because
    // Talkback triggers its click at the center point of these bounds, and if that center point
    // is outside the spannable, it will click on something else.  There is no harm in not outlining
    // the wrapped part of the string, as the text for the whole string will be read regardless of
    // the bounding box.
    final int selectionPathEnd = startLine == endLine ? end : textLayout.getLineVisibleEnd(startLine);

    textLayout.getSelectionPath(start, selectionPathEnd, sTempPath);
    sTempPath.computeBounds(sTempRectF, /* unused */true);

    sTempRect.set(componentBoundsLeft + (int) sTempRectF.left, componentBoundsTop + (int) sTempRectF.top,
            componentBoundsLeft + (int) sTempRectF.right, componentBoundsTop + (int) sTempRectF.bottom);

    if (sTempRect.isEmpty()) {
        // Text is not actually visible.
        // Override bounds so it doesn't crash ExploreByTouchHelper.java
        sTempRect.set(0, 0, 1, 1);/* www  .  j  a v  a 2s.  co  m*/
        node.setBoundsInParent(sTempRect);
        node.setContentDescription(""); // make node non-focusable
        return;
    }

    node.setBoundsInParent(sTempRect);

    node.setClickable(true);
    node.setFocusable(true);
    node.setEnabled(true);
    node.setVisibleToUser(true);
    if (span instanceof AccessibleClickableSpan) {
        node.setText(((AccessibleClickableSpan) span).getAccessibilityDescription());
    } else {
        node.setText(spanned.subSequence(start, end));
    }
}

From source file:com.android.inputmethod.accessibility.AccessibilityEntityProvider.java

/**
 * Returns an {@link AccessibilityNodeInfoCompat} representing a virtual
 * view, i.e. a descendant of the host View, with the given <code>virtualViewId</code> or
 * the host View itself if <code>virtualViewId</code> equals to {@link View#NO_ID}.
 * <p>//w w  w .ja v  a2  s . c om
 * A virtual descendant is an imaginary View that is reported as a part of
 * the view hierarchy for accessibility purposes. This enables custom views
 * that draw complex content to report them selves as a tree of virtual
 * views, thus conveying their logical structure.
 * </p>
 * <p>
 * The implementer is responsible for obtaining an accessibility node info
 * from the pool of reusable instances and setting the desired properties of
 * the node info before returning it.
 * </p>
 *
 * @param virtualViewId A client defined virtual view id.
 * @return A populated {@link AccessibilityNodeInfoCompat} for a virtual
 *         descendant or the host View.
 * @see AccessibilityNodeInfoCompat
 */
@Override
public AccessibilityNodeInfoCompat createAccessibilityNodeInfo(int virtualViewId) {
    AccessibilityNodeInfoCompat info = null;

    if (virtualViewId == UNDEFINED) {
        return null;
    } else if (virtualViewId == View.NO_ID) {
        // We are requested to create an AccessibilityNodeInfo describing
        // this View, i.e. the root of the virtual sub-tree.
        info = AccessibilityNodeInfoCompat.obtain(mKeyboardView);
        ViewCompat.onInitializeAccessibilityNodeInfo(mKeyboardView, info);

        // Add the virtual children of the root View.
        final Keyboard keyboard = mKeyboardView.getKeyboard();
        final Key[] keys = keyboard.mKeys;
        for (Key key : keys) {
            final int childVirtualViewId = generateVirtualViewIdForKey(key);
            info.addChild(mKeyboardView, childVirtualViewId);
        }
    } else {
        // Find the view that corresponds to the given id.
        final Key key = mVirtualViewIdToKey.get(virtualViewId);
        if (key == null) {
            Log.e(TAG, "Invalid virtual view ID: " + virtualViewId);
            return null;
        }

        final String keyDescription = getKeyDescription(key);
        final Rect boundsInParent = key.mHitBox;

        // Calculate the key's in-screen bounds.
        mTempBoundsInScreen.set(boundsInParent);
        mTempBoundsInScreen.offset(mParentLocation[0], mParentLocation[1]);

        final Rect boundsInScreen = mTempBoundsInScreen;

        // Obtain and initialize an AccessibilityNodeInfo with
        // information about the virtual view.
        info = AccessibilityNodeInfoCompat.obtain();
        info.setPackageName(mKeyboardView.getContext().getPackageName());
        info.setClassName(key.getClass().getName());
        info.setContentDescription(keyDescription);
        info.setBoundsInParent(boundsInParent);
        info.setBoundsInScreen(boundsInScreen);
        info.setParent(mKeyboardView);
        info.setSource(mKeyboardView, virtualViewId);
        info.setBoundsInScreen(boundsInScreen);
        info.setEnabled(true);
        info.setVisibleToUser(true);

        if (mAccessibilityFocusedView == virtualViewId) {
            info.addAction(AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
        } else {
            info.addAction(AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS);
        }
    }

    return info;
}