インプット メソッド エディタのサポート

ディスプレイ固有の領域に対する更新内容は次のとおりです。

Android 10 は、デフォルト以外のディスプレイで実行されるアプリのソフトウェア キーボードをサポートしています。

デフォルト以外のディスプレイで実行されるアプリ

インプット メソッド エディタ(IME)のソフトウェア キーボードを表示するディスプレイには、2 つのモードがあります。ソフトウェア キーボードは次のディスプレイに表示されます。

  • フォーカスされているアプリが表示されているのと同じディスプレイ。
  • フォーカスされているアプリがデフォルト以外のディスプレイで実行されているときのデフォルトのディスプレイ。

使用するモードは、フォーカスされているアプリが表示されているディスプレイの設定に応じて決まります。詳しくは、以下をご覧ください。

  • DisplayWindowSettings#shouldShowImeLocked()
  • DisplayWindowSettings#setShouldShowImeLocked()

図 1. ターゲット アプリと同じセカンダリ ディスプレイに表示された IME ソフトウェア キーボード

システムで使用される IME は 1 つですが、ユーザー フォーカスに合わせてディスプレイを切り替えることができます。Android 10 では、Google とサードパーティのすべての IME が自動的にレイアウトを修正し、作成された新しいディスプレイ サイズに合わせてサイズ変更する必要があります。

ディスプレイ A にアクティブな接続があり、ディスプレイ B の入力欄に入力フォーカスが必要な場合、次のフローが発生します。

  1. 新しい入力接続がディスプレイ B の入力欄から行われる。
  2. 接続が承認されるかどうかを InputMethodManagerService が確認する。
  3. IME のディスプレイが選択される。ディスプレイ B が IME の表示をサポートしており、IME を表示できる場合は、B が使用される。これに該当しない場合は、プライマリ デバイスのディスプレイが選択される。
  4. 選択されたディスプレイがディスプレイ A ではない場合は、接続が再確立される。InputMethodService が破棄されて再作成される。

セキュリティ制限

システムが所有していない仮想ディスプレイには IME は表示されません。これは、セキュリティ上の懸念として、悪意のあるアプリがシステム デコレーション サポートを有効にした仮想ディスプレイを作成し、サーフェスからユーザー機密情報(入力予測やカスタム背景など)を読み取る可能性があるためです。

実装

画面上の入力方法で説明されているように、Android 9 以前ではデフォルトの画面でのみ IME を使用できました。Android 10 以降では、フォーカスを切り替えて IME ウィンドウをセカンダリ ディスプレイに移動させることで、別のディスプレイの入力テキスト欄に切り替えることができます。

WindowManager の実装では、入力方法ウィンドウ(ソフト キーボードが表示される IME ウィンドウ)と入力方法ターゲット(IME 入力が行われるウィンドウ)をトラッキングして IME の状態を管理します。

InputMethodManagerService(IMMS)については、フォーカスを別のディスプレイに移動したときにディスプレイの変更を InputMethodService(IMS)に反映して、ランタイムにキーボード レイアウトを再構成できる組み込みメカニズムは他にありません。

ディスプレイ間で IME ウィンドウを切り替えられるように、Android 10 には以下が実装されています。

  • IME と入力ターゲット ウィンドウが、DisplayContent#mInputMethodWindowDisplayContent#mInputMethodTarget でディスプレイごとにトラッキングされるため、WindowManager(WM)は各ディスプレイの IME フォーカス状態を個別に管理できるようになりました。
  • IMMS 側では、外部ディスプレイから ViewRootImpl#handleWindowFocusChanged -> InputMethodManager#onPostWindowFocus -> IMMS#startInputOrWindowGainedFocus 経由でアプリ クライアントのフォーカス リクエストを受け取ると、最初に現在の入力方法サービスをバインド解除し、次にサービスを再バインドして、onServiceConnected() の外部ディスプレイ用に新しい IME ウィンドウ トークンを再度割り当てます。
  • IMS 側では、IMS#attachToken を受け取った後、次のフローが発生します。
    • InputMethodService#attachToken() のサービス コンテキストの表示を更新するために、ContextImpl#updateDisplay が呼び出されます。これによって呼び出された ViewGroup#addView() が、現在のコンテキストを確認し、キーボードのレイアウトを修正してターゲット ディスプレイに合わせて調整します。
    • DisplayContent#setInputMethodWindowLocked() が呼び出された後、実装は WindowProcessController を使用してプロセスレベルのディスプレイ構成の変更を IME プロセスに送信し、リソースとディスプレイの指標をオーバーライドします。
    • InputMethodService クライアントは、onConfigurationChanged()ViewGroup#addView() の呼び出し後に、正しい構成と正しいディスプレイの指標を取得して入力ビューを再初期化します。

マルチセッションのインプット メソッド エディタのサポート

複数のディスプレイが複数のユーザーに同時に使用されて適切な入力ソースを提供することが求められるデバイスの実装では、複数(ディスプレイごとに 1 つ)のインプット メソッド エディタ(IME)を同時に表示するように構成できます。次の 2 つの図は、2 つのディスプレイでのマルチセッション IME の例です。

図 2. マルチセッション IME の例

図 3. マルチセッション IME の例

ディスプレイごとのフォーカスのサポートは、この機能の前提条件です。前提条件が満たされていない場合、この機能を有効にすることはできません。 セキュリティ制限に起因するディスプレイごとのフォーカスの制約により、この機能は一部のデバイスのみに限定されていました。

Android 10 では、マルチセッション IME のサポートは、異なる API セットと限定的な機能を含む個別のシステム サービスで実装されます。マルチセッション IME は既存の IME と互換性がありません。 マルチセッション サービスまたはシングルセッション サービスのいずれかを使用できますが、両方を使用することはできません。

Android IME API が Android 1.5 で導入される前は、1 つの IME クライアントが作成されると同時にフォーカスされることを前提としており、すでに InputMethodService の多数の公開 API がその前提に大きく依存しているため、InputMethodService クラス上に構築された既存の Android IME を使用することはできません。ところが次の理由により、マルチクライアントのシナリオをサポートするように InputMethodService クラスを更新することは簡単ではありません。

  1. 現状でも維持が困難な InputMethodService が、更新によって許容できないほど複雑になります。
  2. IME デベロッパーは、フォーカスのある複数の IME クライアントからの同時リクエストに対応できるように、引き続き実装を更新する必要があります。これには、入力デコーダや入力履歴データベースなどの大幅な再設計が必要になる可能性があります。
  3. マルチ IME クライアントの実際のユースケースは急速に進化することが見込まれるため、新しいプロトコルが安定せず、公開 API として公開する準備ができません。

シングルセッション(通常)IME と同様に、各ディスプレイでの IME の表示は DisplayWindowSettings を使用して制御します。

マルチセッション IME のサンプルは development/samples/MultiClientInputMethod にあります。

マルチセッション IME をテストするには:

  1. config_perDisplayFocusEnabledtrue に設定します。
  2. 次のコマンドを実行します。
    1. $ make -j MultiClientInputMethod
    2. $ adb install -r $OUT/system/priv-app/MultiClientInputMethod/MultiClientInputMethod.apk
    3. $ adb root
    4. $ adb shell setprop persist.debug.multi_client_ime \
      com.example.android.multiclientinputmethod/.MultiClientInputMethod
    5. $ adb reboot
  3. 複数のテキスト入力シナリオを試します。

実装

実装について詳しくは、MultiClientInputMethodManagerService をご覧ください。