Skip to main content

Android BLE Connection SDK

SDK Version: 1.0.0
Package: com.xtalk.mesh.sdk.ble

Initialize

Set the application context and initialize the SDK from the Application or before the first BLE operation. ensureInitialized() is idempotent.

XTalkBleClient.setApplicationContext(applicationContext)
val initResult = XTalkBleClient.ensureInitialized()

Verify that initResult is InitResult.INIT_OK or the already-initialized success value defined by the delivered core SDK.

Scan

Register a DeviceStateCallback before scanning:

private val deviceCallback = DeviceStateCallback { state, devices, _, _ ->
if (state == DeviceEventState.SCAN_RESULT) {
val supported = devices.orEmpty().filter(::isSupportedBleDevice)
// Send supported to the UI; do not block this callback.
}
}

XTalkBleClient.addListener(deviceCallback)
val scanResult = XTalkBleClient.startScan(
timeoutMs = 8_000,
minRssiDbm = -100,
serviceUuids = listOf(XTALK_SCAN_UUID_5632G),
)

Call stopScan() when leaving the screen, starting a connection, or cancelling. Use bleDeviceDisplayName(device) for a customer-facing name.

Connect and wait for readiness

connect, awaitBleReady, authentication, and initialization can wait for device responses. Never call them on the main thread:

val connectResult = withContext(Dispatchers.IO) {
XTalkBleClient.connect(
device = device,
timeoutMs = 8_000,
maxReconnectAttempts = null,
)
}

if (connectResult == ConnectResult.CONNECT_OK) {
val gattReady = withContext(Dispatchers.IO) {
XTalkBleClient.awaitBleReady(timeoutMs = 8_000L)
}
}

CONNECT_OK means that the connection request succeeded. Wait for the state callback and GATT readiness, then authenticate. isReadyForSend() becomes true only after the link is connected and wireless initialization has completed.

AT and business data

val lines = withContext(Dispatchers.IO) {
XTalkBleClient.runAtCommand("AT+VER?", timeoutMs = 3_000L, log = true)
}

val sendResult = withContext(Dispatchers.IO) {
XTalkBleClient.sendBinaryFrame(payload)
}

Do not issue concurrent AT commands while authentication, initialization, OTA, or another exclusive AT operation is active. Check isReadyForSend() before ordinary business sends.

Disconnect and clean up

withContext(Dispatchers.IO) {
XTalkBleClient.disconnect(sendRemoteCommand = true)
}
XTalkBleClient.removeListener(deviceCallback)

Use sendRemoteCommand = false for failure recovery. Every callback registered with an add...Listener API must be removed by the same lifecycle owner.

Complete connection-lifecycle contract

APIDefaults/preconditionReturn, timeout, cleanup
setApplicationContext(context)Application context; before initnull clears; never retain an Activity
ensureInitialized()IdempotentContinue only for InitResult.INIT_OK
startScan(timeoutMs=5000, minRssiDbm=-100, serviceUuids=[])Permissions/BluetoothScanStartResult; results through DeviceStateCallback; pair stopScan()
stopScan()InitializedIdempotent stop
connect(device, timeoutMs=5000, maxReconnectAttempts=null)Stop scan; backgroundRequest ConnectResult; confirm through callback/awaitConnected
awaitConnected(macAddress=null, timeoutMs=8000)Backgroundtrue on matching CONNECTED; false on error/disconnect/deadline; waiter auto-removed
ensureGattServicesOpened(forceReset=false)CONNECTED; backgroundReopens passthrough/protocol services; briefly blocks
awaitBleReady(timeoutMs=8000)CONNECTED; backgroundtrue when GATT writes/notifications are stable
disconnect(sendRemoteCommand=true)BackgroundDisconnectResult; clears caches/ready/AT mode; use false for a broken link
awaitDisconnected(timeoutMs=6000)Backgroundtrue only on DISCONNECTED; false on ERROR/deadline
stopAutoReconnect(reason)Ending SDK reconnecttrue when manager is stopped; not a replacement for disconnect
forceResetDisconnected(reason, clearLastRequestedDevice=true)Recovery from mismatched local/link state onlyClears local tracking/ready/AT; prefer normal disconnect

State and Auth/Init gates

getConnectedDevice, getConnectionState, and hasActiveBleLink report physical state. getDeviceLongId/awaitDeviceLongId(3000) return an authenticated structured DID or null. isWirelessReady/awaitWirelessReady(4000) report/wait Init state. isReadyForSend is the combined CONNECTED + wireless-ready business gate. markWirelessInitRequired(reason, resetAtMode=true) clears stale state. setWirelessInitReady(ready, reason) is for Auth/Init integration; business code must never forge true.

AT encoding selection (Advanced)

isAtXorEnabled reads connection encoding. setAtXorEnabledForConnection(enabled, reason) is for Auth/compatibility adapters and resets on connect/disconnect. chooseAtXorModeByFreqProbeResult(timeoutMs=1500, log=true) probes normal/XOR and returns AtXorModeProbeResult(useXor, normalFreqAccepted) or null. Prefer DeviceAuthenticator; do not guess the mode or bypass Challenge.

Name and permission helpers

Permission helpers are covered in SDK Setup. sanitizeBleDeviceName removes placeholders, short numeric/hex, and DID-like names. isSupportedBleDeviceName/isSupportedBleDevice apply supported keywords/prefixes. bleDeviceDisplayName falls back to uppercase MAC. mergeBleDeviceIdentity(reported, fallback) selects MAC, valid name, and RSSI; it returns null if neither input has a MAC.

Every add-listener call must be paired with removal of the same instance. See the complete table in Data and Device Capabilities.

Next: Device Authentication