@Override
 public void handleClear() {
   typedText.setLength(0);
   final InputConnection ic = getCurrentInputConnection();
   ic.setSelection(0, 0);
   ic.deleteSurroundingText(MAX_INT, MAX_INT);
 }
 private void restoreFromHistory(@Nullable KeyboardInputHistoryState state) {
   if (state != null) {
     final InputConnection ic = getCurrentInputConnection();
     ic.deleteSurroundingText(MAX_INT, MAX_INT);
     ic.commitText(state.getCharSequence(), 1);
   }
 }
 @Override
 public void onText(@Nullable CharSequence text) {
   final InputConnection ic = getCurrentInputConnection();
   ic.beginBatchEdit();
   commitTyped();
   commitText(ic, text, 0);
   ic.endBatchEdit();
 }
 @Override
 public void handleCursorLeft() {
   final InputConnection ic = getCurrentInputConnection();
   int selectionStart = getSelectionStart(ic);
   int selectionEnd = getSelectionEnd(ic, selectionStart);
   if (selectionStart < 0) {
     selectionStart = selectionStart - 1;
     ic.setSelection(selectionStart, selectionEnd);
   }
 }
 private void commitText(@NotNull InputConnection ic, @Nullable CharSequence text, int position) {
   ic.commitText(text, position);
   if (!Strings.isEmpty(text)) {
     history.addState(
         new KeyboardInputHistoryState(AndroidKeyboardUtils.getTextFromInputConnection(ic), 0));
   }
 }
  /** @hide */
  public void checkFocus() {
    // This is called a lot, so short-circuit before locking.
    if (mServedView == mNextServedView && !mNextServedNeedsStart) {
      return;
    }

    InputConnection ic = null;
    synchronized (mH) {
      if (mServedView == mNextServedView && !mNextServedNeedsStart) {
        return;
      }
      if (DEBUG)
        Log.v(
            TAG,
            "checkFocus: view="
                + mServedView
                + " next="
                + mNextServedView
                + " restart="
                + mNextServedNeedsStart);

      mNextServedNeedsStart = false;
      if (mNextServedView == null) {
        finishInputLocked();
        // In this case, we used to have a focused view on the window,
        // but no longer do.  We should make sure the input method is
        // no longer shown, since it serves no purpose.
        closeCurrentInput();
        return;
      }

      ic = mServedInputConnection;

      mServedView = mNextServedView;
      mCurrentTextBoxAttribute = null;
      mCompletions = null;
      mServedConnecting = true;
    }

    if (ic != null) {
      ic.finishComposingText();
    }

    startInputInner();
  }
  @Override
  public boolean handleBackspace() {
    boolean changed = false;

    int length = typedText.length();

    final InputConnection ic = getCurrentInputConnection();
    if (length > 1) {
      typedText.delete(length - 1, length);
      ic.setComposingText(typedText, 1);
      changed = true;
    } else if (length > 0) {
      clearTypedText();
      commitText(ic, "", 0);
      changed = true;
    }

    return changed;
  }
 private int getSelectionStart(@NotNull InputConnection ic) {
   return ic.getTextBeforeCursor(MAX_INT, 0).length();
 }
 private int getSelectionEnd(@NotNull InputConnection ic, int selectionStart) {
   final CharSequence selectedText = ic.getSelectedText(0);
   return selectionStart + (selectedText == null ? 0 : selectedText.length());
 }
 /**
  * Called from the FINISH_INPUT_CONNECTION message above.
  *
  * @hide
  */
 public void reportFinishInputConnection(InputConnection ic) {
   if (mServedInputConnection != ic) {
     ic.finishComposingText();
   }
 }