与手机一样,访问音频眼镜和显示眼镜上的摄像头和麦克风等敏感硬件需要征得用户的明确同意。 这些权限被视为眼镜专用权限,即使您的应用已在手机上获得相应的权限,也必须在运行时请求这些权限。
在应用的清单中声明权限
在请求权限之前,您必须使用 <uses-permission> 元素在应用的清单中声明这些权限。无论权限是针对手机还是眼镜专用功能,此声明都保持不变,但您仍必须针对眼镜专用硬件或功能明确请求该权限。
<manifest ...>
<!-- Only declare permissions that your app actually needs. In this example,
we declare permissions for the camera. -->
<uses-permission android:name="android.permission.CAMERA"/>
<application ...>
...
</application>
</manifest>
在请求眼镜权限之前
请查看权限原则和工作流,确保您为用户提供出色的体验,例如检查用户是否已授予应用所需的运行时权限,以及应用是否应在请求眼镜专用权限之前向用户显示理由。
权限情景
在音频眼镜和显示眼镜上请求危险的运行时权限时,您可能会遇到以下几种情况:
- 从投射的 activity 请求运行时权限
- 从手机 activity 请求运行时权限
如需详细了解每种情况,请参阅本指南中的以下部分。
从投影的 activity 请求运行时权限
如需从投影的 activity 请求音频或显示眼镜的运行时权限,请使用 ProjectedActivityCompat.requestPermissions 方法。
调用此方法会触发眼镜和宿主手机之间的协调用户流程。
- 在眼镜上:系统会在眼镜上打开一个投影的配套 activity,指示用户检查手机以响应权限请求。
- 在手机上:手机屏幕上会显示 Android 系统权限对话框。该对话框明确指出,用户授予的是眼镜的权限,而不是手机本身的权限。然后,用户可以授予或拒绝该请求。
以下示例展示了如何从投影的 activity 请求眼镜权限:
@RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) private fun requestCameraPermission() { lifecycleScope.launch { try { ProjectedActivityCompat.requestPermissions( this@PermissionsFromProjectedActivity, arrayOf(Manifest.permission.CAMERA), // CAMERA_PERMISSION_REQUEST_CODE is a developer defined constant CAMERA_PERMISSION_REQUEST_CODE, ) } catch (e: IllegalStateException) { // Thrown when the projected system service can't be bound. Log.e(TAG, "Camera permission request failed: projected service unavailable.", e) } } }
代码要点
- 使用
ProjectedActivityCompat.requestPermissions,而不是标准ActivityCompat方法。此方法会明确针对音频和带屏眼镜的运行时权限,而不是主机手机。
处理权限结果
用户在手机上响应权限对话框后,系统会通过调用 onRequestPermissionsResult 回调将用户的决定传递给您的应用。
系统会自动关闭投屏的辅助活动。在音频眼镜上,此操作会在音频提醒播放完毕后发生。在显示眼镜上,它会在用户响应所有权限对话框后发生。
如需处理响应,请在发起权限请求的 Activity 实例中替换 onRequestPermissionsResult()。
以下代码段展示了如何处理回调并验证用户是否授予了所请求的权限:
@RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) override fun onRequestPermissionsResult( requestCode: Int, permissions: Array<String>, grantResults: IntArray, deviceId: Int, ) { super.onRequestPermissionsResult(requestCode, permissions, grantResults, deviceId) if (requestCode != CAMERA_PERMISSION_REQUEST_CODE) return val isCameraGranted = grantResults.getOrNull(permissions.indexOf(Manifest.permission.CAMERA)) == PackageManager.PERMISSION_GRANTED if (isCameraGranted) { initializeCameraFeatures() } else { onCameraPermissionDenied() } }
代码要点
- 使用
deviceId重载和onRequestPermissionsResult回调,以确保权限状态正确映射到特定情境,例如音频或显示眼镜,而不是主机手机。 - 您的应用应妥善处理授予和拒绝的结果。
在手机 activity 中请求运行时权限
如果您的应用在手机 activity 中运行,但需要音频或显示眼镜的权限(例如,允许用户将视频流切换到眼镜的摄像头以获得第一人称视角),请使用特定于设备的 Activity#requestPermissions(permissions, requestCode,
deviceId) 方法请求权限:
// Request the projected permission from phone activity requestPermissions( arrayOf(Manifest.permission.CAMERA), // REQUEST_CODE_GLASSES_CAMERA is a developer-defined constant REQUEST_CODE_GLASSES_CAMERA, projectedDeviceId )
代码要点
- 如需以音频眼镜和显示眼镜为目标平台,请从使用
createProjectedDeviceContext创建的投影上下文中获取相应的设备 ID。在调用requestPermissions方法时传递此 ID。
处理权限结果
用户在手机上响应权限对话框后,系统会通过调用 onRequestPermissionsResult 回调将用户的决定传递给您的应用。
如需处理响应,请在发起权限请求的 Activity 实例中替换 onRequestPermissionsResult。
以下代码段展示了如何处理回调并验证用户是否授予了所请求的权限:
@RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) override fun onRequestPermissionsResult( requestCode: Int, permissions: Array<String>, grantResults: IntArray, deviceId: Int, ) { super.onRequestPermissionsResult(requestCode, permissions, grantResults, deviceId) if (requestCode != CAMERA_PERMISSION_REQUEST_CODE) return val isCameraGranted = grantResults.getOrNull(permissions.indexOf(Manifest.permission.CAMERA)) == PackageManager.PERMISSION_GRANTED if (isCameraGranted) { initializeCameraFeatures() } else { onCameraPermissionDenied() } }
代码要点
- 使用带有
onRequestPermissionsResult回调的deviceId重载,确保权限状态正确映射到特定上下文,例如音频或带屏眼镜,而不是主机手机。 - 您的应用应妥善处理授予和拒绝的结果。