Processar entrada física de óculos com áudio e tela virtual

Dispositivos XR relevantes
Estas orientações ajudam você a criar experiências para esses tipos de dispositivos XR.
Óculos de áudio e
vídeo

Para capturar e processar a entrada do usuário que é entregue à atividade projetada do app ou para implementar comportamentos personalizados do touchpad, use entradas de ponteiro indiretas. Para processar outros tipos de eventos (como a ação da câmera), consulte as seções a seguir neste guia.

Processar a ação da câmera

Sempre que um usuário pressiona o botão da câmera de um dispositivo, o sistema entrega um evento de entrada à atividade projetada do app como uma ação ProjectedInputEvent.ProjectedInputAction.TOGGLE_APP_CAMERA. O app pode observar essa ação usando um dispatcher dedicado:

@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!")
    }
}

Inspecionar eventos de movimento genéricos

Use dispatchGenericMotionEvent para inspecionar eventos de movimento genéricos entregues à atividade projetada do app. Os eventos de movimento genéricos são entregues no limite da atividade e não exigem um componente Glimmer do Jetpack Compose com foco.

Um MotionEvent pode incluir:

Nem todos os valores são significativos para todas as ações. Inspecione a ação e a origem antes de tratar um evento bruto como um gesto concluído.

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)
    }
}

Retorne true somente quando a atividade consumir intencionalmente o evento. Caso contrário, retorne super.dispatchGenericMotionEvent(ev) para que o evento possa continuar com o envio normal.

Processar o gesto "Voltar" do sistema

Quando uma tela precisa de um comportamento de retorno personalizado, o app precisa processar o gesto "Voltar" dos óculos usando as mesmas APIs Android que você usa para outras atividades, como OnBackPressedDispatcher e OnBackPressedCallback.

O gesto do usuário depende do tipo de óculos:

  • Em óculos com tela virtual, deslizar para baixo no touchpad executa o gesto "Voltar" do sistema.
  • Em óculos com áudio, deslizar para trás no touchpad executa o gesto "Voltar" do sistema.

Registre um callback de retorno quando a tela atual precisar interceptar o botão "Voltar", como fechar uma sobreposição ou mostrar uma confirmação de saída.

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")
    }
}

O callback só precisa ser ativado quando a tela ativa interceptar o botão "Voltar". Desative ou remova o callback quando o comportamento padrão do sistema ou de navegação precisar processar o botão "Voltar".

Próximas etapas

Depois de implementar o processamento de entrada para esses eventos, você pode saber mais sobre como processar outros tipos de eventos de entrada nos tópicos a seguir: