<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/xr-headsets-icon.svg) XR Headsets [](https://developer.android.com/develop/xr/devices#xr-headsets)  
![](https://developer.android.com/static/images/develop/xr/xr-glasses-icon.svg) Wired XR Glasses [](https://developer.android.com/develop/xr/devices#xr-glasses)  
[Learn about XR device types →](https://developer.android.com/develop/xr/devices)

<br />

After the user [grants permission for head tracking](https://developer.android.com/training/permissions/requesting),
your app can retrieve head pose information through ARCore for Jetpack XR. Head
pose information can help your app create more intuitive experiences, such as a
window following the user's field of view.

## Create an ARCore for Jetpack XR session

Obtain head pose information through a Jetpack XR Runtime [`Session`](https://developer.android.com/reference/kotlin/androidx/xr/runtime/Session),
which your [app can create](https://developer.android.com/develop/xr/jetpack-xr-sdk/add-session#access-session).

## Configure the session

Head tracking is not enabled by default on XR sessions. To enable head
tracking, configure the session and set the
[`HeadTrackingMode.LAST_KNOWN`](https://developer.android.com/reference/kotlin/androidx/xr/runtime/Config.HeadTrackingMode#LAST_KNOWN()) mode:


```kotlin
val newConfig = session.config.copy(
    headTracking = Config.HeadTrackingMode.LAST_KNOWN,
)
when (val result = session.configure(newConfig)) {
    is SessionConfigureSuccess -> TODO(/* Success! */)
    is SessionConfigureConfigurationNotSupported ->
        TODO(/* Some combinations of configurations are not valid. Handle this failure case. */)

    else ->
        TODO(/* The session could not be configured. See SessionConfigureResult for possible causes. */)
}
```

<br />

| **Note:** Enabling this mode requires the `android.permission.HEAD_TRACKING` [runtime permission](https://developer.android.com/training/permissions/requesting) to be granted to your app.

## Retrieve head pose data

Head pose data is exposed through an [`RenderViewpoint`](https://developer.android.com/reference/kotlin/androidx/xr/arcore/RenderViewpoint).
A `RenderViewpoint` describes the pose and field of view for a given point of
view of a device. A device can have a left, right, or mono viewpoints, depending
on the device's capabilities.
| **Note:** If a device has a left and a right viewpoint, then the mono viewpoint is expressed by averaging left and right values.

To obtain data for the mono viewpoint:


```kotlin
val mono = RenderViewpoint.mono(session) ?: return
mono.state.collect { state ->
    val fov = state.fieldOfView
    val viewpointPose = state.pose
}
```

<br />

## Applications of head tracking

One way your app could use head tracking is to keep entities in the user's field
of view, for apps that require your users to look or move around.


Your browser doesn't support HTML video. Here is a
[link to the video](https://developer.android.com/static/develop/xr/develop/videos/arcore_panel_follow.mp4) instead.

Avoid using headlocked entities in the user's field of view because this can
cause motion sickness. Instead, use entity movement that follows the user's head
after a small duration:


```kotlin
val viewpointPose = RenderViewpoint.left(session)!!.state
lifecycleScope.launch {
    while (true) {
        delay(2000)
        val start = panel.getPose()
        val startTime = session.state.value.timeMark

        val pose = session.scene.perceptionSpace.transformPoseTo(
            viewpointPose.value.pose,
            session.scene.activitySpace
        )
        val target = Pose(pose.translation + pose.forward * 1f, pose.rotation)
        while (true) {
            val ratio =
                (session.state.value.timeMark - startTime).inWholeMilliseconds / 500f
            panel.setPose(Pose.lerp(start, target, ratio))
            if (ratio > 1f) break
        }
    }
}
```

<br />