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
| API | Defaults/precondition | Return, timeout, cleanup |
|---|---|---|
setApplicationContext(context) | Application context; before init | null clears; never retain an Activity |
ensureInitialized() | Idempotent | Continue only for InitResult.INIT_OK |
startScan(timeoutMs=5000, minRssiDbm=-100, serviceUuids=[]) | Permissions/Bluetooth | ScanStartResult; results through DeviceStateCallback; pair stopScan() |
stopScan() | Initialized | Idempotent stop |
connect(device, timeoutMs=5000, maxReconnectAttempts=null) | Stop scan; background | Request ConnectResult; confirm through callback/awaitConnected |
awaitConnected(macAddress=null, timeoutMs=8000) | Background | true on matching CONNECTED; false on error/disconnect/deadline; waiter auto-removed |
ensureGattServicesOpened(forceReset=false) | CONNECTED; background | Reopens passthrough/protocol services; briefly blocks |
awaitBleReady(timeoutMs=8000) | CONNECTED; background | true when GATT writes/notifications are stable |
disconnect(sendRemoteCommand=true) | Background | DisconnectResult; clears caches/ready/AT mode; use false for a broken link |
awaitDisconnected(timeoutMs=6000) | Background | true only on DISCONNECTED; false on ERROR/deadline |
stopAutoReconnect(reason) | Ending SDK reconnect | true when manager is stopped; not a replacement for disconnect |
forceResetDisconnected(reason, clearLastRequestedDevice=true) | Recovery from mismatched local/link state only | Clears 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.