@glassly/bluetooth-sdk 0.1.0-dev.89 → 0.1.0-dev.96

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. package/android/src/main/java/com/glassly/bluetoothsdk/GeneratedChangelogCatalog.kt +1 -0
  2. package/android/src/main/java/com/glassly/bluetoothsdk/GeneratedReleaseMetadata.kt +3 -3
  3. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G1.kt +8 -49
  4. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2.kt +3 -2
  5. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/Mach1.kt +0 -13
  6. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/MentraLive.kt +11 -86
  7. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/MentraNex.kt +1 -4
  8. package/android/src/main/java/com/glassly/bluetoothsdk/stt/VadGateSpeechPolicy.kt +0 -2
  9. package/build/generated/changelogCatalog.d.ts +3 -0
  10. package/build/generated/changelogCatalog.d.ts.map +1 -1
  11. package/build/generated/changelogCatalog.js +4 -0
  12. package/build/generated/changelogCatalog.js.map +1 -1
  13. package/build/generated/releaseMetadata.js +3 -3
  14. package/build/generated/releaseMetadata.js.map +1 -1
  15. package/ios/Source/BluetoothSdkDefaults.swift +1 -1
  16. package/ios/Source/DeviceManager.swift +5 -7
  17. package/ios/Source/GeneratedChangelogCatalog.swift +1 -0
  18. package/ios/Source/GeneratedReleaseMetadata.swift +3 -3
  19. package/ios/Source/sgcs/G2.swift +3 -10
  20. package/ios/Source/sgcs/MentraLive.swift +4 -4
  21. package/ios/Source/sgcs/MentraNex.swift +43 -44
  22. package/ios/Source/tts/TTSTools.swift +0 -4
  23. package/package.json +1 -1
  24. package/src/generated/changelogCatalog.ts +4 -0
  25. package/src/generated/releaseMetadata.ts +3 -3
  26. package/ios/Source/sgcs/Frame.swift +0 -649
@@ -3,6 +3,7 @@ package com.glassly.bluetoothsdk
3
3
  /** Generated from /changelogs. Do not edit directly. */
4
4
  internal val GENERATED_RELEASE_CHANGELOGS: List<ReleaseChangelog> =
5
5
  listOf(
6
+ ReleaseChangelog(version = "3.2.0", markdown = "This release is under active development. User-facing changes will be documented as they land."),
6
7
  ReleaseChangelog(version = "3.1.0", markdown = "Software updates are more reliable, with clearer progress and recovery when the glasses restart.\n\n- GlasslyOS, Glassly Engine, the Bluetooth SDK, and the glasses client now share one coordinated release version.\n- Mentra Live updates can continue across APK, system, and firmware restarts without asking the user to start the same update again.\n- Bluetooth photo capture and transfer diagnostics are more precise and less disruptive to normal glasses traffic."),
7
8
  ReleaseChangelog(version = "0.1.0", markdown = "First coordinated Glassly release: the app, Glassly Engine, and the Bluetooth SDK now ship one shared release version.\n\n- The Glassly App, Glassly Engine, and the Bluetooth SDK are versioned and published together.\n- Mentra Live updates can continue across APK, system, and firmware restarts without asking the user to start the same update again.\n- Bluetooth photo capture and transfer diagnostics are more precise and less disruptive to normal glasses traffic."),
8
9
  )
@@ -3,9 +3,9 @@ package com.glassly.bluetoothsdk
3
3
  /** Generated by release CI. Do not edit in a release checkout. */
4
4
  internal object GeneratedReleaseMetadata {
5
5
  const val FAMILY_BASE_VERSION: String = "0.1.0"
6
- const val RELEASE_IDENTITY: String = "0.1.0-dev.89"
7
- const val RELEASE_SET_ID: String = "glassly-0.1.0-dev.89"
8
- const val SOURCE_COMMIT: String = "c66a621d66d70251e257f73c9a79ee1f8e079be9"
6
+ const val RELEASE_IDENTITY: String = "0.1.0-dev.96"
7
+ const val RELEASE_SET_ID: String = "glassly-0.1.0-dev.96"
8
+ const val SOURCE_COMMIT: String = "440518cf281588df779cd13d78922782db027ad4"
9
9
  const val OTA_MANIFEST_URL: String = ""
10
10
  const val OTA_MANIFEST_SHA256: String = ""
11
11
  }
@@ -41,7 +41,6 @@ import java.nio.ByteBuffer
41
41
 
42
42
  import com.google.gson.Gson
43
43
 
44
- import org.greenrobot.eventbus.EventBus
45
44
  import org.json.JSONArray
46
45
  import org.json.JSONException
47
46
  import org.json.JSONObject
@@ -222,11 +221,10 @@ class G1 : SGCManager() {
222
221
  private var rightTxChar: BluetoothGattCharacteristic? = null
223
222
  private var leftRxChar: BluetoothGattCharacteristic? = null
224
223
  private var rightRxChar: BluetoothGattCharacteristic? = null
225
- // NOTE: named connectionState in G1.java; renamed because Kotlin can't shadow
226
- // SGCManager's public val connectionState with a private field of another type.
224
+ // Not named connectionState: Kotlin can't shadow SGCManager's public val
225
+ // connectionState with a private field of another type.
227
226
  private var g1ConnectionState = SmartGlassesConnectionState.DISCONNECTED
228
- // Executor for parallel bitmap operations (declared before init so the
229
- // constructor body can assign it; in G1.java this field lived in the BMP section)
227
+ // Declared before init so the constructor body can assign it.
230
228
  private var bitmapExecutor: ExecutorService? = null
231
229
  private val handler = Handler(Looper.getMainLooper())
232
230
  private val queryBatteryStatusHandler = Handler(Looper.getMainLooper())
@@ -319,12 +317,9 @@ class G1 : SGCManager() {
319
317
  private var shouldUseGlassesMic = false
320
318
  private var lastThingDisplayedWasAnImage = false
321
319
 
322
- // Serial number and style/color information
323
- // NOTE: G1.java declared public fields serialNumber/style/color here, but they were
324
- // never read or written; in Kotlin they would clash with SGCManager's val properties,
325
- // so they are omitted.
320
+ // serialNumber/style/color come from SGCManager's val properties; do not
321
+ // redeclare them here.
326
322
 
327
- // lock writing until the last write is successful
328
323
  // fonts in G1
329
324
  private var g1Text: G1Text? = null
330
325
 
@@ -658,16 +653,9 @@ class G1 : SGCManager() {
658
653
  DeviceStore.apply("glasses", "headUp", false)
659
654
  }
660
655
  }
661
- // DOUBLE TAP
662
- // appears to be completely broken - clears the screen - we should not tell
663
- // people to use the touchpads yet til this is fixed
664
- // else if (data.length > 1 && (data[0] & 0xFF) == 0xF5 && ((data[1] & 0xFF) ==
665
- // 0x20) || ((data[1] & 0xFF) == 0x00)) {
666
- // boolean isRight = deviceName.contains("R_");
667
- // Bridge.log("G1: GOT DOUBLE TAP from isRight?: " + isRight);
668
- // EventBus.getDefault().post(new GlassesTapOutputEvent(2, isRight,
669
- // System.currentTimeMillis()));
670
- // }
656
+ // Double tap (0xF5 0x20 / 0x00) is deliberately unhandled: on this
657
+ // firmware it clears the screen. Don't surface the touchpads until
658
+ // that is fixed.
671
659
  // BATTERY RESPONSE
672
660
  else if (data.size > 2 && data[0] == 0x2C.toByte() && data[1] == 0x66.toByte()) {
673
661
  if (deviceName.contains("L_")) {
@@ -680,8 +668,6 @@ class G1 : SGCManager() {
680
668
 
681
669
  if (batteryLeft != -1 && batteryRight != -1) {
682
670
  val minBatt = Math.min(batteryLeft, batteryRight)
683
- // Bridge.log("G1: Minimum Battery Level: " + minBatt);
684
- // EventBus.getDefault().post(new BatteryLevelEvent(minBatt, false));
685
671
  DeviceStore.apply("glasses", "batteryLevel", minBatt)
686
672
  }
687
673
  }
@@ -695,28 +681,20 @@ class G1 : SGCManager() {
695
681
  else if (data.size > 1 && (data[0].toInt() and 0xFF) == 0xF5 && (data[1].toInt() and 0xFF) == 0x08) {
696
682
  DeviceStore.apply("glasses", "caseOpen", true)
697
683
  DeviceStore.apply("glasses", "caseRemoved", false)
698
- // EventBus.getDefault()
699
- // .post(new CaseEvent(caseBatteryLevel, caseCharging, caseOpen, caseRemoved));
700
684
  }
701
685
  // CASE CLOSED
702
686
  else if (data.size > 1 && (data[0].toInt() and 0xFF) == 0xF5 && (data[1].toInt() and 0xFF) == 0x0B) {
703
687
  DeviceStore.apply("glasses", "caseOpen", false)
704
688
  DeviceStore.apply("glasses", "caseRemoved", false)
705
- // EventBus.getDefault()
706
- // .post(new CaseEvent(caseBatteryLevel, caseCharging, caseOpen, caseRemoved));
707
689
  }
708
690
  // CASE CHARGING STATUS
709
691
  else if (data.size > 3 && (data[0].toInt() and 0xFF) == 0xF5 && (data[1].toInt() and 0xFF) == 0x0E) {
710
692
  DeviceStore.apply("glasses", "caseCharging", (data[2].toInt() and 0xFF) == 0x01)// TODO: verify this is correct
711
- // EventBus.getDefault()
712
- // .post(new CaseEvent(caseBatteryLevel, caseCharging, caseOpen, caseRemoved));
713
693
  }
714
694
  // CASE CHARGING INFO
715
695
  else if (data.size > 3 && (data[0].toInt() and 0xFF) == 0xF5 && (data[1].toInt() and 0xFF) == 0x0F) {
716
696
  val newCaseBatteryLevel = (data[2].toInt() and 0xFF)// TODO: verify this is correct
717
697
  DeviceStore.apply("glasses", "caseBatteryLevel", newCaseBatteryLevel)
718
- // EventBus.getDefault()
719
- // .post(new CaseEvent(caseBatteryLevel, caseCharging, caseOpen, caseRemoved));
720
698
  }
721
699
  // HEARTBEAT RESPONSE
722
700
  else if (data.isNotEmpty() && data[0] == 0x25.toByte()) {
@@ -785,8 +763,6 @@ class G1 : SGCManager() {
785
763
  if ("Left" == side) {
786
764
  isLeftConnected = true
787
765
  Bridge.log("G1: PROC_QUEUE - left side setup complete")
788
-
789
- // Manufacturer data decoding moved to connection start
790
766
  } else {
791
767
  isRightConnected = true
792
768
  // Bridge.log("G1: PROC_QUEUE - right side setup complete");
@@ -810,11 +786,8 @@ class G1 : SGCManager() {
810
786
  // Bridge.log("G1: Sending debug 0xF4 Command");
811
787
  // sendDataSequentially(new byte[]{(byte) 0xF4, (byte) 0x01});
812
788
 
813
- // no longer need to be staggered as we fixed the sender
814
- // do first battery status query
815
789
  queryBatteryStatusHandler.postDelayed({ queryBatteryStatus() }, 10L)
816
790
 
817
- // setup brightness
818
791
  val brightnessValue = (DeviceStore.get("bluetooth", "brightness") as Number).toInt()
819
792
  val shouldUseAutoBrightness = DeviceStore.get("bluetooth", "auto_brightness") as Boolean
820
793
  sendBrightnessCommandHandler
@@ -2556,11 +2529,6 @@ class G1 : SGCManager() {
2556
2529
  scanner.stopScan(bleScanCallback)
2557
2530
  isScanningForCompatibleDevices = false
2558
2531
  Bridge.log("G1: Stopped scanning for smart glasses.")
2559
- // EventBus.getDefault().post(
2560
- // new GlassesBluetoothSearchStopEvent(
2561
- // smartGlassesDevice.deviceModelName
2562
- // )
2563
- // );
2564
2532
  }, 10000L)
2565
2533
  }
2566
2534
 
@@ -2650,13 +2618,6 @@ class G1 : SGCManager() {
2650
2618
 
2651
2619
  Bridge.log("G1: Sent auto light brightness command => Brightness: " + brightness + ", Auto Light: "
2652
2620
  + (if (autoLight) "Open" else "Close"))
2653
-
2654
- // send to AugmentOS core
2655
- // if (autoLight) {
2656
- // EventBus.getDefault().post(new BrightnessLevelEvent(autoLight));
2657
- // } else {
2658
- // EventBus.getDefault().post(new BrightnessLevelEvent(brightness));
2659
- // }
2660
2621
  }
2661
2622
 
2662
2623
  fun sendHeadUpAngleCommand(headUpAngle: Int) {
@@ -2677,7 +2638,6 @@ class G1 : SGCManager() {
2677
2638
  sendDataSequentially(buffer.array(), false, 100)
2678
2639
 
2679
2640
  Bridge.log("G1: Sent headUp angle command => Angle: " + headUpAngleValue)
2680
- // EventBus.getDefault().post(new HeadUpAngleEvent(headUpAngle));
2681
2641
  }
2682
2642
 
2683
2643
  fun sendDashboardPositionCommand(height: Int, depth: Int) {
@@ -2700,7 +2660,6 @@ class G1 : SGCManager() {
2700
2660
  sendDataSequentially(buffer.array(), false, 100)
2701
2661
 
2702
2662
  Bridge.log("G1: Sent dashboard height/depth command => Height: " + heightValue + ", Depth: " + depthValue)
2703
- // EventBus.getDefault().post(new DashboardPositionEvent(height, depth));
2704
2663
  }
2705
2664
 
2706
2665
  fun updateGlassesBrightness(brightness: Int) {
@@ -6091,8 +6091,9 @@ class G2 : SGCManager() {
6091
6091
  setControllerFullyConnected()
6092
6092
  }
6093
6093
 
6094
- // Double-tap policy (dashboard vs head-up toggle) moved to the engine's
6095
- // DeviceEventRouter, which subscribes to the touch_event stream.
6094
+ // Double-tap policy (dashboard vs head-up toggle) belongs to the engine's
6095
+ // DeviceEventRouter, which subscribes to the touch_event stream. Do not
6096
+ // act on it here.
6096
6097
 
6097
6098
  // System exit: the firmware killed our page (and the mic). ONLY mark state dead; do
6098
6099
  // NOT rebuild here. systemExit is fired alongside the dashboard-close (08011A00) event
@@ -25,17 +25,8 @@ import com.glassly.bluetoothsdk.utils.MessageChunker
25
25
  import com.glassly.bluetoothsdk.utils.audio.Lc3Player
26
26
  import com.glassly.bluetoothsdk.utils.BlePhotoUploadService
27
27
  import com.glassly.bluetoothsdk.DeviceStore
28
-
29
- // import com.augmentos.augmentos_core.R;
30
- // import com.augmentos.augmentos_core.smarterglassesmanager.smartglassescommunicators.SmartGlassesCommunicator;
31
- // import com.augmentos.augmentos_core.smarterglassesmanager.smartglassescommunicators.SmartGlassesFontSize;
32
- // import com.augmentos.augmentos_core.smarterglassesmanager.utils.SmartGlassesConnectionState;
33
28
  import com.squareup.picasso.Picasso
34
29
  import com.squareup.picasso.Target
35
- // import com.augmentos.augmentos_core.smarterglassesmanager.eventbusmessages.BatteryLevelEvent;
36
- // import com.augmentos.augmentos_core.smarterglassesmanager.eventbusmessages.GlassesBluetoothSearchDiscoverEvent;
37
- // import com.augmentos.augmentos_core.smarterglassesmanager.eventbusmessages.GlassesDisplayPowerEvent;
38
- // import com.augmentos.augmentos_core.smarterglassesmanager.supportedglasses.SmartGlassesDevice;
39
30
  import com.vuzix.ultralite.Anchor
40
31
  import com.vuzix.ultralite.BatteryStatus
41
32
  import com.vuzix.ultralite.EventListener
@@ -45,7 +36,6 @@ import com.vuzix.ultralite.TextWrapMode
45
36
  import com.vuzix.ultralite.UltraliteColor
46
37
  import com.vuzix.ultralite.UltraliteSDK
47
38
 
48
- import org.greenrobot.eventbus.EventBus
49
39
 
50
40
  import java.util.ArrayList
51
41
  import java.util.Arrays
@@ -434,7 +424,6 @@ class Mach1 : SGCManager() {
434
424
 
435
425
  if (!screenToggleOff) {
436
426
  Log.d(TAG, "screen toggle off NOT on, showing turn ON message")
437
- // EventBus.getDefault().post(new GlassesDisplayPowerEvent(screenToggleOff));
438
427
  } else {
439
428
  Log.d(TAG, "screen toggle off IS on")
440
429
  }
@@ -585,9 +574,7 @@ class Mach1 : SGCManager() {
585
574
  }
586
575
 
587
576
  fun findCompatibleDeviceNames() {
588
- // EventBus.getDefault().post(new GlassesBluetoothSearchDiscoverEvent(smartGlassesDevice.deviceModelName, "NOTREQUIREDSKIP"));
589
577
  Bridge.sendDiscoveredDevice(this.type, "NOTREQUIREDSKIP") // Use this.type to support both Mach1 and Z100
590
- //this.destroy();
591
578
  }
592
579
 
593
580
  fun connectToSmartGlasses() {
@@ -1,7 +1,5 @@
1
1
  package com.glassly.bluetoothsdk.sgcs
2
2
 
3
- // Glassly
4
- // old augmentos imports:
5
3
  import android.Manifest
6
4
  import android.bluetooth.BluetoothA2dp
7
5
  import android.bluetooth.BluetoothAdapter
@@ -2125,19 +2123,6 @@ class MentraLive : SGCManager() {
2125
2123
  )
2126
2124
  }
2127
2125
 
2128
- // Save the connected device name for future reconnections
2129
- // no longer needed as we now save it immediately in connectToDevice()
2130
- // if (connectedDevice != null && connectedDevice.getName() != null) {
2131
- // SharedPreferences prefs =
2132
- // context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
2133
- // prefs.edit().putString(PREF_DEVICE_NAME,
2134
- // connectedDevice.getName()).apply();
2135
- // Log.i(TAG, "🔌 💾 Saved device name for future reconnection: " +
2136
- // connectedDevice.getName());
2137
- // Bridge.log("LIVE: Saved device name for future reconnection: " +
2138
- // connectedDevice.getName());
2139
- // }
2140
-
2141
2126
  // Register early so we don't miss bond broadcasts, but defer
2142
2127
  // createBond / A2DP until BLE GATT setup finishes (see
2143
2128
  // maybeInitiateCtkdAudioAfterBleReady).
@@ -4404,8 +4389,8 @@ class MentraLive : SGCManager() {
4404
4389
  }
4405
4390
  }
4406
4391
 
4407
- // Removed: version_info_1 and version_info_2 cases
4408
- // Now handled by flexible parsing in default case below
4392
+ // version_info_1 / version_info_2 fall through to the default case,
4393
+ // which prefix-matches every chunk variant.
4409
4394
 
4410
4395
  "version_info" -> {
4411
4396
  // Process version information from ASG client (legacy single-message format)
@@ -4490,51 +4475,21 @@ class MentraLive : SGCManager() {
4490
4475
  else "")
4491
4476
  )
4492
4477
 
4493
- // Emit EventBus event for AugmentosService on main thread
4478
+ // Status is validated only; progress is surfaced via the logs above.
4494
4479
  try {
4495
- // DownloadProgressEvent.DownloadStatus downloadEventStatus;
4496
- // final DownloadProgressEvent event;
4497
4480
  when (downloadStatus) {
4498
- "STARTED" -> {
4499
- // downloadEventStatus = DownloadProgressEvent.DownloadStatus.STARTED;
4500
- // event = new DownloadProgressEvent(downloadEventStatus, totalBytes);
4501
- }
4502
- "PROGRESS" -> {
4503
- // downloadEventStatus = DownloadProgressEvent.DownloadStatus.PROGRESS;
4504
- // event = new DownloadProgressEvent(downloadEventStatus,
4505
- // downloadProgress, bytesDownloaded, totalBytes);
4506
- }
4507
- "FINISHED" -> {
4508
- // downloadEventStatus = DownloadProgressEvent.DownloadStatus.FINISHED;
4509
- // event = new DownloadProgressEvent(downloadEventStatus, totalBytes,
4510
- // true);
4511
- }
4512
- "FAILED" -> {
4513
- // downloadEventStatus = DownloadProgressEvent.DownloadStatus.FAILED;
4514
- // event = new DownloadProgressEvent(downloadEventStatus,
4515
- // downloadErrorMessage);
4516
- }
4481
+ "STARTED" -> {}
4482
+ "PROGRESS" -> {}
4483
+ "FINISHED" -> {}
4484
+ "FAILED" -> {}
4517
4485
  else -> {
4518
4486
  Log.w(TAG, "Unknown download status: " + downloadStatus)
4519
4487
  return
4520
4488
  }
4521
4489
  }
4522
-
4523
- // Post event on main thread to ensure proper delivery
4524
- handler.post {
4525
- // Bridge.log("LIVE: 📡 Posting download progress event on main thread: " +
4526
- // downloadEventStatus);
4527
- // EventBus.getDefault().post(event);
4528
- // Bridge.
4529
- }
4530
4490
  } catch (e: Exception) {
4531
4491
  Log.e(TAG, "Error creating download progress event", e)
4532
4492
  }
4533
-
4534
- // Forward to data observable for cloud communication
4535
- // if (dataObservable != null) {
4536
- // dataObservable.onNext(json);
4537
- // }
4538
4493
  }
4539
4494
  "ota_installation_progress" -> {
4540
4495
  // Process OTA installation progress from ASG client
@@ -4559,49 +4514,19 @@ class MentraLive : SGCManager() {
4559
4514
  else "")
4560
4515
  )
4561
4516
 
4562
- // Emit EventBus event for AugmentosService on main thread
4517
+ // Status is validated only; progress is surfaced via the logs above.
4563
4518
  try {
4564
- // InstallationProgressEvent.InstallationStatus installationEventStatus;
4565
- // final InstallationProgressEvent event;
4566
4519
  when (installationStatus) {
4567
- "STARTED" -> {
4568
- // installationEventStatus =
4569
- // InstallationProgressEvent.InstallationStatus.STARTED;
4570
- // event = new InstallationProgressEvent(installationEventStatus,
4571
- // apkPath);
4572
- }
4573
- "FINISHED" -> {
4574
- // installationEventStatus =
4575
- // InstallationProgressEvent.InstallationStatus.FINISHED;
4576
- // event = new InstallationProgressEvent(installationEventStatus,
4577
- // apkPath);
4578
- }
4579
- "FAILED" -> {
4580
- // installationEventStatus =
4581
- // InstallationProgressEvent.InstallationStatus.FAILED;
4582
- // event = new InstallationProgressEvent(installationEventStatus,
4583
- // apkPath, installationErrorMessage);
4584
- }
4520
+ "STARTED" -> {}
4521
+ "FINISHED" -> {}
4522
+ "FAILED" -> {}
4585
4523
  else -> {
4586
- // Log.w(TAG, "Unknown installation status: " + installationStatus);
4587
4524
  return
4588
4525
  }
4589
4526
  }
4590
-
4591
- // Post event on main thread to ensure proper delivery
4592
- handler.post {
4593
- // Bridge.log("LIVE: 📡 Posting installation progress event on main thread:
4594
- // " + installationEventStatus);
4595
- // EventBus.getDefault().post(event);
4596
- }
4597
4527
  } catch (e: Exception) {
4598
4528
  Log.e(TAG, "Error creating installation progress event", e)
4599
4529
  }
4600
-
4601
- // Forward to data observable for cloud communication
4602
- // if (dataObservable != null) {
4603
- // dataObservable.onNext(json);
4604
- // }
4605
4530
  }
4606
4531
  "mtk_update_complete" -> {
4607
4532
  // Process MTK firmware update complete notification from ASG client
@@ -1069,8 +1069,7 @@ class MentraNex : SGCManager() {
1069
1069
  queryBatteryStatus()
1070
1070
  }
1071
1071
  MAIN_TASK_HANDLER_CODE_HEART_BEAT -> {
1072
- // Note: Heartbeat is now handled by receiving ping from glasses
1073
- // This case is kept for backward compatibility but no longer used
1072
+ // No-op: heartbeat is driven by the ping the glasses send us.
1074
1073
  }
1075
1074
  else -> { }
1076
1075
  }
@@ -1613,8 +1612,6 @@ class MentraNex : SGCManager() {
1613
1612
  lastConnectionTimestamp = System.currentTimeMillis()
1614
1613
  DeviceStore.apply("glasses", "fullyBooted", true)
1615
1614
  DeviceStore.apply("glasses", "connected", true)
1616
- // Removed commented sleep code as it's not needed
1617
- // connectionEvent(it)
1618
1615
  } else {
1619
1616
  DeviceStore.apply("glasses", "connectionState", ConnTypes.DISCONNECTED)
1620
1617
  Bridge.log("Nex: No Main glasses connected")
@@ -18,8 +18,6 @@ import java.nio.ByteOrder
18
18
  * - 8-second silence timeout before declaring "not speaking"
19
19
  * - Bypass modes for debugging and PCM streaming
20
20
  * - 512-sample frame size (matches Sherpa-ONNX requirements)
21
- *
22
- * Ported from android_core VadGateSpeechPolicy.java
23
21
  */
24
22
  class VadGateSpeechPolicy(private val context: Context) {
25
23
  companion object {
@@ -1,5 +1,8 @@
1
1
  /** Generated from /changelogs. Do not edit directly. */
2
2
  export declare const GENERATED_RELEASE_CHANGELOGS: readonly [{
3
+ readonly version: "3.2.0";
4
+ readonly markdown: "This release is under active development. User-facing changes will be documented as they land.";
5
+ }, {
3
6
  readonly version: "3.1.0";
4
7
  readonly markdown: "Software updates are more reliable, with clearer progress and recovery when the glasses restart.\n\n- GlasslyOS, Glassly Engine, the Bluetooth SDK, and the glasses client now share one coordinated release version.\n- Mentra Live updates can continue across APK, system, and firmware restarts without asking the user to start the same update again.\n- Bluetooth photo capture and transfer diagnostics are more precise and less disruptive to normal glasses traffic.";
5
8
  }, {
@@ -1 +1 @@
1
- {"version":3,"file":"changelogCatalog.d.ts","sourceRoot":"","sources":["../../src/generated/changelogCatalog.ts"],"names":[],"mappings":"AAAA,wDAAwD;AACxD,eAAO,MAAM,4BAA4B;;;;;;EAWxC,CAAA"}
1
+ {"version":3,"file":"changelogCatalog.d.ts","sourceRoot":"","sources":["../../src/generated/changelogCatalog.ts"],"names":[],"mappings":"AAAA,wDAAwD;AACxD,eAAO,MAAM,4BAA4B;;;;;;;;;EAexC,CAAA"}
@@ -1,5 +1,9 @@
1
1
  /** Generated from /changelogs. Do not edit directly. */
2
2
  export const GENERATED_RELEASE_CHANGELOGS = Object.freeze([
3
+ {
4
+ "version": "3.2.0",
5
+ "markdown": "This release is under active development. User-facing changes will be documented as they land."
6
+ },
3
7
  {
4
8
  "version": "3.1.0",
5
9
  "markdown": "Software updates are more reliable, with clearer progress and recovery when the glasses restart.\n\n- GlasslyOS, Glassly Engine, the Bluetooth SDK, and the glasses client now share one coordinated release version.\n- Mentra Live updates can continue across APK, system, and firmware restarts without asking the user to start the same update again.\n- Bluetooth photo capture and transfer diagnostics are more precise and less disruptive to normal glasses traffic."
@@ -1 +1 @@
1
- {"version":3,"file":"changelogCatalog.js","sourceRoot":"","sources":["../../src/generated/changelogCatalog.ts"],"names":[],"mappings":"AAAA,wDAAwD;AACxD,MAAM,CAAC,MAAM,4BAA4B,GAAG,MAAM,CAAC,MAAM,CACzD;IACE;QACE,SAAS,EAAE,OAAO;QAClB,UAAU,EAAE,idAAid;KAC9d;IACD;QACE,SAAS,EAAE,OAAO;QAClB,UAAU,EAAE,odAAod;KACje;CACO,CACT,CAAA","sourcesContent":["/** Generated from /changelogs. Do not edit directly. */\nexport const GENERATED_RELEASE_CHANGELOGS = Object.freeze(\n[\n {\n \"version\": \"3.1.0\",\n \"markdown\": \"Software updates are more reliable, with clearer progress and recovery when the glasses restart.\\n\\n- GlasslyOS, Glassly Engine, the Bluetooth SDK, and the glasses client now share one coordinated release version.\\n- Mentra Live updates can continue across APK, system, and firmware restarts without asking the user to start the same update again.\\n- Bluetooth photo capture and transfer diagnostics are more precise and less disruptive to normal glasses traffic.\"\n },\n {\n \"version\": \"0.1.0\",\n \"markdown\": \"First coordinated Glassly release: the app, Glassly Engine, and the Bluetooth SDK now ship one shared release version.\\n\\n- The Glassly App, Glassly Engine, and the Bluetooth SDK are versioned and published together.\\n- Mentra Live updates can continue across APK, system, and firmware restarts without asking the user to start the same update again.\\n- Bluetooth photo capture and transfer diagnostics are more precise and less disruptive to normal glasses traffic.\"\n }\n] as const,\n)\n"]}
1
+ {"version":3,"file":"changelogCatalog.js","sourceRoot":"","sources":["../../src/generated/changelogCatalog.ts"],"names":[],"mappings":"AAAA,wDAAwD;AACxD,MAAM,CAAC,MAAM,4BAA4B,GAAG,MAAM,CAAC,MAAM,CACzD;IACE;QACE,SAAS,EAAE,OAAO;QAClB,UAAU,EAAE,gGAAgG;KAC7G;IACD;QACE,SAAS,EAAE,OAAO;QAClB,UAAU,EAAE,idAAid;KAC9d;IACD;QACE,SAAS,EAAE,OAAO;QAClB,UAAU,EAAE,odAAod;KACje;CACO,CACT,CAAA","sourcesContent":["/** Generated from /changelogs. Do not edit directly. */\nexport const GENERATED_RELEASE_CHANGELOGS = Object.freeze(\n[\n {\n \"version\": \"3.2.0\",\n \"markdown\": \"This release is under active development. User-facing changes will be documented as they land.\"\n },\n {\n \"version\": \"3.1.0\",\n \"markdown\": \"Software updates are more reliable, with clearer progress and recovery when the glasses restart.\\n\\n- GlasslyOS, Glassly Engine, the Bluetooth SDK, and the glasses client now share one coordinated release version.\\n- Mentra Live updates can continue across APK, system, and firmware restarts without asking the user to start the same update again.\\n- Bluetooth photo capture and transfer diagnostics are more precise and less disruptive to normal glasses traffic.\"\n },\n {\n \"version\": \"0.1.0\",\n \"markdown\": \"First coordinated Glassly release: the app, Glassly Engine, and the Bluetooth SDK now ship one shared release version.\\n\\n- The Glassly App, Glassly Engine, and the Bluetooth SDK are versioned and published together.\\n- Mentra Live updates can continue across APK, system, and firmware restarts without asking the user to start the same update again.\\n- Bluetooth photo capture and transfer diagnostics are more precise and less disruptive to normal glasses traffic.\"\n }\n] as const,\n)\n"]}
@@ -1,9 +1,9 @@
1
1
  export const BLUETOOTH_SDK_RELEASE_METADATA = Object.freeze({
2
2
  "schemaVersion": 1,
3
3
  "familyBaseVersion": "0.1.0",
4
- "releaseIdentity": "0.1.0-dev.89",
5
- "releaseSetId": "glassly-0.1.0-dev.89",
6
- "sourceCommit": "c66a621d66d70251e257f73c9a79ee1f8e079be9",
4
+ "releaseIdentity": "0.1.0-dev.96",
5
+ "releaseSetId": "glassly-0.1.0-dev.96",
6
+ "sourceCommit": "440518cf281588df779cd13d78922782db027ad4",
7
7
  "otaManifestUrl": null,
8
8
  "otaManifestSha256": null
9
9
  });
@@ -1 +1 @@
1
- {"version":3,"file":"releaseMetadata.js","sourceRoot":"","sources":["../../src/generated/releaseMetadata.ts"],"names":[],"mappings":"AAWA,MAAM,CAAC,MAAM,8BAA8B,GAA0C,MAAM,CAAC,MAAM,CAAC;IACjG,eAAe,EAAE,CAAC;IAClB,mBAAmB,EAAE,OAAO;IAC5B,iBAAiB,EAAE,cAAc;IACjC,cAAc,EAAE,sBAAsB;IACtC,cAAc,EAAE,0CAA0C;IAC1D,gBAAgB,EAAE,IAAI;IACtB,mBAAmB,EAAE,IAAI;CAC1B,CAAC,CAAA","sourcesContent":["/** Generated by release CI. Do not edit in a release checkout. */\nexport interface BluetoothSdkReleaseMetadata {\n schemaVersion: 1\n familyBaseVersion: string | null\n releaseIdentity: string | null\n releaseSetId: string | null\n sourceCommit: string | null\n otaManifestUrl: string | null\n otaManifestSha256: string | null\n}\n\nexport const BLUETOOTH_SDK_RELEASE_METADATA: Readonly<BluetoothSdkReleaseMetadata> = Object.freeze({\n \"schemaVersion\": 1,\n \"familyBaseVersion\": \"0.1.0\",\n \"releaseIdentity\": \"0.1.0-dev.89\",\n \"releaseSetId\": \"glassly-0.1.0-dev.89\",\n \"sourceCommit\": \"c66a621d66d70251e257f73c9a79ee1f8e079be9\",\n \"otaManifestUrl\": null,\n \"otaManifestSha256\": null\n})\n"]}
1
+ {"version":3,"file":"releaseMetadata.js","sourceRoot":"","sources":["../../src/generated/releaseMetadata.ts"],"names":[],"mappings":"AAWA,MAAM,CAAC,MAAM,8BAA8B,GAA0C,MAAM,CAAC,MAAM,CAAC;IACjG,eAAe,EAAE,CAAC;IAClB,mBAAmB,EAAE,OAAO;IAC5B,iBAAiB,EAAE,cAAc;IACjC,cAAc,EAAE,sBAAsB;IACtC,cAAc,EAAE,0CAA0C;IAC1D,gBAAgB,EAAE,IAAI;IACtB,mBAAmB,EAAE,IAAI;CAC1B,CAAC,CAAA","sourcesContent":["/** Generated by release CI. Do not edit in a release checkout. */\nexport interface BluetoothSdkReleaseMetadata {\n schemaVersion: 1\n familyBaseVersion: string | null\n releaseIdentity: string | null\n releaseSetId: string | null\n sourceCommit: string | null\n otaManifestUrl: string | null\n otaManifestSha256: string | null\n}\n\nexport const BLUETOOTH_SDK_RELEASE_METADATA: Readonly<BluetoothSdkReleaseMetadata> = Object.freeze({\n \"schemaVersion\": 1,\n \"familyBaseVersion\": \"0.1.0\",\n \"releaseIdentity\": \"0.1.0-dev.96\",\n \"releaseSetId\": \"glassly-0.1.0-dev.96\",\n \"sourceCommit\": \"440518cf281588df779cd13d78922782db027ad4\",\n \"otaManifestUrl\": null,\n \"otaManifestSha256\": null\n})\n"]}
@@ -11,7 +11,7 @@ enum BluetoothSdkDefaults {
11
11
  static let voiceActivityDetectionEnabled = false
12
12
  static let loudnessGateEnabled = true
13
13
  private static let infoSdkVersionKey = "BluetoothSdkVersion"
14
- private static let swiftPackageSdkVersion = "0.1.0-dev.89"
14
+ private static let swiftPackageSdkVersion = "0.1.0-dev.96"
15
15
  private static let swiftPackageSdkVersionPlaceholder = "__GLASSLY" + "_BLUETOOTH_SDK_VERSION__"
16
16
 
17
17
  private static func normalizedSdkVersion(_ value: String?) -> String? {
@@ -589,8 +589,8 @@ struct ViewState {
589
589
  func setOnboardMicEnabled(_ isEnabled: Bool) {
590
590
  Task {
591
591
  if isEnabled {
592
- // Just check permissions - we no longer request them directly from Swift
593
- // Permissions should already be granted via React Native UI flow
592
+ // Check only; never request from Swift. The React Native UI flow
593
+ // owns the mic permission prompt.
594
594
  if !(PhoneMic.shared.checkPermissions()) {
595
595
  Bridge.log("Microphone permissions not granted. Cannot enable microphone.")
596
596
  return
@@ -1293,11 +1293,9 @@ struct ViewState {
1293
1293
  }
1294
1294
  }
1295
1295
 
1296
- // NOTE: positioned_text used to bypass the viewState slot here (the
1297
- // "sticky overlay" hack for the old nav HUD). Scenes made that
1298
- // obsolete: multi-element frames arrive as ONE scene event, so nothing
1299
- // clobbers anything. Legacy positioned_text now flows through the slot
1300
- // like every other layout (matching Android).
1296
+ // positioned_text flows through the viewState slot like every other
1297
+ // layout (matching Android): multi-element frames arrive as ONE scene
1298
+ // event, so nothing clobbers anything.
1301
1299
 
1302
1300
  let cS = viewState
1303
1301
  let nS = newViewState
@@ -2,6 +2,7 @@ import Foundation
2
2
 
3
3
  /// Generated from /changelogs. Do not edit directly.
4
4
  let generatedReleaseChangelogs: [ReleaseChangelog] = [
5
+ ReleaseChangelog(version: "3.2.0", markdown: "This release is under active development. User-facing changes will be documented as they land."),
5
6
  ReleaseChangelog(version: "3.1.0", markdown: "Software updates are more reliable, with clearer progress and recovery when the glasses restart.\n\n- GlasslyOS, Glassly Engine, the Bluetooth SDK, and the glasses client now share one coordinated release version.\n- Mentra Live updates can continue across APK, system, and firmware restarts without asking the user to start the same update again.\n- Bluetooth photo capture and transfer diagnostics are more precise and less disruptive to normal glasses traffic."),
6
7
  ReleaseChangelog(version: "0.1.0", markdown: "First coordinated Glassly release: the app, Glassly Engine, and the Bluetooth SDK now ship one shared release version.\n\n- The Glassly App, Glassly Engine, and the Bluetooth SDK are versioned and published together.\n- Mentra Live updates can continue across APK, system, and firmware restarts without asking the user to start the same update again.\n- Bluetooth photo capture and transfer diagnostics are more precise and less disruptive to normal glasses traffic."),
7
8
  ]
@@ -3,9 +3,9 @@ import Foundation
3
3
  /// Generated by release CI. Do not edit in a release checkout.
4
4
  enum GeneratedReleaseMetadata {
5
5
  static let familyBaseVersion = "0.1.0"
6
- static let releaseIdentity = "0.1.0-dev.89"
7
- static let releaseSetId = "glassly-0.1.0-dev.89"
8
- static let sourceCommit = "c66a621d66d70251e257f73c9a79ee1f8e079be9"
6
+ static let releaseIdentity = "0.1.0-dev.96"
7
+ static let releaseSetId = "glassly-0.1.0-dev.96"
8
+ static let sourceCommit = "440518cf281588df779cd13d78922782db027ad4"
9
9
  static let otaManifestUrl = ""
10
10
  static let otaManifestSha256 = ""
11
11
  }
@@ -6180,16 +6180,9 @@ final class G2: NSObject, SGCManager {
6180
6180
  setControllerFullyConnected()
6181
6181
  }
6182
6182
 
6183
- // Double-tap policy (dashboard vs head-up toggle) moved to the engine's
6184
- // DeviceEventRouter, which subscribes to the touch_event stream.
6185
-
6186
- // if eventType == .foregroundEnter {
6187
- // Bridge.log("G2: Foreground enter detected")
6188
- // }
6189
-
6190
- // if eventType == .click {
6191
- // Bridge.log("G2: Click detected")
6192
- // }
6183
+ // Double-tap policy (dashboard vs head-up toggle) belongs to the
6184
+ // engine's DeviceEventRouter, which subscribes to the touch_event
6185
+ // stream. Do not act on it here.
6193
6186
 
6194
6187
  // System exit: the firmware killed our page (and the mic). ONLY mark state dead;
6195
6188
  // do NOT rebuild here. systemExit is fired alongside the dashboard-close (08011A00)
@@ -2865,8 +2865,8 @@ class MentraLive: NSObject, SGCManager {
2865
2865
  case "button_press":
2866
2866
  handleButtonPress(json)
2867
2867
 
2868
- // Removed: version_info_1, version_info_2, and version_info cases
2869
- // Now handled by flexible parsing in the default case below
2868
+ // version_info* falls through to the default case, which prefix-matches
2869
+ // every chunk variant.
2870
2870
 
2871
2871
  case "touch_event":
2872
2872
  let gestureName = json["gesture_name"] as? String ?? "unknown"
@@ -4015,8 +4015,8 @@ class MentraLive: NSObject, SGCManager {
4015
4015
  }
4016
4016
  }
4017
4017
 
4018
- // requestMissingPackets() removed - no longer used with ACK system
4019
- // Phone now sends transfer_complete with success=false to trigger full retry
4018
+ // There is no per-packet re-request: the phone sends transfer_complete with
4019
+ // success=false to trigger a full retry.
4020
4020
 
4021
4021
  // MARK: - File Transfer Processing
4022
4022