<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.md.txt) ![](https://developer.android.com/static/images/develop/xr/ai-glasses-icon.svg) Audio \&  
Display Glasses [](https://developer.android.com/develop/xr/devices.md.txt#audio-display) [Learn about XR device types →](https://developer.android.com/develop/xr/devices.md.txt)

<br />

Different types of audio glasses and display glasses have different
capabilities. After [planning how you'll support different types of AI
devices](https://developer.android.com/develop/xr/jetpack-xr-sdk/glasses/support-different-types), you can check for device capabilities at runtime to provide the
best experience for a user's device.

## Check whether a device has a display

Display glasses can show [UIs built with Jetpack Compose Glimmer](https://developer.android.com/develop/xr/jetpack-xr-sdk/jetpack-compose-glimmer). The
following example shows how to check whether a glasses device has a display:


```kotlin
// Check device capabilities
val projectedDeviceController = ProjectedDeviceController.create(this@ProjectedMainActivity)
isVisualUiSupported = projectedDeviceController.capabilities.contains(CAPABILITY_VISUAL_UI)
```

<br />

## React to display state changes

On display glasses, the display can time out or the user can turn off the
display. To design activities that run whether the display is on or off, use
[`addPresentationModeChangedListener`](https://developer.android.com/reference/kotlin/androidx/xr/projected/ProjectedDisplayController.md.txt#addPresentationModeChangedListener(java.util.concurrent.Executor,java.util.function.Consumer)) to be notified when the display state
changes. You can tune your activity for the appropriate amount of audio
information depending on display state.

```kotlin
ProjectedDisplayController.create(activity).addPresentationModeChangedListener {
    presentationModeFlags ->

    val areVisualsOff = !presentationModeFlags.hasPresentationMode(VISUALS_ON)
}
```

> [!NOTE]
> **Note:** Monitor display state changes for the display glasses directly within the [projected activity](https://developer.android.com/develop/xr/jetpack-xr-sdk/glasses/support-different-types.md.txt#activity-lifecycle).

## Keep the display on

On display glasses, you can request that the system keep the screen on and
prevent the screen from timing out using [`addLayoutParamsFlags`](https://developer.android.com/reference/kotlin/androidx/xr/projected/ProjectedDisplayController.md.txt#addLayoutParamsFlags(kotlin.Int)).

> [!NOTE]
> **Note:** Keeping the device's screen on can drain the battery quickly. Ordinarily, you should let the device turn the screen off if the user isn't interacting with it. If you do need to keep the screen on, do so for as short a time as possible.

```kotlin
var projectedDisplayController = ProjectedDisplayController.create(activity)

projectedDisplayController.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
```

## Monitor battery state changes

To track the real-time battery status of connected audio or display glasses, use
the [`addBatteryStateChangedListener`](https://developer.android.com/reference/kotlin/androidx/xr/projected/ProjectedDeviceController.md.txt#addBatteryStateChangedListener(kotlin.coroutines.CoroutineContext,kotlin.Function1)) method provided by the
[`ProjectedDeviceController`](https://developer.android.com/reference/kotlin/androidx/xr/projected/ProjectedDeviceController.md.txt). This listener notifies your app whenever the
battery level or charging state changes, allowing you to optimize app
performance, enable power-savings modes, or update your user interface.


```kotlin
@OptIn(ExperimentalProjectedApi::class)
private var deviceController: ProjectedDeviceController? = null

private val batteryListener = { batteryState: BatteryState ->
    val batteryLevel = batteryState.batteryLevel
    val isCharging = batteryState.isCharging

    if (batteryLevel <= 15 && !isCharging) {
        switchToLowPowerMode()
    }

    updateBatteryUi(batteryLevel, isCharging)
}
// ...

@OptIn(ExperimentalProjectedApi::class)
private fun monitorBatteryStatus() {
    lifecycleScope.launch {
        try {
            if (deviceController == null) {
                deviceController = ProjectedDeviceController.create(this@PhoneMainActivity)
            }

            if (lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) {
                deviceController?.addBatteryStateChangedListener(coroutineContext, batteryListener)
            }
        } catch (e: Exception) {
            Log.e("BatteryMonitor", "Unexpected error: ${e.message}")
        }
    }
}
```

<br />

When you are done monitoring the device or when your component is being
destroyed, call `close` on the `ProjectedDeviceController` to release underlying
resources properly.


```kotlin
@OptIn(ExperimentalProjectedApi::class)
override fun onDestroy() {
    super.onDestroy()
    // Unregisters the active listeners
    deviceController?.close()
    deviceController = null
}
```

<br />

You can also unregister a listener explicitly before the scope ends by using
[`removeBatteryStateChangedListener`](https://developer.android.com/reference/kotlin/androidx/xr/projected/ProjectedDeviceController.md.txt#removeBatteryStateChangedListener(kotlin.Function1)).


```kotlin
@OptIn(ExperimentalProjectedApi::class)
override fun onPause() {
    super.onPause()
    // Explicitly unregister the listener when it is no longer needed
    deviceController?.removeBatteryStateChangedListener(batteryListener)
}
```

<br />