使用投影的上下文来访问 AI 眼镜硬件

适用的 XR 设备
本指南可帮助您为这些类型的 XR 设备打造体验。
AI 眼镜

请求并获得必要的权限后,您的应用便可访问 AI 眼镜硬件。访问眼镜硬件(而非手机硬件)的关键在于使用投影上下文

获取投影上下文主要有两种方式,具体取决于代码的执行位置:

如果您的代码在 AI 眼镜 activity 中运行,则获取预测的上下文

如果您的应用代码是从 AI 眼镜 activity 中运行的,那么其自身的 activity 上下文已是投影上下文。在这种情况下,在该 activity 内进行的调用已可访问眼镜的硬件。

如果您的代码在手机应用组件中运行,则获取投影的上下文

如果应用中 AI 眼镜 activity 之外的部分(例如手机 activity 或服务)需要访问眼镜的硬件,则必须明确获取投影的 context。为此,请使用 createProjectedDeviceContext() 方法:

// From a phone Activity, get a context for the AI glasses
try {
    val glassesContext = ProjectedContext.createProjectedDeviceContext(this)
    // Now use glassesContext to access glasses' system services
} catch (e: IllegalStateException) {
    // Projected device was not found
}

检查有效性

创建预测性上下文后,监控 ProjectedContext.isProjectedDeviceConnected。虽然此方法返回 true,但投影的上下文对已连接的设备仍然有效,并且手机应用 activity 或服务(例如 CameraManager)可以访问 AI 眼镜硬件。

断开连接时清理

投影的上下文与所连接设备的生命周期相关联,因此会在设备断开连接时被销毁。当设备断开连接时,ProjectedContext.isProjectedDeviceConnected 会返回 false。您的应用应监听此更改,并清理使用该投影上下文创建的任何系统服务(例如 CameraManager)或资源。

重新连接时重新初始化

当 AI 眼镜设备重新连接时,您的应用可以使用 createProjectedDeviceContext() 获取另一个投影的上下文实例,然后使用新的投影上下文重新初始化任何系统服务或资源。

使用蓝牙访问音频

目前,AI 眼镜会以标准蓝牙音频设备的形式连接到手机。同时支持耳机和 A2DP(高级音频分发配置文件)配置文件。通过这种方法,任何支持音频输入或输出的 Android 应用都可以在眼镜上运行,即使这些应用并非专门为支持眼镜而构建。在某些情况下,使用蓝牙可能比使用投影上下文访问眼镜的硬件更适合应用的用例。

与任何标准蓝牙音频设备一样,授予 RECORD_AUDIO 权限的权限由手机控制,而不是眼镜。

使用 AI 眼镜的摄像头拍摄图片

如需使用 AI 眼镜的相机拍摄照片,请使用应用的正确上下文设置 CameraX 的 ImageCapture 用例并将其绑定到眼镜的相机:

private fun startCamera() {
    // Get the CameraProvider using the projected context.

    val cameraProviderFuture = ProcessCameraProvider.getInstance(
        ProjectedContext.createProjectedDeviceContext(this)
    )

    cameraProviderFuture.addListener({
        // Used to bind the lifecycle of cameras to the lifecycle owner
        val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()

        // Select the camera. When using the projected context, DEFAULT_BACK_CAMERA maps to the AI glasses' camera.
        val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
    
        // Check for the presence of a camera before initializing the ImageCapture use case.
       if (!cameraProvider.hasCamera(cameraSelector)) {
            Log.w(TAG, "The selected camera is not available.")
            return@addListener
        }

        // Get supported streaming resolutions.
        val cameraInfo = cameraProvider.getCameraInfo(cameraSelector)
        val camera2CameraInfo = Camera2CameraInfo.from(cameraInfo)
        val cameraCharacteristics = camera2CameraInfo.getCameraCharacteristic(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)

        // 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()

        // 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, 30)
        val captureRequestOptions = CaptureRequestOptions.Builder()
                .setCaptureRequestOption(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE,fpsRange)
                .build()

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

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

            // 4. Bind use cases to camera
            cameraProvider.bindToLifecycle(this as LifecycleOwner, cameraSelector, imageCapture)

        } catch(exc: Exception) {
            // This catches exceptions like IllegalStateException if use case binding fails
            Log.e(TAG, "Use case binding failed", exc)
        }

    }, ContextCompat.getMainExecutor(this))
}

代码要点

设置好 AI 眼镜的摄像头后,您可以使用 CameraX 的 ImageCapture 类拍摄图片。请参阅 CameraX 的文档,了解如何使用 takePicture() 拍摄图片

使用 AI 眼镜的摄像头拍摄视频

如需使用 AI 眼镜的摄像头拍摄视频而非图片,请将 ImageCapture 组件替换为相应的 VideoCapture 组件,并修改拍摄执行逻辑。

主要变化包括使用不同的使用情形、创建不同的输出文件,以及使用适当的视频录制方法来启动捕获。 如需详细了解 VideoCapture API 及其使用方法,请参阅 CameraX 的视频拍摄文档

下表显示了建议的分辨率和帧速率,具体取决于应用的使用情形:

用例 分辨率 帧速率
视频通信 1280x720 15 FPS
计算机视觉 640 x 480 10 FPS
AI 视频串流 640 x 480 1 FPS

从 AI 眼镜 activity 访问手机的硬件

AI 眼镜活动还可以使用 createHostDeviceContext(context) 获取宿主设备(手机)的上下文,从而访问手机的硬件(例如摄像头或麦克风):

// From an AI glasses Activity, get a context for the phone
val phoneContext = ProjectedContext.createHostDeviceContext(this)
// Now use phoneContext to access the phone's hardware

在混合应用(同时包含移动设备和 AI 眼镜体验的应用)中访问主机设备(手机)特有的硬件或资源时,您必须明确选择正确的上下文,以确保应用可以访问正确的硬件: