/** Report the current selection range. */
  public void updateSelection(
      View view, int selStart, int selEnd, int candidatesStart, int candidatesEnd) {
    checkFocus();
    synchronized (mH) {
      if ((mServedView != view
              && (mServedView == null || !mServedView.checkInputConnectionProxy(view)))
          || mCurrentTextBoxAttribute == null
          || mCurMethod == null) {
        return;
      }

      if (mCursorSelStart != selStart
          || mCursorSelEnd != selEnd
          || mCursorCandStart != candidatesStart
          || mCursorCandEnd != candidatesEnd) {
        if (DEBUG) Log.d(TAG, "updateSelection");

        try {
          if (DEBUG) Log.v(TAG, "SELECTION CHANGE: " + mCurMethod);
          mCurMethod.updateSelection(
              mCursorSelStart, mCursorSelEnd, selStart, selEnd, candidatesStart, candidatesEnd);
          mCursorSelStart = selStart;
          mCursorSelEnd = selEnd;
          mCursorCandStart = candidatesStart;
          mCursorCandEnd = candidatesEnd;
        } catch (RemoteException e) {
          Log.w(TAG, "IME died: " + mCurId, e);
        }
      }
    }
  }
 /**
  * When the focused window is dismissed, this method is called to finish the input method started
  * before.
  *
  * @hide
  */
 public void windowDismissed(IBinder appWindowToken) {
   checkFocus();
   synchronized (mH) {
     if (mServedView != null && mServedView.getWindowToken() == appWindowToken) {
       finishInputLocked();
     }
   }
 }
 /** Return true if the given view is the currently active view for the input method. */
 public boolean isActive(View view) {
   checkFocus();
   synchronized (mH) {
     return (mServedView == view
             || (mServedView != null && mServedView.checkInputConnectionProxy(view)))
         && mCurrentTextBoxAttribute != null;
   }
 }
  /**
   * If the input method is currently connected to the given view, restart it with its new contents.
   * You should call this when the text within your view changes outside of the normal input method
   * or key input flow, such as when an application calls TextView.setText().
   *
   * @param view The view whose text has changed.
   */
  public void restartInput(View view) {
    checkFocus();
    synchronized (mH) {
      if (mServedView != view
          && (mServedView == null || !mServedView.checkInputConnectionProxy(view))) {
        return;
      }

      mServedConnecting = true;
    }

    startInputInner();
  }
  /**
   * Request to hide the soft input window from the context of the window that is currently
   * accepting input. This should be called as a result of the user doing some actually than fairly
   * explicitly requests to have the input window hidden.
   *
   * @param windowToken The token of the window that is making the request, as returned by {@link
   *     View#getWindowToken() View.getWindowToken()}.
   * @param flags Provides additional operating flags. Currently may be 0 or have the {@link
   *     #HIDE_IMPLICIT_ONLY} bit set.
   * @param resultReceiver If non-null, this will be called by the IME when it has processed your
   *     request to tell you what it has done. The result code you receive may be either {@link
   *     #RESULT_UNCHANGED_SHOWN}, {@link #RESULT_UNCHANGED_HIDDEN}, {@link #RESULT_SHOWN}, or
   *     {@link #RESULT_HIDDEN}.
   */
  public boolean hideSoftInputFromWindow(
      IBinder windowToken, int flags, ResultReceiver resultReceiver) {
    checkFocus();
    synchronized (mH) {
      if (mServedView == null || mServedView.getWindowToken() != windowToken) {
        return false;
      }

      try {
        return mService.hideSoftInput(mClient, flags, resultReceiver);
      } catch (RemoteException e) {
      }
      return false;
    }
  }
  /**
   * Explicitly request that the current input method's soft input area be shown to the user, if
   * needed. Call this if the user interacts with your view in such a way that they have expressed
   * they would like to start performing input into it.
   *
   * @param view The currently focused view, which would like to receive soft keyboard input.
   * @param flags Provides additional operating flags. Currently may be 0 or have the {@link
   *     #SHOW_IMPLICIT} bit set.
   * @param resultReceiver If non-null, this will be called by the IME when it has processed your
   *     request to tell you what it has done. The result code you receive may be either {@link
   *     #RESULT_UNCHANGED_SHOWN}, {@link #RESULT_UNCHANGED_HIDDEN}, {@link #RESULT_SHOWN}, or
   *     {@link #RESULT_HIDDEN}.
   */
  public boolean showSoftInput(View view, int flags, ResultReceiver resultReceiver) {
    checkFocus();
    synchronized (mH) {
      if (mServedView != view
          && (mServedView == null || !mServedView.checkInputConnectionProxy(view))) {
        return false;
      }

      try {
        return mService.showSoftInput(mClient, flags, resultReceiver);
      } catch (RemoteException e) {
      }

      return false;
    }
  }
  public void updateExtractedText(View view, int token, ExtractedText text) {
    checkFocus();
    synchronized (mH) {
      if (mServedView != view
          && (mServedView == null || !mServedView.checkInputConnectionProxy(view))) {
        return;
      }

      if (mCurMethod != null) {
        try {
          mCurMethod.updateExtractedText(token, text);
        } catch (RemoteException e) {
        }
      }
    }
  }
  public void displayCompletions(View view, CompletionInfo[] completions) {
    checkFocus();
    synchronized (mH) {
      if (mServedView != view
          && (mServedView == null || !mServedView.checkInputConnectionProxy(view))) {
        return;
      }

      mCompletions = completions;
      if (mCurMethod != null) {
        try {
          mCurMethod.displayCompletions(mCompletions);
        } catch (RemoteException e) {
        }
      }
    }
  }
 /**
  * Call {@link InputMethodSession#appPrivateCommand(String, Bundle)
  * InputMethodSession.appPrivateCommand()} on the current Input Method.
  *
  * @param view Optional View that is sending the command, or null if you want to send the command
  *     regardless of the view that is attached to the input method.
  * @param action Name of the command to be performed. This <em>must</em> be a scoped name, i.e.
  *     prefixed with a package name you own, so that different developers will not create
  *     conflicting commands.
  * @param data Any data to include with the command.
  */
 public void sendAppPrivateCommand(View view, String action, Bundle data) {
   checkFocus();
   synchronized (mH) {
     if ((mServedView != view
             && (mServedView == null || !mServedView.checkInputConnectionProxy(view)))
         || mCurrentTextBoxAttribute == null
         || mCurMethod == null) {
       return;
     }
     try {
       if (DEBUG) Log.v(TAG, "APP PRIVATE COMMAND " + action + ": " + data);
       mCurMethod.appPrivateCommand(action, data);
     } catch (RemoteException e) {
       Log.w(TAG, "IME died: " + mCurId, e);
     }
   }
 }
  /**
   * Called by ViewRoot when its window gets input focus.
   *
   * @hide
   */
  public void onWindowFocus(
      View rootView, View focusedView, int softInputMode, boolean first, int windowFlags) {
    synchronized (mH) {
      if (DEBUG)
        Log.v(
            TAG,
            "onWindowFocus: "
                + focusedView
                + " softInputMode="
                + softInputMode
                + " first="
                + first
                + " flags=#"
                + Integer.toHexString(windowFlags));
      if (mHasBeenInactive) {
        if (DEBUG) Log.v(TAG, "Has been inactive!  Starting fresh");
        mHasBeenInactive = false;
        mNextServedNeedsStart = true;
      }
      focusInLocked(focusedView != null ? focusedView : rootView);
    }

    checkFocus();

    synchronized (mH) {
      try {
        final boolean isTextEditor = focusedView != null && focusedView.onCheckIsTextEditor();
        mService.windowGainedFocus(
            mClient,
            rootView.getWindowToken(),
            focusedView != null,
            isTextEditor,
            softInputMode,
            first,
            windowFlags);
      } catch (RemoteException e) {
      }
    }
  }
  /** Report the current cursor location in its window. */
  public void updateCursor(View view, int left, int top, int right, int bottom) {
    checkFocus();
    synchronized (mH) {
      if ((mServedView != view
              && (mServedView == null || !mServedView.checkInputConnectionProxy(view)))
          || mCurrentTextBoxAttribute == null
          || mCurMethod == null) {
        return;
      }

      mTmpCursorRect.set(left, top, right, bottom);
      if (!mCursorRect.equals(mTmpCursorRect)) {
        if (DEBUG) Log.d(TAG, "updateCursor");

        try {
          if (DEBUG) Log.v(TAG, "CURSOR CHANGE: " + mCurMethod);
          mCurMethod.updateCursor(mTmpCursorRect);
          mCursorRect.set(mTmpCursorRect);
        } catch (RemoteException e) {
          Log.w(TAG, "IME died: " + mCurId, e);
        }
      }
    }
  }
 /**
  * Return true if the currently served view is accepting full text edits. If false, it has no
  * input connection, so can only handle raw key events.
  */
 public boolean isAcceptingText() {
   checkFocus();
   return mServedInputConnection != null;
 }
 /** Return true if any view is currently active in the input method. */
 public boolean isActive() {
   checkFocus();
   synchronized (mH) {
     return mServedView != null && mCurrentTextBoxAttribute != null;
   }
 }