Example usage for android.support.v4.view.accessibility AccessibilityWindowInfoCompat recycle

List of usage examples for android.support.v4.view.accessibility AccessibilityWindowInfoCompat recycle

Introduction

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

Prototype

public void recycle() 

Source Link

Document

Return an instance back to be reused.

Usage

From source file:com.android.talkback.formatter.TouchExplorationFormatter.java

private static int getWindowType(AccessibilityNodeInfoCompat nodeCompat) {
    if (nodeCompat == null) {
        return -1;
    }/*from   www  .j  a  v  a 2s.  co m*/

    AccessibilityWindowInfoCompat windowInfoCompat = nodeCompat.getWindow();
    if (windowInfoCompat == null) {
        return -1;
    }

    int windowType = windowInfoCompat.getType();
    windowInfoCompat.recycle();
    return windowType;
}

From source file:com.android.talkback.eventprocessor.ProcessorScreen.java

/**
 * Uses a heuristic to guess whether an event should be announced.
 * Any event that comes from an IME, or an invisible window is considered
 * an announcement.//from  w w  w . jav  a 2 s.  c o m
 */
private boolean shouldAnnounceEvent(AccessibilityEvent event, int windowId) {
    // Assume window ID of 0 is the keyboard.
    if (windowId == WINDOW_ID_NONE) {
        return true;
    }

    // If there's an actual window ID, we need to check the window type (if window available).
    boolean shouldAnnounceWindow = false;
    AccessibilityRecordCompat record = AccessibilityEventCompat.asRecord(event);
    AccessibilityNodeInfoCompat source = record.getSource();
    if (source != null) {
        AccessibilityWindowInfoCompat window = source.getWindow();
        if (window != null) {
            shouldAnnounceWindow = window.getType() == AccessibilityWindowInfoCompat.TYPE_INPUT_METHOD;
            window.recycle();
        } else {
            // If window is not visible, we cannot know whether the window type is input method
            // or not. Let's announce it for the case. If window is visible but window info is
            // not available, it can be non-focusable visible window. Don't announce it for the
            // case. It can be a toast.
            shouldAnnounceWindow = !source.isVisibleToUser();
        }
        source.recycle();
    }
    return shouldAnnounceWindow;
}

From source file:com.android.talkback.eventprocessor.ProcessorScreen.java

private int getWindowType(AccessibilityEvent event) {
    if (event == null) {
        return WINDOW_TYPE_NONE;
    }/*from  ww w.  ja v  a  2 s .  com*/

    AccessibilityNodeInfo nodeInfo = event.getSource();
    if (nodeInfo == null) {
        return WINDOW_TYPE_NONE;
    }

    AccessibilityNodeInfoCompat nodeInfoCompat = new AccessibilityNodeInfoCompat(nodeInfo);
    AccessibilityWindowInfoCompat windowInfoCompat = nodeInfoCompat.getWindow();
    if (windowInfoCompat == null) {
        nodeInfoCompat.recycle();
        return WINDOW_TYPE_NONE;
    }

    int windowType = windowInfoCompat.getType();
    windowInfoCompat.recycle();
    nodeInfoCompat.recycle();

    return windowType;
}

From source file:com.android.talkback.controller.CursorControllerApp.java

/**
 * Attempts to move in the direction indicated.
 * <p>/*from  ww w .  j  ava 2  s . c om*/
 * If a navigation granularity other than DEFAULT has been applied, attempts
 * to move within the current object at the specified granularity.
 * </p>
 * <p>
 * If no granularity has been applied, or if the DEFAULT granularity has
 * been applied, attempts to move in the specified direction using
 * {@link android.view.View#focusSearch(int)}.
 * </p>
 *
 * @param direction The direction to move.
 * @param shouldWrap Whether navigating past the last item on the screen
 *            should wrap around to the first item on the screen.
 * @param shouldScroll Whether navigating past the last visible item in a
 *            scrollable container should automatically scroll to the next
 *            visible item.
 * @param useInputFocusAsPivotIfEmpty Whether navigation should start from node that has input
 *                                    focused editable node if there is no node with
 *                                    accessibility focus
 * @return true on success, false on failure.
 */
private boolean navigateWithGranularity(@TraversalStrategy.SearchDirection int direction, boolean shouldWrap,
        boolean shouldScroll, boolean useInputFocusAsPivotIfEmpty, int inputMode) {
    @TraversalStrategy.SearchDirection
    int logicalDirection = TraversalStrategyUtils.getLogicalDirection(direction, mService.isScreenLayoutRTL());

    final int navigationAction;
    if (logicalDirection == TraversalStrategy.SEARCH_FOCUS_FORWARD) {
        navigationAction = AccessibilityNodeInfoCompat.ACTION_NEXT_AT_MOVEMENT_GRANULARITY;
    } else if (logicalDirection == TraversalStrategy.SEARCH_FOCUS_BACKWARD) {
        navigationAction = AccessibilityNodeInfoCompat.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY;
    } else {
        throw new IllegalStateException("Unknown logical direction");
    }

    mService.getInputModeManager().setInputMode(inputMode);

    final int scrollDirection = TraversalStrategyUtils.convertSearchDirectionToScrollAction(direction);
    if (scrollDirection == 0) {
        // We won't be able to handle scrollable views very well on older SDK versions,
        // so don't allow d-pad navigation,
        return false;
    }

    AccessibilityNodeInfoCompat current = null;
    AccessibilityNodeInfoCompat target = null;
    TraversalStrategy traversalStrategy = null;
    AccessibilityNodeInfoCompat rootNode = null;
    boolean processResult = false;

    try {
        current = getCurrentCursor(useInputFocusAsPivotIfEmpty);
        if (current == null) {
            processResult = false;
            return processResult;
        }

        if (!mIsWindowNavigationAvailable) {
            // If we're in a background window, we need to return the cursor to the current
            // window and prevent navigation within the background window.
            AccessibilityWindowInfoCompat currentWindow = current.getWindow();
            if (currentWindow != null) {
                if (!currentWindow.isActive()) {
                    AccessibilityNodeInfoCompat activeRoot = AccessibilityServiceCompatUtils
                            .getRootInActiveWindow(mService);
                    if (activeRoot != null) {
                        current.recycle();
                        current = activeRoot;
                    }
                }
                currentWindow.recycle();
            }
        }

        // If granularity is set to anything other than default, restrict
        // navigation to the current node.
        if (mGranularityManager.isLockedTo(current)) {
            final int result = mGranularityManager.navigate(navigationAction);
            if (result == CursorGranularityManager.SUCCESS) {
                mGranularityNavigationReachedEdge = false;
                processResult = true;
                return processResult;
            }

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1
                    && result == CursorGranularityManager.HIT_EDGE && !current.isEditable()) {
                if (!mGranularityNavigationReachedEdge) {
                    // alert when we navigate to the edge with a web granularity.
                    if (mGranularityManager.getCurrentGranularity().isWebGranularity()) {
                        int resId = mGranularityManager.getCurrentGranularity().resourceId;
                        String htmlElement = null;
                        if (resId == CursorGranularity.WEB_CONTROL.resourceId) {
                            htmlElement = HTML_ELEMENT_CONTROL;
                        } else if (resId == CursorGranularity.WEB_LINK.resourceId) {
                            htmlElement = HTML_ELEMENT_LINK;
                        } else if (resId == CursorGranularity.WEB_LIST.resourceId) {
                            htmlElement = HTML_ELEMENT_LIST;
                        } else if (resId == CursorGranularity.WEB_SECTION.resourceId) {
                            htmlElement = HTML_ELEMENT_SECTION;
                        }
                        alertWebNavigationHitEdge(htmlElement,
                                logicalDirection == TraversalStrategy.SEARCH_FOCUS_FORWARD);
                    }
                    // skip one swipe when hit edge during granularity navigation
                    mGranularityNavigationReachedEdge = true;
                    processResult = false;
                    return processResult;
                } else {
                    // We shouldn't navigate past the last "link", "heading", etc. when
                    // navigating with a web granularity.
                    // It makes sense to navigate to the next node with other kinds of
                    // granularities(characters, words, etc.).
                    if (mGranularityManager.getCurrentGranularity().isWebGranularity()) {
                        processResult = false;
                        return processResult;
                    }
                    mSwitchNodeWithGranularityDirection = navigationAction;
                    EventState.getInstance()
                            .addEvent(EventState.EVENT_SKIP_FOCUS_PROCESSING_AFTER_GRANULARITY_MOVE);
                    EventState.getInstance().addEvent(EventState.EVENT_SKIP_HINT_AFTER_GRANULARITY_MOVE);
                }
            } else {
                processResult = false;
                return processResult;
            }
        }

        // If the current node has web content, attempt HTML navigation.
        if (shouldAttemptHtmlNavigation(current, direction)) {
            if (attemptHtmlNavigation(current, direction)) {
                // Succeeded finding destination inside WebView
                processResult = true;
                return true;
            } else {
                // Ascend to WebView, preparing to navigate past WebView with normal navigation
                AccessibilityNodeInfoCompat webView = ascendToWebView(current);
                if (webView != null) {
                    current.recycle();
                    current = webView;
                }
            }
        }

        // If the user has disabled automatic scrolling, don't attempt to scroll.
        // TODO: Remove once auto-scroll is settled.
        if (shouldScroll) {
            final SharedPreferences prefs = SharedPreferencesUtils.getSharedPreferences(mService);
            shouldScroll = SharedPreferencesUtils.getBooleanPref(prefs, mService.getResources(),
                    R.string.pref_auto_scroll_key, R.bool.pref_auto_scroll_default);
        }

        rootNode = AccessibilityNodeInfoUtils.getRoot(current);
        traversalStrategy = TraversalStrategyUtils.getTraversalStrategy(rootNode, direction);

        // If the current item is at the edge of a scrollable view, try to
        // automatically scroll the view in the direction of navigation.
        if (shouldScroll
                && AccessibilityNodeInfoUtils.isAutoScrollEdgeListItem(current, direction, traversalStrategy)
                && attemptScrollAction(current, scrollDirection, true)) {
            processResult = true;
            return processResult;
        }

        // Otherwise, move focus to next or previous focusable node.
        target = navigateFrom(current, direction, traversalStrategy);
        if ((target != null)) {
            // The `spatial` condition provides a work-around for RecyclerViews.
            // Currently RecyclerViews do not support ACTION_SCROLL_LEFT, UP, etc.
            // TODO: Remove `spatial` check when RecyclerViews support new scroll actions.
            final boolean spatial = TraversalStrategyUtils.isSpatialDirection(direction);
            boolean autoScroll = AccessibilityNodeInfoUtils.isAutoScrollEdgeListItem(target, direction,
                    traversalStrategy) || spatial;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && shouldScroll && autoScroll) {
                PerformActionUtils.performAction(target,
                        AccessibilityNodeInfo.AccessibilityAction.ACTION_SHOW_ON_SCREEN.getId());
            }

            if (setCursor(target)) {
                mReachedEdge = false;
                processResult = true;
                return processResult;
            }
        }

        // skip one swipe if in the border of window and no other application window to
        // move focus to
        if (!mReachedEdge && needPauseInTraversalAfterCurrentWindow(direction)) {
            mReachedEdge = true;
            processResult = false;
            return processResult;
        }

        // move focus from application to next application window
        if (navigateToNextOrPreviousWindow(direction,
                WINDOW_TYPE_APPLICATION | WINDOW_TYPE_SPLIT_SCREEN_DIVIDER, FOCUS_STRATEGY_WRAP_AROUND,
                false /* useInputFocusAsPivot */, inputMode)) {
            mReachedEdge = false;
            processResult = true;
            return processResult;
        }

        if (mReachedEdge && shouldWrap) {
            mReachedEdge = false;
            processResult = navigateWrapAround(rootNode, direction, traversalStrategy, inputMode);
            return processResult;
        }

        processResult = false;
        return processResult;
    } finally {
        AccessibilityNodeInfoUtils.recycleNodes(current, target, rootNode);
        if (traversalStrategy != null) {
            traversalStrategy.recycle();
        }

        if (!processResult) {
            mSwitchNodeWithGranularityDirection = 0;
            EventState.getInstance().clearEvent(EventState.EVENT_SKIP_FOCUS_PROCESSING_AFTER_GRANULARITY_MOVE);
            EventState.getInstance().clearEvent(EventState.EVENT_SKIP_HINT_AFTER_GRANULARITY_MOVE);
        }
    }
}