List of usage examples for android.support.v4.view.accessibility AccessibilityWindowInfoCompat recycle
public void recycle()
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); } } }