ARCore for Jetpack XR can detect flat surfaces in the user's environment and
provide information on them such as their pose, size, and orientation. This can
help your app find surfaces like tables to place objects on.

## Create an ARCore for Jetpack XR session

Access plane information through an ARCore for Jetpack XR session. See
[Understand a Session's lifecycle](https://developer.android.com/develop/xr/jetpack-xr-sdk/work-with-arcore#session-lifecycle) to obtain a [`Session`](https://developer.android.com/reference/kotlin/androidx/xr/runtime/Session).

## Configure the Session

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


```kotlin
val newConfig = session.config.copy(
    planeTracking = Config.PlaneTrackingMode.HORIZONTAL_AND_VERTICAL,
)
when (val result = session.configure(newConfig)) {
    is SessionConfigureSuccess -> TODO(/* Success! */)
    else ->
        TODO(/* The session could not be configured. See SessionConfigureResult for possible causes. */)
}https://github.com/android/snippets/blob/2f246fb3f712172fefe2e1761f3483568348bf90/xr/src/main/java/com/example/xr/arcore/Planes.kt#L29-L36
```

<br />

| **Note:** Plane tracking requires the `android.permission.SCENE_UNDERSTANDING_COARSE` [runtime permission](https://developer.android.com/training/permissions/requesting) to be granted to your app.

## Retrieve the state of perceived planes

ARCore for Jetpack XR provides the state of planes through a
[`StateFlow`](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-state-flow/) that emits the state of planes. Subscribing to
planes in a session notifies your app when planes are added, updated, or
removed.


```kotlin
Plane.subscribe(session).collect { planes ->
    // Planes have changed; update plane rendering
}https://github.com/android/snippets/blob/2f246fb3f712172fefe2e1761f3483568348bf90/xr/src/main/java/com/example/xr/arcore/Planes.kt#L42-L44
```

<br />

A plane has the following properties:

- [`label`](https://developer.android.com/reference/kotlin/androidx/xr/arcore/Plane.State#label()): a semantic description of a given [`Plane`](https://developer.android.com/reference/kotlin/androidx/xr/arcore/Plane). Could be a [`WALL`](https://developer.android.com/reference/kotlin/androidx/xr/arcore/Plane.Label#WALL()), [`FLOOR`](https://developer.android.com/reference/kotlin/androidx/xr/arcore/Plane.Label#FLOOR()), [`CEILING`](https://developer.android.com/reference/kotlin/androidx/xr/arcore/Plane.Label#CEILING()), or [`TABLE`](https://developer.android.com/reference/kotlin/androidx/xr/arcore/Plane.Label#TABLE()).
- [`centerPose`](https://developer.android.com/reference/kotlin/androidx/xr/arcore/Plane.State#centerPose()): The pose of the center of the detected plane.
- [`extents`](https://developer.android.com/reference/kotlin/androidx/xr/arcore/Plane.State#extents()): The dimensions of the detected plane, in meters.
- [`vertices`](https://developer.android.com/reference/kotlin/androidx/xr/arcore/Plane.State#vertices()): A list of vertices of a convex polygon that approximates the plane.

### Perform a hit-test against planes

A hit-test is a method of calculating the intersection of a ray with objects
tracked by the session. A common application of a hit-test is to point at a
table and place an object at that location. Conducting a hit-test results in a
list of hit objects. In other words, a hit-test doesn't stop at the first object
hit. However, often you may only be interested in the first object hit of a
given type.

To perform a hit-test, use [`Interaction.hitTest()`](https://developer.android.com/reference/kotlin/androidx/xr/arcore/package-summary#hittest) with a [`Ray`](https://developer.android.com/reference/kotlin/androidx/xr/runtime/math/Ray):


```kotlin
val results = androidx.xr.arcore.hitTest(session, ray)
// When interested in the first Table hit:
val tableHit = results.firstOrNull {
    val trackable = it.trackable
    trackable is Plane && trackable.state.value.label == Plane.Label.TABLE
}https://github.com/android/snippets/blob/2f246fb3f712172fefe2e1761f3483568348bf90/xr/src/main/java/com/example/xr/arcore/Planes.kt#L52-L57
```

<br />