オーディオ グラスの物理入力ルーティングについて

対象となる XR デバイス
このガイダンスは、次のようなタイプの XR デバイス向けのエクスペリエンスを構築する際に役立ちます。
オーディオ グラス

オーディオ グラスでは、システムは視覚的なディスプレイ フォーカスではなく、ユーザーの認識に基づいて物理入力(タッチパッド ジェスチャーやボタンの押下など)をルーティングします。ユーザーはユーザー インターフェースを見ることができないため、システムは、ユーザーが感知している、またはアクティブに操作しているアプリ エクスペリエンスの投影されたアクティビティに物理入力をルーティングします。

システムがユーザーの認識を判断する方法

システムは、次のどのデータ ストリームがアクティブであるかをモニタリングして、ユーザーの認識を判断します。

  • 音声出力ストリーム: 音声読み上げ、音声キュー、メディア再生。
  • マイク録音ストリーム: 進行中の音声コマンドまたはユーザーの周囲からの音声キャプチャ。
  • カメラ キャプチャ ストリーム: 動画または写真のストリーム。

一部のデータ ストリームは一時的なものであり、ユーザーの認識を短時間だけ保持します。たとえば、ルートをナビゲートしているときに、ユーザーが次に曲がる方向を音声で読み上げます。その他のデータ ストリームは無期限であり、継続する限りユーザーの認識を保持します。たとえば、ランダム化された再生リストをエンドレスに再生するメディア再生などです。一時的なデータ ストリームが、無期限のデータ ストリームに割り込むと、一時的にユーザーの注意を引きます。

同時実行と入力フォーカス

ユーザーは、オーディオ グラスで複数のアプリ エクスペリエンスを同時に実行することがよくあります。たとえば、ユーザーはターンバイターン方式のナビに従いながら音楽を聴くことができます。このような場合、システムは同時実行状態を割り当て、次の処理を行うことで、オーディオ フォーカスに合わせて入力フォーカスをシフトします。

  • アプリの投影されたアクティビティを再開または停止する。
  • 物理入力をフォアグラウンドに投影されたアクティビティにルーティングする。

このアプローチにより、一貫性のあるユーザー エクスペリエンスを維持できます。

システムが投影されたアクティビティを再起動できるようにする

アプリがユーザーの認識を得たとき、特にその予測されるアクティビティがバックグラウンドにあった場合、システムはアクティビティを再開し、物理入力をルーティングできる必要があります。

システムがアクティビティを再起動できるようにするには、次の操作を行います。

  1. ペンディング インテントを作成する: ターゲットの投影アクティビティを指す明示的な Intent を作成します。インテントを PendingIntent でラップし、FLAG_UPDATE_CURRENT または FLAG_IMMUTABLE を設定して、安全で予測可能な起動動作を維持します。

    // Build an explicit Intent pointing to this projected activity and wrap it in a
    // PendingIntent so the system can relaunch it and route physical input to it.
    private val pendingIntent: PendingIntent by lazy {
        val intent = Intent(this, ProjectedInputFocusActivity::class.java)
    
        PendingIntent.getActivity(
            this,
            0,
            intent,
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
        )
    }

  2. 入力レシーバーを登録する: ProjectedActivityCompat のインスタンスを取得し、PendingIntent を setActivityAsInputReceiver に渡して、指定された入力レシーバーとして登録します。

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    
        lifecycleScope.launch {
            // Create or obtain the ProjectedActivityCompat instance
            val projectedActivity = ProjectedActivityCompat.create(this@ProjectedInputFocusActivity)
    
            // Register the PendingIntent as the designated input receiver
            projectedActivity.setActivityAsInputReceiver(pendingIntent)
        }

  3. クリーンアップ時に入力レシーバーをクリアする: アクティビティが破棄されたとき、または物理入力を受信する必要がなくなったときは、入力レシーバーをクリアして、古い PendingIntent のディスパッチを防ぎ、メモリリークを回避します。

    override fun onDestroy() {
        super.onDestroy()
        lifecycleScope.launch {
            val projectedActivity = ProjectedActivityCompat.create(this@ProjectedInputFocusActivity)
            projectedActivity.clearActivityAsInputReceiver()
        }
    }

同時実行状態間で入力フォーカスがどのようにシフトするかを理解する

どのアプリが入力フォーカスを受け取るかを判断するために、システムはアクティブなデータ ストリームを評価し、次の同時実行状態に基づいて入力をルーティングします。

同時実行状態 環境状況 システムの動作と入力フォーカス 例

非同時

スタンドアロンの投影アクティビティがアクティブで、バックグラウンド メディア セッションが実行されていない。

入力フォーカスは、読み上げの合間の無音期間中も含め、完全に投影されたアクティビティにルーティングされます。

ユーザーがワークアウト記録アプリを実行している。無音のときでも、タッチパッド入力はフィットネス アプリに直接ルーティングされる。

半同時

投影されたアクティビティがアクティブであるが、バックグラウンド メディア セッションが一時停止状態である。

アプリのアクティブな読み上げの間の無音期間中は、入力フォーカスはデフォルトで一時停止中のメディア コントロールに設定されます。

ユーザーが音楽を一時停止している間に、ワークアウト記録アプリを実行します。フィットネス コーチの更新の合間にタッチパッドをタップすると、ワークアウト機能がトリガーされるのではなく、音楽が再開される。

同時実行

デュアル再生が有効になっている(アプリの音声アナウンスがバックグラウンド ミュージックを中断またはダッキングするなど)。

音声フォーカスは入力フォーカスと同じです。

入力フォーカスは、読み上げ中は投影されたアクティビティにルーティングされ、音声ストリームが終了するとメディア コントロールに戻ります。

ユーザーが音楽を聴いているときに、ナビゲーション アプリが指示の読み上げを開始します。読み上げ中、ナビゲーション アプリは入力フォーカスを取得します。読み上げが完了すると、入力フォーカスがメディア コントロールに戻ります。

システム タイミングの安全保護対策

システムには、ユーザーによる誤入力や予期しない動作を防ぐために、次の安全保護対策が用意されています。

  • 新しく起動された投影アクティビティの猶予期間: コールド スタートのアセット読み込みやネットワーク遅延に対応するため、新しく起動された投影アクティビティには、システムが投影アクティビティを停止してバックグラウンドに移動する前に、データ ストリームを確立してユーザーに認識されるための短い猶予期間が与えられます。
  • フォーカスはユーザーの認識に基づいてルーティングされる: 音声読み上げなどの新しいアクティブなデータ ストリームからユーザーの認識が変化すると、システムは投影されたアクティビティを即座に再開し、入力フォーカスをそのアクティビティにルーティングします。
  • メディア再生中の遷移バッファ: バックグラウンドでのメディア再生中に一時的な読み上げが完了すると、入力フォーカスは投影されたアクティビティに一時的に残ります。バッファ期間は、ユーザーが読み上げをミュートしようとして音楽トラックをスキップしてしまうなど、誤った入力の防止に役立ちます。移行バッファの後、システムはアプリの投影されたアクティビティを停止し、入力フォーカスをメディア コントロールにルーティングします。
  • アイドル状態の投影アクティビティが停止または一時停止される: システムは、アクティブなデータ ストリームがないアイドル状態の投影アクティビティを数分後に停止します(一時停止中のメディア出力は、一時的に停止します)。

入力フォーカスの遷移の実践

同時実行状態間で入力フォーカスがどのように移行するかを理解するために、ターンバイターン方式のガイダンスを提供するナビゲーション アプリの次のシナリオ例を考えてみましょう。

シナリオ A: 非同時(非アクティブなメディア)

このシナリオでは、システムは入力をナビゲーション アプリにルーティングします。ナビゲーション アプリは、移動全体を通じてユーザーを認識しています。

図 1. この非同時実行シナリオで、ナビゲーション アプリに入力フォーカスがどのようにルーティングされるか。
  1. ユーザーがバックグラウンド ミュージックを再生せずにナビゲーションを開始します。
  2. ナビゲーション アプリが、オーディオ グラスに投影されたアクティビティを起動します。
  3. アクティブなメディア セッションがないため、ナビゲーション アプリは移動中ずっとタッチパッドの入力フォーカスを維持します。
  4. ユーザーの操作: 読み上げ中にタップすると、案内がミュートされることがあります。 無音時にタップすると、最後の指示が繰り返されることがあります。

シナリオ B: 準同時(メディアの一時停止)

このシナリオでは、ナビゲーション アプリがユーザーの認識を得ていない場合、システムは入力をシステム メディア コントロールにルーティングします。

図 2. この半同時実行シナリオで、ナビゲーション アプリの入力フォーカスがどのようにルーティングされるか。
  1. バックグラウンド ミュージックが一時停止しているときに、ユーザーがナビゲーションを起動します。
  2. 読み上げの合間の無音期間中は、入力フォーカスはデフォルトでメディア コントロールに設定されます。
  3. ナビゲーション アプリが「500 フィート先を左折」と発話すると、入力フォーカスが取得されます。
  4. ユーザーの操作: 読み上げ中にタップすると、音声案内がミュートされる可能性があります。無音中にタップすると、音楽の再生が再開されます。

シナリオ C: 同時(アクティブなメディア)

このシナリオでは、ナビゲーション アプリがユーザーに認識されていないときは、システムは入力をシステム メディア コントロールにルーティングします。また、ナビゲーション アプリからの読み上げ中は、アクティブなメディア再生の音声がダッキングされます。

図 3. この同時実行シナリオで、ナビゲーション アプリの入力フォーカスがどのようにルーティングされるか。
  1. 音楽の再生中にナビゲーションを起動する。
  2. ルート案内を読み上げている間、システムはバックグラウンド オーディオをダッキングし、入力フォーカスをナビゲーション アプリに切り替えます。
  3. ユーザーの操作: 読み上げ中にタップすると、音声案内がミュートされる可能性があります。無音時にタップすると、メディアの再生を操作(一時停止または再開)できます。