<br />


Applicable XR devices  
This guidance helps you build experiences for these types of XR devices.  
[Learn about XR device types →](https://developer.android.com/develop/xr/devices)  
![](https://developer.android.com/static/images/develop/xr/ai-glasses-icon.svg) AI Glasses [](https://developer.android.com/develop/xr/devices#ai-glasses)  
[Learn about XR device types →](https://developer.android.com/develop/xr/devices)

<br />

Just like on a phone, accessing sensitive hardware like the camera and
microphone on AI 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.

Follow this guide to:

- Declare permissions in your app's manifest
- Request permissions
- Learn about the permissions user flow

## Declare the permissions in your app's manifest

Before requesting permissions, you must [declare them in your app's manifest](https://developer.android.com/training/permissions/declaring)
file using the [`<uses-permission>`](https://developer.android.com/guide/topics/manifest/uses-permission-element) element. This declaration remains the
same whether the permission is for a phone or an AI-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 microphone. -->
        <uses-permission android:name="android.permission.RECORD_AUDIO"/>
        <application ...>
            ...
        </application>
    </manifest>

## Request permissions

To request permissions for AI glasses, you use the [`ActivityResultLauncher`](https://developer.android.com/reference/kotlin/androidx/activity/result/ActivityResultLauncher)
with the [`ProjectedPermissionsResultContract()`](https://developer.android.com/reference/kotlin/androidx/xr/projected/permissions/ProjectedPermissionsResultContract#ProjectedPermissionsResultContract()) method. You need to specify
which permissions your app requires, such as [`Manifest.permission.CAMERA`](https://developer.android.com/reference/kotlin/android/Manifest.permission#camera)
or [`Manifest.permission.RECORD_AUDIO`](https://developer.android.com/reference/kotlin/android/Manifest.permission#record_audio). Provide a clear and concise
rationale explaining why your app needs these permissions. This rationale is
displayed to the user to help them make an informed decision.  

    class SampleGlassesActivity : ComponentActivity() {

      // Register the permissions launcher
        private val requestPermissionLauncher: ActivityResultLauncher<List<ProjectedPermissionsRequestParams>> =
            registerForActivityResult(ProjectedPermissionsResultContract()) { results ->
                // Check the result for the specific RECORD_AUDIO permission
                if (results[Manifest.permission.RECORD_AUDIO] == true) {
                    onPermissionGranted()
                } else {
                    onPermissionDenied()
                }
            }

        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)

            // Audio permission is critical for the displayless AI glasses experience
            checkAndRequestAudioPermission()

            setContent {
                GlimmerTheme {
                    DisplayGlassesUi()
                }
            }
        }

        // Checks for the required RECORD_AUDIO permission and requests it if necessary.

        private fun checkAndRequestAudioPermission() {
            val permission = Manifest.permission.RECORD_AUDIO
            val permissionStatus = ContextCompat.checkSelfPermission(this, permission)

            if (permissionStatus == PackageManager.PERMISSION_GRANTED) {
                // Permission is already granted
                onPermissionGranted()
            } else {
                // Permission is not granted, request it
                requestAudioPermission()
            }
        }

        private fun requestAudioPermission() {
            val params = ProjectedPermissionsRequestParams(
                            permissions = listOf(Manifest.permission.RECORD_AUDIO),
                // The rationale should explain why this permission is needed.
                // For displayless AI glasses, it's often the main input mechanism.
                rationale = "Microphone access is essential for voice commands and features on these AI glasses."
            )
            requestPermissionLauncher.launch(listOf(params))
        }

        private fun onPermissionGranted() {
            // Implement the logic for when the permission is granted

        }

        private fun onPermissionDenied() {
            // Implement the logic for when the permission is denied.
            // On displayless AI glasses, if the app requires voice/mic it should exit the activity if the critical permission is denied.
            finish()
        }
    }

### Key points about the code

- We create an [`ActivityResultLauncher`](https://developer.android.com/reference/kotlin/androidx/activity/result/ActivityResultLauncher) using the [`ProjectedPermissionsResultContract()`](https://developer.android.com/reference/kotlin/androidx/xr/projected/permissions/ProjectedPermissionsResultContract#ProjectedPermissionsResultContract()) method. The callback receives a map of permission names to their granted status.
- The `requestAudioPermission()` function builds a [`ProjectedPermissionsRequestParams`](https://developer.android.com/reference/kotlin/androidx/xr/projected/permissions/ProjectedPermissionsRequestParams) object. This object bundles the list of permissions we need and the user-facing rationale.
- Calling `launch()` on the launcher triggers the [permission request user
  flow](https://developer.android.com/develop/xr/jetpack-xr-sdk/request-hardware-permissions#permissions-user-flow).
- Your app should handle both granted and denied results gracefully in the launcher's callback.

## Understand the permission request user flow

When you launch a permission request using the
[`ProjectedPermissionsResultContract()`](https://developer.android.com/reference/kotlin/androidx/xr/projected/permissions/ProjectedPermissionsResultContract#ProjectedPermissionsResultContract()) method, the system initiates a
coordinated user flow across both the AI glasses and the phone.

<br />

| **Important:** You should call the `ProjectedPermissionsResultContract` method from an [`Activity`](https://developer.android.com/reference/kotlin/android/app/Activity) displayed on AI glasses. Don't use the standard Android permission APIs (such as [`requestPermissions()`](https://developer.android.com/reference/kotlin/androidx/core/app/ActivityCompat#requestPermissions(android.app.Activity,%20java.lang.String%5B%5D,%20int)) with [`ActivityResultLauncher<String>`](https://developer.android.com/reference/kotlin/androidx/activity/result/ActivityResultLauncher)) in code running on the glasses. Doing so attempts to launch a non-interactable permission dialog on the glasses, breaking the user flow.
|
| <br />
|
| If your app already has an `Activity` displayed on the phone, you should use
| [`Activity#requestPermissions(permissions, requestCode, deviceId)`](https://developer.android.com/reference/kotlin/android/app/Activity#requestpermissions_1), where
| the `deviceId` comes from calling the [`getDeviceId()`](https://developer.android.com/reference/kotlin/android/content/Context#getdeviceid) method on the
| [`Context`](https://developer.android.com/reference/kotlin/android/content/Context) returned by calling
| [`ProjectedContext.createProjectedDeviceContext()`](https://developer.android.com/reference/kotlin/androidx/xr/projected/ProjectedContext#createProjectedDeviceContext(android.content.Context)).
|
| <br />
|
<br />

During the permissions user flow, here is what your app and the user can expect:

1. **On the AI glasses** : An activity appears on the **projected device
   (glasses)**, instructing the user to look at their phone to continue.

   <br />

   | **Preview:** Currently, the instructions and rationale provided by the system are not audible to the user. To provide an audible rationale to the user, we recommend using [Text to Speech (TTS)](https://developer.android.com/develop/xr/jetpack-xr-sdk/tts). For example:
   |
   | <br />
   |
   |     tts?.speak("Please review the permission request on your host device",
   |     TextToSpeech.QUEUE_ADD,
   |     null,
   |     "permission_request")
   |
   | <br />
   |
   <br />

2. **On the phone** : Concurrently, an activity launches on the **host device
   (phone)**. This screen displays the rationale string you provided and gives
   the user the option to proceed or cancel.

3. **On the phone** : If the user accepts the rationale, a modified Android
   system permission dialog appears on the phone telling the user that they are
   granting the permission **for the AI glasses device** (not the phone), and the
   user can formally grant or deny the permission.

4. **Receiving the result** : After the user makes their final choice, the
   activities on both the phone and AI glasses are dismissed. Your
   [`ActivityResultLauncher`](https://developer.android.com/reference/kotlin/androidx/activity/result/ActivityResultLauncher) callback is then invoked with a map containing
   the granted status for each requested permission.