在您请求并获得必要的权限后,您的应用 即可访问 AI 眼镜硬件。访问眼镜硬件 (而不是手机硬件)的关键是使用投影上下文。
根据代码的执行位置,您可以通过以下两种主要方式获取投影上下文:
如果代码在 AI 眼镜 activity 中运行,请获取投影上下文
如果应用的代码在 AI 眼镜 activity 中运行,则其自身的 activity 上下文已是投影上下文。在这种情况下,在该 activity 中进行的调用已可以访问眼镜的硬件。
为在手机应用组件中运行的代码获取投影上下文
如果 AI 眼镜 activity 之外的应用部分(例如手机 activity 或服务)需要访问眼镜的硬件,则必须明确获取投影上下文。为此,请使用
createProjectedDeviceContext() 方法:
@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 } }
检查有效性
创建投影上下文后,请监控
ProjectedContext.isProjectedDeviceConnected。当此方法返回 true 时,投影上下文对已连接的设备仍然有效,并且您的手机应用活动或服务(例如 CameraManager)可以访问 AI 眼镜硬件。
断开连接时清理
投影上下文与已连接的设备的生命周期相关联,因此会在设备断开连接时被销毁。当设备断开连接时,
ProjectedContext.isProjectedDeviceConnected 会返回 false。您的应用应监听此更改,并清理应用使用该投影上下文创建的任何系统服务(例如 CameraManager)或资源。
重新连接时重新初始化
当 AI 眼镜设备重新连接时,您的应用可以使用 createProjectedDeviceContext() 获取另一个投影
上下文实例,然后
使用新的投影上下文重新初始化任何系统服务或资源。
使用蓝牙访问音频
目前,AI 眼镜作为标准蓝牙音频设备连接到您的手机。耳机和 A2DP(高级音频分发配置文件) 配置文件均受支持。使用此方法,任何支持音频输入或输出的 Android 应用都可以在眼镜上运行,即使这些应用并非专门为支持眼镜而构建也是如此。在某些情况下,使用蓝牙可能比使用投影上下文访问眼镜硬件更适合您的应用用例。
与任何标准蓝牙音频设备一样,授予
RECORD_AUDIO权限的权限由手机控制,而不是由眼镜控制。
使用 AI 眼镜的相机拍摄图片
如需使用 AI 眼镜的相机拍摄图片,请使用应用的正确
上下文设置 CameraX 的
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)) }
代码要点
- 使用
投影设备上下文 获取
ProcessCameraProvider的实例。 - 在投影上下文的范围内,选择相机时,AI 眼镜的主摄像头(指向外部)会映射到
DEFAULT_BACK_CAMERA。 - 预绑定检查使用
cameraProvider.hasCamera(cameraSelector)来 验证所选相机在设备上是否可用,然后再 继续。 - 使用 Camera2 Interop 和
Camera2CameraInfo读取 底层CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP, 这对于对受支持分辨率进行高级检查非常有用。 - 构建自定义
ResolutionSelector以精确控制输出 图片分辨率,用于ImageCapture。 - 创建使用自定义
ResolutionSelector配置的ImageCapture用例。 - 将
ImageCapture用例绑定到 activity 的生命周期。这会根据 activity 的状态自动管理相机的打开和关闭(例如,在 activity 暂停时停止相机)。
设置 AI 眼镜的相机后,您可以使用 CameraX 的 ImageCapture 类拍摄图片。如需了解
如何使用 takePicture() 来拍摄图片,请参阅 CameraX 的文档。
使用 AI 眼镜的相机拍摄视频
如需使用 AI 眼镜的相机拍摄视频而不是图片,请将
ImageCapture 组件替换为相应的 VideoCapture 组件
并修改拍摄执行逻辑。
主要更改包括使用不同的用例、创建不同的输出文件,以及使用适当的视频录制方法启动拍摄。
如需详细了解 VideoCapture API 及其使用方法,请参阅
CameraX 的视频拍摄文档。
下表显示了根据应用用例推荐的分辨率和帧速率:
| 用例 | 分辨率 | 帧速率 |
|---|---|---|
| 视频通信 | 1280 x 720 | 15 FPS |
| 计算机视觉 | 640 x 480 | 10 FPS |
| AI 视频流式传输 | 640 x 480 | 1 FPS |
从 AI 眼镜 activity 访问手机的硬件
AI 眼镜 activity 还可以使用 createHostDeviceContext(context) 获取主机
设备(手机)的上下文,从而访问手机的硬件(例如相机
或麦克风):
@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 } }
在混合应用(同时包含移动设备和 AI 眼镜体验的应用)中访问特定于主机设备(手机)的硬件或资源时,您必须明确选择正确的上下文,以确保应用可以访问正确的硬件:
- 使用手机
Activity中的Activity上下文或ProjectedContext.createHostDeviceContext()获取手机的 上下文。 - 请勿使用
getApplicationContext(),因为应用上下文如果眼镜 Activity 是最近启动的组件,可能会错误地返回 AI 眼镜的上下文。