content: /*
   * Copyright (C) 2018 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package android.inputmethodservice;
  
  import android.annotation.Nullable;
  import android.content.Context;
  import android.content.Intent;
  import android.os.Bundle;
  import android.os.IBinder;
  import android.os.Looper;
  import android.os.ResultReceiver;
  import android.view.KeyEvent;
  import android.view.MotionEvent;
  import android.view.View;
  import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
  import android.view.inputmethod.CompletionInfo;
  import android.view.inputmethod.CursorAnchorInfo;
  import android.view.inputmethod.EditorInfo;
  import android.view.inputmethod.InputConnection;
  
  import com.android.internal.inputmethod.StartInputFlags;
  
  /**
   * Defines all the public APIs and interfaces that are necessary to implement multi-client IMEs.
   *
   * <p>Actual implementation is further delegated to
   * {@link MultiClientInputMethodServiceDelegateImpl}.</p>
   *
   * @hide
   */
  public final class MultiClientInputMethodServiceDelegate {
      // @SdkConstant(SdkConstantType.SERVICE_ACTION)
      public static final String SERVICE_INTERFACE =
              "android.inputmethodservice.MultiClientInputMethodService";
  
      /**
       * Special value that is guaranteed to be not used for IME client ID.
       */
      public static final int INVALID_CLIENT_ID = -1;
  
      /**
       * Special value that is guaranteed to be not used for window handle.
       */
      public static final int INVALID_WINDOW_HANDLE = -1;
  
      private final MultiClientInputMethodServiceDelegateImpl mImpl;
  
      /**
       * Top-level callbacks for this {@link MultiClientInputMethodServiceDelegate}.
       */
      public interface ServiceCallback {
          /**
           * Called when this {@link MultiClientInputMethodServiceDelegate} is recognized by the
           * system and privileged operations like {@link #createInputMethodWindowToken(int)} are
           * ready to be called.
           */
          void initialized();
  
          /**
           * Called when a new IME client is recognized by the system.
           *
           * <p>Once the IME receives this callback, the IME can start interacting with the IME client
           * by calling {@link #acceptClient(int, ClientCallback, KeyEvent.DispatcherState, Looper)}.
           * </p>
           *
           * @param clientId ID of the client.
           * @param uid UID of the IME client.
           * @param pid PID of the IME client.
           * @param selfReportedDisplayId display ID reported from the IME client. Since the system
           *        does not validate this display ID, and at any time the IME client can lose the
           *        access to this display ID, the IME needs to call
           *        {@link #isUidAllowedOnDisplay(int, int)} to check whether the IME client still
           *        has access to this display or not.
           */
          void addClient(int clientId, int uid, int pid, int selfReportedDisplayId);
  
          /**
           * Called when an IME client is being destroyed.
           *
           * @param clientId ID of the client.
           */
          void removeClient(int clientId);
      }
  
      /**
       * Per-client callbacks.
       */
      public interface ClientCallback {
          /**
           * Called when the associated IME client called {@link
           * android.view.inputmethod.InputMethodManager#sendAppPrivateCommand(View, String, Bundle)}.
           *
           * @param action Name of the command to be performed.
           * @param data Any data to include with the command.
           * @see android.inputmethodservice.InputMethodService#onAppPrivateCommand(String, Bundle)
           */
          void onAppPrivateCommand(String action, Bundle data);
  
          /**
           * Called when the associated IME client called {@link
           * android.view.inputmethod.InputMethodManager#displayCompletions(View, CompletionInfo[])}.
           *
           * @param completions Completion information provided from the IME client.
           * @see android.inputmethodservice.InputMethodService#onDisplayCompletions(CompletionInfo[])
           */
          void onDisplayCompletions(CompletionInfo[] completions);
  
          /**
           * Called when this callback session is closed. No further callback should not happen on
           * this callback object.
           */
          void onFinishSession();
  
          /**
           * Called when the associated IME client called {@link
           * android.view.inputmethod.InputMethodManager#hideSoftInputFromWindow(IBinder, int)} or
           * {@link android.view.inputmethod.InputMethodManager#hideSoftInputFromWindow(IBinder, int,
           * ResultReceiver)}.
           *
           * @param flags The flag passed by the client.
           * @param resultReceiver The {@link ResultReceiver} passed by the client.
           * @see android.inputmethodservice.InputMethodService#onWindowHidden()
           */
          void onHideSoftInput(int flags, ResultReceiver resultReceiver);
  
          /**
           * Called when the associated IME client called {@link
           * android.view.inputmethod.InputMethodManager#showSoftInput(View, int)} or {@link
           * android.view.inputmethod.InputMethodManager#showSoftInput(View, int, ResultReceiver)}.
           *
           * @param flags The flag passed by the client.
           * @param resultReceiver The {@link ResultReceiver} passed by the client.
           * @see android.inputmethodservice.InputMethodService#onWindowShown()
           */
          void onShowSoftInput(int flags, ResultReceiver resultReceiver);
  
          /**
           * A generic callback when {@link InputConnection} is being established.
           *
           * @param inputConnection The {@link InputConnection} to be established.
           * @param editorInfo The {@link EditorInfo} reported from the IME client.
           * @param startInputFlags Any combinations of {@link StartInputFlags}.
           * @param softInputMode SoftWindowMode specified to this window.
           * @param targetWindowHandle A unique Window token.
           * @see android.inputmethodservice.InputMethodService#onStartInput(EditorInfo, boolean)
           */
          void onStartInputOrWindowGainedFocus(
                  @Nullable InputConnection inputConnection,
                  @Nullable EditorInfo editorInfo,
                  @StartInputFlags int startInputFlags,
                  @SoftInputModeFlags int softInputMode,
                  int targetWindowHandle);
  
          /**
           * Called when the associated IME client called {@link
           * android.view.inputmethod.InputMethodManager#toggleSoftInput(int, int)}.
           *
           * @param showFlags The flag passed by the client.
           * @param hideFlags The flag passed by the client.
           * @see android.inputmethodservice.InputMethodService#onToggleSoftInput(int, int)
           */
          void onToggleSoftInput(int showFlags, int hideFlags);
  
          /**
           * Called when the associated IME client called {@link
           * android.view.inputmethod.InputMethodManager#updateCursorAnchorInfo(View,
           * CursorAnchorInfo)}.
           *
           * @param info The {@link CursorAnchorInfo} passed by the client.
           * @see android.inputmethodservice.InputMethodService#onUpdateCursorAnchorInfo(
           *      CursorAnchorInfo)
           */
          void onUpdateCursorAnchorInfo(CursorAnchorInfo info);
  
          /**
           * Called when the associated IME client called {@link
           * android.view.inputmethod.InputMethodManager#updateSelection(View, int, int, int, int)}.
           *
           * @param oldSelStart The previous selection start index.
           * @param oldSelEnd The previous selection end index.
           * @param newSelStart The new selection start index.
           * @param newSelEnd The new selection end index.
           * @param candidatesStart The new candidate start index.
           * @param candidatesEnd The new candidate end index.
           * @see android.inputmethodservice.InputMethodService#onUpdateSelection(int, int, int, int,
           *      int, int)
           */
          void onUpdateSelection(int oldSelStart, int oldSelEnd, int newSelStart, int newSelEnd,
                  int candidatesStart, int candidatesEnd);
  
          /**
           * Called to give a chance for the IME to intercept generic motion events before they are
           * processed by the application.
           *
           * @param event {@link MotionEvent} that is about to be handled by the IME client.
           * @return {@code true} to tell the IME client that the IME handled this event.
           * @see android.inputmethodservice.InputMethodService#onGenericMotionEvent(MotionEvent)
           */
          boolean onGenericMotionEvent(MotionEvent event);
  
          /**
           * Called to give a chance for the IME to intercept key down events before they are
           * processed by the application.
           *
           * @param keyCode The value in {@link KeyEvent#getKeyCode()}.
           * @param event {@link KeyEvent} for this key down event.
           * @return {@code true} to tell the IME client that the IME handled this event.
           * @see android.inputmethodservice.InputMethodService#onKeyDown(int, KeyEvent)
           */
          boolean onKeyDown(int keyCode, KeyEvent event);
  
          /**
           * Called to give a chance for the IME to intercept key long press events before they are
           * processed by the application.
           *
           * @param keyCode The value in {@link KeyEvent#getKeyCode()}.
           * @param event {@link KeyEvent} for this key long press event.
           * @return {@code true} to tell the IME client that the IME handled this event.
           * @see android.inputmethodservice.InputMethodService#onKeyLongPress(int, KeyEvent)
           */
          boolean onKeyLongPress(int keyCode, KeyEvent event);
  
          /**
           * Called to give a chance for the IME to intercept key multiple events before they are
           * processed by the application.
           *
           * @param keyCode The value in {@link KeyEvent#getKeyCode()}.
           * @param event {@link KeyEvent} for this key multiple event.
           * @return {@code true} to tell the IME client that the IME handled this event.
           * @see android.inputmethodservice.InputMethodService#onKeyMultiple(int, int, KeyEvent)
           */
          boolean onKeyMultiple(int keyCode, KeyEvent event);
  
          /**
           * Called to give a chance for the IME to intercept key up events before they are processed
           * by the application.
           *
           * @param keyCode The value in {@link KeyEvent#getKeyCode()}.
           * @param event {@link KeyEvent} for this key up event.
           * @return {@code true} to tell the IME client that the IME handled this event.
           * @see android.inputmethodservice.InputMethodService#onKeyUp(int, KeyEvent)
           */
          boolean onKeyUp(int keyCode, KeyEvent event);
  
          /**
           * Called to give a chance for the IME to intercept generic motion events before they are
           * processed by the application.
           *
           * @param event {@link MotionEvent} that is about to be handled by the IME client.
           * @return {@code true} to tell the IME client that the IME handled this event.
           * @see android.inputmethodservice.InputMethodService#onTrackballEvent(MotionEvent)
           */
          boolean onTrackballEvent(MotionEvent event);
      }
  
      private MultiClientInputMethodServiceDelegate(Context context,
              ServiceCallback serviceCallback) {
          mImpl = new MultiClientInputMethodServiceDelegateImpl(context, serviceCallback);
      }
  
      /**
       * Must be called by the multi-client IME implementer to create
       * {@link MultiClientInputMethodServiceDelegate}.
       *
       * @param context {@link Context} with which the delegate should interact with the system.
       * @param serviceCallback {@link ServiceCallback} to receive service-level callbacks.
       * @return A new instance of {@link MultiClientInputMethodServiceDelegate}.
       */
      public static MultiClientInputMethodServiceDelegate create(Context context,
              ServiceCallback serviceCallback) {
          return new MultiClientInputMethodServiceDelegate(context, serviceCallback);
      }
  
      /**
       * Must be called by the multi-client IME service when {@link android.app.Service#onDestroy()}
       * is called.
       */
      public void onDestroy() {
          mImpl.onDestroy();
      }
  
      /**
       * Must be called by the multi-client IME service when
       * {@link android.app.Service#onBind(Intent)} is called.
       *
       * @param intent {@link Intent} passed to {@link android.app.Service#onBind(Intent)}.
       * @return An {@link IBinder} object that needs to be returned from
       *         {@link android.app.Service#onBind(Intent)}.
       */
      public IBinder onBind(Intent intent) {
          return mImpl.onBind(intent);
      }
  
      /**
       * Must be called by the multi-client IME service when
       * {@link android.app.Service#onUnbind(Intent)} is called.
       *
       * @param intent {@link Intent} passed to {@link android.app.Service#onUnbind(Intent)}.
       * @return A boolean value that needs to be returned from
       *         {@link android.app.Service#onUnbind(Intent)}.
       */
      public boolean onUnbind(Intent intent) {
          return mImpl.onUnbind(intent);
      }
  
      /**
       * Must be called by the multi-client IME service to create a special window token for IME
       * window.
       *
       * <p>This method is available only after {@link ServiceCallback#initialized()}.</p>
       *
       * @param displayId display ID on which the IME window will be shown.
       * @return Window token to be specified to the IME window/
       */
      public IBinder createInputMethodWindowToken(int displayId) {
          return mImpl.createInputMethodWindowToken(displayId);
      }
  
      /**
       * Must be called by the multi-client IME service to notify the system when the IME is ready to
       * accept callback events from the specified IME client.
       *
       * @param clientId The IME client ID specified in
       *                 {@link ServiceCallback#addClient(int, int, int, int)}.
       * @param clientCallback The {@link ClientCallback} to receive callback events from this IME
       *                       client.
       * @param dispatcherState {@link KeyEvent.DispatcherState} to be used when receiving key-related
       *                        callbacks in {@link ClientCallback}.
       * @param looper {@link Looper} on which {@link ClientCallback} will be called back.
       */
      public void acceptClient(int clientId, ClientCallback clientCallback,
              KeyEvent.DispatcherState dispatcherState, Looper looper) {
          mImpl.acceptClient(clientId, clientCallback, dispatcherState, looper);
      }
  
      /**
       * Must be called by the multi-client IME service to notify the system when the IME is ready to
       * interact with the window in the IME client.
       *
       * @param clientId The IME client ID specified in
       *                 {@link ServiceCallback#addClient(int, int, int, int)}.
       * @param targetWindowHandle The window handle specified in
       *                           {@link ClientCallback#onStartInputOrWindowGainedFocus}.
       * @param imeWindowToken The IME window token returned from
       *                       {@link #createInputMethodWindowToken(int)}.
       */
      public void reportImeWindowTarget(int clientId, int targetWindowHandle,
              IBinder imeWindowToken) {
          mImpl.reportImeWindowTarget(clientId, targetWindowHandle, imeWindowToken);
      }
  
      /**
       * Can be called by the multi-client IME service to check if the given {@code uid} is allowed
       * to access to {@code displayId}.
       *
       * @param displayId Display ID to be queried.
       * @param uid UID to be queried.
       * @return {@code true} if {@code uid} is allowed to access to {@code displayId}.
       */
      public boolean isUidAllowedOnDisplay(int displayId, int uid) {
          return mImpl.isUidAllowedOnDisplay(displayId, uid);
      }
  
      /**
       * Can be called by MSIME to activate/deactivate a client when it is gaining/losing focus
       * respectively.
       *
       * @param clientId client ID to activate/deactivate.
       * @param active {@code true} to activate a client.
       */
      public void setActive(int clientId, boolean active) {
          mImpl.setActive(clientId, active);
      }
  }
  