Usar un contexto proyectado para acceder al hardware de los lentes con IA

Dispositivos de realidad extendida correspondientes
Esta guía te ayuda a crear experiencias para estos tipos de dispositivos de realidad extendida.
Lentes de IA

Después de solicitar y obtener los permisos necesarios, tu app puede acceder al hardware de los lentes de IA. La clave para acceder al hardware de los lentes (en lugar del hardware del teléfono) es usar un contexto proyectado.

Existen dos formas principales de obtener un contexto proyectado, según dónde se ejecute el código:

Obtén un contexto proyectado si tu código se ejecuta en una actividad de lentes de IA

Si el código de tu app se ejecuta desde la actividad de los lentes de IA, su propio contexto de actividad ya es un contexto proyectado. En este caso, las llamadas realizadas dentro de esa actividad ya pueden acceder al hardware de los lentes.

Obtén un contexto proyectado para el código que se ejecuta en un componente de la app para teléfonos

Si una parte de tu app fuera de la actividad de los lentes de IA (como una actividad del teléfono o un servicio) necesita acceder al hardware de los lentes, debe obtener explícitamente un contexto proyectado. Para ello, usa el 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
    }
}

Verifica la validez

Después de crear el contexto proyectado, supervisa ProjectedContext.isProjectedDeviceConnected. Mientras este método muestra true, el contexto proyectado sigue siendo válido para el dispositivo conectado, y la actividad o el servicio de la app para teléfonos (como CameraManager) pueden acceder al hardware de los lentes de IA.

Realiza una limpieza al desconectar

El contexto proyectado está vinculado al ciclo de vida del dispositivo conectado, por lo que se destruye cuando se desconecta el dispositivo. Cuando el dispositivo se desconecta, ProjectedContext.isProjectedDeviceConnected muestra false. Tu app debe detectar este cambio y limpiar cualquier servicio del sistema (como CameraManager) o recursos que haya creado con ese contexto proyectado.

Reinicializa al volver a conectar

Cuando se vuelve a conectar el dispositivo de lentes de IA, tu app puede obtener otra instancia de contexto proyectado con createProjectedDeviceContext() y, luego , reinicializar cualquier servicio o recurso del sistema con el nuevo contexto proyectado.

Accede al audio con Bluetooth

Actualmente, los lentes de IA se conectan a tu teléfono como un dispositivo de audio Bluetooth estándar. Se admiten los perfiles de auriculares y A2DP (perfil de distribución de audio avanzado) profiles. Con este enfoque, cualquier app para Android que admita entrada o salida de audio puede funcionar en los lentes, incluso si no se crearon específicamente para admitirlos. En algunos casos, usar Bluetooth puede funcionar mejor para el caso de uso de tu app como alternativa para acceder al hardware de los lentes con un contexto proyectado.

Al igual que con cualquier dispositivo de audio Bluetooth estándar, el permiso para otorgar el RECORD_AUDIO lo controla el teléfono y no los lentes.

Captura una imagen con la cámara de los lentes de IA

Para capturar una imagen con la cámara de los lentes de IA, configura y vincula el caso de uso `ImageCapture` de CameraX a la cámara de los lentes con el contexto correcto para tu 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))
}

Puntos clave sobre el código

  • Obtiene una instancia de ProcessCameraProvider con el contexto del dispositivo proyectado.
  • Dentro del alcance del contexto proyectado, la cámara principal de los lentes de IA, que apunta hacia afuera, se asigna a DEFAULT_BACK_CAMERA cuando se selecciona una cámara.
  • Una verificación previa a la vinculación usa cameraProvider.hasCamera(cameraSelector) para verificar que la cámara seleccionada esté disponible en el dispositivo antes de continuar.
  • Usa Camera2 Interop con Camera2CameraInfo para leer el CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP subyacente, que puede ser útil para verificaciones avanzadas de las resoluciones admitidas.
  • Se compila un ResolutionSelector personalizado para controlar con precisión la resolución de la imagen de salida para ImageCapture.
  • Crea un caso de uso ImageCapture que se configura con un ResolutionSelector personalizado.
  • Vincula el caso de uso ImageCapture al ciclo de vida de la actividad. Esto administra automáticamente la apertura y el cierre de la cámara según el estado de la actividad (por ejemplo, detiene la cámara cuando se pausa la actividad).

Después de configurar la cámara de los lentes de IA, puedes capturar una imagen con la clase ImageCapture de CameraX. Consulta la documentación de CameraX para obtener información sobre el uso de takePicture() para capturar una imagen.

Captura un video con la cámara de los lentes de IA

Para capturar un video en lugar de una imagen con la cámara de los lentes de IA, reemplaza los ImageCapture componentes con los componentes VideoCapture correspondientes y modifica la lógica de ejecución de captura.

Los cambios principales implican usar un caso de uso diferente, crear un archivo de salida diferente y iniciar la captura con el método de grabación de video adecuado. Para obtener más información sobre la API de VideoCapture y cómo usarla, consulta la documentación de captura de video de CameraX.

En la siguiente tabla, se muestran la resolución y la velocidad de fotogramas recomendadas según el caso de uso de tu app:

Caso de uso Resolución Velocidad de fotogramas
Comunicación por video 1280 x 720 15 FPS
Visión artificial 640 x 480 10 FPS
Transmisión de video con IA 640 x 480 1 FPS

Accede al hardware de un teléfono desde una actividad de lentes de IA

Una actividad de lentes de IA también puede acceder al hardware del teléfono (como la cámara o el micrófono) con createHostDeviceContext(context) para obtener el contexto del dispositivo host (teléfono):

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

Cuando accedas a hardware o recursos específicos del dispositivo host (teléfono) en una app híbrida (una app que contiene experiencias para dispositivos móviles y lentes de IA), debes seleccionar explícitamente el contexto correcto para asegurarte de que tu app pueda acceder al hardware correcto: