Full API reference: https://wearables.developer.meta.com/llms.txt?full=true DAT docs MCP: https://mcp.facebook.com/wearables_dat Developer docs: https://wearables.developer.meta.com/docs/develop/
| Task | Command |
|---|---|
| Build app | ./gradlew assembleDebug |
| Run tests | ./gradlew test |
| Install app | ./gradlew installDebug |
| Lint app | ./gradlew lint |
The SDK is organized into four public modules:
- mwdat-core: Registration, permissions, devices, and session creation
- mwdat-camera: Stream capability, video frames, and photo capture
- mwdat-display: Display capability, display UI components, icons, images, buttons, and video
- mwdat-mockdevice: MockDeviceKit for testing without hardware
Wearables.initialize(context)
val session = Wearables.createSession(AutoDeviceSelector()).getOrElse { error ->
throw IllegalStateException(error.description)
}
session.start()
val stream = session.addStream(StreamConfiguration()).getOrElse { error ->
throw IllegalStateException(error.description)
}
stream.start().getOrElse { error ->
throw IllegalStateException(error.description)
}- Use
DatResult<T, E>for typed success and failure handling - Observe state with
StateFlowandFlow - Create a
Sessionfirst, then attach capabilities such asStreamorDisplay - Keep frame handling off the main thread when doing heavier processing
Wearables.checkPermissionStatus(Permission.CAMERA)
.onSuccess { status -> /* handle status */ }
.onFailure { error, _ -> /* handle error */ }Avoid getOrThrow() in user-facing samples. Surface typed errors from DatResult instead.
| Type | Purpose | Example |
|---|---|---|
Session |
Device connection lifecycle | Wearables.createSession(...) |
Stream |
Camera capability on a session | session.addStream(...) |
Display |
Display capability on a session | session.addDisplay(...) |
*Selector |
Device targeting | AutoDeviceSelector |
*Error |
Typed failure surface | SessionError, StreamError |
Wearables— SDK entry pointSession— lifecycle for an interaction with a linked deviceStream— camera capability attached to a sessionDisplay— display capability attached to a sessionStreamConfiguration— video quality and frame rate configurationMockDeviceKit— simulated device environment for testing
If your editor supports remote MCP servers, connect https://mcp.facebook.com/wearables_dat and use search_dat_docs for current DAT setup, session lifecycle, camera streaming, MockDeviceKit, permissions, and exact API symbols.
Use llms.txt when your tool only supports static reference context.
val mockDeviceKit = MockDeviceKit.getInstance(context)
mockDeviceKit.enable()
val device = mockDeviceKit.pairRaybanMeta()Use MockDeviceKit to drive registration, device availability, streaming media, and permission scenarios without physical hardware.
- Do not call SDK APIs before
Wearables.initialize(context) - Do not assume a session implies streaming or display access; capabilities are attached separately
- Do not ignore
DatResultfailures fromcreateSession,start,addStream,addDisplay, orcapturePhoto - Do not reuse terminally stopped sessions
Set up the Meta Wearables Device Access Toolkit in an Android app.
- Android Studio Flamingo or newer
- Android 10+ test device with the Meta AI app installed
- Supported Meta glasses or MockDeviceKit for local testing
- Developer Mode enabled in the Meta AI app for development builds
- GitHub personal access token with
read:packagesscope
In settings.gradle.kts:
val localProperties =
Properties().apply {
val localPropertiesPath = rootDir.toPath() / "local.properties"
if (localPropertiesPath.exists()) {
load(localPropertiesPath.inputStream())
}
}
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven {
url = uri("https://maven.pkg.github.com/facebook/meta-wearables-dat-android")
credentials {
username = ""
password = System.getenv("GITHUB_TOKEN") ?: localProperties.getProperty("github_token")
}
}
}
}In libs.versions.toml:
[versions]
mwdat = "0.7.0"
[libraries]
mwdat-core = { group = "com.meta.wearable", name = "mwdat-core", version.ref = "mwdat" }
mwdat-camera = { group = "com.meta.wearable", name = "mwdat-camera", version.ref = "mwdat" }
mwdat-mockdevice = { group = "com.meta.wearable", name = "mwdat-mockdevice", version.ref = "mwdat" }In app/build.gradle.kts:
dependencies {
implementation(libs.mwdat.core)
implementation(libs.mwdat.camera)
implementation(libs.mwdat.mockdevice)
}<manifest ...>
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.INTERNET" />
<application ...>
<meta-data
android:name="com.meta.wearable.mwdat.APPLICATION_ID"
android:value="0" />
<activity android:name=".MainActivity" ...>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="myexampleapp" />
</intent-filter>
</activity>
</application>
</manifest>Use 0 for APPLICATION_ID in Developer Mode. Replace myexampleapp with your app's URL scheme.
import com.meta.wearable.dat.core.Wearables
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
Wearables.initialize(this)
.onFailure { error, _ -> error("Failed to initialize DAT: ${error.description}") }
}
}import com.meta.wearable.dat.core.Wearables
import com.meta.wearable.dat.core.selectors.AutoDeviceSelector
fun connect(activity: Activity) {
Wearables.startRegistration(activity)
}
fun startSession() {
val session = Wearables.createSession(AutoDeviceSelector()).getOrElse { error ->
throw IllegalStateException(error.description)
}
session.start()
}Observe registration and available devices:
lifecycleScope.launch {
Wearables.registrationState.collect { state ->
// Update registration UI
}
}
lifecycleScope.launch {
Wearables.devices.collect { devices ->
// Update the device list
}
}import com.meta.wearable.dat.camera.addStream
import com.meta.wearable.dat.camera.types.StreamConfiguration
import com.meta.wearable.dat.camera.types.VideoQuality
val stream = session.addStream(
StreamConfiguration(videoQuality = VideoQuality.MEDIUM, frameRate = 24),
).getOrElse { error ->
throw IllegalStateException(error.description)
}
stream.start().onFailure { error, _ ->
throw IllegalStateException(error.description)
}- Camera Streaming — Stream capability, video frames, photo capture
- MockDevice Testing — Test without hardware
- Session Lifecycle — Handle session and stream state changes
- Permissions — Registration and permission flows
- Full Android API reference
Use MockDeviceKit to test DAT SDK integrations without physical Meta glasses.
MockDeviceKit simulates Meta glasses behavior for development and testing. It provides:
MockDeviceKit— Entry point for creating simulated devicesMockRaybanMeta— Simulated Ray-Ban Meta glassesMockCameraKit— Simulated camera with configurable video feed and photo capture
Add mwdat-mockdevice to your Gradle dependencies:
dependencies {
implementation(libs.mwdat.mockdevice)
}import com.meta.wearable.dat.mockdevice.MockDeviceKit
import com.meta.wearable.dat.mockdevice.api.MockDeviceKitConfig
val mockDeviceKit = MockDeviceKit.getInstance(context)
// Attach fake registration and connectivity (auto-initializes Wearables if needed).
// By default, Wearables.registrationState transitions to Registered.
mockDeviceKit.enable()
// Or start in unregistered state to test registration flows:
// mockDeviceKit.enable(MockDeviceKitConfig(initiallyRegistered = false))
val device = mockDeviceKit.pairRaybanMeta()You can check mockDeviceKit.isEnabled to query whether the mock environment is active.
// Simulate glasses lifecycle
device.powerOn()
device.unfold()
device.don() // Simulate wearing the glasses
// Later...
device.doff() // Simulate removing
device.fold()
device.powerOff()MockDeviceKit provides permissions to control permission behavior without the Meta AI app.
By default, RequestPermissionContract returns Granted. Use set() to control checkPermissionStatus() and setRequestResult() to control request outcomes.
val mockDeviceKit = MockDeviceKit.getInstance(context)
// Simulate denied camera permission status
mockDeviceKit.permissions.set(Permission.CAMERA, PermissionStatus.Denied)
// Simulate denied request result (user tapping "deny")
mockDeviceKit.permissions.setRequestResult(Permission.CAMERA, PermissionStatus.Denied)val camera = device.services.camera
camera.setCameraFeed(videoUri)val camera = device.services.camera
camera.setCapturedImage(imageUri)Note: Android doesn't transcode video automatically. Mock video files must be in h.265 format. Use FFmpeg to convert:
ffmpeg -hwaccel videotoolbox -i input.mp4 -c:v hevc_videotoolbox -c:a aac_at -tag:v hvc1 -vf "scale=540:960" output.movCreate a reusable test base class:
import android.content.Context
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.platform.app.InstrumentationRegistry
import com.meta.wearable.dat.mockdevice.MockDeviceKit
import com.meta.wearable.dat.mockdevice.api.MockDeviceKitInterface
import org.junit.After
import org.junit.Before
import org.junit.Rule
open class MockDeviceKitTestCase<T : Any>(
private val activityClass: Class<T>
) {
@get:Rule
val scenarioRule = ActivityScenarioRule(activityClass)
protected lateinit var mockDeviceKit: MockDeviceKitInterface
protected lateinit var targetContext: Context
@Before
open fun setUp() {
val instrumentation = InstrumentationRegistry.getInstrumentation()
targetContext = instrumentation.targetContext
mockDeviceKit = MockDeviceKit.getInstance(targetContext)
grantRuntimePermissions()
}
@After
open fun tearDown() {
mockDeviceKit.disable()
}
private fun grantRuntimePermissions() {
val packageName = targetContext.packageName
val shell = InstrumentationRegistry.getInstrumentation().uiAutomation
shell.executeShellCommand("pm grant $packageName android.permission.BLUETOOTH_CONNECT")
shell.executeShellCommand("pm grant $packageName android.permission.CAMERA")
}
}The CameraAccess sample app includes a Debug menu for MockDeviceKit:
- Tap the Debug icon to open the MockDeviceKit menu
- Tap Pair RayBan Meta to create a simulated device
- Use PowerOn, Unfold, Don to simulate glasses states
- Select video/image files for mock camera feeds
- Start streaming to see simulated frames
| Type | Formats |
|---|---|
| Video | h.264 (AVC), h.265 (HEVC) |
| Image | JPEG, PNG |
Use a Session and attached Stream to receive frames and capture photos.
- Session: Device connection lifecycle created through
Wearables.createSession(...) - Stream: Camera capability attached to a session with
session.addStream(...) - StreamConfiguration: Resolution and frame rate configuration for the stream
- PhotoData: Still image captured from glasses while streaming
import com.meta.wearable.dat.camera.Stream
import com.meta.wearable.dat.camera.addStream
import com.meta.wearable.dat.camera.types.StreamConfiguration
import com.meta.wearable.dat.camera.types.VideoQuality
import com.meta.wearable.dat.core.Wearables
import com.meta.wearable.dat.core.selectors.AutoDeviceSelector
val session = Wearables.createSession(AutoDeviceSelector()).getOrElse { error ->
throw IllegalStateException(error.description)
}
session.start()
val stream: Stream = session.addStream(
StreamConfiguration(
videoQuality = VideoQuality.MEDIUM,
frameRate = 24,
),
).getOrElse { error ->
throw IllegalStateException(error.description)
}
stream.start().getOrElse { error ->
throw IllegalStateException(error.description)
}| Quality | Size |
|---|---|
VideoQuality.HIGH |
720 x 1280 |
VideoQuality.MEDIUM |
504 x 896 |
VideoQuality.LOW |
360 x 640 |
Valid values: 2, 7, 15, 24, 30 FPS.
Lower resolution and frame rate usually produce better visual quality per frame over Bluetooth.
StreamState transitions: STOPPED -> STARTING -> STARTED -> STREAMING -> STOPPING -> STOPPED -> CLOSED
lifecycleScope.launch {
stream.state.collect { state ->
when (state) {
StreamState.STREAMING -> {
// Frames are flowing
}
StreamState.STOPPED -> {
// Streaming ended
}
StreamState.CLOSED -> {
// Stream fully closed
}
else -> Unit
}
}
}lifecycleScope.launch {
stream.videoStream.collect { frame ->
updatePreview(frame)
}
}lifecycleScope.launch {
stream.capturePhoto()
.onSuccess { photoData ->
val imageBytes = photoData.data
savePhoto(imageBytes)
}
.onFailure { error, _ ->
showCaptureError(error.description)
}
}Stop the stream when you no longer need camera data, then stop the parent session if the device interaction is finished.
stream.stop()
session.stop()If you want to remove the capability entirely before re-adding it, call session.removeStream().
Manage session and stream state in DAT SDK integrations.
Create a Session with Wearables.createSession(...), start it, then attach capabilities such as camera streaming. Session lifecycle and stream lifecycle are related but distinct.
| State | Meaning | App action |
|---|---|---|
IDLE |
Session created, not started yet | Call session.start() |
STARTING |
Connecting to the device | Show loading UI |
STARTED |
Session active and ready for capabilities | Add or use capabilities |
PAUSED |
Session temporarily suspended | Keep state, wait for resume or stop |
STOPPING |
Session is shutting down | Stop user work and wait |
STOPPED |
Session ended | Release resources and create a new session if needed |
val session = Wearables.createSession(AutoDeviceSelector()).getOrElse { error ->
throw IllegalStateException(error.description)
}
session.start()
lifecycleScope.launch {
session.state.collect { state ->
when (state) {
DeviceSessionState.STARTED -> onStarted()
DeviceSessionState.PAUSED -> onPaused()
DeviceSessionState.STOPPED -> onStopped()
else -> Unit
}
}
}Camera streaming has its own state flow after you attach a stream:
STOPPED -> STARTING -> STARTED -> STREAMING -> STOPPING -> STOPPED -> CLOSED
lifecycleScope.launch {
stream.state.collect { state ->
// React to camera capability state changes
}
}The SDK may pause or stop a session when:
- Another experience takes over the device
- The user removes or folds the glasses
- Bluetooth connectivity drops
- The user unregisters the app or revokes needed access
When a session is paused:
- The device connection may remain active
- Attached capabilities stop doing useful work
- Your app should wait for the next observed session state instead of trying to force a restart
lifecycleScope.launch {
Wearables.devices.collect { devices ->
// Update the list of available devices
}
}Use Wearables.devices and device metadata to decide when it is sensible to create a new session after a stop.
- Handle all
DeviceSessionStatevalues you care about - Observe stream state separately from session state
- Release resources only after stop or close
- Recreate sessions after terminal stops instead of reusing dead ones
- Surface typed
SessionErrorandStreamErrorfailures
Register your app with Meta AI, then request the device permissions it needs.
The DAT SDK separates two steps:
- Registration: The user connects your app to Meta AI.
- Device permissions: After registration, your app requests capabilities such as camera access.
Both flows depend on the Meta AI app being installed on the phone.
Wearables.startRegistration(activity)Observe registration state:
lifecycleScope.launch {
Wearables.registrationState.collect { state ->
// Update your registration UI
}
}To unregister:
Wearables.startUnregistration(activity)checkPermissionStatus(...) is a suspend API that returns a DatResult.
lifecycleScope.launch {
Wearables.checkPermissionStatus(Permission.CAMERA)
.onSuccess { status ->
if (status == PermissionStatus.Granted) {
startStreaming()
}
}
.onFailure { error, _ ->
showPermissionError(error.description)
}
}Use Wearables.RequestPermissionContract() with the Activity Result API:
private val permissionLauncher =
registerForActivityResult(Wearables.RequestPermissionContract()) { result ->
result.onSuccess { status ->
if (status == PermissionStatus.Granted) {
startStreaming()
}
}.onFailure { error, _ ->
showPermissionError(error.description)
}
}
fun requestCameraPermission() {
permissionLauncher.launch(Permission.CAMERA)
}Users can allow once or allow always through the Meta AI flow.
| Mode | Registration behavior |
|---|---|
| Developer Mode | Use APPLICATION_ID = 0 for local development |
| Production | Use the application ID assigned in the Wearables Developer Center |
For development builds, enable Developer Mode in the Meta AI app before testing registration and permissions.
- Internet connection for registration
- Meta AI app installed on the phone
- Callback URI scheme configured in
AndroidManifest.xml - Bluetooth permission granted on Android
Diagnose common setup, session, and stream issues in DAT SDK integrations.
No eligible device or session won't start?
|
+-- Did you call Wearables.initialize(context)? -> Must happen before SDK usage
|
+-- Did registration complete? -> Observe Wearables.registrationState
|
+-- Is Developer Mode enabled? -> Enable it in the Meta AI app for dev builds
|
+-- Does Wearables.devices contain a linked device? -> Check Bluetooth and range
|
+-- Did createSession() or addStream() return a DatResult failure? -> Surface the typed error
Developer Mode must be enabled for local development builds that use APPLICATION_ID = 0.
- Registration flow completes but the device never becomes eligible
- Permission requests do not succeed for development builds
Wearables.createSession(...)fails with no eligible device
- Developer Mode may reset after app or firmware updates
- Developer Mode is configured per linked device
- Production builds use a real
APPLICATION_IDand release-channel gating instead
- Verify
Wearables.registrationState - Check that
Wearables.devicescontains a compatible linked device - Ensure the glasses are powered on, unfolded, and in range
- Confirm
session.start()succeeded before callingsession.addStream(...) - Check camera permission status through
Wearables.checkPermissionStatus(...) - Make sure
stream.start()returned success
capturePhoto()only succeeds while the stream is actively streaming- Surface the returned
CaptureErrorinstead of discarding theDatResult
Ensure compatible versions of the SDK, Meta AI app, and glasses firmware. See version dependencies for the current compatibility matrix.
private const val TAG = "DATWearables"
stream.start()
.onFailure { error, _ -> Log.e(TAG, "Failed to start stream: ${error.description}") }Prefer logging typed DatResult failures and observed state transitions over generic exceptions.
-
Wearables.initialize(context)ran before SDK usage - Developer Mode enabled for development builds
-
APPLICATION_IDmatches the build mode - Registration completed before session creation
- Bluetooth permission granted
- Camera permission granted through Meta AI
- Session and stream
DatResultfailures are surfaced in logs or UI
Build an Android DAT app with registration, sessions, camera streaming, and photo capture.
Pair this with the CameraAccess sample.
- Create an Android Studio app project.
- Add the DAT Maven repository and dependencies.
- Configure
AndroidManifest.xmlfor registration callbacks andAPPLICATION_ID. - Initialize
Wearablesin yourApplication.
app/src/main/java/com/example/myapp/
├── MyApplication.kt
├── MainActivity.kt
├── session/
│ └── SessionViewModel.kt
└── ui/
├── RegistrationScreen.kt
└── CameraScreen.kt
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycleScope.launch {
Wearables.registrationState.collect { state ->
// Update registration UI
}
}
}
fun register() {
Wearables.startRegistration(this)
}
}class SessionViewModel : ViewModel() {
private var session: Session? = null
private var stream: Stream? = null
fun startCameraSession() {
val createdSession = Wearables.createSession(AutoDeviceSelector()).getOrElse { error ->
throw IllegalStateException(error.description)
}
createdSession.start()
session = createdSession
stream = createdSession.addStream(
StreamConfiguration(videoQuality = VideoQuality.MEDIUM, frameRate = 24),
).getOrElse { error ->
throw IllegalStateException(error.description)
}.also { addedStream ->
addedStream.start().getOrElse { error ->
throw IllegalStateException(error.description)
}
}
}
}viewModelScope.launch {
stream?.videoStream?.collect { frame ->
// Render preview
}
}
fun capturePhoto() {
viewModelScope.launch {
stream?.capturePhoto()
?.onSuccess { photoData ->
savePhoto(photoData.data)
}
?.onFailure { error, _ ->
showCaptureError(error.description)
}
}
}fun stopCameraSession() {
stream?.stop()
session?.stop()
stream = null
session = null
}Use MockDeviceKit to simulate linking glasses, permission state, and camera media without physical hardware. See MockDevice Testing for setup details.
Add mwdat-display when rendering content on Meta Ray-Ban Display glasses. Display apps also need the core DAT setup from getting-started and permissions-registration: initialize DAT once, complete registration, request Bluetooth and Internet permissions, configure DAT manifest metadata, and set com.meta.wearable.mwdat.DAM_ENABLED to true.
mwdat-display = { group = "com.meta.wearable", name = "mwdat-display", version.ref = "mwdat" }dependencies {
implementation(libs.mwdat.core)
implementation(libs.mwdat.display)
}Set mwdat_application_id and mwdat_client_token from manifest placeholders or local.properties, as in the DisplayAccess sample. Request runtime permissions before Wearables.initialize(context). Observe Wearables.registrationState and Wearables.registrationErrorStream; wait for RegistrationState.REGISTERED before creating a display session.
For a picker, collect Wearables.devices and per-device Wearables.devicesMetadata[id]. Show the device name, device.deviceType.description, device.linkState, device.compatibility, and device.isDisplayCapable(). Enable selection only for connected display-capable devices, surface DeviceCompatibility.DEVICE_UPDATE_REQUIRED with Wearables.openFirmwareUpdate(activity), and use SpecificDeviceSelector(selectedDeviceId) for the selected row. Use AutoDeviceSelector(filter = { it.isDisplayCapable() }) only when automatic selection is acceptable.
Attach Display only after the DeviceSession reaches STARTED, and enable user content only once the Display capability reaches DisplayState.STARTED. Observe session.errors; DeviceSession.start() returns Unit. If session creation or session.errors reports DeviceSessionError.DAT_APP_ON_THE_GLASSES_UPDATE_REQUIRED, show an update action that calls Wearables.openDATGlassesAppUpdate(activity).
import com.meta.wearable.dat.core.Wearables
import com.meta.wearable.dat.core.selectors.SpecificDeviceSelector
import com.meta.wearable.dat.core.session.DeviceSessionState
import com.meta.wearable.dat.core.types.DeviceIdentifier
import com.meta.wearable.dat.core.types.DeviceSessionError
import com.meta.wearable.dat.core.types.RegistrationState
import com.meta.wearable.dat.display.Display
import com.meta.wearable.dat.display.addDisplay
import com.meta.wearable.dat.display.types.DisplayState
import com.meta.wearable.dat.display.views.ButtonStyle
import com.meta.wearable.dat.display.views.FlexBoxBackground
import com.meta.wearable.dat.display.views.IconName
import com.meta.wearable.dat.display.views.TextStyle
fun startDisplaySession(selectedDeviceId: DeviceIdentifier) {
if (Wearables.registrationState.value != RegistrationState.REGISTERED) {
showError("Register with Meta AI before starting Display")
return
}
val session =
Wearables.createSession(SpecificDeviceSelector(selectedDeviceId)).fold(
onSuccess = { it },
onFailure = { error, _ ->
if (error == DeviceSessionError.DAT_APP_ON_THE_GLASSES_UPDATE_REQUIRED) {
showDatAppUpdateAction()
}
showError(error.description)
return
},
)
var display: Display? = null
lifecycleScope.launch {
session.errors.collect { error ->
if (error == DeviceSessionError.DAT_APP_ON_THE_GLASSES_UPDATE_REQUIRED) {
showDatAppUpdateAction()
}
showError(error.description)
}
}
lifecycleScope.launch {
session.state.collect { state ->
if (state == DeviceSessionState.STARTED && display == null) {
session.addDisplay()
.onSuccess { newDisplay ->
display = newDisplay
lifecycleScope.launch {
newDisplay.state.collect { displayState ->
setTryItEnabled(displayState == DisplayState.STARTED)
if (displayState == DisplayState.STARTED) {
newDisplay.sendContent {
flexBox(
gap = 12,
padding = 24,
background = FlexBoxBackground.CARD,
) {
text("Bike ride", style = TextStyle.HEADING)
button(
label = "Done",
style = ButtonStyle.PRIMARY,
iconName = IconName.CHECKMARK,
onClick = { showDoneState() },
)
}
}
}
}
}
}
.onFailure { error, _ -> showError(error.description) }
}
}
}
session.start()
}Build exactly one root view per sendContent call: use a root flexBox { ... } for UI, or a root video(player = player) for video. Do not put video(...) inside a flexBox. Button and clickable flexBox callbacks are routed back to the phone app; keep callbacks fast and delegate to app state or ViewModel methods. Use IconName enum values such as IconName.GEAR, not raw strings.
For URL video, create VideoPlayer(source = VideoSource.Url(...), codec = VideoCodec.MP4), send it with display.sendContent { video(player = player) }, and call player.play() after send success. Collect player.state and player.error; on VideoPlayerState.ENDED, cancel the video observer and send the next display screen. On cleanup, cancel state/error collection jobs, close or replace active video players, call session.removeDisplay(), then stop the session.