オーディオ グラスとディスプレイ グラスからの物理入力を処理する

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

アプリの投影されたアクティビティに配信されるユーザー入力をキャプチャして処理する場合や、カスタムのタッチパッド動作を実装する場合は、間接ポインタ入力を使用します。他のタイプのイベント(カメラ アクションなど)を処理するには、このガイドの以下のセクションをご覧ください。

カメラのアクションを処理する

ユーザーがデバイスのカメラボタンを押すたびに、システムは入力イベントをアプリのプロジェクション アクティビティに ProjectedInputEvent.ProjectedInputAction.TOGGLE_APP_CAMERA アクションとして配信します。アプリは、専用のディスパッチャを使用してこのアクションをモニタリングできます。

@OptIn(ExperimentalProjectedApi::class)
class CameraActionInputSnippetActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Observe hardware camera action events when RESUMED
        lifecycleScope.launch {
            repeatOnLifecycle(Lifecycle.State.RESUMED) {
                withContext(Dispatchers.Default) {
                    try {
                        val projectedActivity = ProjectedActivityCompat.create(this@CameraActionInputSnippetActivity)
                        try {
                            projectedActivity.projectedInputEvents.collect { inputEvent ->
                                if (inputEvent.inputAction == TOGGLE_APP_CAMERA) {
                                    withContext(Dispatchers.Main) {
                                        onCameraActionTriggered()
                                    }
                                }
                            }
                        } finally {
                            projectedActivity.close()
                        }
                    } catch (e: CancellationException) {
                        throw e
                    } catch (e: Exception) {
                        Log.w("CameraActionSnippet", "ProjectedActivityCompat unavailable: ${e.message}")
                    }
                }
            }
        }

        setContent {
            GlimmerTheme {
                TouchpadInputSnippet(
                    onTap = { Log.i("CameraActionSnippet", "Touchpad tapped") }
                )
            }
        }
    }

    private fun onCameraActionTriggered() {
        Log.i("CameraActionSnippet", "Camera action button double-pressed!")
    }
}

一般的なモーション イベントを検査する

dispatchGenericMotionEvent を使用して、アプリのプロジェクション アクティビティに配信された汎用モーション イベントを検査します。汎用モーション イベントはアクティビティ境界で配信され、フォーカスされた Jetpack Compose Glimmer コンポーネントを必要としません。

MotionEvent には次のものを含めることができます。

すべての値がすべてのアクションで意味を持つわけではありません。未加工のイベントを完了した操作として扱う前に、アクションとソースを検査します。

class MotionGestureInputSnippetActivity : ComponentActivity() {

    override fun dispatchGenericMotionEvent(ev: MotionEvent): Boolean {
        val actionName = when (ev.actionMasked) {
            MotionEvent.ACTION_DOWN -> "ACTION_DOWN" // First contact with the glasses touchpad
            MotionEvent.ACTION_MOVE -> "ACTION_MOVE" // Contact moving across the glasses touchpad
            MotionEvent.ACTION_UP -> "ACTION_UP"     // Contact lifted from the glasses touchpad
            else -> "ACTION_${ev.actionMasked}"
        }

        Log.d(
            "MotionGestureSnippet",
            "MotionEvent: action=$actionName x=${ev.x} y=${ev.y}"
        )

        // Delegate to super unless intentionally consuming the event
        return super.dispatchGenericMotionEvent(ev)
    }
}

アクティビティがイベントを意図的に消費する場合にのみ true を返します。それ以外の場合は、super.dispatchGenericMotionEvent(ev) を返して、通常のディスパッチでイベントを続行できるようにします。

システムの「戻る」ジェスチャーを処理する

画面でカスタムの戻る動作が必要な場合、アプリは、OnBackPressedDispatcherOnBackPressedCallback など、他のアクティビティで使用するのと同じ Android API を使用して、メガネの戻るジェスチャーを処理する必要があります。

ユーザー ジェスチャーはメガネの種類によって異なります。

  • ディスプレイ グラスでは、タッチパッドを下にスワイプすると、システムの戻る操作が実行されます。
  • オーディオ グラスでは、タッチパッドを逆方向にスワイプすると、システムの戻る操作が実行されます。

現在の画面で戻るボタンをインターセプトする必要がある場合(オーバーレイを閉じる、終了確認を表示するなど)に、戻るコールバックを登録します。

class BackGestureInputSnippetActivity : ComponentActivity() {

    private val backCallback = object : OnBackPressedCallback(true) {
        override fun handleOnBackPressed() {
            onBackGestureReceived()
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Register back gesture callback with Activity's onBackPressedDispatcher
        onBackPressedDispatcher.addCallback(this, backCallback)
    }

    private fun onBackGestureReceived() {
        Log.i("BackGestureSnippet", "System back gesture intercepted")
    }
}

コールバックは、アクティブな画面が Back をインターセプトする必要がある場合にのみ有効にする必要があります。デフォルトのシステムまたはナビゲーションの動作で「戻る」を処理する必要がある場合は、コールバックを無効にするか削除します。

次のステップ

これらのイベントの入力処理を実装したら、以下のトピックで他の種類の入力イベントの処理について詳しく学ぶことができます。