Example usage for android.view.accessibility AccessibilityNodeInfo FOCUS_ACCESSIBILITY

List of usage examples for android.view.accessibility AccessibilityNodeInfo FOCUS_ACCESSIBILITY

Introduction

In this page you can find the example usage for android.view.accessibility AccessibilityNodeInfo FOCUS_ACCESSIBILITY.

Prototype

int FOCUS_ACCESSIBILITY

To view the source code for android.view.accessibility AccessibilityNodeInfo FOCUS_ACCESSIBILITY.

Click Source Link

Document

The accessibility focus.

Usage

From source file:com.android.screenspeak.eventprocessor.ProcessorFocusAndSingleTap.java

private void followScrollEvent(AccessibilityNodeInfoCompat source, AccessibilityRecordCompat record,
        int movingDirection, boolean wasScrollAction) {
    AccessibilityNodeInfoCompat root = null;
    AccessibilityNodeInfoCompat accessibilityFocused = null;

    try {//from w  w w  .j a  v a 2 s. c o  m
        // First, see if we've already placed accessibility focus.
        root = AccessibilityServiceCompatUtils.getRootInAccessibilityFocusedWindow(mService);
        if (root == null) {
            return;
        }

        accessibilityFocused = root.findFocus(AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
        boolean validAccessibilityFocus = AccessibilityNodeInfoUtils.shouldFocusNode(accessibilityFocused);
        // there are cases when scrollable container was scrolled and application set
        // focus on node that is on new container page. We should keep this focus
        boolean hasInputFocus = accessibilityFocused != null && accessibilityFocused.isFocused();

        if (validAccessibilityFocus && (hasInputFocus || !wasScrollAction)) {
            // focused on valid node and scrolled not by scroll action
            // keep focus
            return;
        }

        if (validAccessibilityFocus) {
            // focused on valid node and scrolled by scroll action
            // focus on next focusable node
            if (source == null) {
                source = record.getSource();
                if (source == null)
                    return;
            }
            if (!AccessibilityNodeInfoUtils.hasAncestor(accessibilityFocused, source)) {
                return;
            }
            TraversalStrategy traversal = new OrderedTraversalStrategy(root);
            try {
                focusNextFocusedNode(traversal, accessibilityFocused, movingDirection);
            } finally {
                traversal.recycle();
            }
        } else {
            if (mLastFocusedItem == null) {
                // there was no focus - don't set focus
                return;
            }

            if (source == null) {
                source = record.getSource();
                if (source == null)
                    return;
            }
            if (mLastFocusedItem.equals(source)
                    || AccessibilityNodeInfoUtils.hasAncestor(mLastFocusedItem, source)) {

                // There is no focus now, but it was on source node's child before
                // Try focusing the appropriate child node.
                if (tryFocusingChild(source, movingDirection)) {
                    return;
                }

                // Finally, try focusing the scrollable node itself.
                tryFocusing(source);
            }
        }
    } finally {
        AccessibilityNodeInfoUtils.recycleNodes(root, accessibilityFocused);
    }
}

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

private void followScrollEvent(AccessibilityNodeInfoCompat source, AccessibilityRecordCompat record,
        @TraversalStrategy.SearchDirectionOrUnknown int direction, boolean wasScrollAction) {
    // SEARCH_FOCUS_UNKNOWN can be passed, so need to guarantee that direction is a
    // @TraversalStrategy.SearchDirection before continuing.
    if (direction == TraversalStrategy.SEARCH_FOCUS_UNKNOWN) {
        return;/* www  .  j  a va  2  s .  c o m*/
    }

    AccessibilityNodeInfoCompat root = null;
    AccessibilityNodeInfoCompat accessibilityFocused = null;

    try {
        // First, see if we've already placed accessibility focus.
        root = AccessibilityServiceCompatUtils.getRootInAccessibilityFocusedWindow(mService);
        if (root == null) {
            return;
        }

        accessibilityFocused = root.findFocus(AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
        boolean validAccessibilityFocus = AccessibilityNodeInfoUtils.shouldFocusNode(accessibilityFocused);
        // there are cases when scrollable container was scrolled and application set
        // focus on node that is on new container page. We should keep this focus
        boolean hasInputFocus = accessibilityFocused != null && accessibilityFocused.isFocused();

        if (validAccessibilityFocus && (hasInputFocus || !wasScrollAction)) {
            // focused on valid node and scrolled not by scroll action
            // keep focus
            return;
        }

        if (validAccessibilityFocus) {
            // focused on valid node and scrolled by scroll action
            // focus on next focusable node
            if (source == null) {
                source = record.getSource();
                if (source == null)
                    return;
            }
            if (!AccessibilityNodeInfoUtils.hasAncestor(accessibilityFocused, source)) {
                return;
            }
            TraversalStrategy traversal = TraversalStrategyUtils.getTraversalStrategy(root, direction);
            try {
                focusNextFocusedNode(traversal, accessibilityFocused, direction);
            } finally {
                traversal.recycle();
            }
        } else {
            if (mLastFocusedItem == null) {
                // there was no focus - don't set focus
                return;
            }

            if (source == null) {
                source = record.getSource();
                if (source == null)
                    return;
            }
            if (mLastFocusedItem.equals(source)
                    || AccessibilityNodeInfoUtils.hasAncestor(mLastFocusedItem, source)) {

                // There is no focus now, but it was on source node's child before
                // Try focusing the appropriate child node.
                if (tryFocusingChild(source, direction)) {
                    return;
                }

                // Finally, try focusing the scrollable node itself.
                tryFocusing(source);
            }
        }
    } finally {
        AccessibilityNodeInfoUtils.recycleNodes(root, accessibilityFocused);
    }
}

From source file:com.googlecode.eyesfree.brailleback.IMENavigationModeTest.java

/**
 * Tests that text and navigation mode is not triggered when the input view
 * is not shown, even if input is started. This distinction is needed to
 * handle Chrome correctly.// ww  w .  ja va2s .co  m
 */
public void testTextAndNavigationModeRequiresStartInputView() {
    EditorInfo ei = new EditorInfo();

    // Mock out the AccessibilityNodeInfo.
    // The class actually uses the compat variant, but on recent API
    // releases (including the test environment) they should call through.
    AccessibilityNodeInfo rawNode = mock(AccessibilityNodeInfo.class);
    when(mAccessibilityService.getRootInActiveWindow()).thenReturn(rawNode);
    when(rawNode.findFocus(AccessibilityNodeInfo.FOCUS_INPUT)).thenReturn(rawNode);
    when(rawNode.findFocus(AccessibilityNodeInfo.FOCUS_ACCESSIBILITY)).thenReturn(rawNode);
    when(rawNode.getClassName()).thenReturn("com.example.ExampleWebView");
    when(mSelfBrailleManager.hasContentForNode(compatWrapperForNode(rawNode))).thenReturn(true);

    mIMENavMode.onActivate();
    mIMENavMode.onCreateIME();
    verify(mNext).onActivate();
    mIMENavMode.onBindInput();
    mIMENavMode.onStartInput(ei, false /* restarting */);

    assertEquals(mBrailleTranslator, mIMENavMode.getBrailleTranslator());
    assertNull(mIMENavMode.getDisplayManager());
    assertEquals(mFeedbackManager, mIMENavMode.getFeedbackManager());
    verify(mSelfBrailleManager, atLeastOnce()).setImeOpen(false);

    AccessibilityEvent accessibilityEvent = AccessibilityEvent.obtain();
    try {
        mIMENavMode.onObserveAccessibilityEvent(accessibilityEvent);
        verify(mNext).onObserveAccessibilityEvent(accessibilityEvent);
    } finally {
        accessibilityEvent.recycle();
    }

    accessibilityEvent = AccessibilityEvent.obtain();
    try {
        mIMENavMode.onAccessibilityEvent(accessibilityEvent);
        verify(mNext).onAccessibilityEvent(accessibilityEvent);
    } finally {
        accessibilityEvent.recycle();
    }

    AccessibilityNodeInfoCompat node = AccessibilityNodeInfoCompat.obtain();
    try {
        mIMENavMode.onInvalidateAccessibilityNode(node);
        verify(mNext).onInvalidateAccessibilityNode(node);
    } finally {
        node.recycle();
    }

    DisplayManager.Content content = new DisplayManager.Content("");
    mIMENavMode.onPanLeftOverflow(content);
    verify(mNext).onPanLeftOverflow(content);
    mIMENavMode.onPanRightOverflow(content);
    verify(mNext).onPanRightOverflow(content);

    BrailleInputEvent inputEvent = new BrailleInputEvent(BrailleInputEvent.CMD_KEY_ENTER, 0, 0);
    mIMENavMode.onMappedInputEvent(inputEvent, content);
    verify(mNext, never()).onMappedInputEvent(inputEvent, content);
    verify(mIME).sendAndroidKey(KeyEvent.KEYCODE_ENTER);

    inputEvent = new BrailleInputEvent(BrailleInputEvent.CMD_KEY_DEL, 0, 0);
    mIMENavMode.onMappedInputEvent(inputEvent, content);
    verify(mNext, never()).onMappedInputEvent(inputEvent, content);
    verify(mIME).sendAndroidKey(KeyEvent.KEYCODE_DEL);

    inputEvent = new BrailleInputEvent(BrailleInputEvent.CMD_BRAILLE_KEY, 0x1b, 0);
    mIMENavMode.onMappedInputEvent(inputEvent, content);
    verify(mNext, never()).onMappedInputEvent(inputEvent, content);
    verify(mIME).handleBrailleKey(0x1b);

    inputEvent = new BrailleInputEvent(BrailleInputEvent.CMD_NAV_ITEM_NEXT, 0, 0);
    mIMENavMode.onMappedInputEvent(inputEvent, content);
    verify(mNext).onMappedInputEvent(inputEvent, content);
    verify(mIME, never()).moveCursor(anyInt(), anyInt());

    inputEvent = new BrailleInputEvent(BrailleInputEvent.CMD_ACTIVATE_CURRENT, 0, 0);
    mIMENavMode.onMappedInputEvent(inputEvent, content);
    verify(mNext).onMappedInputEvent(inputEvent, content);
    verify(mIME, never()).sendDefaultAction();

    inputEvent = new BrailleInputEvent(BrailleInputEvent.CMD_ROUTE, 0, 0);
    mIMENavMode.onMappedInputEvent(inputEvent, content);
    verify(mNext).onMappedInputEvent(inputEvent, content);
    verify(mIME, never()).route(anyInt(), any(DisplayManager.Content.class));

    mIMENavMode.onFinishInput();
    mIMENavMode.onUnbindInput();
    mIMENavMode.onDestroyIME();

    verify(mSelfBrailleManager, never()).setImeOpen(true);

    // Deactivate, but make sure it didn't happen too early.
    verify(mNext, never()).onDeactivate();
    mIMENavMode.onDeactivate();
    verify(mNext).onDeactivate();
}

From source file:com.google.android.marvin.mytalkback.ProcessorFocusAndSingleTap.java

private boolean followScrollEvent(AccessibilityNodeInfoCompat source, boolean isMovingForward,
        boolean wasScrollAction) {
    AccessibilityNodeInfoCompat root = null;
    AccessibilityNodeInfoCompat focused = null;

    try {/*from   w w  w.  j ava 2 s. c  om*/
        // First, see if we've already placed accessibility focus.
        root = AccessibilityServiceCompatUtils.getRootInActiveWindow(mService);
        if (root == null) {
            return false;
        }

        focused = root.findFocus(AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
        if (focused != null) {
            // If a node already has focus, ensure it should still have
            // focus. Return immediately if it's correctly focused and this
            // event is not the result a scroll action OR we successfully
            // refocus the node.
            if (AccessibilityNodeInfoUtils.shouldFocusNode(mService, focused)
                    && (!wasScrollAction || mCursorController.refocus())) {
                return true;
            }

            LogUtils.log(this, Log.DEBUG, "Clear focus from %s", focused);
            focused.performAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
        }

        // Try focusing the appropriate child node.
        if (tryFocusingChild(source, isMovingForward)) {
            return true;
        }

        // Finally, try focusing the scrollable node itself.
        if (tryFocusing(source)) {
            return true;
        }

        return false;
    } finally {
        AccessibilityNodeInfoUtils.recycleNodes(root, focused);
    }
}

From source file:com.android.screenspeak.eventprocessor.ProcessorFocusAndSingleTap.java

/**
 * @param record the AccessbilityRecord for the event
 * @param isViewFocusedEvent true if the event is TYPE_VIEW_FOCUSED, otherwise it is
 * TYPE_VIEW_SELECTED./*from   w  w  w .  j  a  v a 2s.c om*/
 */
private boolean setFocusOnView(AccessibilityRecordCompat record, boolean isViewFocusedEvent) {
    AccessibilityNodeInfoCompat source = null;
    AccessibilityNodeInfoCompat existing = null;
    AccessibilityNodeInfoCompat child = null;

    try {
        source = record.getSource();
        if (source == null) {
            return false;
        }

        if (record.getItemCount() > 0) {
            final int index = (record.getCurrentItemIndex() - record.getFromIndex());
            if (index >= 0 && index < source.getChildCount()) {
                child = source.getChild(index);
                if (child != null) {
                    if (AccessibilityNodeInfoUtils.isTopLevelScrollItem(child) && tryFocusing(child)) {
                        return true;
                    }
                }
            }
        }

        if (!isViewFocusedEvent) {
            return false;
        }

        // Logic below is only specific to TYPE_VIEW_FOCUSED event
        // Try focusing the source node.
        if (tryFocusing(source)) {
            return true;
        }

        // If we fail and the source node already contains focus, abort.
        existing = source.findFocus(AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
        if (existing != null) {
            return false;
        }

        // If we fail to focus a node, perhaps because it is a focusable
        // but non-speaking container, we should still attempt to place
        // focus on a speaking child within the container.
        child = AccessibilityNodeInfoUtils.searchFromBfs(source,
                AccessibilityNodeInfoUtils.FILTER_SHOULD_FOCUS);
        return child != null && tryFocusing(child);

    } finally {
        AccessibilityNodeInfoUtils.recycleNodes(source, existing, child);
    }
}

From source file:com.googlecode.eyesfree.brailleback.IMENavigationModeTest.java

/**
 * Tests the behaviour of the "text and navigation" mode.
 */// w  ww  .  java  2s.  c  om
public void testTextAndNavigationMode() {
    EditorInfo ei = new EditorInfo();

    // Mock out the AccessibilityNodeInfo.
    // The class actually uses the compat variant, but on recent API
    // releases (including the test environment) they should call through.
    AccessibilityNodeInfo rawNode = mock(AccessibilityNodeInfo.class);
    when(mAccessibilityService.getRootInActiveWindow()).thenReturn(rawNode);
    when(rawNode.findFocus(AccessibilityNodeInfo.FOCUS_INPUT)).thenReturn(rawNode);
    when(rawNode.findFocus(AccessibilityNodeInfo.FOCUS_ACCESSIBILITY)).thenReturn(rawNode);
    when(rawNode.getClassName()).thenReturn("com.example.ExampleWebView");
    when(mSelfBrailleManager.hasContentForNode(compatWrapperForNode(rawNode))).thenReturn(true);

    mIMENavMode.onActivate();
    mIMENavMode.onCreateIME();
    verify(mNext).onActivate();
    mIMENavMode.onBindInput();
    mIMENavMode.onStartInput(ei, false /* restarting */);
    verify(mSelfBrailleManager, atLeastOnce()).setImeOpen(false);
    verify(mSelfBrailleManager, never()).setImeOpen(true);
    mIMENavMode.onStartInputView(ei, false /* restarting */);

    assertEquals(mBrailleTranslator, mIMENavMode.getBrailleTranslator());
    assertNull(mIMENavMode.getDisplayManager());
    assertEquals(mFeedbackManager, mIMENavMode.getFeedbackManager());
    verify(mSelfBrailleManager, atLeastOnce()).setImeOpen(true);

    AccessibilityEvent accessibilityEvent = AccessibilityEvent.obtain();
    try {
        mIMENavMode.onObserveAccessibilityEvent(accessibilityEvent);
        verify(mNext).onObserveAccessibilityEvent(accessibilityEvent);
    } finally {
        accessibilityEvent.recycle();
    }

    accessibilityEvent = AccessibilityEvent.obtain();
    try {
        mIMENavMode.onAccessibilityEvent(accessibilityEvent);
        verify(mNext).onAccessibilityEvent(accessibilityEvent);
    } finally {
        accessibilityEvent.recycle();
    }

    AccessibilityNodeInfoCompat node = AccessibilityNodeInfoCompat.obtain();
    try {
        mIMENavMode.onInvalidateAccessibilityNode(node);
        verify(mNext).onInvalidateAccessibilityNode(node);
    } finally {
        node.recycle();
    }

    DisplayManager.Content content = new DisplayManager.Content("");
    mIMENavMode.onPanLeftOverflow(content);
    verify(mNext).onPanLeftOverflow(content);
    mIMENavMode.onPanRightOverflow(content);
    verify(mNext).onPanRightOverflow(content);

    BrailleInputEvent inputEvent = new BrailleInputEvent(BrailleInputEvent.CMD_KEY_ENTER, 0, 0);
    mIMENavMode.onMappedInputEvent(inputEvent, content);
    verify(mNext, never()).onMappedInputEvent(inputEvent, content);
    verify(mIME).sendAndroidKey(KeyEvent.KEYCODE_ENTER);

    inputEvent = new BrailleInputEvent(BrailleInputEvent.CMD_KEY_DEL, 0, 0);
    mIMENavMode.onMappedInputEvent(inputEvent, content);
    verify(mNext, never()).onMappedInputEvent(inputEvent, content);
    verify(mIME).sendAndroidKey(KeyEvent.KEYCODE_DEL);

    inputEvent = new BrailleInputEvent(BrailleInputEvent.CMD_BRAILLE_KEY, 0x1b, 0);
    mIMENavMode.onMappedInputEvent(inputEvent, content);
    verify(mNext, never()).onMappedInputEvent(inputEvent, content);
    verify(mIME).handleBrailleKey(0x1b);

    inputEvent = new BrailleInputEvent(BrailleInputEvent.CMD_ACTIVATE_CURRENT, 0, 0);
    mIMENavMode.onMappedInputEvent(inputEvent, content);
    verify(mNext).onMappedInputEvent(inputEvent, content);
    verify(mIME, never()).sendDefaultAction();

    inputEvent = new BrailleInputEvent(BrailleInputEvent.CMD_ROUTE, 0, 0);
    mIMENavMode.onMappedInputEvent(inputEvent, content);
    verify(mNext).onMappedInputEvent(inputEvent, content);
    verify(mIME, never()).route(anyInt(), any(DisplayManager.Content.class));

    // Nothing above this point should have triggered an action on the
    // accessibility node.
    verify(rawNode, never()).performAction(anyInt(), any(Bundle.class));
    verifyEventCausesNavigation(BrailleInputEvent.CMD_NAV_ITEM_NEXT, ACTION_NEXT_AT_MOVEMENT_GRANULARITY,
            MOVEMENT_GRANULARITY_CHARACTER, rawNode, content);
    verifyEventCausesNavigation(BrailleInputEvent.CMD_NAV_ITEM_PREVIOUS,
            ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, MOVEMENT_GRANULARITY_CHARACTER, rawNode, content);
    verifyEventCausesNavigation(BrailleInputEvent.CMD_NAV_LINE_NEXT, ACTION_NEXT_AT_MOVEMENT_GRANULARITY,
            MOVEMENT_GRANULARITY_LINE, rawNode, content);
    verifyEventCausesNavigation(BrailleInputEvent.CMD_NAV_LINE_PREVIOUS,
            ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, MOVEMENT_GRANULARITY_LINE, rawNode, content);

    Mockito.reset(mSelfBrailleManager);

    mIMENavMode.onFinishInputView(true);
    verify(mSelfBrailleManager).setImeOpen(false);
    mIMENavMode.onFinishInput();
    mIMENavMode.onUnbindInput();
    mIMENavMode.onDestroyIME();
    verify(mSelfBrailleManager, never()).setImeOpen(true);

    // Deactivate, but make sure it didn't happen too early.
    verify(mNext, never()).onDeactivate();
    mIMENavMode.onDeactivate();
    verify(mNext).onDeactivate();
}

From source file:com.android.screenspeak.eventprocessor.ProcessorFocusAndSingleTap.java

/**
 * Attempts to place focus within a new window.
 *//* w  w  w.  ja v a2s .co m*/
private boolean ensureFocusConsistency() {
    AccessibilityNodeInfoCompat root = null;
    AccessibilityNodeInfoCompat focused = null;

    try {
        root = AccessibilityServiceCompatUtils.getRootInAccessibilityFocusedWindow(mService);
        if (root == null) {
            return false;
        }

        // First, see if we've already placed accessibility focus.
        focused = root.findFocus(AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
        if (focused != null) {
            if (AccessibilityNodeInfoUtils.shouldFocusNode(focused)) {
                return true;
            }

            LogUtils.log(Log.VERBOSE, "Clearing focus from invalid node");
            PerformActionUtils.performAction(focused, AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
        }

        return false;
    } finally {
        AccessibilityNodeInfoUtils.recycleNodes(root, focused);
    }
}

From source file:com.googlecode.eyesfree.brailleback.IMENavigationModeTest.java

/**
 * Tests the behaviour of the "modal editor" mode.
 *//*from   w  ww .ja v a 2  s.  com*/
public void testModalEditorMode() {
    mIMENavMode.onActivate();
    verify(mNext).onActivate();
    EditorInfo ei = new EditorInfo();

    // Mock out the AccessibilityNodeInfo.
    // The class actually uses the compat variant, but on recent API
    // releases (including the test environment) they should call through.
    AccessibilityNodeInfo rawNode = mock(AccessibilityNodeInfo.class);
    when(mAccessibilityService.getRootInActiveWindow()).thenReturn(rawNode);
    when(rawNode.findFocus(AccessibilityNodeInfo.FOCUS_ACCESSIBILITY)).thenReturn(rawNode);
    when(rawNode.getClassName()).thenReturn(EditText.class.getName());
    when(rawNode.isFocused()).thenReturn(true);

    mIMENavMode.onCreateIME();
    mIMENavMode.onBindInput();

    mIMENavMode.onStartInput(ei, false /* restarting */);
    mIMENavMode.onStartInputView(ei, false /* restarting */);
    verify(mNext, times(1)).onDeactivate();

    assertEquals(mBrailleTranslator, mIMENavMode.getBrailleTranslator());
    assertEquals(mDisplayManager, mIMENavMode.getDisplayManager());
    assertEquals(mFeedbackManager, mIMENavMode.getFeedbackManager());

    AccessibilityEvent accessibilityEvent = AccessibilityEvent.obtain();
    try {
        mIMENavMode.onObserveAccessibilityEvent(accessibilityEvent);
        verify(mNext).onObserveAccessibilityEvent(accessibilityEvent);
    } finally {
        accessibilityEvent.recycle();
    }

    accessibilityEvent = AccessibilityEvent.obtain();
    try {
        mIMENavMode.onAccessibilityEvent(accessibilityEvent);
        verify(mNext, never()).onAccessibilityEvent(accessibilityEvent);
    } finally {
        accessibilityEvent.recycle();
    }

    AccessibilityNodeInfoCompat node = AccessibilityNodeInfoCompat.obtain();
    try {
        mIMENavMode.onInvalidateAccessibilityNode(node);
        verify(mNext, never()).onInvalidateAccessibilityNode(node);
    } finally {
        node.recycle();
    }

    // Move input focus away and back again.
    when(rawNode.isFocused()).thenReturn(false);
    accessibilityEvent = AccessibilityEvent.obtain();
    accessibilityEvent.setEventType(AccessibilityEvent.TYPE_VIEW_FOCUSED);
    try {
        mIMENavMode.onObserveAccessibilityEvent(accessibilityEvent);
        verify(mNext, times(2)).onActivate();
        when(rawNode.isFocused()).thenReturn(true);
        mIMENavMode.onObserveAccessibilityEvent(accessibilityEvent);
        verify(mNext, times(2)).onDeactivate();
    } finally {
        accessibilityEvent.recycle();
    }

    DisplayManager.Content content = new DisplayManager.Content("");
    mIMENavMode.onPanLeftOverflow(content);
    verify(mNext).onPanLeftOverflow(content);
    mIMENavMode.onPanRightOverflow(content);
    verify(mNext).onPanRightOverflow(content);

    BrailleInputEvent inputEvent = new BrailleInputEvent(BrailleInputEvent.CMD_KEY_ENTER, 0, 0);
    mIMENavMode.onMappedInputEvent(inputEvent, content);
    verify(mNext, never()).onMappedInputEvent(inputEvent, content);
    verify(mIME).sendAndroidKey(KeyEvent.KEYCODE_ENTER);

    inputEvent = new BrailleInputEvent(BrailleInputEvent.CMD_KEY_DEL, 0, 0);
    mIMENavMode.onMappedInputEvent(inputEvent, content);
    verify(mNext, never()).onMappedInputEvent(inputEvent, content);
    verify(mIME).sendAndroidKey(KeyEvent.KEYCODE_DEL);

    inputEvent = new BrailleInputEvent(BrailleInputEvent.CMD_BRAILLE_KEY, 0x1b, 0);
    mIMENavMode.onMappedInputEvent(inputEvent, content);
    verify(mNext, never()).onMappedInputEvent(inputEvent, content);
    verify(mIME).handleBrailleKey(0x1b);

    inputEvent = new BrailleInputEvent(BrailleInputEvent.CMD_NAV_ITEM_NEXT, 0, 0);
    mIMENavMode.onMappedInputEvent(inputEvent, content);
    verify(mNext, never()).onMappedInputEvent(inputEvent, content);
    verify(mIME).moveCursor(BrailleIME.DIRECTION_FORWARD,
            AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_CHARACTER);

    inputEvent = new BrailleInputEvent(BrailleInputEvent.CMD_ACTIVATE_CURRENT, 0, 0);
    mIMENavMode.onMappedInputEvent(inputEvent, content);
    verify(mNext, never()).onMappedInputEvent(inputEvent, content);
    verify(mIME).sendDefaultAction();

    inputEvent = new BrailleInputEvent(BrailleInputEvent.CMD_ROUTE, 0, 0);
    mIMENavMode.onMappedInputEvent(inputEvent, content);
    verify(mNext, never()).onMappedInputEvent(inputEvent, content);
    verify(mIME).route(0, content);

    // Finishing and unbinding the input should activate the next nav mode
    // again.
    mIMENavMode.onFinishInputView(true);
    mIMENavMode.onFinishInput();
    mIMENavMode.onUnbindInput();
    verify(mNext, times(3)).onActivate();

    mIMENavMode.onDestroyIME();

    // Deactivate, but make sure it didn't happen too early.
    verify(mNext, times(2)).onDeactivate();
    mIMENavMode.onDeactivate();
    verify(mNext, times(3)).onDeactivate();
}