/** @see BaseInputConnection#setComposingRegion(int, int) */
  @Override
  public boolean setComposingRegion(int start, int end) {
    if (DEBUG) Log.w(TAG, "setComposingRegion [" + start + " " + end + "]");
    int textLength = mEditable.length();
    int a = Math.min(start, end);
    int b = Math.max(start, end);
    if (a < 0) a = 0;
    if (b < 0) b = 0;
    if (a > textLength) a = textLength;
    if (b > textLength) b = textLength;

    CharSequence regionText = null;
    if (a == b) {
      removeComposingSpans(mEditable);
    } else {
      if (a == 0 && b == mEditable.length()) {
        regionText = mEditable.subSequence(a, b);
        // If setting composing region that matches, at least in length, of the entire
        // editable region then check it for image placeholders.  If any are found,
        // don't continue this operation.
        // This fixes the problem where, on Android 4.3, pasting an image is followed
        // by setting the composing region which then causes the image to be deleted.
        // http://crbug.com/466755
        for (int i = a; i < b; ++i) {
          if (regionText.charAt(i) == '\uFFFC') return true;
        }
      }
      super.setComposingRegion(a, b);
    }
    updateSelectionIfRequired();

    return mImeAdapter.setComposingRegion(regionText, a, b);
  }
  /**
   * Updates the AdapterInputConnection's internal representation of the text being edited and its
   * selection and composition properties. The resulting Editable is accessible through the
   * getEditable() method. If the text has not changed, this also calls updateSelection on the
   * InputMethodManager.
   *
   * @param text The String contents of the field being edited.
   * @param selectionStart The character offset of the selection start, or the caret position if
   *     there is no selection.
   * @param selectionEnd The character offset of the selection end, or the caret position if there
   *     is no selection.
   * @param compositionStart The character offset of the composition start, or -1 if there is no
   *     composition.
   * @param compositionEnd The character offset of the composition end, or -1 if there is no
   *     selection.
   * @param isNonImeChange True when the update was caused by non-IME (e.g. Javascript).
   */
  @VisibleForTesting
  public void updateState(
      String text,
      int selectionStart,
      int selectionEnd,
      int compositionStart,
      int compositionEnd,
      boolean isNonImeChange) {
    if (DEBUG) {
      Log.w(
          TAG,
          "updateState ["
              + text
              + "] ["
              + selectionStart
              + " "
              + selectionEnd
              + "] ["
              + compositionStart
              + " "
              + compositionEnd
              + "] ["
              + isNonImeChange
              + "]");
    }
    // If this update is from the IME, no further state modification is necessary because the
    // state should have been updated already by the IM framework directly.
    if (!isNonImeChange) return;

    // Non-breaking spaces can cause the IME to get confused. Replace with normal spaces.
    text = text.replace('\u00A0', ' ');

    selectionStart = Math.min(selectionStart, text.length());
    selectionEnd = Math.min(selectionEnd, text.length());
    compositionStart = Math.min(compositionStart, text.length());
    compositionEnd = Math.min(compositionEnd, text.length());

    String prevText = mEditable.toString();
    boolean textUnchanged = prevText.equals(text);

    if (!textUnchanged) {
      mEditable.replace(0, mEditable.length(), text);
    }

    Selection.setSelection(mEditable, selectionStart, selectionEnd);

    if (compositionStart == compositionEnd) {
      removeComposingSpans(mEditable);
    } else {
      super.setComposingRegion(compositionStart, compositionEnd);
    }
    updateSelectionIfRequired();
  }