Usar um contexto projetado para acessar o hardware dos óculos de IA

Dispositivos XR relevantes
Estas orientações ajudam você a criar experiências para esses tipos de dispositivos XR.
Óculos de IA

Depois de solicitar e receber as permissões necessárias, seu app poderá acessar o hardware dos óculos com IA. A chave para acessar o hardware dos óculos (em vez do hardware do smartphone) é usar um contexto projetado.

Há duas maneiras principais de receber um contexto projetado, dependendo de onde o código está sendo executado:

Receber um contexto projetado se o código estiver sendo executado em uma atividade de óculos com IA

Se o código do app estiver sendo executado na atividade dos óculos com IA, o próprio contexto da atividade já será um contexto projetado. Nesse cenário, as chamadas feitas nessa atividade já podem acessar o hardware dos óculos.

Receber um contexto projetado para código em execução em um componente de app para smartphone

Se uma parte do app fora da atividade dos óculos com IA (como uma atividade ou um serviço de smartphone) precisar acessar o hardware dos óculos, ela precisará receber um contexto projetado explicitamente. Para fazer isso, use o createProjectedDeviceContext() método:

@OptIn(ExperimentalProjectedApi::class)
private fun getGlassesContext(context: Context): Context? {
    return try {
        // From a phone Activity or Service, get a context for the AI glasses.
        ProjectedContext.createProjectedDeviceContext(context)
    } catch (e: IllegalStateException) {
        Log.e(TAG, "Failed to create projected device context", e)
        null
    }
}

Verificar a validade

Encapsule a chamada createProjectedDeviceContext em ProjectedContext.isProjectedDeviceConnected. Enquanto esse método retornar true, o contexto projetado permanecerá válido para o dispositivo conectado, e a atividade ou o serviço do app para smartphone (como um CameraManager) poderá acessar o hardware dos óculos com IA.

Limpar na desconexão

O contexto projetado está vinculado ao ciclo de vida do dispositivo conectado. Portanto, ele é destruído quando o dispositivo é desconectado. Quando o dispositivo é desconectado, ProjectedContext.isProjectedDeviceConnected retorna false. O app precisa detectar essa mudança e limpar todos os serviços do sistema (como um CameraManager) ou recursos criados pelo app usando esse contexto projetado.

Reinicializar na reconexão

Quando o dispositivo de óculos com IA se reconectar, o app poderá receber outra instância de contexto projetado usando createProjectedDeviceContext() e, em seguida, reinicializar todos os serviços ou recursos do sistema usando o novo contexto projetado.

Acessar áudio usando o Bluetooth

Atualmente, os óculos com IA se conectam ao smartphone como um dispositivo de áudio Bluetooth padrão. Os perfis de fone de ouvido e A2DP (Advanced Audio Distribution Profile) são compatíveis. Essa abordagem permite que qualquer app Android compatível com entrada ou saída de áudio funcione em óculos, mesmo que não tenham sido criados propositadamente para oferecer suporte a óculos. Em alguns casos, o uso do Bluetooth pode funcionar melhor para o caso de uso do app como uma alternativa ao acesso ao hardware dos óculos usando um contexto projetado.

Como acontece com qualquer dispositivo de áudio Bluetooth padrão, a permissão para conceder a RECORD_AUDIO permissão é controlada pelo smartphone, e não pelos óculos.

Capturar uma imagem com a câmera dos óculos com IA

Para capturar uma imagem com a câmera dos óculos com IA, configure e vincule o caso de uso `ImageCapture` do CameraX à câmera dos óculos usando o contexto correto para seu app:ImageCapture

private fun startCameraOnGlasses(activity: ComponentActivity) {
    // 1. Get the CameraProvider using the projected context.
    // When using the projected context, DEFAULT_BACK_CAMERA maps to the AI glasses' camera.
    val projectedContext = try {
        ProjectedContext.createProjectedDeviceContext(activity)
    } catch (e: IllegalStateException) {
        Log.e(TAG, "AI Glasses context could not be created", e)
        return
    }

    val cameraProviderFuture = ProcessCameraProvider.getInstance(projectedContext)

    cameraProviderFuture.addListener({
        val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
        val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA

        // 2. Check for the presence of a camera.
        if (!cameraProvider.hasCamera(cameraSelector)) {
            Log.w(TAG, "The selected camera is not available.")
            return@addListener
        }

        // 3. Query supported streaming resolutions using Camera2 Interop.
        val cameraInfo = cameraProvider.getCameraInfo(cameraSelector)
        val camera2CameraInfo = Camera2CameraInfo.from(cameraInfo)
        val cameraCharacteristics = camera2CameraInfo.getCameraCharacteristic(
            CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP
        )

        // 4. Define the resolution strategy.
        val targetResolution = Size(1920, 1080)
        val resolutionStrategy = ResolutionStrategy(
            targetResolution,
            ResolutionStrategy.FALLBACK_RULE_CLOSEST_LOWER
        )
        val resolutionSelector = ResolutionSelector.Builder()
            .setResolutionStrategy(resolutionStrategy)
            .build()

        // 5. If you have other continuous use cases bound, such as Preview or ImageAnalysis,
        // you can use  Camera2 Interop's CaptureRequestOptions to set the FPS
        val fpsRange = Range(30, 60)
        val captureRequestOptions = CaptureRequestOptions.Builder()
            .setCaptureRequestOption(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, fpsRange)
            .build()

        // 6. Initialize the ImageCapture use case with options.
        val imageCapture = ImageCapture.Builder()
            // Optional: Configure resolution, format, etc.
            .setResolutionSelector(resolutionSelector)
            .build()

        try {
            // Unbind use cases before rebinding.
            cameraProvider.unbindAll()

            // Bind use cases to camera using the Activity as the LifecycleOwner.
            cameraProvider.bindToLifecycle(
                activity,
                cameraSelector,
                imageCapture
            )
        } catch (exc: Exception) {
            Log.e(TAG, "Use case binding failed", exc)
        }
    }, ContextCompat.getMainExecutor(activity))
}

Principais pontos sobre o código

  • Recebe uma instância do ProcessCameraProvider usando o contexto do dispositivo projetado.
  • No escopo do contexto projetado, a câmera principal dos óculos com IA, voltada para fora, é mapeada para DEFAULT_BACK_CAMERA ao selecionar uma câmera.
  • Uma verificação de pré-vinculação usa cameraProvider.hasCamera(cameraSelector) para verificar se a câmera selecionada está disponível no dispositivo antes de continuar.
  • Usa o Camera2 Interop com Camera2CameraInfo para ler o CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP subjacente, que pode ser útil para verificações avançadas em resoluções compatíveis.
  • Um ResolutionSelector personalizado é criado para controlar com precisão a resolução da imagem de saída para ImageCapture.
  • Cria um caso de uso ImageCapture configurado com um ResolutionSelector personalizado.
  • Vincula o caso de uso ImageCapture ao ciclo de vida da atividade. Isso gerencia automaticamente a abertura e o fechamento da câmera com base no estado da atividade (por exemplo, interrompendo a câmera quando a atividade é pausada).

Depois que a câmera dos óculos com IA estiver configurada, você poderá capturar uma imagem com a classe ImageCapture do CameraX. Consulte a documentação do CameraX para saber como usar takePicture() para capturar uma imagem.

Capturar um vídeo com a câmera dos óculos com IA

Para capturar um vídeo em vez de uma imagem com a câmera dos óculos com IA, substitua os ImageCapture componentes pelos componentes VideoCapture correspondentes e modifique a lógica de execução da captura.

As principais mudanças envolvem o uso de um caso de uso diferente, a criação de um arquivo de saída diferente e a inicialização da captura usando o método de gravação de vídeo apropriado. Para mais informações sobre a API VideoCapture e como usá-la, consulte a documentação de captura de vídeo do CameraX.

A tabela a seguir mostra a resolução e o frame rate recomendados, dependendo do caso de uso do app:

Caso de uso Resolução Frame rate
Comunicação por vídeo 1280 x 720 15 FPS
Visão computacional 640 x 480 10 FPS
Streaming de vídeo com IA 640 x 480 1 FPS

Acessar o hardware de um smartphone em uma atividade de óculos com IA

Uma atividade de óculos com IA também pode acessar o hardware do smartphone (como a câmera ou microfone) usando createHostDeviceContext(context) para receber o contexto do dispositivo host (smartphone):

@OptIn(ExperimentalProjectedApi::class)
private fun getPhoneContext(activity: ComponentActivity): Context? {
    return try {
        // From an AI glasses Activity, get a context for the phone.
        ProjectedContext.createHostDeviceContext(activity)
    } catch (e: IllegalStateException) {
        Log.e(TAG, "Failed to create host device context", e)
        null
    }
}

Ao acessar hardware ou recursos específicos do dispositivo host (smartphone) em um app híbrido (um app que contém experiências para dispositivos móveis e óculos com IA), você precisa selecionar explicitamente o contexto correto para garantir que o app possa acessar o hardware correto: