@glassly/bluetooth-sdk 0.1.0-dev.102 → 0.1.0-dev.103

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.
@@ -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.102"
7
- const val RELEASE_SET_ID: String = "glassly-0.1.0-dev.102"
8
- const val SOURCE_COMMIT: String = "25f1ae8ddfcd46216e222643d54f498d21e01d59"
6
+ const val RELEASE_IDENTITY: String = "0.1.0-dev.103"
7
+ const val RELEASE_SET_ID: String = "glassly-0.1.0-dev.103"
8
+ const val SOURCE_COMMIT: String = "ba3c3655d8255014fc9292896ef73dd34f12afff"
9
9
  const val OTA_MANIFEST_URL: String = ""
10
10
  const val OTA_MANIFEST_SHA256: String = ""
11
11
  }
@@ -1734,9 +1734,9 @@ class G2 : SGCManager() {
1734
1734
  private var recoveryInFlight = false
1735
1735
  private var lastRecoveryRebuildMs: Long = 0
1736
1736
  private val RECOVERY_DEBOUNCE_MS: Long = 1500
1737
- // Debug hold (dbg1/dbg2): page rebuilds, fbguard lease and CFW frames stay
1738
- // down so the stock UI can be exercised without EvenHub sends interfering.
1739
- @Volatile private var debugPageHold = false
1737
+ // Stock notifications panel hold: page rebuilds, fbguard lease and CFW frames stay
1738
+ // down while the panel opens so EvenHub sends cannot snatch the screen back.
1739
+ @Volatile private var notificationsPanelHold = false
1740
1740
 
1741
1741
  // Dashboard menu state
1742
1742
  private var menuAppIdToPackageName: MutableMap<Int, String> = mutableMapOf()
@@ -2889,7 +2889,7 @@ class G2 : SGCManager() {
2889
2889
  /** Install the single carrier and render the whole scene through CFW mode 3. */
2890
2890
  private suspend fun applyCfwScene(frame: SceneFrame) {
2891
2891
  // Held: retain the frame so the post-hold rebuild re-sends it, but paint nothing now.
2892
- if (debugPageHold) {
2892
+ if (notificationsPanelHold) {
2893
2893
  cfwLastFrame = frame
2894
2894
  return
2895
2895
  }
@@ -2974,7 +2974,7 @@ class G2 : SGCManager() {
2974
2974
  * under a preserved direct frame.
2975
2975
  */
2976
2976
  private fun startFbLease() {
2977
- if (fbLeaseJob != null || debugPageHold) return
2977
+ if (fbLeaseJob != null || notificationsPanelHold) return
2978
2978
  sendFaceclawFbControl(acquire = true)
2979
2979
  fbLeaseJob =
2980
2980
  displayScope.launch {
@@ -3664,8 +3664,8 @@ class G2 : SGCManager() {
3664
3664
  Bridge.log("G2: rebuildState() skipped — navigation mode owns the screen")
3665
3665
  return
3666
3666
  }
3667
- if (debugPageHold) {
3668
- Bridge.log("G2: rebuildState() skipped — debug page hold (dbg1)")
3667
+ if (notificationsPanelHold) {
3668
+ Bridge.log("G2: rebuildState() skipped — notifications panel hold")
3669
3669
  return
3670
3670
  }
3671
3671
  Bridge.log("G2: rebuildState()")
@@ -4186,9 +4186,20 @@ class G2 : SGCManager() {
4186
4186
  * 3. SKILL{skillId=NOTIFICATION, skillParam=show, ...} — dispatches the intent
4187
4187
  * The SKILL step alone is ignored by firmware; the preceding ENTER+ASK
4188
4188
  * supply the session context that lets the glasses act on the SKILL.
4189
+ * Our EvenHub page is torn down first and every path that would bring it
4190
+ * back (recovery rebuilds, fbguard lease, CFW frames, mic re-arm) is held
4191
+ * for 3 s, or the sends race the stock panel for the screen.
4189
4192
  */
4190
4193
  override suspend fun showNotificationsPanel() {
4191
4194
  Bridge.log("G2: showNotificationsPanel()")
4195
+
4196
+ notificationsPanelHold = true
4197
+ stopFbLease(sendRelease = true)
4198
+ sendEvenHubCommand(EvenHubProto.shutdownMessage())
4199
+ pageCreated = false
4200
+ // Page death takes the mic with it; intent is untouched so the post-hold rebuild re-arms.
4201
+ DeviceStore.apply("glasses", "micEnabled", false)
4202
+
4192
4203
  val enterPayload = EvenAIProto.aiCtrl(
4193
4204
  magicRandom = sendManager.nextMagicRandom(),
4194
4205
  status = 2 // EVEN_AI_ENTER
@@ -4213,6 +4224,10 @@ class G2 : SGCManager() {
4213
4224
  fTextEnd = 1
4214
4225
  )
4215
4226
  sendEvenAICommand(skillPayload)
4227
+
4228
+ delay(3_000)
4229
+ notificationsPanelHold = false
4230
+ Bridge.log("G2: notifications resurrect re-enabled")
4216
4231
  }
4217
4232
 
4218
4233
  override fun setBrightness(level: Int, autoMode: Boolean) {
@@ -4527,7 +4542,7 @@ class G2 : SGCManager() {
4527
4542
  // off then back on (the firmware needs the off→on edge to re-arm).
4528
4543
  evenHubMicIntent = true
4529
4544
  // Held: intent is recorded; the post-hold rebuild re-arms the mic.
4530
- if (debugPageHold) return
4545
+ if (notificationsPanelHold) return
4531
4546
  DeviceStore.apply("glasses", "micEnabled", true)
4532
4547
  val msg = EvenHubProto.audioControlMessage(false)
4533
4548
  sendEvenHubCommand(msg)
@@ -4680,7 +4695,7 @@ class G2 : SGCManager() {
4680
4695
  textContainers.clear()
4681
4696
  dashboardShowing = 0
4682
4697
  dashboardOpening = false
4683
- debugPageHold = false
4698
+ notificationsPanelHold = false
4684
4699
  heartbeatCounter = 0
4685
4700
  currentBitmapBase64 = ""
4686
4701
  menuAppIdToPackageName.clear()
@@ -4727,33 +4742,9 @@ class G2 : SGCManager() {
4727
4742
  sendEvenHubHeartbeat()
4728
4743
  }
4729
4744
 
4730
- /**
4731
- * Tear down the EvenHub page and hold every path that would bring it back
4732
- * (recovery rebuilds, fbguard lease, CFW frames, mic re-arm) until [dbg2]
4733
- * lifts the hold. Isolates the stock notifications UI from our sends.
4734
- */
4735
- override fun dbg1() {
4736
- Bridge.log("G2: dbg1() — EvenHub page down, resurrect held")
4737
- debugPageHold = true
4738
- stopFbLease(sendRelease = true)
4739
- sendEvenHubCommand(EvenHubProto.shutdownMessage())
4740
- pageCreated = false
4741
- // Page death takes the mic with it; intent is untouched so the post-hold rebuild re-arms.
4742
- DeviceStore.apply("glasses", "micEnabled", false)
4743
- }
4745
+ override fun dbg1() {}
4744
4746
 
4745
- /**
4746
- * Open the stock notifications panel, then lift the dbg1 hold 1 s later so
4747
- * recovery resumes on the next firmware event / pending content.
4748
- */
4749
- override fun dbg2() {
4750
- displayScope.launch {
4751
- showNotificationsPanel()
4752
- delay(1_000)
4753
- debugPageHold = false
4754
- Bridge.log("G2: dbg2() — resurrect re-enabled")
4755
- }
4756
- }
4747
+ override fun dbg2() {}
4757
4748
 
4758
4749
  /** Raw wake lease start — no durable intent; a reconnect drops it. */
4759
4750
  override fun dbg3() {
@@ -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.102",
5
- "releaseSetId": "glassly-0.1.0-dev.102",
6
- "sourceCommit": "25f1ae8ddfcd46216e222643d54f498d21e01d59",
4
+ "releaseIdentity": "0.1.0-dev.103",
5
+ "releaseSetId": "glassly-0.1.0-dev.103",
6
+ "sourceCommit": "ba3c3655d8255014fc9292896ef73dd34f12afff",
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,eAAe;IAClC,cAAc,EAAE,uBAAuB;IACvC,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.102\",\n \"releaseSetId\": \"glassly-0.1.0-dev.102\",\n \"sourceCommit\": \"25f1ae8ddfcd46216e222643d54f498d21e01d59\",\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,eAAe;IAClC,cAAc,EAAE,uBAAuB;IACvC,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.103\",\n \"releaseSetId\": \"glassly-0.1.0-dev.103\",\n \"sourceCommit\": \"ba3c3655d8255014fc9292896ef73dd34f12afff\",\n \"otaManifestUrl\": null,\n \"otaManifestSha256\": null\n})\n"]}
@@ -61,6 +61,7 @@ public class BluetoothSdkModule: Module, BluetoothSDKDelegate {
61
61
  "speaker_enroll_result",
62
62
  "phone_notification",
63
63
  "phone_notification_dismissed",
64
+ "notification_app_seen",
64
65
  "ws_text",
65
66
  "ws_bin",
66
67
  "mic_pcm",
@@ -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.102"
14
+ private static let swiftPackageSdkVersion = "0.1.0-dev.103"
15
15
  private static let swiftPackageSdkVersionPlaceholder = "__GLASSLY" + "_BLUETOOTH_SDK_VERSION__"
16
16
 
17
17
  private static func normalizedSdkVersion(_ value: String?) -> String? {
@@ -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.102"
7
- static let releaseSetId = "glassly-0.1.0-dev.102"
8
- static let sourceCommit = "25f1ae8ddfcd46216e222643d54f498d21e01d59"
6
+ static let releaseIdentity = "0.1.0-dev.103"
7
+ static let releaseSetId = "glassly-0.1.0-dev.103"
8
+ static let sourceCommit = "ba3c3655d8255014fc9292896ef73dd34f12afff"
9
9
  static let otaManifestUrl = ""
10
10
  static let otaManifestSha256 = ""
11
11
  }
@@ -106,13 +106,26 @@ class ObservableStore {
106
106
  if let l = lhs as? Double, let r = rhs as? Double { return l == r }
107
107
  if let l = lhs as? [String], let r = rhs as? [String] { return l == r }
108
108
  if let l = lhs as? [[String: Any]], let r = rhs as? [[String: Any]] {
109
- return toJson(l) == toJson(r)
109
+ return jsonEqual(l, r)
110
+ }
111
+ // Dict-valued settings (notification_ctrl / notification_filter) — without this every
112
+ // apply re-fires the subscriber, e.g. a full whitelist file push to both arms.
113
+ if let l = lhs as? [String: Any], let r = rhs as? [String: Any] {
114
+ return jsonEqual(l, r)
110
115
  }
111
116
  return false
112
117
  }
113
118
 
119
+ /// Unserializable on either side is "changed" — nil == nil must not read as equal.
120
+ private func jsonEqual(_ lhs: Any, _ rhs: Any) -> Bool {
121
+ guard let l = toJson(lhs), let r = toJson(rhs) else { return false }
122
+ return l == r
123
+ }
124
+
114
125
  private func toJson(_ value: Any) -> String? {
115
- guard let data = try? JSONSerialization.data(withJSONObject: value) else { return nil }
126
+ guard JSONSerialization.isValidJSONObject(value),
127
+ let data = try? JSONSerialization.data(withJSONObject: value, options: [.sortedKeys])
128
+ else { return nil }
116
129
  return String(data: data, encoding: .utf8)
117
130
  }
118
131
  }
@@ -1841,9 +1841,9 @@ final class G2: NSObject, SGCManager {
1841
1841
  private var recoveryInFlight = false
1842
1842
  private var lastRecoveryRebuildMs: Int64 = 0
1843
1843
  private let RECOVERY_DEBOUNCE_MS: Int64 = 1500
1844
- // Debug hold (dbg1/dbg2): page rebuilds, fbguard lease and CFW frames stay
1845
- // down so the stock UI can be exercised without EvenHub sends interfering.
1846
- private var debugPageHold = false
1844
+ // Stock notifications panel hold: page rebuilds, fbguard lease and CFW frames stay
1845
+ // down while the panel opens so EvenHub sends cannot snatch the screen back.
1846
+ private var notificationsPanelHold = false
1847
1847
  // A systemExit that arrives while the page acked a carrier fragment this
1848
1848
  // recently is a phantom (the firmware emits exits even for healthy pages)
1849
1849
  // and is dropped entirely — see the SysEvent handler.
@@ -2582,7 +2582,8 @@ final class G2: NSObject, SGCManager {
2582
2582
  let ctrl = DeviceStore.shared.get("bluetooth", "notification_ctrl") as? [String: Any] ?? [:]
2583
2583
  let enabled = ctrl["enabled"] as? Bool ?? true
2584
2584
  let autoDisplay = ctrl["auto_display"] as? Bool ?? true
2585
- let dispTime = ctrl["disp_time"] as? Int ?? 5
2585
+ // Nested numbers cross the Expo bridge as Double; `as? Int` would silently fall back to 5.
2586
+ let dispTime = (ctrl["disp_time"] as? NSNumber)?.intValue ?? 5
2586
2587
  let avoidDisturb = ctrl["avoid_disturb"] as? Bool ?? true
2587
2588
 
2588
2589
  var ctrlW = ProtobufWriter()
@@ -2623,7 +2624,14 @@ final class G2: NSObject, SGCManager {
2623
2624
  // The file is written even when filtering is off so a later enable
2624
2625
  // toggles against the user's current list, not a stale one.
2625
2626
  let json = G2NotifyFile.whitelistJson(filterEnabled: enabled, apps: entries)
2626
- await sendNotifyFile(named: G2NotifyFile.whitelistFilename, content: json)
2627
+ let pushed = await sendNotifyFile(named: G2NotifyFile.whitelistFilename, content: json)
2628
+ // Enabling against a list that never landed (flash in progress, file characteristic not
2629
+ // yet discovered) would filter on whatever is on flash — absent means every notification
2630
+ // is dropped. Leave the firmware toggle alone; device-ready re-pushes the whole config.
2631
+ if enabled, !pushed {
2632
+ Bridge.log("G2: notification filter enable deferred — whitelist file not pushed")
2633
+ return
2634
+ }
2627
2635
 
2628
2636
  var wlW = ProtobufWriter()
2629
2637
  wlW.writeInt32Field(1, enabled ? 0 : 1) // whitelistDisable (disabled = fail-open)
@@ -2639,14 +2647,20 @@ final class G2: NSObject, SGCManager {
2639
2647
  /// characteristic): FILE_CHECK header → START → DATA → END, per arm. The
2640
2648
  /// glasses cache by checksum but still expect the data packets either way,
2641
2649
  /// so no branching on the CACHE_HIT/MISS response is needed.
2642
- private func sendNotifyFile(named filename: String, content: Data) async {
2643
- guard !firmwareFlashLifecycleActive, !firmwareFlasher.isActive else { return }
2650
+ /// Returns false when the file was skipped for any connected arm (flash in
2651
+ /// progress, file characteristic not discovered) so callers don't act on it.
2652
+ @discardableResult
2653
+ private func sendNotifyFile(named filename: String, content: Data) async -> Bool {
2654
+ guard !firmwareFlashLifecycleActive, !firmwareFlasher.isActive else { return false }
2644
2655
  let header = G2NotifyFile.fileCheckHeader(filename: filename, content: content)
2645
2656
  var pushedSides: [String] = []
2657
+ var skippedArm = false
2646
2658
  for right in [true, false] {
2647
- guard let peripheral = right ? rightPeripheral : leftPeripheral,
2648
- let char = right ? rightFileWriteChar : leftFileWriteChar
2649
- else { continue }
2659
+ guard let peripheral = right ? rightPeripheral : leftPeripheral else { continue }
2660
+ guard let char = right ? rightFileWriteChar : leftFileWriteChar else {
2661
+ skippedArm = true
2662
+ continue
2663
+ }
2650
2664
  let writeType: CBCharacteristicWriteType =
2651
2665
  char.properties.contains(.writeWithoutResponse) ? .withoutResponse : .withResponse
2652
2666
 
@@ -2670,6 +2684,7 @@ final class G2: NSObject, SGCManager {
2670
2684
  Bridge.log(
2671
2685
  "G2: Pushed \(filename) (\(content.count) bytes) to [\(pushedSides.joined(separator: ","))]"
2672
2686
  )
2687
+ return !pushedSides.isEmpty && !skippedArm
2673
2688
  }
2674
2689
 
2675
2690
  // MARK: - SGCManager: Display Control
@@ -2924,7 +2939,7 @@ final class G2: NSObject, SGCManager {
2924
2939
  /// `cfwLastFrame` once the new page is up.
2925
2940
  private func applyCfwScene(_ frame: SceneFrame) async {
2926
2941
  // Held: retain the frame so the post-hold rebuild re-sends it, but paint nothing now.
2927
- if debugPageHold {
2942
+ if notificationsPanelHold {
2928
2943
  cfwLastFrame = frame
2929
2944
  return
2930
2945
  }
@@ -3001,7 +3016,7 @@ final class G2: NSObject, SGCManager {
3001
3016
  /// is inactive or the page went down, so a stock surface (dashboard, nav)
3002
3017
  /// is never frozen under a preserved direct frame.
3003
3018
  private func startFbLease() {
3004
- guard fbLeaseTask == nil, !debugPageHold else { return }
3019
+ guard fbLeaseTask == nil, !notificationsPanelHold else { return }
3005
3020
  sendFaceclawFbControl(acquire: true)
3006
3021
  fbLeaseTask = Task { @MainActor [weak self] in
3007
3022
  while !Task.isCancelled {
@@ -4085,8 +4100,8 @@ final class G2: NSObject, SGCManager {
4085
4100
  Bridge.log("G2: rebuildState() skipped — navigation mode owns the screen")
4086
4101
  return
4087
4102
  }
4088
- if debugPageHold {
4089
- Bridge.log("G2: rebuildState() skipped — debug page hold (dbg1)")
4103
+ if notificationsPanelHold {
4104
+ Bridge.log("G2: rebuildState() skipped — notifications panel hold")
4090
4105
  return
4091
4106
  }
4092
4107
  Bridge.log("G2: rebuildState()")
@@ -4766,7 +4781,7 @@ final class G2: NSObject, SGCManager {
4766
4781
  // toggle it off then back on (the firmware needs the off→on edge to re-arm).
4767
4782
  evenHubMicIntent = true
4768
4783
  // Held: intent is recorded; the post-hold rebuild re-arms the mic.
4769
- if debugPageHold { return }
4784
+ if notificationsPanelHold { return }
4770
4785
  DeviceStore.shared.apply("glasses", "micEnabled", true)
4771
4786
  let msg = EvenHubProto.audioControlMessage(enable: false)
4772
4787
  sendEvenHubCommand(msg)
@@ -4890,7 +4905,7 @@ final class G2: NSObject, SGCManager {
4890
4905
  stockImageStreamWarmedUp = false
4891
4906
  dashboardShowing = 0
4892
4907
  dashboardOpening = false
4893
- debugPageHold = false
4908
+ notificationsPanelHold = false
4894
4909
  heartbeatCounter = 0
4895
4910
  cfwCapabilityString = nil
4896
4911
  cfwClassified = false
@@ -5031,9 +5046,19 @@ final class G2: NSObject, SGCManager {
5031
5046
  /// 3. SKILL{skillId=NOTIFICATION, skillParam=show, ...} — dispatches the intent
5032
5047
  /// The SKILL step alone is ignored by firmware; the preceding ENTER+ASK
5033
5048
  /// supply the session context that lets the glasses act on the SKILL.
5049
+ /// Our EvenHub page is torn down first and every path that would bring it
5050
+ /// back (recovery rebuilds, fbguard lease, CFW frames, mic re-arm) is held
5051
+ /// for 3 s, or the sends race the stock panel for the screen.
5034
5052
  func showNotificationsPanel() async {
5035
5053
  Bridge.log("G2: showNotificationsPanel()")
5036
5054
 
5055
+ notificationsPanelHold = true
5056
+ stopFbLease(sendRelease: true)
5057
+ sendEvenHubCommand(EvenHubProto.shutdownMessage())
5058
+ pageCreated = false
5059
+ // Page death takes the mic with it; intent is untouched so the post-hold rebuild re-arms.
5060
+ DeviceStore.shared.apply("glasses", "micEnabled", false)
5061
+
5037
5062
  let enterPayload = EvenAIProto.aiCtrl(
5038
5063
  magicRandom: sendManager.nextMagicRandom(),
5039
5064
  status: 2 // EVEN_AI_ENTER
@@ -5054,32 +5079,15 @@ final class G2: NSObject, SGCManager {
5054
5079
  text: " ",
5055
5080
  streamEnable: 1, fTextEnd: 1
5056
5081
  )
5057
- }
5058
5082
 
5059
- /// Tear down the EvenHub page and hold every path that would bring it
5060
- /// back (recovery rebuilds, fbguard lease, CFW frames, mic re-arm) until
5061
- /// `dbg2` lifts the hold. Isolates the stock notifications UI from our sends.
5062
- func dbg1() {
5063
- Bridge.log("G2: dbg1() — EvenHub page down, resurrect held")
5064
- debugPageHold = true
5065
- stopFbLease(sendRelease: true)
5066
- sendEvenHubCommand(EvenHubProto.shutdownMessage())
5067
- pageCreated = false
5068
- // Page death takes the mic with it; intent is untouched so the post-hold rebuild re-arms.
5069
- DeviceStore.shared.apply("glasses", "micEnabled", false)
5083
+ try? await Task.sleep(nanoseconds: 3_000_000_000)
5084
+ notificationsPanelHold = false
5085
+ Bridge.log("G2: notifications resurrect re-enabled")
5070
5086
  }
5071
5087
 
5072
- /// Open the stock notifications panel, then lift the dbg1 hold 1 s later
5073
- /// so recovery resumes on the next firmware event / pending content.
5074
- func dbg2() {
5075
- Task { [weak self] in
5076
- await self?.showNotificationsPanel()
5077
- try? await Task.sleep(nanoseconds: 1_000_000_000)
5078
- guard let self else { return }
5079
- self.debugPageHold = false
5080
- Bridge.log("G2: dbg2() — resurrect re-enabled")
5081
- }
5082
- }
5088
+ func dbg1() {}
5089
+
5090
+ func dbg2() {}
5083
5091
 
5084
5092
  /// Raw wake lease start — no durable intent; a reconnect drops it.
5085
5093
  func dbg3() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glassly/bluetooth-sdk",
3
- "version": "0.1.0-dev.102",
3
+ "version": "0.1.0-dev.103",
4
4
  "description": "SDK for communicating with smart glasses",
5
5
  "main": "build/index.js",
6
6
  "react-native": "src/index.ts",
@@ -12,9 +12,9 @@ export interface BluetoothSdkReleaseMetadata {
12
12
  export const BLUETOOTH_SDK_RELEASE_METADATA: Readonly<BluetoothSdkReleaseMetadata> = Object.freeze({
13
13
  "schemaVersion": 1,
14
14
  "familyBaseVersion": "0.1.0",
15
- "releaseIdentity": "0.1.0-dev.102",
16
- "releaseSetId": "glassly-0.1.0-dev.102",
17
- "sourceCommit": "25f1ae8ddfcd46216e222643d54f498d21e01d59",
15
+ "releaseIdentity": "0.1.0-dev.103",
16
+ "releaseSetId": "glassly-0.1.0-dev.103",
17
+ "sourceCommit": "ba3c3655d8255014fc9292896ef73dd34f12afff",
18
18
  "otaManifestUrl": null,
19
19
  "otaManifestSha256": null
20
20
  })