package com.android.utils.traversal; import android.os.Build; import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; public class TraversalStrategyUtils { private TraversalStrategyUtils() { // Prevent utility class from being instantiated. } /** * Depending on whether the direction is spatial or logical, returns the appropriate * traversal strategy to handle the case. */ public static TraversalStrategy getTraversalStrategy(AccessibilityNodeInfoCompat root, @TraversalStrategy.SearchDirection int direction) { switch (direction) { case TraversalStrategy.SEARCH_FOCUS_BACKWARD: case TraversalStrategy.SEARCH_FOCUS_FORWARD: return new OrderedTraversalStrategy(root); case TraversalStrategy.SEARCH_FOCUS_LEFT: case TraversalStrategy.SEARCH_FOCUS_RIGHT: case TraversalStrategy.SEARCH_FOCUS_UP: case TraversalStrategy.SEARCH_FOCUS_DOWN: return new DirectionalTraversalStrategy(root); } throw new IllegalArgumentException("direction must be a SearchDirection"); } /** * Determines whether the given search direction corresponds to an actual spatial direction * as opposed to a logical direction. */ public static boolean isSpatialDirection(@TraversalStrategy.SearchDirection int direction) { switch (direction) { case TraversalStrategy.SEARCH_FOCUS_FORWARD: case TraversalStrategy.SEARCH_FOCUS_BACKWARD: return false; case TraversalStrategy.SEARCH_FOCUS_UP: case TraversalStrategy.SEARCH_FOCUS_DOWN: case TraversalStrategy.SEARCH_FOCUS_LEFT: case TraversalStrategy.SEARCH_FOCUS_RIGHT: return true; } throw new IllegalArgumentException("direction must be a SearchDirection"); } /** * Converts a spatial direction to a logical direction based on whether the user is LTR or RTL. * If the direction is already a logical direction, it is returned. */ public static @TraversalStrategy.SearchDirection int getLogicalDirection( @TraversalStrategy.SearchDirection int direction, boolean isRtl) { @TraversalStrategy.SearchDirection int left; @TraversalStrategy.SearchDirection int right; if (isRtl) { left = TraversalStrategy.SEARCH_FOCUS_FORWARD; right = TraversalStrategy.SEARCH_FOCUS_BACKWARD; } else { left = TraversalStrategy.SEARCH_FOCUS_BACKWARD; right = TraversalStrategy.SEARCH_FOCUS_FORWARD; } switch (direction) { case TraversalStrategy.SEARCH_FOCUS_LEFT: return left; case TraversalStrategy.SEARCH_FOCUS_RIGHT: return right; case TraversalStrategy.SEARCH_FOCUS_UP: case TraversalStrategy.SEARCH_FOCUS_BACKWARD: return TraversalStrategy.SEARCH_FOCUS_BACKWARD; case TraversalStrategy.SEARCH_FOCUS_DOWN: case TraversalStrategy.SEARCH_FOCUS_FORWARD: return TraversalStrategy.SEARCH_FOCUS_FORWARD; } throw new IllegalArgumentException("direction must be a SearchDirection"); } /** * Returns the scroll action for the given {@link TraversalStrategy.SearchDirection} if the * scroll action is available on the current SDK version. Otherwise, returns 0. */ public static int convertSearchDirectionToScrollAction( @TraversalStrategy.SearchDirection int direction) { boolean supportsDirectional = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; if (direction == TraversalStrategy.SEARCH_FOCUS_FORWARD) { return AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD; } else if (direction == TraversalStrategy.SEARCH_FOCUS_BACKWARD) { return AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD; } else if (supportsDirectional) { if (direction == TraversalStrategy.SEARCH_FOCUS_LEFT) { return AccessibilityAction.ACTION_SCROLL_LEFT.getId(); } else if (direction == TraversalStrategy.SEARCH_FOCUS_RIGHT) { return AccessibilityAction.ACTION_SCROLL_RIGHT.getId(); } else if (direction == TraversalStrategy.SEARCH_FOCUS_UP) { return AccessibilityAction.ACTION_SCROLL_UP.getId(); } else if (direction == TraversalStrategy.SEARCH_FOCUS_DOWN) { return AccessibilityAction.ACTION_SCROLL_DOWN.getId(); } } return 0; } /** * Returns the {@link TraversalStrategy.SearchDirectionOrUnknown} for the given scroll * action; {@link TraversalStrategy#SEARCH_FOCUS_UNKNOWN} is returned for a scroll action * that can't be handled (e.g. because the current API level doesn't support it). */ public static @TraversalStrategy.SearchDirectionOrUnknown int convertScrollActionToSearchDirection(int scrollAction) { boolean supportsDirectional = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; if (scrollAction == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD) { return TraversalStrategy.SEARCH_FOCUS_FORWARD; } else if (scrollAction == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD) { return TraversalStrategy.SEARCH_FOCUS_BACKWARD; } else if (supportsDirectional) { if (scrollAction == AccessibilityAction.ACTION_SCROLL_LEFT.getId()) { return TraversalStrategy.SEARCH_FOCUS_LEFT; } else if (scrollAction == AccessibilityAction.ACTION_SCROLL_RIGHT.getId()) { return TraversalStrategy.SEARCH_FOCUS_RIGHT; } else if (scrollAction == AccessibilityAction.ACTION_SCROLL_UP.getId()) { return TraversalStrategy.SEARCH_FOCUS_UP; } else if (scrollAction == AccessibilityAction.ACTION_SCROLL_DOWN.getId()) { return TraversalStrategy.SEARCH_FOCUS_DOWN; } } return TraversalStrategy.SEARCH_FOCUS_UNKNOWN; } }