/** * Moves <code>count</code> units in the specified direction using the current granularity and * action. * * @param count The number of units to move. * @param forward <code>true</code> to move <code>count</code> units forward, <code>false</code> * to move backward. * @param isShiftPressed <code>true</code> if the shift key is pressed. * @return <code>true</code> if successful or <code>false</code> if no input connection was * available or the movement failed */ private boolean moveUnit(int granularity, int count, boolean forward, boolean isShiftPressed) { // If the input connection is null or count is 0, no-op. AccessibleInputConnection inputConnection = getCurrentInputConnection(); if (inputConnection == null || !inputConnection.hasExtractedText()) { return false; } else if (count == 0) { return true; } // If the shift key is held down, force ACTION_EXTEND mode. int action = (isShiftPressed ? TextNavigation.ACTION_EXTEND : mAction); // Disable sending accessibility events while we send multiple events, // then announce only the last event. boolean savedSendAccessibilityEvents = inputConnection.isSendAccessibilityEvents(); inputConnection.setSendAccessibilityEvents(false); for (int i = 0; i < count - 1; i++) { if (forward) { inputConnection.next(granularity, action); } else { inputConnection.previous(granularity, action); } } inputConnection.setSendAccessibilityEvents(savedSendAccessibilityEvents); // Obtain the new position from the final event. If the position is // null, we failed to move and should return false. Position newPosition = null; if (forward) { newPosition = inputConnection.next(granularity, action); } else { newPosition = inputConnection.previous(mGranularity, action); } return (newPosition != null); }
/** * Captures and stores directional pad events. If onKeyUp() preserves default behavior, the * original down event will be released. */ @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (mUserCommandHandler.onKeyDown(event)) { return true; } AccessibleInputConnection aic = getCurrentInputConnection(); if (aic == null || !aic.hasExtractedText()) { return super.onKeyDown(keyCode, event); } // If we've captured a meta key, capture all subsequent keys. if (mPreviousMetaDownEvent != null) { mPreviousDpadDownEvent = event; return true; } switch (event.getKeyCode()) { case KeyEvent.KEYCODE_DPAD_DOWN: case KeyEvent.KEYCODE_DPAD_UP: case KeyEvent.KEYCODE_DPAD_LEFT: case KeyEvent.KEYCODE_DPAD_RIGHT: mPreviousDpadDownEvent = event; return true; case KeyEvent.KEYCODE_ALT_LEFT: case KeyEvent.KEYCODE_ALT_RIGHT: { mAIC.trySendAccessiblityEvent(mAltString); mPreviousMetaDownEvent = event; return true; } case KeyEvent.KEYCODE_SHIFT_LEFT: case KeyEvent.KEYCODE_SHIFT_RIGHT: { mAIC.trySendAccessiblityEvent(mShiftString); mPreviousMetaDownEvent = event; return true; } default: return super.onKeyDown(keyCode, event); } }
/** * Sets action to be performed on the current selection. * * @param action Value could be either {@link TextNavigation#ACTION_MOVE} or {@link * TextNavigation#ACTION_EXTEND}. */ public boolean setAction(int action) { AccessibleInputConnection.checkValidAction(action); if (mAction == action) { return false; } mAction = action; String speak = String.format(mActionSet, mActionTypes[action]); getCurrentInputConnection().trySendAccessiblityEvent(speak); onActionChanged(action); return true; }
/** * Sets granularity (unit type) for text navigation. * * @param granularity Value could be {@link TextNavigation#GRANULARITY_CHAR} , {@link * TextNavigation#GRANULARITY_WORD}, {@link TextNavigation#GRANULARITY_SENTENCE}, {@link * TextNavigation#GRANULARITY_PARAGRAPH} or {@link TextNavigation#GRANULARITY_ENTIRE_TEXT} * @return <code>true</code> if granularity changed */ public boolean setGranularity(int granularity) { AccessibleInputConnection.checkValidGranularity(granularity); String speak = String.format(mGranularitySet, mGranularityTypes[granularity]); getCurrentInputConnection().trySendAccessiblityEvent(speak); if (mGranularity == granularity) { return false; } mGranularity = granularity; onGranularityChanged(granularity); return true; }
@Override public void onUpdateSelection( int oldSelStart, int oldSelEnd, int newSelStart, int newSelEnd, int candidatesStart, int candidatesEnd) { super.onUpdateSelection( oldSelStart, oldSelEnd, newSelStart, newSelEnd, candidatesStart, candidatesEnd); if (mWasUpDownPressed) { mWasUpDownPressed = false; android.util.Log.e("AIME", "updown was pressed, speaking"); mAIC.speakCurrentUnit(mGranularity); } }
/** * Overrides default directional pad behavior: * * <ul> * <li>Up/down: Increases/decreases text navigation granularity * <li>Left/right: Moves to previous/next unit of text * </ul> * * <p>If one of the following conditions is met, default behavior is preserved: * * <ul> * <li>No input connection available * <li>Input view is hidden * <li>Not currently editing text * <li>Cannot move in the specified direction * </ul> */ @Override public boolean onKeyUp(int keyCode, KeyEvent event) { if (mUserCommandHandler.onKeyUp(event)) { return true; } final AccessibleInputConnection aic = getCurrentInputConnection(); if (aic == null || !aic.hasExtractedText()) { return super.onKeyUp(keyCode, event); } final KeyEvent downEvent = mPreviousDpadDownEvent; mPreviousDpadDownEvent = null; final KeyEvent metaDownEvent = mPreviousMetaDownEvent; mPreviousMetaDownEvent = null; if (downEvent != null) { boolean captureEvent = false; switch (downEvent.getKeyCode()) { case KeyEvent.KEYCODE_DPAD_LEFT: if (!event.isAltPressed()) { captureEvent = previousUnit(mGranularity, 1, event.isShiftPressed()); } else { mWasUpDownPressed = true; } break; case KeyEvent.KEYCODE_DPAD_RIGHT: if (!event.isAltPressed()) { captureEvent = nextUnit(mGranularity, 1, event.isShiftPressed()); } else { mWasUpDownPressed = true; } break; case KeyEvent.KEYCODE_DPAD_UP: if (event.isAltPressed()) { adjustGranularity(1); captureEvent = true; } else { mWasUpDownPressed = true; } break; case KeyEvent.KEYCODE_DPAD_DOWN: if (event.isAltPressed()) { adjustGranularity(-1); captureEvent = true; } else { mWasUpDownPressed = true; } break; } if (captureEvent) { return true; } } // If we didn't capture the meta event, attempt to send the previous // meta down event and then preserve default behavior. if (metaDownEvent != null) { if (!super.onKeyDown(metaDownEvent.getKeyCode(), metaDownEvent)) { aic.sendKeyEvent(metaDownEvent); } } // If we didn't capture the event, attempt to send the previous down // event and then preserve default behavior. if (downEvent != null) { if (!super.onKeyDown(downEvent.getKeyCode(), downEvent)) { aic.sendKeyEvent(downEvent); } } if (!super.onKeyUp(keyCode, event)) { aic.sendKeyEvent(event); } return true; }