Request hardware permissions for audio glasses and display glasses

Applicable XR devices
This guidance helps you build experiences for these types of XR devices.
Audio &
Display Glasses

Just like on a phone, accessing sensitive hardware like the camera and microphone on audio glasses and display glasses requires explicit user consent. These are considered glasses-specific permissions, and your app must request them at runtime, even if it already has the corresponding permissions on the phone.

Declare the permissions in your app's manifest

Before requesting permissions, you must declare them in your app's manifest file using the <uses-permission> element. This declaration remains the same whether the permission is for a phone or a glasses-specific feature, but you must still explicitly request it for glasses-specific hardware or functionality.

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

Before requesting glasses permissions

Review the permission principles and workflows to make sure you provide the best experience for your users, like checking whether the user has already granted the runtime permissions your app requires and whether your app should show a rationale to the user before requesting glasses-specific permissions.

Permission scenarios

There are different scenarios you might encounter when requesting dangerous runtime permissions on audio and display glasses:

  • Request runtime permissions from a projected activity
  • Request runtime permissions from a phone activity

See the following sections in this guide for details about each scenario.

Request runtime permissions from a projected activity

To request runtime permissions for audio or display glasses from a projected activity, use the ProjectedActivityCompat.requestPermissions method.

Calling this method triggers a coordinated user flow across both the glasses and the host phone.

  1. On the glasses: The system opens a projected companion activity on the glasses, instructing the user to check their phone to respond to the permission request.
  2. On the phone: An Android system permission dialog appears on the phone screen. The dialog explicitly indicates that the user is granting the permission for the glasses rather than the phone itself. The user can then grant or deny the request.

The following example shows how to request glasses permissions from a projected 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)
        }
    }
}

Key points about the code

  • Use ProjectedActivityCompat.requestPermissions instead of the standard ActivityCompat method. This method explicitly targets the runtime permissions for audio and display glasses rather than the host phone.

Handle the permission results

Once the user responds to the permission dialog on the phone, their decision is delivered to your app by invoking the onRequestPermissionsResult callback.

The system closes the projected companion activity automatically. On audio glasses, this occurs after the audio alert finishes playing. On display glasses, it happens after the user responds to all the permission dialogs.

To handle the response, override onRequestPermissionsResult() within the Activity instance that initiated the permission request.

The following code snippet shows how to handle the callback and verify whether the user granted the requested permissions:

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

Key points about the code
  • Use the deviceId overload with the onRequestPermissionsResult callback to ensure the permission status is correctly mapped to the specific context, such as the audio or display glasses rather than the host phone.
  • Your app should handle both granted and denied results gracefully.

Request runtime permissions in a phone activity

If your app is running in a phone activity but requires permissions for audio or display glasses—for example, to let a user switch a video stream to the glasses' camera for a first-person point of view—request the permissions using the device-specific Activity#requestPermissions(permissions, requestCode, deviceId) method:

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

Key points about the code

  • To target audio and display glasses, obtain the appropriate device ID from a projected context that you've created using createProjectedDeviceContext. Pass this ID with your call to the requestPermissions method.

Handle the permission results

Once the user responds to the permission dialog on the phone, their decision is delivered to your app by invoking the onRequestPermissionsResult callback.

To handle the response, override onRequestPermissionsResult within the Activity instance that initiated the permission request.

The following code snippet shows how to handle the callback and verify whether the user granted the requested permissions:

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

Key points about the code
  • Use the deviceId overload with the onRequestPermissionsResult callback to ensure the permission status is correctly mapped to the specific context, such as the audio or display glasses rather than the host phone.
  • Your app should handle both granted and denied results gracefully.