CXR-L(EN)
cxr-l-sdk · v1.0.3 · snapshot 2026-06-02· ↗ source

Custom Commands

Android: Custom Commands

Overview

On a CUSTOMAPP session with the same CXRLink instance, build payloads with Caps and send via sendCustomCmd, receiving replies in ICustomCmdCbk. Enables bidirectional binary messaging between the phone app and the glasses-side custom app.

CustomView sessions do not support custom commands.

Bidirectional channels

Must match glasses CXRServiceBridge and RenewCXRLSample CustomCmdViewModel:

DirectionPhone CXR-LGlasses CXR-S
Phone → glassessendCustomCmd(“rk_custom_client”, Caps)subscribe(“rk_custom_client”, MsgCallback)
Glasses → phoneonCustomCmdResult(“rk_custom_key”, bytes)sendMessage(“rk_custom_key”, Caps)

Sample Caps fields (demo)

Phone → glasses (sendCustomCmd payload):

Caps().apply {
write(“rk_custom_key”)
write(“from client click times = $count”)
}

Glasses → phone (sendMessage payload):

Caps().apply {
write(“message”)
write(str)
}

Prerequisites

  • Session type is CUSTOMAPP.
  • Global CXRLink connected.
  • Scene building completed: target app running on glasses.
  • Link ready (CXR + Bluetooth).

Core APIs (phone)

MethodDescription
setCXRCustomCmdCbk(ICustomCmdCbk)Register command callbacks
sendCustomCmd(key: String, payload: Caps)Send; pass a Caps instance directly

ICustomCmdCbk

fun onCustomCmdResult(key: String?, payload: ByteArray?)

Parse with Caps.fromBytes(payload) following the agreed field order.

Caps example (phone)

link.sendCustomCmd(“rk_custom_client”, Caps().apply {
write(“rk_custom_key”)
write(“message from phone”)
})
link.setCXRCustomCmdCbk(object : ICustomCmdCbk {
override fun onCustomCmdResult(key: String?, payload: ByteArray?) {
if (key == “rk_custom_key” && payload != null) {
val caps = Caps.fromBytes(payload)
}
}
})

Agree with the glasses app on channel keys, field order, types, and max packet size.

Constraints

  • Send only when scene is ready and link is up.
  • Clear Cmd callback on page destroy.
  • Reuse the same CXRLink from CustomApp session creation.

Glasses-side: CXRServiceBridge

After CUSTOMAPP session build, the glasses app subscribes to phone command channels and replies via sendMessage.

Prerequisites

  • Phone appStart succeeded (onOpenAppResult(true)).
  • Glasses MainViewModel (or equivalent) has called subscribe on the agreed channel.

Core APIs

MethodDescription
setStatusListener(StatusListener)Connection lifecycle
subscribe(name: String, MsgCallback)Subscribe to phone channel
sendMessage(name: String, caps: Caps)Send reply to phone

StatusListener (excerpt)

CallbackDescription
onConnectedBridge connected
onDisconnectedBridge disconnected
onConnectingConnecting

MsgCallback

fun onReceive(name: String?, args: Caps?, bytes: ByteArray?)

Integration example (glasses)

class MainViewModel : ViewModel() {
private val cxrBridge = CXRServiceBridge()
private val clientKey = “rk_custom_client”
private val cmdKey = “rk_custom_key”
private val msgCallback = object : CXRServiceBridge.MsgCallback {
override fun onReceive(name: String?, args: Caps?, bytes: ByteArray?) {
// Update UI from args
}
}
init {
cxrBridge.setStatusListener(/* StatusListener impl */)
cxrBridge.subscribe(clientKey, msgCallback)
}
fun sendMessage(text: String) {
cxrBridge.sendMessage(cmdKey, Caps().apply {
write(“message”)
write(text)
})
}
}

Constraints

  • Channel keys, field order, and types must match on both sides.
  • Register subscribe before relying on phone traffic; release on destroy per SDK guidance.
  • Glasses do not call connect separately.

Key reporting uses the same sendMessage(“rk_custom_key”, …) channel — see Keys and System Broadcasts chapter.

Appendix: reference sample

SideClass
PhoneCustomCmdViewModel.ktsendCustomCmd, onCustomCmdResult filters rk_custom_key
GlassesMainViewModel.ktclientKey / cmdKey, subscribe, sendMessage, parseCaps
Marcin Miazga