Changelog
V2.1.9-E(2026-5-25)
- Phone SDK version:
com.rokid.security:phone.sdk:2.1.9-E - Glasses SDK version:
com.rokid.security:glass3.open.sdk:2.1.9-E - Recommended OTA version:
1.17.e002-20260509-150201or later
Glasses SDK API Changes
1. Event Interception APIs
1.1 GlassSdk.setPrimaryEventListener()
Location: GlassSdk.kt
@JvmStatic
fun setPrimaryEventListener(listener: DeviceEventListener?)Description:
- Set the primary device event listener
- The SDK internally holds a single DeviceEventListener slot
- Listeners registered through this method receive all events except those intercepted by Leqi
Use Case: Use this when you need to listen for device events (such as keys and battery) without being affected by the Leqi interceptor
1.2 GlassSdk.registerLeqiInterceptor()
Location: GlassSdk.kt
@JvmStatic
fun registerLeqiInterceptor(context: Context, interceptor: LeqiInterceptor)Description:
- Register the Leqi voice command interceptor
- The interceptor takes effect when the app is in the foreground and automatically becomes inactive after the app moves to the background
- Call this in Activity.onCreate and call unregisterLeqiInterceptor() in onDestroy
Parameters:
context: Android Context, used for lifecycle managementinterceptor: interceptor implementation
Usage Example:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
GlassSdk.registerLeqiInterceptor(this, object : LeqiInterceptor {
override fun onLeqiInstruction(extra: String?): Boolean {
// Return true to intercept, false to allow it through
return handleCustomInstruction(extra)
}
})
}
override fun onDestroy() {
GlassSdk.unregisterLeqiInterceptor()
super.onDestroy()
}
}1.3 GlassSdk.unregisterLeqiInterceptor()
Location: GlassSdk.kt
@JvmStatic
fun unregisterLeqiInterceptor()Description:
- Unregister the Leqi voice command interceptor
- Usually called in Activity.onDestroy
1.4 LeqiInterceptor Interface
Location: LeqiInterceptor.kt (new file)
interface LeqiInterceptor {
/**
* Leqi voice command callback
* @param extra Extra parameters (JSON format)
* @return true means intercept this command; false means allow it through
*/
fun onLeqiInstruction(extra: String?): Boolean
}Description:
- Defines the Leqi voice command interceptor interface
- Apps can implement this interface to customize voice command handling logic
2. CameraShareHelper Configuration Switching
2.1 CameraShareHelper.restartSurfaceWithConfig()
Location: CameraShareHelper.kt
fun restartSurfaceWithConfig(config: CameraShareConfig, callback: SurfaceCallback)Description:
- Important: Switch configuration under the same callbackId to avoid multiple residual Surface sessions in system-server caused by creating new Helpers
- Internally calls
releaseSurface()first, theninitSurfaceWithConfig() - Must be called on the GL thread
Parameters:
config: New camera configuration (resolution, frame rate, stabilization, zoom)callback: Callback interface
Use Case:
- Dynamically switch camera resolution or frame rate
- Avoid memory leaks caused by creating multiple Helper instances
Usage Example:
// Initial configuration
val config1 = CameraShareConfig(
previewWidth = 1280,
previewHeight = 720,
previewTargetFps = 15,
zoomLevel = 1
)
helper.initSurfaceWithConfig(config1, callback)
// Switch to the new configuration (reuse the same helper)
val config2 = CameraShareConfig(
previewWidth = 1920,
previewHeight = 1080,
previewTargetFps = 24,
zoomLevel = 2
)
helper.restartSurfaceWithConfig(config2, callback)Notes:
- ⚠️ Must be called on the GL thread (the same thread as initSurfaceWithConfig)
- ⚠️ Do not create multiple CameraShareHelper instances to switch configurations
2.2 CameraShareHelper.restartNv21ExportWithConfig()
Location: CameraShareHelper.kt
fun restartNv21ExportWithConfig(enableMix: Boolean, config: CameraShareConfig, callback: Nv21Callback)Description:
- Switch NV21 export configuration under the same callbackId to avoid residual sessions from multiple Helpers
- Internally calls
releaseNv21Export()first, theninitNv21ExportWithConfig()
Parameters:
enableMix: Whether to enable Mix mode (camera + screen overlay)config: New camera configurationcallback: NV21 callback interface
Use Case:
- Dynamically switch the resolution or frame rate of NV21 export
- Avoid memory leaks caused by creating multiple Helper instances
3. Status Query APIs
3.1 CameraShareHelper.isSurfaceActive()
Location: CameraShareHelper.kt
fun isSurfaceActive(): BooleanDescription:
- Check whether Surface sharing is active
- Returns true if Surface has been initialized and not released
Use Case:
- Check the current state before switching configuration
- Avoid repeated initialization or release
3.2 CameraShareHelper.isNv21Active()
Location: CameraShareHelper.kt
fun isNv21Active(): BooleanDescription:
- Check whether NV21 export is active
- Returns true if NV21 export has been initialized and not released
Use Case:
- Check the current state before switching configuration
- State check during resource cleanup
4. Important Notes
1. APIs Related to Memory Leak Fixes
Background: Previous versions had a memory leak issue caused by repeatedly creating Surface sessions
Solution:
- Added
restartSurfaceWithConfig()andrestartNv21ExportWithConfig() - These two methods reuse the session under the same callbackId to avoid creating multiple sessions
Migration Recommendation:
// Old approach (causes memory leaks)
var helper = CameraShareHelper()
helper.initSurfaceWithConfig(config1, callback)
// ... when configuration needs to be switched
helper.releaseSurface()
helper = CameraShareHelper() // create a new instance <- the problem
helper.initSurfaceWithConfig(config2, callback)
// New approach (recommended)
val helper = CameraShareHelper()
helper.initSurfaceWithConfig(config1, callback)
// ... when configuration needs to be switched
helper.restartSurfaceWithConfig(config2, callback) // reuse helper2. Notes for Using the Leqi Interceptor
Lifecycle Management:
- The interceptor is active only when the app is in the foreground
- LifecycleOwner manages it automatically; manual start/stop is not required
- However, calling
unregisterLeqiInterceptor()in onDestroy is recommended to ensure cleanup
Interception Logic:
GlassSdk.registerLeqiInterceptor(this, object : LeqiInterceptor {
override fun onLeqiInstruction(extra: String?): Boolean {
return try {
val json = JSONObject(extra ?: "{}")
val command = json.optString("command")
when (command) {
"take_photo" -> {
// Custom photo capture logic
takePhoto()
true // Intercept and prevent Leqi from handling it
}
else -> false // Do not intercept; let Leqi handle it
}
} catch (e: Exception) {
false // Parsing failed; do not intercept
}
}
})3. Using Configuration Change Callbacks
Although no new callback methods are added in this release, existing callbacks are now triggered correctly:
SurfaceCallback:
object : CameraShareHelper.SurfaceCallback {
override fun onSurfaceShareConfigChanged(
width: Int,
height: Int,
appliedPreviewFps: Int,
videoStabilizationEnabled: Boolean
) {
// Automatically called when configuration changes
Log.d(TAG, "Config changed: ${width}x${height}@${appliedPreviewFps}fps")
}
override fun onZoomLevelChanged(zoomLevel: Int) {
// Called when the zoom level changes
Log.d(TAG, "Zoom changed: $zoomLevel")
}
}Nv21Callback:
object : CameraShareHelper.Nv21Callback {
override fun onNv21ExportResolutionChanged(
width: Int,
height: Int,
appliedPreviewFps: Int
) {
// Called when the NV21 export resolution changes
}
override fun onNv21ExportRuntimeParamsChanged(
appliedPreviewFps: Int,
videoStabilizationEnabled: Boolean
) {
// Called when runtime parameters change
}
override fun onZoomLevelChanged(zoomLevel: Int) {
// Called when the zoom level changes
}
}V2.1.8-E(2026-5-9)
- Phone SDK version:
com.rokid.security:phone.sdk:2.1.8-E - Glasses SDK version:
com.rokid.security:glass3.open.sdk:2.1.8-E-20260518.101638-5 - Recommended OTA version:
1.17.e002-20260509-150201or later
Phone SDK API Changes
Wi-Fi P2P H.264 Decode Control (Core Change)
When the phone receives H.264, it still automatically converts to NV21 by default. External callers can disable this through the SDK. The following APIs are added to IWifiP2PClientOperate:
// Set whether H.264 is automatically decoded to NV21 (enabled by default)
fun setAutoDecodeH264ToNv21(enable: Boolean)
// Query whether automatic H.264-to-NV21 decoding is currently enabled
fun isAutoDecodeH264ToNv21Enabled(): BooleanFeature Description:
- Default behavior: Maintains backward compatibility. Automatic H.264-to-NV21 decoding is enabled by default
- Performance optimization: When the app only needs H.264 data, automatic decoding can be disabled to save CPU and memory
- Flexible control: External callers can dynamically enable or disable it based on actual needs
Use Case:
// Scenario 1: Only the H.264 stream is needed for network transmission; disable automatic decoding
wifiP2PClientService?.setAutoDecodeH264ToNv21(false)
// Scenario 2: NV21 data is needed for AI recognition; enable automatic decoding (default)
wifiP2PClientService?.setAutoDecodeH264ToNv21(true)GlassVideoStreamParam Data Class
class GlassVideoStreamParam{
var fps = 20
var bitrate = 5184000
/** When true, this video stream uses AR overlay encoding (consistent with USE_AR_MIX on the glasses side). Disabled by default */
var isARMixEnabled = false
/** Expected video stream width. -1 indicates using the default glasses-side resolution */
var width = -1
/** Expected video stream height. -1 indicates using the default glasses-side resolution */
var height = -1
}IDevice Interface Extension
A parameter is added to the requestVideoStream method:
fun requestVideoStream(
tag: String,
videoStreamParam: GlassVideoStreamParam = GlassVideoStreamParam(),
callback: (isSuccess: Boolean) -> Unit
)Feature Description:
- Supports specifying a custom resolution when the phone requests camera data from the glasses
- Works with CameraShareConfig in open-sdk to implement end-to-end custom resolution control
- A default value of 0 indicates using the system default configuration, maintaining backward compatibility
Usage Example:
// Request a 1280x720@30fps video stream
val extra = GlassVideoStreamParam(width = 1280, height = 720, fps = 30)
deviceService?.requestVideoStream("my_tag", extra) { success ->
if (success) {
// Start receiving the video stream
}
}Glasses SDK API Changes
GlassSdk.kt Enhancements
- New compatibility methods: Three compatibility methods are added for the offline command service to ensure backward compatibility between new and old SDK versions:
setOfflineCmdLanguage(language: String): Boolean- Set the offline command languagesetOfflineCmdWords(language: String, voiceActions: List<VoiceAction>): Boolean- Override offline command words by languageclearOfflineCmdWords(language: String): Boolean- Clear offline command words for a specified language
These methods use a try-catch mechanism to handle compatibility issues between new and old system-server versions.
CameraShareHelper.kt New Features
Configurable camera sharing: New camera sharing methods with configuration support
initSurfaceWithConfig(config: CameraShareConfig, callback: SurfaceCallback)- Configurable Surface sharing initializationinitNv21ExportWithConfig(enableMix: Boolean, config: CameraShareConfig, callback: Nv21Callback)- Configurable NV21 export
Dynamic configuration change notifications: New callback methods support runtime configuration changes
onSurfaceShareConfigChanged(width: Int, height: Int, appliedPreviewFps: Int, videoStabilizationEnabled: Boolean)- Surface sharing configuration change notificationonNv21ExportResolutionChanged(width: Int, height: Int, appliedPreviewFps: Int)- NV21 export resolution change notificationonNv21ExportRuntimeParamsChanged(appliedPreviewFps: Int, videoStabilizationEnabled: Boolean)- NV21 export runtime parameter change notification
Zoom support: Adds a zoom level change callback
onZoomLevelChanged(zoomLevel: Int)- Zoom level change notification (supported in both SurfaceCallback and Nv21Callback)
Get supported preview resolutions: Adds a method to get the list of preview resolutions supported by the Camera API
getSupportedPreviewSizes(): List<Triple<Int, Int, Boolean>>- Get supported preview resolutions (the camera sensor orientation is rotated 270 degrees, so the width and height are swapped compared with the resolutions passed to initSurfaceWithConfig and initNv21ExportWithConfig)
IDeviceService.aidl New APIs
interface IDeviceService {
/**
* Set capture light
* @param timestamp Timestamp
*/
void setCameraLedEnable(boolean enable);
/**
* Set network access mode: 0 phone access; 1 glasses access
* @param timestamp Timestamp
*/
void setNetworkType(int type);
int getNetworkType();
/**
* Configure app visibility and the display order of third-party apps
* Used to batch configure the show/hide status of built-in system apps and third-party apps.
*
* @param appConfig App configuration information, including:
* - appList: List of built-in system apps to hide
* - thirdApps: Third-party app list, which will be displayed at the front
* @param callback Set result callback; success=true indicates success, false indicates failure
*
*/
void configureAppVisibility(in GlassAppConfig appConfig, IAppVisibilityListener callback);
/**
* Set the time synchronization server address
* Supports HTTP/HTTPS and NTP protocols, and automatically identifies the protocol type based on the URL
*
* @param serverUrl Time server address, supporting the following formats:
* - HTTP/HTTPS protocol: https://time.example.com or http://time.example.com
* - NTP protocol: ntp.example.com or 192.168.1.100
* - null or empty string: Use the default NTP protocol and public NTP servers
*
* @note If the URL starts with http:// or https://, HTTP is used to obtain the time
* Otherwise, NTP is used (standard UDP protocol, port 123)
*/
void setTimeServer(String serverUrl);
/**
* Get the currently configured time server address
*
* @return Currently configured time server address; returns null if not configured
*/
String getTimeServer();
}IMediaServer.aidl New APIs
interface IMediaServer {
/**
* Start cross-process Surface sharing (renders only camera frames to the Surface, without NV21 data)
* @param surface Surface created by the client to receive camera frames
* @param callback Lifecycle callback
*/
void startCameraShare(in Surface surface, ICameraSurfaceCallback callback);
/**
* Stop cross-process Surface sharing
* @param callback Previously registered callback
*/
void stopCameraShare(ICameraSurfaceCallback callback);
/**
* Start NV21 data export (share frame data through SharedMemory double buffering)
* @param callback Callback interface that receives frame data through onNv21FrameAvailable
* @param enableMix Whether to enable overlay mode (camera + screen overlay),
* false: Export pure camera NV21 data
* true: Export NV21 data after overlaying camera with screen content
*/
void startCameraNv21Export(ICameraShareCallback callback, boolean enableMix);
/**
* Stop NV21 data export
* @param callback Previously registered callback
*/
void stopCameraNv21Export(ICameraShareCallback callback);
/**
* Close camera
* @param callback Callback interface: true indicates the camera was closed successfully, false indicates the camera was not closed
*/
void closeCamera(ICameraCloseCallback callback);
/**
* Start NV21 export (preview resolution, target frame rate, and stabilization can be specified; binary compatibility with the old interface is maintained by client-side call selection).
* When multiple sessions share the same physical camera, the later configuration preempts the pipeline; existing sessions are synchronized through
* {@link com.rokid.security.system.server.media.callback.ICameraShareCallback#onNv21ExportResolutionChanged}
* or {@link com.rokid.security.system.server.media.callback.ICameraShareCallback#onNv21ExportRuntimeParamsChanged}.
*/
void startCameraNv21ExportWithConfig(ICameraShareCallback callback, boolean enableMix, in CameraShareConfig config);
/**
* Start cross-process Surface sharing (configurable version)
* @param surface Surface created by the client to receive camera frames
* @param callback Lifecycle callback
* @param enableMix Whether to enable AR Mix mode (camera + screen overlay)
* @param config Configuration items, consistent with CameraShareConfig
*/
void startCameraShareWithConfig(in Surface surface, ICameraSurfaceCallback callback, boolean enableMix, in CameraShareConfig config);
/**
* Get the list of preview resolutions supported by the Camera API
* @return Supported resolution list (camera raw resolution, landscape orientation)
*/
List<CameraSize> getSupportedPreviewSizes();
}ICameraSurfaceCallback.aidl New APIs
/**
* Lightweight callback for cross-process Surface sharing (lifecycle only, no NV21 data)
*/
interface ICameraSurfaceCallback {
/**
* Camera opened
* @param width Camera width
* @param height Camera height
*/
void onCameraOpened(int width, int height);
/**
* Camera closed
*/
void onCameraClosed();
/**
* An error occurred
* @param code Error code
* @param msg Error message
*/
void onError(int code, String msg);
/**
* Unique callback identifier
*/
String getCallbackId();
/**
* Surface sharing configuration changed (resolution, frame rate, stabilization, etc.)
* Triggered when configuration is updated through startCameraShareWithConfig to avoid restarting the camera
* @param width New width
* @param height New height
* @param appliedPreviewFps Negotiated frame rate
* @param videoStabilizationEnabled Whether stabilization is enabled
*/
void onSurfaceShareConfigChanged(int width, int height, int appliedPreviewFps, boolean videoStabilizationEnabled);
/**
* Zoom level changed
* @param zoomLevel Current zoom level (integer)
*/
void onZoomLevelChanged(int zoomLevel);
}ICameraShareCallback.aidl New APIs
interface ICameraShareCallback {
/**
* Camera opened, with resolution and NV21 double-buffered SharedMemory provided
* @param width Camera width
* @param height Camera height
* @param nv21Buffer0 NV21 double buffer 0
* @param nv21Buffer1 NV21 double buffer 1
*/
void onCameraOpened(int width, int height, in SharedMemory nv21Buffer0, in SharedMemory nv21Buffer1);
/**
* A new NV21 frame has been written to the specified buffer
* @param bufferIndex Buffer index (0 or 1)
* @param width Frame width
* @param height Frame height
* @param timestamp Frame timestamp (milliseconds)
*/
void onNv21FrameAvailable(int bufferIndex, int width, int height, long timestamp);
/**
* Camera closed
*/
void onCameraClosed();
/**
* An error occurred
* @param code Error code
* @param msg Error message
*/
void onError(int code, String msg);
/**
* Unique callback identifier
*/
String getCallbackId();
/**
* A new NV21 frame has been written to the specified buffer (asynchronous version, better performance)
* @param bufferIndex Buffer index (0 or 1)
* @param width Frame width
* @param height Frame height
* @param timestamp Frame timestamp (milliseconds)
*/
oneway void onNv21FrameAvailableAsync(int bufferIndex, int width, int height, long timestamp);
/**
* The NV21 output size or SharedMemory buffer has switched (because multiple apps preempt the pipeline, or because the session actively changed configuration).
* The client should close the old mapping and remap using the new SharedMemory. Subsequent {@link #onNv21FrameAvailable} callbacks use the width and height from this callback.
*
* @param width NV21 logical width
* @param height NV21 logical height
* @param nv21Buffer0 New double buffer 0
* @param nv21Buffer1 New double buffer 1
* @param appliedPreviewFps Upper bound of the preview AE target frame-rate range negotiated by the device (representative value)
*/
void onNv21ExportResolutionChanged(int width, int height, in SharedMemory nv21Buffer0, in SharedMemory nv21Buffer1, int appliedPreviewFps);
/**
* The output size is unchanged, but the preview frame rate or stabilization switch changed due to pipeline reconfiguration.
*
* @param appliedPreviewFps Representative negotiated preview frame rate (upper bound of the AE range)
* @param videoStabilizationEnabled Whether video stabilization is currently requested
*/
void onNv21ExportRuntimeParamsChanged(int appliedPreviewFps, boolean videoStabilizationEnabled);
/**
* Zoom level changed
* @param zoomLevel Current zoom level (integer)
*/
void onZoomLevelChanged(int zoomLevel);
}V2.1.7-E(2026-4-7)
- Phone SDK version:
com.rokid.security:phone.sdk:2.1.7-E - Glasses SDK version:
com.rokid.security:glass3.open.sdk:2.1.7-E - Recommended OTA version:
1.11.e003-20260331-150201or later
Phone SDK API Changes
RTC module removed: All RTC-related engine parameters and initialization configurations were removed from EngineParam.kt and MobileEngineServerImpl.kt (under sdk-base and sdk-server, respectively). In other words, the SDK no longer includes real-time audio/video calling features.
Phone SDK: AR Recording API Added
The getIARMixControl() method is added to IWifiP2PClientOperate, returning an IARMixControl object. Integrators can obtain the P2P capability object through PSecuritySDK.getWifiP2PClientService(), then call getIARMixControl() to get the AR recording control interface and configure AR recording on the phone side (such as enable/disable and parameter adjustment).
Example 1
private val mIARMixControl by lazy {
PSecuritySDK.getWifiP2PClientService()?.getIARMixControl()
}
// Set AR mixed recording switch
binding.switchArMix.setOnCheckedChangeListener { _, isChecked ->
if (GlobalData.btConnectState.value) {
mIARMixControl?.setARMixEnabled(isChecked) { success ->
if (!success) {
L.i(TAG, "setARMixEnabled: Fail")
getARMixState()
}
}
} else {
Toast.makeText(this, "Please connect the device over Bluetooth first", Toast.LENGTH_LONG).show()
}
}
// Get AR mixed recording state
private fun getARMixState() {
if (GlobalData.btConnectState.value) {
val activityRef = WeakReference(this)
mIARMixControl?.getARMixState(
action = { isOpen ->
activityRef.get()?.runOnUiThread {
L.i(TAG, "getARMixState: $isOpen")
}
},
onFail = { errMsg, code ->
activityRef.get()?.runOnUiThread {
L.i(TAG, "getARMixState: onFail --- errMsg=$errMsg")
}
}
)
}
}Example 2
class GlassVideoStreamParam {
var fps = 20 // Frame rate
var bitrate = 5184000 // Video bitrate
/**
* Whether to enable AR overlay mode (camera feed + screen content)
* When true, the video stream obtained through P2P is the real-time image after overlaying camera feed with screen content
* Default value is false
*/
var isARMixEnabled = false
}
// Request video stream
val param = GlassVideoStreamParam().apply {
this.fps = fps
this.bitrate = bitrate
this.isARMixEnabled = true
}
PSecuritySDK.getAbsDeviceInfoService()?.requestVideoStream(VIDEO_TAG, videoStreamParam = param) {}Glasses SDK API Changes
IMediaServer Adds the Following Four APIs
public interface IMediaServer extends IInterface {
/**
* Start cross-process Surface sharing (renders only camera frames to the Surface, without NV21 data)
* @param surface Surface created by the client to receive camera frames
* @param callback Lifecycle callback
*/
void startCameraShare(in Surface surface, ICameraSurfaceCallback callback);
/**
* Stop cross-process Surface sharing
* @param callback Previously registered callback
*/
void stopCameraShare(ICameraSurfaceCallback callback);
/**
* Start NV21 data export (share frame data through SharedMemory double buffering)
* @param callback Callback interface that receives frame data through onNv21FrameAvailable
* @param enableMix Whether to enable overlay mode (camera + screen overlay),
* false: Export pure camera NV21 data
* true: Export NV21 data after overlaying camera with screen content
*/
void startCameraNv21Export(ICameraShareCallback callback, boolean enableMix);
/**
* Stop NV21 data export
* @param callback Previously registered callback
*/
void stopCameraNv21Export(ICameraShareCallback callback);
}Usage can refer to the
SendMessageActivityclass in the demo.
IMediaServer Parameter Addition
The isArRMixEnabled parameter is added to the startRecord method (implemented by adding this field to RecordConfig) to control whether AR mixed recording is enabled.
@Keep
@Parcelize
data class RecordConfig(
val path: String,
val min: Int,
val enableAudio: Boolean,
val width: Int = 1280,
val height: Int = 720,
val fps: Int = 20,
/**
* Whether AR overlay is enabled for this recording (camera feed + screen content).
* Default value is false,Old clients keep false when this field is not passed.
* When applied, the glasses side merges this with the persistent AR screen recording switch on the phone side.
*/
val isArRMixEnabled: Boolean = false,
) : Parcelable {
override fun toString(): String {
return "RecordConfig(path='$path', min=$min, enableAudio=$enableAudio, width=$width, height=$height, fps=$fps, isArRMixEnabled=$isArRMixEnabled)"
}
}Usage can refer to the
SdkMediaActivityclass in the demo.
V2.1.5-E(2026-2-5)
- Phone SDK version:
com.rokid.security:phone.sdk:2.1.5-E - Glasses SDK version:
com.rokid.security:glass3.open.sdk:2.1.5-E - Recommended OTA version:
1.11.e003-20260131-150201or later
Phone SDK API Changes
IBTRingClientListener Adds a Method:
interface IBTRingClientListener {
/***
* Bluetooth connection status callback
* @param extra Callback parameter
*/
fun onConnect(extra: RingExtra)
}Glasses SDK API Changes
IDeviceService Adds a Method:
void setSystemTime(long var1) throws RemoteException;
// Usage example: set the glasses-side system time after SDK initialization succeeds
GlassSdk.getGlassDeviceService()?.setSystemTime(1770014682490)V2.1.04-E(2026-1-16)
- Phone SDK version:
com.rokid.security:phone.sdk:2.1.04-E - Glasses SDK version:
com.rokid.security:glass3.open.sdk:2.1.04-E - Recommended OTA version:
1.11.e002-20260116-150201or later
New Features
- GB-standard/RTC supports landscape 1080p display
- Added Scan-to-connect Wi-Fi app: Wi-Fi QR code generator
- Added glasses-side audio prompts for Bluetooth, app connection, and low battery
- Added phone-side default startup app configuration; after selection, the glasses enter that app by default on boot
- Fixed removing a single offline voice command
Phone SDK API Changes
IDevice Adds Methods:
package com.rokid.security.phone.sdk.api.device
import com.rokid.security.sdk.base.common.GlassVideoStreamParam
import com.rokid.security.sdk.base.common.out.GlassDeviceInfo
interface IDevice {
/**
* Request pulling the glasses-side video stream
* @param tag Video stream request identifier, used to cancel the video stream request
* @param videoStreamParam Modify video frame rate
* @param callback true indicates video stream request success; false indicates failure
*/
fun requestVideoStream(tag: String,videoStreamParam: GlassVideoStreamParam = GlassVideoStreamParam(),callback: (isSuccess: Boolean) -> Unit)
/**
* Stop pulling the glasses-side video stream
* @param tag Video stream stop identifier, used to cancel stopping the video stream
* @param callback true indicates video stream stopped successfully; false indicates failure
*/
fun stopVideoStream(tag: String,callback: (isSuccess: Boolean) -> Unit)
/**
* Request pulling the glasses-side audio stream
* @param tag Audio stream identifier, used to cancel the audio stream request
* @param callback true indicates audio stream request success; false indicates failure
*/
fun requestAudioStream(tag: String,callback: (isSuccess: Boolean) -> Unit)
/**
* Stop pulling the glasses-side audio stream
* @param tag Audio stream identifier, used to cancel stopping the audio stream
* @param callback true indicates audio stream stopped successfully; false indicates failure
*/
fun stopAudioStream(tag: String,callback: (isSuccess: Boolean) -> Unit)
}IFileOperate Adds Methods:
package com.rokid.security.phone.sdk.api.msg.api
import com.rokid.security.phone.sdk.api.msg.listener.FileReceiveListener
import com.rokid.security.phone.sdk.api.msg.listener.FileReceiveV2Listener
import com.rokid.security.phone.sdk.api.msg.listener.IMessageListener
import com.rokid.security.phone.sdk.base.data.callback.IResult
import java.io.File
/**
* Created by wjm on 2025/5/9
*/
interface IFileOperate {
/**
* Add the local file receiving listener
* @param listener
*/
@Deprecated(
message = "Deprecated in version V2.1.4; use addFileReceiveV2Listener",
replaceWith = ReplaceWith("addFileReceiveV2Listener(listener)"),
level = DeprecationLevel.WARNING
)
fun addFileReceiveListener(listener: FileReceiveListener)
/**
* Remove the local file receiving listener
* @param listener
*/
@Deprecated(
message = "Deprecated in version V2.1.4; use removeFileReceiveV2Listener",
replaceWith = ReplaceWith("removeFileReceiveV2Listener(listener)"),
level = DeprecationLevel.WARNING
)
fun removeFileReceiveListener(listener: FileReceiveListener)
/**
* Add the local file receiving listener
* @param listener
*/
fun addFileReceiveV2Listener(listener: FileReceiveV2Listener)
/**
* Remove the local file receiving listener
* @param listener
*/
fun removeFileReceiveV2Listener(listener: FileReceiveV2Listener)
}IBluetoothRing Method Change:
package com.rokid.security.phone.sdk.api.bluetooth.ring.api
import android.bluetooth.BluetoothDevice
import com.rokid.security.phone.sdk.api.bluetooth.classic.listener.IClassicBTClientListener
/**
* Author: zhangshengwei
* Date: 2025/6/24
*/
interface IBluetoothRing {
/**
* Start classic Bluetooth scan
* @param timeoutMillis Scan timeout setting
* */
fun startScan(
deviceNameFilter:List<String> = listOf("D01"),
timeoutMillis: Long = 20000L,
){}
}Glasses SDK API Changes
ICommonInfoListener Adds a Method:
/**
* Created by wjm on 2025/9/3
*/
interface ICommonInfoListener {
/**
* Configuration information on the glasses side
*/
fun onConfig(config: String)
}PreviewResolution: Video File Resolution During Recording
/**
* Video file resolution during recording
*/
object PreviewResolution{
val ResolutionInfo_720P = ResolutionInfo("720P", 1280, 720) //Preview
val ResolutionInfo_1080P = ResolutionInfo("1080P", 1080,1920) //Preview
// Added landscape camera preview
val ResolutionInfo_1080P_Land = ResolutionInfo("1080P_Land", 1920, 1080) //Preview
}v2.1.2 (2025-12-15)
- Phone SDK version:
com.rokid.security:phone.sdk:2.1.2-E - Glasses SDK version:
com.rokid.security:glass3.open.sdk:2.1.2-E - Recommended OTA version:
1.10.e001-20251215-150202or later
New Features
- Added offline TTS small voice model support
- Added key listener support
- System face recognition algorithm upgraded to NPU acceleration for faster recognition
- Supports dual-system mode
- Developer mode enabled by default
Phone SDK API Changes
IWifiP2PClientOperate Adds Methods:
interface IWifiP2PClientOperate {
/**
* Get P2P group information
* @param action Callback function that returns a WifiP2pGroup object
*/
fun getGroupInfo(action: (group: WifiP2pGroup?) -> Unit)
/**
* Get the P2P connection strategy management instance
* @return IP2PConnectControl interface instance
*/
fun getIP2PConnectControl(): IP2PConnectControl
}IAIChat Adds Methods:
interface IAIChat {
/**
* Remove AI chat listener
*/
fun removeAiChatListener()
/**
* Get runtime chat history
* @return Mutable chat history list
*/
fun getRunTimeChatList(): MutableList<ChatBean>
}Glasses SDK API Changes
GlassSdk Adds Service Getter Methods
object GlassSdk {
/**
* Get image collection service (face/license plate, etc.)
* @return ICollectService instance
*/
@JvmStatic
fun getGlassCollectService(): ICollectService? {
return getService(ServerType.COLLECT, ICollectService::class.java)
}
/**
* Get offline TTS management service
* @return IOfflineTtsService instance
*/
@JvmStatic
fun getGlassOfflineTtsService(): IOfflineTtsService? {
return getService(ServerType.SERVICE_OFFLINE_TTS, IOfflineTtsService::class.java)
}
}New ICollectService Interface:
/**
* Image collection service interface
* Provides collection, transfer, and query capabilities for face, license plate, and other images
*/
interface ICollectService {
/**
* Start image collection
* @param mode Collection mode
*/
fun startCollect(mode: Int)
/**
* Stop image collection
*/
fun stopCollect()
/**
* Set image collection listener
* @param listener Collection listener instance
*/
fun setCollectListener(listener: IGlassCollectListener)
/**
* Remove image collection listener
* @param listener Listener instance to remove
*/
fun removeCollectListener(listener: IGlassCollectListener)
/**
* Send face image to a specified target
* @param identifier Target identifier (such as device ID, user ID, etc.)
* @param param Collection parameters, including collection configuration information
* @param callback Send result callback
*/
fun sendFacePicture(identifier: String, param: CollectParam, callback: ICollectCallback)
/**
* Send license plate recognition image to a specified target
* @param identifier Target identifier
* @param platNo License plate number
* @param callback Send result callback
*/
fun sendLPRPicture(identifier: String, platNo: String, callback: ICollectCallback)
/**
* Switch collection mode
* @param mode New collection mode
*/
fun changeMode(mode: Int)
/**
* Get small face image
* @param frameId Frame ID
* @param trackId Track ID
* @return Small face Bitmap; returns null if retrieval fails
*/
fun getFaceSmallBitmap(frameId: Long, trackId: Long): Bitmap?
/**
* Get small license plate image
* @param plateNo License plate number
* @return Small license plate Bitmap; returns null if retrieval fails
*/
fun getLprSmallBitmap(plateNo: String): Bitmap?
}New IOfflineTtsService Interface:
interface IOfflineTtsService {
/**
* Play speech for the specified text
* @param ttsMsg Text content to be spoken
*/
fun playTtsMsg(ttsMsg: String)
}IMediaServer Adds Listener Management Methods:
interface IMediaServer {
/**
* Register media service status listener
* @param listener Listener instance
*/
fun setMediaStateLister(listener: IMediaStateLister)
/**
* Unregister media service status listener
* @param listener Listener instance
*/
fun removeMediaStateLister(listener: IMediaStateLister)
}IOfflineRecServer Adds Face Recognition Result Reporting Method:
interface IOfflineRecServer {
/**
* Report face recognition result
* @param info Face recognition submission information
* @param face Face image Bitmap
*/
fun submitRecognizedFaceInfo(info: RecognizeFaceSubmitInfo, face: Bitmap)
}