react-native-mytatva-rn-sdk 1.2.95 → 1.2.97
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.
- package/android/src/main/java/com/mytatvarnsdk/CgmTrackyLibModule.kt +60 -2
- package/android/src/main/java/com/mytatvarnsdk/MainApplication.kt +1 -5
- package/android/src/main/java/com/mytatvarnsdk/activity/ConnectSensorActivity.kt +146 -6
- package/android/src/main/java/com/mytatvarnsdk/activity/PermissionActivity.kt +43 -0
- package/android/src/main/java/com/mytatvarnsdk/activity/PlaceSensorActivity.kt +17 -0
- package/android/src/main/java/com/mytatvarnsdk/activity/PlaceTransmitterActivity.kt +17 -0
- package/android/src/main/java/com/mytatvarnsdk/activity/QRActivity.kt +146 -5
- package/android/src/main/java/com/mytatvarnsdk/activity/SearchTransmitterActivity.kt +100 -0
- package/android/src/main/java/com/mytatvarnsdk/activity/SensorConnectSuccessActivity.kt +31 -0
- package/android/src/main/java/com/mytatvarnsdk/activity/StartCGMActivity.kt +17 -0
- package/android/src/main/java/com/mytatvarnsdk/network/AuthenticateSDKService.kt +63 -0
- package/android/src/main/java/com/mytatvarnsdk/utils/CgmModuleSentryLog.kt +205 -0
- package/android/src/main/java/com/mytatvarnsdk/utils/CgmSentryLog.kt +28 -0
- package/package.json +1 -1
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
package com.mytatvarnsdk
|
|
3
2
|
import android.app.Application
|
|
4
3
|
import android.bluetooth.BluetoothAdapter
|
|
5
4
|
import android.content.Intent
|
|
@@ -283,6 +282,63 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
283
282
|
}
|
|
284
283
|
}
|
|
285
284
|
|
|
285
|
+
/** SDK `latestGlucose` observer telemetry — must never throw or block queue/upload. */
|
|
286
|
+
private fun logSdkGlucoseReceivedSafely(pocGlucose: PocGlucose) {
|
|
287
|
+
try {
|
|
288
|
+
safeLogModuleEvent {
|
|
289
|
+
val activeSensorId = try {
|
|
290
|
+
prefsHelper?.qrInformation?.sensor ?: lastConnectCgm ?: ""
|
|
291
|
+
} catch (_: Throwable) {
|
|
292
|
+
""
|
|
293
|
+
}
|
|
294
|
+
val pocJson = try {
|
|
295
|
+
Gson().toJson(pocGlucose)
|
|
296
|
+
} catch (_: Throwable) {
|
|
297
|
+
try {
|
|
298
|
+
pocGlucose.toString()
|
|
299
|
+
} catch (_: Throwable) {
|
|
300
|
+
""
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
val attributes = try {
|
|
304
|
+
mapOf(
|
|
305
|
+
"glucoseId" to safePocField { pocGlucose.glucoseId?.toString() ?: "" },
|
|
306
|
+
"activeSensorId" to activeSensorId,
|
|
307
|
+
"timeInMillis" to safePocField { pocGlucose.timeInMillis.toString() },
|
|
308
|
+
"showGlucoseMG" to safePocField { pocGlucose.showGlucoseMG.toString() },
|
|
309
|
+
"showGlucose" to safePocField { pocGlucose.showGlucose.toString() },
|
|
310
|
+
"deviceId" to safePocField { pocGlucose.deviceId?.toString() ?: "" },
|
|
311
|
+
"errorCode" to safePocField { pocGlucose.errorCode?.toString() ?: "" },
|
|
312
|
+
"name" to safePocField { pocGlucose.name ?: "" }
|
|
313
|
+
)
|
|
314
|
+
} catch (_: Throwable) {
|
|
315
|
+
emptyMap()
|
|
316
|
+
}
|
|
317
|
+
val message = try {
|
|
318
|
+
"SDK latestGlucose received | glucoseId=${pocGlucose.glucoseId ?: ""} | showGlucoseMG=${pocGlucose.showGlucoseMG} | activeSensorId=$activeSensorId"
|
|
319
|
+
} catch (_: Throwable) {
|
|
320
|
+
"SDK latestGlucose received"
|
|
321
|
+
}
|
|
322
|
+
logModuleEvent(
|
|
323
|
+
where = "observeGlucoseData.sdkGlucoseReceived",
|
|
324
|
+
message = message,
|
|
325
|
+
level = SentryLogLevel.INFO,
|
|
326
|
+
jsonPayload = pocJson,
|
|
327
|
+
attributes = attributes
|
|
328
|
+
)
|
|
329
|
+
}
|
|
330
|
+
} catch (_: Throwable) {
|
|
331
|
+
// Observer callback must always continue to queue/upload.
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
private inline fun safePocField(block: () -> String): String =
|
|
336
|
+
try {
|
|
337
|
+
block()
|
|
338
|
+
} catch (_: Throwable) {
|
|
339
|
+
""
|
|
340
|
+
}
|
|
341
|
+
|
|
286
342
|
private fun cgmStatusDeviceAttributes(
|
|
287
343
|
status: String,
|
|
288
344
|
device: PocDevice?,
|
|
@@ -744,6 +800,8 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
744
800
|
return@Observer
|
|
745
801
|
}
|
|
746
802
|
|
|
803
|
+
logSdkGlucoseReceivedSafely(pocGlucose)
|
|
804
|
+
|
|
747
805
|
// Check for duplicate using glucoseId instead of timestamp
|
|
748
806
|
val glucoseId = pocGlucose.glucoseId ?: run {
|
|
749
807
|
Log.w("observeGlucoseData", "Glucose ID is null, skipping")
|
|
@@ -19,7 +19,7 @@ class MainApplication : BApplication(), ReactApplication {
|
|
|
19
19
|
MultiDex.install(base)
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
override val reactNativeHost: ReactNativeHost = object : DefaultReactNativeHost(this) {
|
|
23
23
|
override fun getUseDeveloperSupport(): Boolean {
|
|
24
24
|
return BuildConfig.DEBUG
|
|
25
25
|
}
|
|
@@ -42,8 +42,4 @@ class MainApplication : BApplication(), ReactApplication {
|
|
|
42
42
|
// BleService.startService(this)
|
|
43
43
|
// BSharedPreferences.init(this)
|
|
44
44
|
}
|
|
45
|
-
|
|
46
|
-
override fun getReactNativeHost(): ReactNativeHost {
|
|
47
|
-
return mReactNativeHost
|
|
48
|
-
}
|
|
49
45
|
}
|
|
@@ -42,6 +42,9 @@ import com.mytatvarnsdk.myView.progress.ProgressManagement
|
|
|
42
42
|
import com.mytatvarnsdk.myView.progress.ProgressType
|
|
43
43
|
import com.mytatvarnsdk.network.AuthenticateSDKService
|
|
44
44
|
import com.mytatvarnsdk.utils.TATVA_ENVIRONMENT
|
|
45
|
+
import com.mytatvarnsdk.utils.CgmModuleSentryLog.logModuleEvent
|
|
46
|
+
import com.mytatvarnsdk.utils.CgmModuleSentryLog.safeLogModuleEvent
|
|
47
|
+
import io.sentry.SentryLogLevel
|
|
45
48
|
import kotlinx.coroutines.CoroutineScope
|
|
46
49
|
import kotlinx.coroutines.Dispatchers
|
|
47
50
|
import kotlinx.coroutines.SupervisorJob
|
|
@@ -139,6 +142,21 @@ class ConnectSensorActivity : BaseBleActivity() {
|
|
|
139
142
|
fun manageErrorState(showError: Boolean, errorStatus: String) {
|
|
140
143
|
ProgressManagement.getInstance().dismissWait(this)
|
|
141
144
|
if (showError) {
|
|
145
|
+
if (errorStatus.isNotEmpty()) {
|
|
146
|
+
safeLogModuleEvent {
|
|
147
|
+
logModuleEvent(
|
|
148
|
+
where = "ConnectSensorActivity.error",
|
|
149
|
+
message = "CGM journey error | screen=${javaClass.simpleName} | $errorStatus",
|
|
150
|
+
level = SentryLogLevel.WARN,
|
|
151
|
+
attributes = mapOf(
|
|
152
|
+
"error_message" to errorStatus,
|
|
153
|
+
"screen" to javaClass.simpleName,
|
|
154
|
+
"is_reconnect" to isForReconnect.toString(),
|
|
155
|
+
),
|
|
156
|
+
logsOnly = true,
|
|
157
|
+
)
|
|
158
|
+
}
|
|
159
|
+
}
|
|
142
160
|
binding.clFail.visibility = View.VISIBLE
|
|
143
161
|
binding.clMain.visibility = View.GONE
|
|
144
162
|
binding.commonButton.root.visibility = View.GONE
|
|
@@ -299,6 +317,20 @@ class ConnectSensorActivity : BaseBleActivity() {
|
|
|
299
317
|
if (requestCode == REQUEST_QR && resultCode == RESULT_OK && data != null) {
|
|
300
318
|
val device: PocDevice? = data.getParcelableExtra("device")
|
|
301
319
|
if (device != null) {
|
|
320
|
+
safeLogModuleEvent {
|
|
321
|
+
logModuleEvent(
|
|
322
|
+
where = "cgmJourney.cgm_qr_activity_result_ok",
|
|
323
|
+
message = "CGM journey | screen=${javaClass.simpleName} | step=cgm_qr_activity_result_ok",
|
|
324
|
+
level = SentryLogLevel.INFO,
|
|
325
|
+
attributes = mapOf(
|
|
326
|
+
"journey_step" to "cgm_qr_activity_result_ok",
|
|
327
|
+
"screen" to javaClass.simpleName,
|
|
328
|
+
"is_reconnect" to isForReconnect.toString(),
|
|
329
|
+
"transmitter_name" to (device.name ?: ""),
|
|
330
|
+
),
|
|
331
|
+
logsOnly = true,
|
|
332
|
+
)
|
|
333
|
+
}
|
|
302
334
|
val lastConnectCgm = CgmTrackyLibModule.lastConnectCgm
|
|
303
335
|
Log.d("ConnectSensor", "lastConnectCgm: $lastConnectCgm")
|
|
304
336
|
|
|
@@ -337,6 +369,17 @@ class ConnectSensorActivity : BaseBleActivity() {
|
|
|
337
369
|
val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
|
338
370
|
val authenticateSDKService = AuthenticateSDKService(scope = scope)
|
|
339
371
|
|
|
372
|
+
safeLogModuleEvent {
|
|
373
|
+
logModuleEvent(
|
|
374
|
+
where = "ConnectSensorActivity.verifyDevice.request",
|
|
375
|
+
message = "Diasens device verification request | sensorId=$scannedSensorId",
|
|
376
|
+
level = SentryLogLevel.INFO,
|
|
377
|
+
jsonPayload = """{"sensorId":"$scannedSensorId","deviceType":"CGM","vendor":"diasens"}""",
|
|
378
|
+
attributes = mapOf("sensor_id" to scannedSensorId),
|
|
379
|
+
logsOnly = true,
|
|
380
|
+
)
|
|
381
|
+
}
|
|
382
|
+
|
|
340
383
|
authenticateSDKService.verifyDevice(
|
|
341
384
|
environment = if (envType.lowercase() == "uat") TATVA_ENVIRONMENT.STAGE else TATVA_ENVIRONMENT.PROD,
|
|
342
385
|
token = token,
|
|
@@ -345,6 +388,16 @@ class ConnectSensorActivity : BaseBleActivity() {
|
|
|
345
388
|
override fun onResponseSuccess(response: String) {
|
|
346
389
|
try {
|
|
347
390
|
Log.d("ConnectSensor", "Device verification API response: $response")
|
|
391
|
+
safeLogModuleEvent {
|
|
392
|
+
logModuleEvent(
|
|
393
|
+
where = "ConnectSensorActivity.verifyDevice.success",
|
|
394
|
+
message = "Diasens device verification response",
|
|
395
|
+
level = SentryLogLevel.INFO,
|
|
396
|
+
jsonPayload = "response=$response",
|
|
397
|
+
attributes = mapOf("sensor_id" to scannedSensorId),
|
|
398
|
+
logsOnly = true,
|
|
399
|
+
)
|
|
400
|
+
}
|
|
348
401
|
|
|
349
402
|
val verificationResponse = Gson().fromJson(response, DeviceVerificationResponse::class.java)
|
|
350
403
|
val code = when (val rawCode = verificationResponse.code) {
|
|
@@ -375,6 +428,21 @@ class ConnectSensorActivity : BaseBleActivity() {
|
|
|
375
428
|
}
|
|
376
429
|
} catch (e: Exception) {
|
|
377
430
|
Log.e("ConnectSensor", "Error parsing device verification response: ${e.message}")
|
|
431
|
+
safeLogModuleEvent {
|
|
432
|
+
val errorMessage = e.message ?: "Failed to parse verification response"
|
|
433
|
+
logModuleEvent(
|
|
434
|
+
where = "ConnectSensorActivity.verifyDevice.parseError",
|
|
435
|
+
message = "CGM journey error | screen=${javaClass.simpleName} | $errorMessage",
|
|
436
|
+
level = SentryLogLevel.WARN,
|
|
437
|
+
throwable = e,
|
|
438
|
+
attributes = mapOf(
|
|
439
|
+
"error_message" to errorMessage,
|
|
440
|
+
"screen" to javaClass.simpleName,
|
|
441
|
+
"is_reconnect" to isForReconnect.toString(),
|
|
442
|
+
),
|
|
443
|
+
logsOnly = true,
|
|
444
|
+
)
|
|
445
|
+
}
|
|
378
446
|
runOnUiThread {
|
|
379
447
|
ProgressManagement.getInstance().dismissWait(this@ConnectSensorActivity)
|
|
380
448
|
manageErrorState(true, "Try Again")
|
|
@@ -382,23 +450,66 @@ class ConnectSensorActivity : BaseBleActivity() {
|
|
|
382
450
|
}
|
|
383
451
|
}
|
|
384
452
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
453
|
+
override fun onResponseFail() {
|
|
454
|
+
Log.e("ConnectSensor", "Device verification API call failed")
|
|
455
|
+
safeLogModuleEvent {
|
|
456
|
+
val errorMessage =
|
|
457
|
+
"Diasens device verification API failed | sensorId=$scannedSensorId"
|
|
458
|
+
logModuleEvent(
|
|
459
|
+
where = "ConnectSensorActivity.verifyDevice.fail",
|
|
460
|
+
message = "CGM journey error | screen=${javaClass.simpleName} | $errorMessage",
|
|
461
|
+
level = SentryLogLevel.WARN,
|
|
462
|
+
attributes = mapOf(
|
|
463
|
+
"error_message" to errorMessage,
|
|
464
|
+
"screen" to javaClass.simpleName,
|
|
465
|
+
"is_reconnect" to isForReconnect.toString(),
|
|
466
|
+
),
|
|
467
|
+
logsOnly = true,
|
|
468
|
+
)
|
|
469
|
+
}
|
|
470
|
+
runOnUiThread {
|
|
471
|
+
ProgressManagement.getInstance().dismissWait(this@ConnectSensorActivity)
|
|
472
|
+
manageErrorState(true, "Try Again")
|
|
473
|
+
}
|
|
390
474
|
}
|
|
391
475
|
}
|
|
392
|
-
}
|
|
393
476
|
)
|
|
394
477
|
} catch (e: Exception) {
|
|
395
478
|
Log.e("ConnectSensor", "Error validating diasens sensor: ${e.message}")
|
|
479
|
+
safeLogModuleEvent {
|
|
480
|
+
val errorMessage = e.message ?: "Diasens validation exception"
|
|
481
|
+
logModuleEvent(
|
|
482
|
+
where = "ConnectSensorActivity.validateDiasensSensor",
|
|
483
|
+
message = "CGM journey error | screen=${javaClass.simpleName} | $errorMessage",
|
|
484
|
+
level = SentryLogLevel.WARN,
|
|
485
|
+
throwable = e,
|
|
486
|
+
attributes = mapOf(
|
|
487
|
+
"error_message" to errorMessage,
|
|
488
|
+
"screen" to javaClass.simpleName,
|
|
489
|
+
"is_reconnect" to isForReconnect.toString(),
|
|
490
|
+
),
|
|
491
|
+
logsOnly = true,
|
|
492
|
+
)
|
|
493
|
+
}
|
|
396
494
|
ProgressManagement.getInstance().dismissWait(this)
|
|
397
495
|
manageErrorState(true, "Try Again")
|
|
398
496
|
}
|
|
399
497
|
}
|
|
400
498
|
|
|
401
499
|
private fun manageDeviceVerificationError(message: String) {
|
|
500
|
+
safeLogModuleEvent {
|
|
501
|
+
logModuleEvent(
|
|
502
|
+
where = "ConnectSensorActivity.deviceVerificationError",
|
|
503
|
+
message = "CGM journey error | screen=${javaClass.simpleName} | $message",
|
|
504
|
+
level = SentryLogLevel.WARN,
|
|
505
|
+
attributes = mapOf(
|
|
506
|
+
"error_message" to message,
|
|
507
|
+
"screen" to javaClass.simpleName,
|
|
508
|
+
"is_reconnect" to isForReconnect.toString(),
|
|
509
|
+
),
|
|
510
|
+
logsOnly = true,
|
|
511
|
+
)
|
|
512
|
+
}
|
|
402
513
|
ProgressManagement.getInstance().dismissWait(this)
|
|
403
514
|
binding.clFail.visibility = View.VISIBLE
|
|
404
515
|
binding.clMain.visibility = View.GONE
|
|
@@ -454,6 +565,21 @@ class ConnectSensorActivity : BaseBleActivity() {
|
|
|
454
565
|
}
|
|
455
566
|
} catch (e: Exception) {
|
|
456
567
|
Log.d("bind::-> ", "bind: ${e.message}")
|
|
568
|
+
safeLogModuleEvent {
|
|
569
|
+
val errorMessage = e.message ?: "Sensor bind exception"
|
|
570
|
+
logModuleEvent(
|
|
571
|
+
where = "ConnectSensorActivity.bind",
|
|
572
|
+
message = "CGM journey error | screen=${javaClass.simpleName} | $errorMessage",
|
|
573
|
+
level = SentryLogLevel.WARN,
|
|
574
|
+
throwable = e,
|
|
575
|
+
attributes = mapOf(
|
|
576
|
+
"error_message" to errorMessage,
|
|
577
|
+
"screen" to javaClass.simpleName,
|
|
578
|
+
"is_reconnect" to isForReconnect.toString(),
|
|
579
|
+
),
|
|
580
|
+
logsOnly = true,
|
|
581
|
+
)
|
|
582
|
+
}
|
|
457
583
|
}
|
|
458
584
|
}
|
|
459
585
|
|
|
@@ -482,6 +608,20 @@ class ConnectSensorActivity : BaseBleActivity() {
|
|
|
482
608
|
}
|
|
483
609
|
|
|
484
610
|
private fun sendDataToRN(data: String, status: String) {
|
|
611
|
+
safeLogModuleEvent {
|
|
612
|
+
logModuleEvent(
|
|
613
|
+
where = "cgmJourney.$status",
|
|
614
|
+
message = "CGM journey | screen=${javaClass.simpleName} | step=$status",
|
|
615
|
+
level = SentryLogLevel.INFO,
|
|
616
|
+
jsonPayload = data.takeIf { it.isNotEmpty() },
|
|
617
|
+
attributes = mapOf(
|
|
618
|
+
"journey_step" to status,
|
|
619
|
+
"screen" to javaClass.simpleName,
|
|
620
|
+
"is_reconnect" to isForReconnect.toString(),
|
|
621
|
+
),
|
|
622
|
+
logsOnly = true,
|
|
623
|
+
)
|
|
624
|
+
}
|
|
485
625
|
if (reactContext != null) {
|
|
486
626
|
try {
|
|
487
627
|
val catalystInstance: CatalystInstance = reactContext.catalystInstance
|
|
@@ -39,6 +39,9 @@ import com.mytatvarnsdk.base.BasePermissionActivity
|
|
|
39
39
|
import com.mytatvarnsdk.databinding.ActivityPermissionBinding
|
|
40
40
|
import com.mytatvarnsdk.databinding.BluetoothDialogBottomsheetBinding
|
|
41
41
|
import com.mytatvarnsdk.databinding.ExitDialogBottomsheetBinding
|
|
42
|
+
import com.mytatvarnsdk.utils.CgmModuleSentryLog.logModuleEvent
|
|
43
|
+
import com.mytatvarnsdk.utils.CgmModuleSentryLog.safeLogModuleEvent
|
|
44
|
+
import io.sentry.SentryLogLevel
|
|
42
45
|
import org.json.JSONObject
|
|
43
46
|
|
|
44
47
|
class PermissionActivity : BasePermissionActivity() {
|
|
@@ -202,6 +205,20 @@ class PermissionActivity : BasePermissionActivity() {
|
|
|
202
205
|
}
|
|
203
206
|
|
|
204
207
|
private fun sendDataToRN(data: String, status: String) {
|
|
208
|
+
safeLogModuleEvent {
|
|
209
|
+
logModuleEvent(
|
|
210
|
+
where = "cgmJourney.$status",
|
|
211
|
+
message = "CGM journey | screen=${javaClass.simpleName} | step=$status",
|
|
212
|
+
level = SentryLogLevel.INFO,
|
|
213
|
+
jsonPayload = data.takeIf { it.isNotEmpty() },
|
|
214
|
+
attributes = mapOf(
|
|
215
|
+
"journey_step" to status,
|
|
216
|
+
"screen" to javaClass.simpleName,
|
|
217
|
+
"is_reconnect" to isForReconnect.toString(),
|
|
218
|
+
),
|
|
219
|
+
logsOnly = true,
|
|
220
|
+
)
|
|
221
|
+
}
|
|
205
222
|
if (reactContext != null) {
|
|
206
223
|
try {
|
|
207
224
|
val catalystInstance: CatalystInstance = reactContext.catalystInstance
|
|
@@ -643,12 +660,38 @@ class PermissionActivity : BasePermissionActivity() {
|
|
|
643
660
|
}
|
|
644
661
|
|
|
645
662
|
private fun onLocationPermissionGranted() {
|
|
663
|
+
safeLogModuleEvent {
|
|
664
|
+
logModuleEvent(
|
|
665
|
+
where = "cgmJourney.cgm_location_permission_granted",
|
|
666
|
+
message = "CGM journey | screen=${javaClass.simpleName} | step=cgm_location_permission_granted",
|
|
667
|
+
level = SentryLogLevel.INFO,
|
|
668
|
+
attributes = mapOf(
|
|
669
|
+
"journey_step" to "cgm_location_permission_granted",
|
|
670
|
+
"screen" to javaClass.simpleName,
|
|
671
|
+
"is_reconnect" to isForReconnect.toString(),
|
|
672
|
+
),
|
|
673
|
+
logsOnly = true,
|
|
674
|
+
)
|
|
675
|
+
}
|
|
646
676
|
setSwitchChecked(binding.switchLocation, true)
|
|
647
677
|
updateProceedButtonState()
|
|
648
678
|
}
|
|
649
679
|
|
|
650
680
|
@RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
|
|
651
681
|
private fun onBluetoothPermissionGranted() {
|
|
682
|
+
safeLogModuleEvent {
|
|
683
|
+
logModuleEvent(
|
|
684
|
+
where = "cgmJourney.cgm_bluetooth_permission_granted",
|
|
685
|
+
message = "CGM journey | screen=${javaClass.simpleName} | step=cgm_bluetooth_permission_granted",
|
|
686
|
+
level = SentryLogLevel.INFO,
|
|
687
|
+
attributes = mapOf(
|
|
688
|
+
"journey_step" to "cgm_bluetooth_permission_granted",
|
|
689
|
+
"screen" to javaClass.simpleName,
|
|
690
|
+
"is_reconnect" to isForReconnect.toString(),
|
|
691
|
+
),
|
|
692
|
+
logsOnly = true,
|
|
693
|
+
)
|
|
694
|
+
}
|
|
652
695
|
if (bluetoothAdapter == null) {
|
|
653
696
|
Toast.makeText(this, "Bluetooth not supported", Toast.LENGTH_SHORT).show()
|
|
654
697
|
} else {
|
|
@@ -25,6 +25,9 @@ import com.mytatvarnsdk.CgmTrackyLibModule
|
|
|
25
25
|
import com.mytatvarnsdk.R
|
|
26
26
|
import com.mytatvarnsdk.databinding.ActivityPlaceSensorBinding
|
|
27
27
|
import com.mytatvarnsdk.databinding.ExitDialogBottomsheetBinding
|
|
28
|
+
import com.mytatvarnsdk.utils.CgmModuleSentryLog.logModuleEvent
|
|
29
|
+
import com.mytatvarnsdk.utils.CgmModuleSentryLog.safeLogModuleEvent
|
|
30
|
+
import io.sentry.SentryLogLevel
|
|
28
31
|
|
|
29
32
|
class PlaceSensorActivity : AppCompatActivity() {
|
|
30
33
|
private lateinit var binding: ActivityPlaceSensorBinding
|
|
@@ -99,6 +102,20 @@ class PlaceSensorActivity : AppCompatActivity() {
|
|
|
99
102
|
}
|
|
100
103
|
|
|
101
104
|
private fun sendDataToRN(data: String, status: String) {
|
|
105
|
+
safeLogModuleEvent {
|
|
106
|
+
logModuleEvent(
|
|
107
|
+
where = "cgmJourney.$status",
|
|
108
|
+
message = "CGM journey | screen=${javaClass.simpleName} | step=$status",
|
|
109
|
+
level = SentryLogLevel.INFO,
|
|
110
|
+
jsonPayload = data.takeIf { it.isNotEmpty() },
|
|
111
|
+
attributes = mapOf(
|
|
112
|
+
"journey_step" to status,
|
|
113
|
+
"screen" to javaClass.simpleName,
|
|
114
|
+
"is_reconnect" to isForReconnect.toString(),
|
|
115
|
+
),
|
|
116
|
+
logsOnly = true,
|
|
117
|
+
)
|
|
118
|
+
}
|
|
102
119
|
if (reactContext != null) {
|
|
103
120
|
try {
|
|
104
121
|
val catalystInstance: CatalystInstance = reactContext.catalystInstance
|
|
@@ -25,6 +25,9 @@ import com.mytatvarnsdk.CgmTrackyLibModule
|
|
|
25
25
|
import com.mytatvarnsdk.R
|
|
26
26
|
import com.mytatvarnsdk.databinding.ActivityPlaceTransmitterBinding
|
|
27
27
|
import com.mytatvarnsdk.databinding.ExitDialogBottomsheetBinding
|
|
28
|
+
import com.mytatvarnsdk.utils.CgmModuleSentryLog.logModuleEvent
|
|
29
|
+
import com.mytatvarnsdk.utils.CgmModuleSentryLog.safeLogModuleEvent
|
|
30
|
+
import io.sentry.SentryLogLevel
|
|
28
31
|
|
|
29
32
|
class PlaceTransmitterActivity : AppCompatActivity() {
|
|
30
33
|
private lateinit var binding: ActivityPlaceTransmitterBinding
|
|
@@ -136,6 +139,20 @@ class PlaceTransmitterActivity : AppCompatActivity() {
|
|
|
136
139
|
}
|
|
137
140
|
|
|
138
141
|
private fun sendDataToRN(data: String, status: String) {
|
|
142
|
+
safeLogModuleEvent {
|
|
143
|
+
logModuleEvent(
|
|
144
|
+
where = "cgmJourney.$status",
|
|
145
|
+
message = "CGM journey | screen=${javaClass.simpleName} | step=$status",
|
|
146
|
+
level = SentryLogLevel.INFO,
|
|
147
|
+
jsonPayload = data.takeIf { it.isNotEmpty() },
|
|
148
|
+
attributes = mapOf(
|
|
149
|
+
"journey_step" to status,
|
|
150
|
+
"screen" to javaClass.simpleName,
|
|
151
|
+
"is_reconnect" to isForReconnect.toString(),
|
|
152
|
+
),
|
|
153
|
+
logsOnly = true,
|
|
154
|
+
)
|
|
155
|
+
}
|
|
139
156
|
if (reactContext != null) {
|
|
140
157
|
try {
|
|
141
158
|
val catalystInstance: CatalystInstance = reactContext.catalystInstance
|
|
@@ -15,6 +15,9 @@ import cgmblelib.utils.SharedPreferencesLibraryUtil
|
|
|
15
15
|
import com.myc.library_zxing.QRFragment
|
|
16
16
|
import com.myc.library_zxing.view.OnFragmentListener
|
|
17
17
|
import com.mytatvarnsdk.R
|
|
18
|
+
import com.mytatvarnsdk.utils.CgmModuleSentryLog.logModuleEvent
|
|
19
|
+
import com.mytatvarnsdk.utils.CgmModuleSentryLog.safeLogModuleEvent
|
|
20
|
+
import io.sentry.SentryLogLevel
|
|
18
21
|
import ist.com.sdk.AlgorithmTools
|
|
19
22
|
import ist.com.sdk.KRDecodeData
|
|
20
23
|
|
|
@@ -28,6 +31,18 @@ class QRActivity : AppCompatActivity(), View.OnClickListener {
|
|
|
28
31
|
findViewById<View?>(R.id.btnLeft).setOnClickListener(this)
|
|
29
32
|
mPocDevice = intent.getParcelableExtra("device")
|
|
30
33
|
if (mPocDevice == null) {
|
|
34
|
+
safeLogModuleEvent {
|
|
35
|
+
logModuleEvent(
|
|
36
|
+
where = "QRActivity.missingDevice",
|
|
37
|
+
message = "CGM journey error | screen=${javaClass.simpleName} | QR scan started without transmitter device",
|
|
38
|
+
level = SentryLogLevel.WARN,
|
|
39
|
+
attributes = mapOf(
|
|
40
|
+
"error_message" to "QR scan started without transmitter device",
|
|
41
|
+
"screen" to javaClass.simpleName,
|
|
42
|
+
),
|
|
43
|
+
logsOnly = true,
|
|
44
|
+
)
|
|
45
|
+
}
|
|
31
46
|
finish()
|
|
32
47
|
}
|
|
33
48
|
}
|
|
@@ -36,9 +51,41 @@ class QRActivity : AppCompatActivity(), View.OnClickListener {
|
|
|
36
51
|
super.onResume()
|
|
37
52
|
mQRFragment = QRFragment.newInstance(object : OnFragmentListener {
|
|
38
53
|
override fun onPermissionRequestFail(isForever: Boolean) {
|
|
54
|
+
val errorMessage = if (isForever) {
|
|
55
|
+
"Camera permission denied permanently"
|
|
56
|
+
} else {
|
|
57
|
+
"Camera permission denied"
|
|
58
|
+
}
|
|
59
|
+
safeLogModuleEvent {
|
|
60
|
+
logModuleEvent(
|
|
61
|
+
where = "QRActivity.cameraPermissionDenied",
|
|
62
|
+
message = "CGM journey error | screen=${javaClass.simpleName} | $errorMessage",
|
|
63
|
+
level = SentryLogLevel.WARN,
|
|
64
|
+
attributes = mapOf(
|
|
65
|
+
"error_message" to errorMessage,
|
|
66
|
+
"screen" to javaClass.simpleName,
|
|
67
|
+
"permission_denied_forever" to isForever.toString(),
|
|
68
|
+
),
|
|
69
|
+
logsOnly = true,
|
|
70
|
+
)
|
|
71
|
+
}
|
|
39
72
|
}
|
|
40
73
|
|
|
41
74
|
override fun onCameraOpenError(e: Exception?) {
|
|
75
|
+
val errorMessage = e?.message ?: "Camera failed to open"
|
|
76
|
+
safeLogModuleEvent {
|
|
77
|
+
logModuleEvent(
|
|
78
|
+
where = "QRActivity.cameraOpenError",
|
|
79
|
+
message = "CGM journey error | screen=${javaClass.simpleName} | $errorMessage",
|
|
80
|
+
level = SentryLogLevel.WARN,
|
|
81
|
+
throwable = e,
|
|
82
|
+
attributes = mapOf(
|
|
83
|
+
"error_message" to errorMessage,
|
|
84
|
+
"screen" to javaClass.simpleName,
|
|
85
|
+
),
|
|
86
|
+
logsOnly = true,
|
|
87
|
+
)
|
|
88
|
+
}
|
|
42
89
|
}
|
|
43
90
|
|
|
44
91
|
override fun onScanResult(messages: String?, bitmap: Bitmap?) {
|
|
@@ -71,12 +118,47 @@ class QRActivity : AppCompatActivity(), View.OnClickListener {
|
|
|
71
118
|
*/
|
|
72
119
|
private fun decodeMessageCt3(message: String) {
|
|
73
120
|
Log.d("QR Info ==> ", "decodeMessageCt3: $message")
|
|
121
|
+
try {
|
|
122
|
+
safeLogModuleEvent {
|
|
123
|
+
logModuleEvent(
|
|
124
|
+
where = "cgmJourney.cgm_qr_scanned",
|
|
125
|
+
message = "CGM journey | screen=${javaClass.simpleName} | step=cgm_qr_scanned",
|
|
126
|
+
level = SentryLogLevel.INFO,
|
|
127
|
+
jsonPayload = message,
|
|
128
|
+
attributes = mapOf(
|
|
129
|
+
"journey_step" to "cgm_qr_scanned",
|
|
130
|
+
"screen" to javaClass.simpleName,
|
|
131
|
+
),
|
|
132
|
+
logsOnly = true,
|
|
133
|
+
)
|
|
134
|
+
}
|
|
74
135
|
|
|
75
|
-
|
|
136
|
+
val decodeData: KRDecodeData = AlgorithmTools.getInstance().decodeCT(message.toCharArray())
|
|
76
137
|
|
|
77
|
-
|
|
138
|
+
Log.d("QR Info ==> ", "decodeData: $decodeData")
|
|
78
139
|
|
|
79
|
-
|
|
140
|
+
showMessage(message, decodeData.k, decodeData.r, message)
|
|
141
|
+
} catch (e: Exception) {
|
|
142
|
+
val errorMessage = e.message ?: "QR decode failed"
|
|
143
|
+
safeLogModuleEvent {
|
|
144
|
+
logModuleEvent(
|
|
145
|
+
where = "QRActivity.decodeMessageCt3",
|
|
146
|
+
message = "CGM journey error | screen=${javaClass.simpleName} | $errorMessage",
|
|
147
|
+
level = SentryLogLevel.WARN,
|
|
148
|
+
throwable = e,
|
|
149
|
+
attributes = mapOf(
|
|
150
|
+
"error_message" to errorMessage,
|
|
151
|
+
"screen" to javaClass.simpleName,
|
|
152
|
+
"qr_raw" to message,
|
|
153
|
+
),
|
|
154
|
+
logsOnly = true,
|
|
155
|
+
)
|
|
156
|
+
}
|
|
157
|
+
try {
|
|
158
|
+
mQRFragment?.restartPreviewAfterDelay(0)
|
|
159
|
+
} catch (_: Throwable) {
|
|
160
|
+
}
|
|
161
|
+
}
|
|
80
162
|
}
|
|
81
163
|
|
|
82
164
|
fun showMessage(message: String?, k: Float, r: Float, sensorInfo: String?) {
|
|
@@ -87,20 +169,79 @@ class QRActivity : AppCompatActivity(), View.OnClickListener {
|
|
|
87
169
|
val qrInformation: QRInformation? = prefsHelper.qrInformation
|
|
88
170
|
|
|
89
171
|
Log.d("qrInformation==> ", "mPocDevice: ${mPocDevice.toString()}")
|
|
90
|
-
|
|
172
|
+
val isEffective = qrInformation?.isEffective(mPocDevice?.name, r, k) ?: false
|
|
173
|
+
safeLogModuleEvent {
|
|
174
|
+
logModuleEvent(
|
|
175
|
+
where = "cgmJourney.cgm_qr_is_effective",
|
|
176
|
+
message = "CGM journey | screen=${javaClass.simpleName} | isEffective=$isEffective",
|
|
177
|
+
level = SentryLogLevel.INFO,
|
|
178
|
+
jsonPayload = isEffective.toString(),
|
|
179
|
+
attributes = mapOf(
|
|
180
|
+
"journey_step" to "cgm_qr_is_effective",
|
|
181
|
+
"screen" to javaClass.simpleName,
|
|
182
|
+
"is_effective" to isEffective.toString(),
|
|
183
|
+
),
|
|
184
|
+
logsOnly = true,
|
|
185
|
+
)
|
|
186
|
+
}
|
|
187
|
+
if (isEffective && qrInformation != null) {
|
|
91
188
|
Log.d("qrInformation==> ", "qrInformation: $qrInformation")
|
|
189
|
+
safeLogModuleEvent {
|
|
190
|
+
logModuleEvent(
|
|
191
|
+
where = "cgmJourney.cgm_qr_validation_success",
|
|
192
|
+
message = "CGM journey | screen=${javaClass.simpleName} | step=cgm_qr_validation_success",
|
|
193
|
+
level = SentryLogLevel.INFO,
|
|
194
|
+
jsonPayload = qrInformation.toString(),
|
|
195
|
+
attributes = mapOf(
|
|
196
|
+
"journey_step" to "cgm_qr_validation_success",
|
|
197
|
+
"screen" to javaClass.simpleName,
|
|
198
|
+
"transmitter_name" to (mPocDevice?.name ?: ""),
|
|
199
|
+
"sensor_id" to (qrInformation.sensor ?: ""),
|
|
200
|
+
),
|
|
201
|
+
logsOnly = true,
|
|
202
|
+
)
|
|
203
|
+
}
|
|
92
204
|
setResult(RESULT_OK, Intent().putExtra("device", mPocDevice as Parcelable))
|
|
93
205
|
finish()
|
|
94
206
|
} else {
|
|
207
|
+
val failMessage = getString(R.string.verification_fail)
|
|
208
|
+
safeLogModuleEvent {
|
|
209
|
+
logModuleEvent(
|
|
210
|
+
where = "QRActivity.qrValidationFailed",
|
|
211
|
+
message = "CGM journey error | screen=${javaClass.simpleName} | $failMessage",
|
|
212
|
+
level = SentryLogLevel.WARN,
|
|
213
|
+
attributes = mapOf(
|
|
214
|
+
"error_message" to failMessage,
|
|
215
|
+
"screen" to javaClass.simpleName,
|
|
216
|
+
"transmitter_name" to (mPocDevice?.name ?: ""),
|
|
217
|
+
"qr_raw" to (message ?: ""),
|
|
218
|
+
),
|
|
219
|
+
logsOnly = true,
|
|
220
|
+
)
|
|
221
|
+
}
|
|
95
222
|
Toast.makeText(
|
|
96
223
|
this@QRActivity,
|
|
97
|
-
|
|
224
|
+
failMessage,
|
|
98
225
|
Toast.LENGTH_SHORT
|
|
99
226
|
)
|
|
100
227
|
.show()
|
|
101
228
|
mQRFragment!!.restartPreviewAfterDelay(0)
|
|
102
229
|
}
|
|
103
230
|
} catch (e: Exception) {
|
|
231
|
+
val errorMessage = e.message ?: "QR validation exception"
|
|
232
|
+
safeLogModuleEvent {
|
|
233
|
+
logModuleEvent(
|
|
234
|
+
where = "QRActivity.showMessage",
|
|
235
|
+
message = "CGM journey error | screen=${javaClass.simpleName} | $errorMessage",
|
|
236
|
+
level = SentryLogLevel.WARN,
|
|
237
|
+
throwable = e,
|
|
238
|
+
attributes = mapOf(
|
|
239
|
+
"error_message" to errorMessage,
|
|
240
|
+
"screen" to javaClass.simpleName,
|
|
241
|
+
),
|
|
242
|
+
logsOnly = true,
|
|
243
|
+
)
|
|
244
|
+
}
|
|
104
245
|
e.printStackTrace()
|
|
105
246
|
finish()
|
|
106
247
|
}
|
|
@@ -52,6 +52,9 @@ import com.mytatvarnsdk.myView.dialog.WarnDialogUtils
|
|
|
52
52
|
import com.mytatvarnsdk.myView.progress.ProgressManagement
|
|
53
53
|
import com.mytatvarnsdk.myView.progress.ProgressType
|
|
54
54
|
import com.mytatvarnsdk.network.AuthenticateSDKService
|
|
55
|
+
import com.mytatvarnsdk.utils.CgmModuleSentryLog.logModuleEvent
|
|
56
|
+
import com.mytatvarnsdk.utils.CgmModuleSentryLog.safeLogModuleEvent
|
|
57
|
+
import io.sentry.SentryLogLevel
|
|
55
58
|
import kotlinx.coroutines.CoroutineScope
|
|
56
59
|
import kotlinx.coroutines.Dispatchers
|
|
57
60
|
import kotlinx.coroutines.Job
|
|
@@ -127,6 +130,21 @@ class SearchTransmitterActivity : BaseBleActivity() {
|
|
|
127
130
|
|
|
128
131
|
fun manageErrorState(showError: Boolean, errorStatus: String) {
|
|
129
132
|
if (showError) {
|
|
133
|
+
if (errorStatus.isNotEmpty()) {
|
|
134
|
+
safeLogModuleEvent {
|
|
135
|
+
logModuleEvent(
|
|
136
|
+
where = "SearchTransmitterActivity.error",
|
|
137
|
+
message = "CGM journey error | screen=${javaClass.simpleName} | $errorStatus",
|
|
138
|
+
level = SentryLogLevel.WARN,
|
|
139
|
+
attributes = mapOf(
|
|
140
|
+
"error_message" to errorStatus,
|
|
141
|
+
"screen" to javaClass.simpleName,
|
|
142
|
+
"is_reconnect" to isForReconnect.toString(),
|
|
143
|
+
),
|
|
144
|
+
logsOnly = true,
|
|
145
|
+
)
|
|
146
|
+
}
|
|
147
|
+
}
|
|
130
148
|
binding.clFail.visibility = View.VISIBLE
|
|
131
149
|
binding.clMain.visibility = View.GONE
|
|
132
150
|
binding.commonButton.root.visibility = View.GONE
|
|
@@ -296,11 +314,37 @@ class SearchTransmitterActivity : BaseBleActivity() {
|
|
|
296
314
|
|
|
297
315
|
public override fun checkFailForLowPower() {
|
|
298
316
|
ProgressManagement.getInstance().dismissWait(this)
|
|
317
|
+
safeLogModuleEvent {
|
|
318
|
+
logModuleEvent(
|
|
319
|
+
where = "SearchTransmitterActivity.checkFailForLowPower",
|
|
320
|
+
message = "CGM journey error | screen=${javaClass.simpleName} | Transmitter low power",
|
|
321
|
+
level = SentryLogLevel.WARN,
|
|
322
|
+
attributes = mapOf(
|
|
323
|
+
"error_message" to "Transmitter low power",
|
|
324
|
+
"screen" to javaClass.simpleName,
|
|
325
|
+
"is_reconnect" to isForReconnect.toString(),
|
|
326
|
+
),
|
|
327
|
+
logsOnly = true,
|
|
328
|
+
)
|
|
329
|
+
}
|
|
299
330
|
WarnDialogUtils.getInstance().showWarnDialog(this, DialogType.TYPE_LOW_POWER)
|
|
300
331
|
}
|
|
301
332
|
|
|
302
333
|
public override fun checkFailErrorTemperature() {
|
|
303
334
|
ProgressManagement.getInstance().dismissWait(this)
|
|
335
|
+
safeLogModuleEvent {
|
|
336
|
+
logModuleEvent(
|
|
337
|
+
where = "SearchTransmitterActivity.checkFailErrorTemperature",
|
|
338
|
+
message = "CGM journey error | screen=${javaClass.simpleName} | Transmitter temperature error",
|
|
339
|
+
level = SentryLogLevel.WARN,
|
|
340
|
+
attributes = mapOf(
|
|
341
|
+
"error_message" to "Transmitter temperature error",
|
|
342
|
+
"screen" to javaClass.simpleName,
|
|
343
|
+
"is_reconnect" to isForReconnect.toString(),
|
|
344
|
+
),
|
|
345
|
+
logsOnly = true,
|
|
346
|
+
)
|
|
347
|
+
}
|
|
304
348
|
}
|
|
305
349
|
|
|
306
350
|
public override fun onlineLost() {
|
|
@@ -318,6 +362,21 @@ class SearchTransmitterActivity : BaseBleActivity() {
|
|
|
318
362
|
}
|
|
319
363
|
} catch (e: Exception) {
|
|
320
364
|
Log.d("bind::-> ", "bind: ${e.message}")
|
|
365
|
+
safeLogModuleEvent {
|
|
366
|
+
val errorMessage = e.message ?: "Transmitter bind exception"
|
|
367
|
+
logModuleEvent(
|
|
368
|
+
where = "SearchTransmitterActivity.bind",
|
|
369
|
+
message = "CGM journey error | screen=${javaClass.simpleName} | $errorMessage",
|
|
370
|
+
level = SentryLogLevel.WARN,
|
|
371
|
+
throwable = e,
|
|
372
|
+
attributes = mapOf(
|
|
373
|
+
"error_message" to errorMessage,
|
|
374
|
+
"screen" to javaClass.simpleName,
|
|
375
|
+
"is_reconnect" to isForReconnect.toString(),
|
|
376
|
+
),
|
|
377
|
+
logsOnly = true,
|
|
378
|
+
)
|
|
379
|
+
}
|
|
321
380
|
}
|
|
322
381
|
}
|
|
323
382
|
|
|
@@ -440,6 +499,20 @@ class SearchTransmitterActivity : BaseBleActivity() {
|
|
|
440
499
|
}
|
|
441
500
|
|
|
442
501
|
private fun sendDataToRN(data: String, status: String) {
|
|
502
|
+
safeLogModuleEvent {
|
|
503
|
+
logModuleEvent(
|
|
504
|
+
where = "cgmJourney.$status",
|
|
505
|
+
message = "CGM journey | screen=${javaClass.simpleName} | step=$status",
|
|
506
|
+
level = SentryLogLevel.INFO,
|
|
507
|
+
jsonPayload = data.takeIf { it.isNotEmpty() },
|
|
508
|
+
attributes = mapOf(
|
|
509
|
+
"journey_step" to status,
|
|
510
|
+
"screen" to javaClass.simpleName,
|
|
511
|
+
"is_reconnect" to isForReconnect.toString(),
|
|
512
|
+
),
|
|
513
|
+
logsOnly = true,
|
|
514
|
+
)
|
|
515
|
+
}
|
|
443
516
|
if (reactContext != null) {
|
|
444
517
|
try {
|
|
445
518
|
val catalystInstance: CatalystInstance = reactContext.catalystInstance
|
|
@@ -487,6 +560,19 @@ class SearchTransmitterActivity : BaseBleActivity() {
|
|
|
487
560
|
}
|
|
488
561
|
|
|
489
562
|
private fun startDeviceSearch() {
|
|
563
|
+
safeLogModuleEvent {
|
|
564
|
+
logModuleEvent(
|
|
565
|
+
where = "cgmJourney.cgm_transmitter_scan_started",
|
|
566
|
+
message = "CGM journey | screen=${javaClass.simpleName} | step=cgm_transmitter_scan_started",
|
|
567
|
+
level = SentryLogLevel.INFO,
|
|
568
|
+
attributes = mapOf(
|
|
569
|
+
"journey_step" to "cgm_transmitter_scan_started",
|
|
570
|
+
"screen" to javaClass.simpleName,
|
|
571
|
+
"is_reconnect" to isForReconnect.toString(),
|
|
572
|
+
),
|
|
573
|
+
logsOnly = true,
|
|
574
|
+
)
|
|
575
|
+
}
|
|
490
576
|
mModel = ViewModelProviders.of(this)[MainActivityModel::class.java]
|
|
491
577
|
|
|
492
578
|
ReconnectManagement.getInstance()
|
|
@@ -544,6 +630,20 @@ class SearchTransmitterActivity : BaseBleActivity() {
|
|
|
544
630
|
isTransmitterConnected = true
|
|
545
631
|
|
|
546
632
|
if (transmitterDeviceInfo != null) {
|
|
633
|
+
safeLogModuleEvent {
|
|
634
|
+
logModuleEvent(
|
|
635
|
+
where = "cgmJourney.cgm_transmitter_connect_clicked",
|
|
636
|
+
message = "CGM journey | screen=${javaClass.simpleName} | step=cgm_transmitter_connect_clicked",
|
|
637
|
+
level = SentryLogLevel.INFO,
|
|
638
|
+
jsonPayload = transmitterDeviceInfo?.pocDevice?.name ?: "",
|
|
639
|
+
attributes = mapOf(
|
|
640
|
+
"journey_step" to "cgm_transmitter_connect_clicked",
|
|
641
|
+
"screen" to javaClass.simpleName,
|
|
642
|
+
"is_reconnect" to isForReconnect.toString(),
|
|
643
|
+
),
|
|
644
|
+
logsOnly = true,
|
|
645
|
+
)
|
|
646
|
+
}
|
|
547
647
|
if (isForReconnect) {
|
|
548
648
|
GattTool.unBindInDatabase(this, enumUnBind.UNBIND_FORCE)
|
|
549
649
|
}
|
|
@@ -31,6 +31,9 @@ import com.mytatvarnsdk.network.AuthenticateSDKService
|
|
|
31
31
|
import com.mytatvarnsdk.network.AuthenticateSDKService.LoaderListener
|
|
32
32
|
import com.mytatvarnsdk.utils.DeviceStatus
|
|
33
33
|
import com.mytatvarnsdk.utils.TATVA_ENVIRONMENT
|
|
34
|
+
import com.mytatvarnsdk.utils.CgmModuleSentryLog.logModuleEvent
|
|
35
|
+
import com.mytatvarnsdk.utils.CgmModuleSentryLog.safeLogModuleEvent
|
|
36
|
+
import io.sentry.SentryLogLevel
|
|
34
37
|
import kotlinx.coroutines.CoroutineScope
|
|
35
38
|
import kotlinx.coroutines.Dispatchers
|
|
36
39
|
import kotlinx.coroutines.Job
|
|
@@ -121,6 +124,20 @@ class SensorConnectSuccessActivity : AppCompatActivity() {
|
|
|
121
124
|
}
|
|
122
125
|
|
|
123
126
|
private fun sendDataToRN(data: String, status: String) {
|
|
127
|
+
safeLogModuleEvent {
|
|
128
|
+
logModuleEvent(
|
|
129
|
+
where = "cgmJourney.$status",
|
|
130
|
+
message = "CGM journey | screen=${javaClass.simpleName} | step=$status",
|
|
131
|
+
level = SentryLogLevel.INFO,
|
|
132
|
+
jsonPayload = data.takeIf { it.isNotEmpty() },
|
|
133
|
+
attributes = mapOf(
|
|
134
|
+
"journey_step" to status,
|
|
135
|
+
"screen" to javaClass.simpleName,
|
|
136
|
+
"is_reconnect" to isForReconnect.toString(),
|
|
137
|
+
),
|
|
138
|
+
logsOnly = true,
|
|
139
|
+
)
|
|
140
|
+
}
|
|
124
141
|
if (reactContext != null) {
|
|
125
142
|
try {
|
|
126
143
|
val catalystInstance: CatalystInstance = reactContext.catalystInstance
|
|
@@ -173,6 +190,20 @@ class SensorConnectSuccessActivity : AppCompatActivity() {
|
|
|
173
190
|
obj.put("status", DeviceStatus.CONNECTED.id)
|
|
174
191
|
obj.put("rawData", rawData)
|
|
175
192
|
|
|
193
|
+
safeLogModuleEvent {
|
|
194
|
+
logModuleEvent(
|
|
195
|
+
where = "SensorConnectSuccessActivity.postDeviceData.request",
|
|
196
|
+
message = "POST /cgm/connection CONNECTED on sensor success screen",
|
|
197
|
+
level = SentryLogLevel.INFO,
|
|
198
|
+
jsonPayload = "request=${obj}",
|
|
199
|
+
attributes = mapOf(
|
|
200
|
+
"cgm_status" to DeviceStatus.CONNECTED.id,
|
|
201
|
+
"sensor_id" to (information.sensor ?: ""),
|
|
202
|
+
),
|
|
203
|
+
logsOnly = true,
|
|
204
|
+
)
|
|
205
|
+
}
|
|
206
|
+
|
|
176
207
|
authenticateSDKService.postDeviceData(
|
|
177
208
|
environment = if (CgmTrackyLibModule.env.lowercase() == "uat") TATVA_ENVIRONMENT.STAGE else TATVA_ENVIRONMENT.PROD,
|
|
178
209
|
data = obj.toString(),
|
|
@@ -28,6 +28,9 @@ import com.mytatvarnsdk.CgmTrackyLibModule.Companion.mReactContext
|
|
|
28
28
|
import com.mytatvarnsdk.R
|
|
29
29
|
import com.mytatvarnsdk.databinding.ActivityStartCgmactivityBinding
|
|
30
30
|
import com.mytatvarnsdk.databinding.ExitDialogBottomsheetBinding
|
|
31
|
+
import com.mytatvarnsdk.utils.CgmModuleSentryLog.logModuleEvent
|
|
32
|
+
import com.mytatvarnsdk.utils.CgmModuleSentryLog.safeLogModuleEvent
|
|
33
|
+
import io.sentry.SentryLogLevel
|
|
31
34
|
|
|
32
35
|
|
|
33
36
|
class StartCGMActivity : AppCompatActivity() {
|
|
@@ -168,6 +171,20 @@ class StartCGMActivity : AppCompatActivity() {
|
|
|
168
171
|
}
|
|
169
172
|
|
|
170
173
|
private fun sendDataToRN(data: String, status: String) {
|
|
174
|
+
safeLogModuleEvent {
|
|
175
|
+
logModuleEvent(
|
|
176
|
+
where = "cgmJourney.$status",
|
|
177
|
+
message = "CGM journey | screen=${javaClass.simpleName} | step=$status",
|
|
178
|
+
level = SentryLogLevel.INFO,
|
|
179
|
+
jsonPayload = data.takeIf { it.isNotEmpty() },
|
|
180
|
+
attributes = mapOf(
|
|
181
|
+
"journey_step" to status,
|
|
182
|
+
"screen" to javaClass.simpleName,
|
|
183
|
+
"is_reconnect" to isForReconnect.toString(),
|
|
184
|
+
),
|
|
185
|
+
logsOnly = true,
|
|
186
|
+
)
|
|
187
|
+
}
|
|
171
188
|
if (reactContext != null) {
|
|
172
189
|
try {
|
|
173
190
|
val catalystInstance: CatalystInstance = reactContext.catalystInstance
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
package com.mytatvarnsdk.network
|
|
2
2
|
|
|
3
3
|
import android.util.Log
|
|
4
|
+
import com.mytatvarnsdk.utils.CgmModuleSentryLog.logModuleEvent
|
|
5
|
+
import com.mytatvarnsdk.utils.CgmModuleSentryLog.safeLogModuleEvent
|
|
4
6
|
import com.mytatvarnsdk.utils.EncryptionUtil.getDecryptedData
|
|
5
7
|
import com.mytatvarnsdk.utils.EncryptionUtil.getEncryptedText
|
|
6
8
|
import com.mytatvarnsdk.utils.EncryptionUtil.getEncryptionIv
|
|
7
9
|
import com.mytatvarnsdk.utils.EncryptionUtil.getEncryptionKey
|
|
8
10
|
import com.mytatvarnsdk.utils.RetrofitInstance
|
|
9
11
|
import com.mytatvarnsdk.utils.TATVA_ENVIRONMENT
|
|
12
|
+
import io.sentry.SentryLogLevel
|
|
10
13
|
import com.mytatvarnsdk.utils.TatvaEncryptionConfig.PROD_API_KEY
|
|
11
14
|
import com.mytatvarnsdk.utils.TatvaEncryptionConfig.PROD_BASE_URL
|
|
12
15
|
import com.mytatvarnsdk.utils.TatvaEncryptionConfig.PROD_ENC_IV
|
|
@@ -159,7 +162,29 @@ class AuthenticateSDKService(val scope: CoroutineScope) {
|
|
|
159
162
|
|
|
160
163
|
Log.d("API Response", "API response: $decryptedResponse")
|
|
161
164
|
|
|
165
|
+
safeLogModuleEvent {
|
|
166
|
+
logModuleEvent(
|
|
167
|
+
where = "AuthenticateSDKService.postDeviceData.success",
|
|
168
|
+
message = "POST /cgm/connection succeeded",
|
|
169
|
+
level = SentryLogLevel.INFO,
|
|
170
|
+
jsonPayload = "request=$data | response=$decryptedResponse",
|
|
171
|
+
attributes = mapOf("endpoint" to "/cgm/connection"),
|
|
172
|
+
logsOnly = true,
|
|
173
|
+
)
|
|
174
|
+
}
|
|
175
|
+
|
|
162
176
|
} catch (e: HttpException) {
|
|
177
|
+
safeLogModuleEvent {
|
|
178
|
+
logModuleEvent(
|
|
179
|
+
where = "AuthenticateSDKService.postDeviceData.httpError",
|
|
180
|
+
message = "POST /cgm/connection HTTP ${e.code()}",
|
|
181
|
+
level = SentryLogLevel.WARN,
|
|
182
|
+
jsonPayload = "request=$data",
|
|
183
|
+
throwable = e,
|
|
184
|
+
attributes = mapOf("http_code" to e.code().toString()),
|
|
185
|
+
logsOnly = true,
|
|
186
|
+
)
|
|
187
|
+
}
|
|
163
188
|
if (e.code() == 401) {
|
|
164
189
|
Log.d("API Error", "401 Unauthorized - Token: $token")
|
|
165
190
|
// Further handling if necessary
|
|
@@ -167,6 +192,17 @@ class AuthenticateSDKService(val scope: CoroutineScope) {
|
|
|
167
192
|
throw e
|
|
168
193
|
}
|
|
169
194
|
} catch (e: Exception) {
|
|
195
|
+
safeLogModuleEvent {
|
|
196
|
+
logModuleEvent(
|
|
197
|
+
where = "AuthenticateSDKService.postDeviceData.fail",
|
|
198
|
+
message = "POST /cgm/connection failed",
|
|
199
|
+
level = SentryLogLevel.WARN,
|
|
200
|
+
jsonPayload = "request=$data",
|
|
201
|
+
throwable = e,
|
|
202
|
+
attributes = mapOf("endpoint" to "/cgm/connection"),
|
|
203
|
+
logsOnly = true,
|
|
204
|
+
)
|
|
205
|
+
}
|
|
170
206
|
e.printStackTrace()
|
|
171
207
|
Log.d("API Response", "Exception: ${e.message}")
|
|
172
208
|
} finally {
|
|
@@ -267,8 +303,35 @@ class AuthenticateSDKService(val scope: CoroutineScope) {
|
|
|
267
303
|
|
|
268
304
|
Log.d("API Response", "Device Verification API Response: $decryptedResponse")
|
|
269
305
|
|
|
306
|
+
safeLogModuleEvent {
|
|
307
|
+
logModuleEvent(
|
|
308
|
+
where = "AuthenticateSDKService.verifyDevice.success",
|
|
309
|
+
message = "GET device_verification succeeded | sensorId=$sensorId",
|
|
310
|
+
level = SentryLogLevel.INFO,
|
|
311
|
+
jsonPayload = "response=$decryptedResponse",
|
|
312
|
+
attributes = mapOf("sensor_id" to sensorId),
|
|
313
|
+
logsOnly = true,
|
|
314
|
+
)
|
|
315
|
+
}
|
|
316
|
+
|
|
270
317
|
responseListener.onResponseSuccess(decryptedResponse)
|
|
271
318
|
} catch (e: Exception) {
|
|
319
|
+
safeLogModuleEvent {
|
|
320
|
+
val errorMessage =
|
|
321
|
+
e.message ?: "GET device_verification failed | sensorId=$sensorId"
|
|
322
|
+
logModuleEvent(
|
|
323
|
+
where = "AuthenticateSDKService.verifyDevice.fail",
|
|
324
|
+
message = "CGM journey error | screen=AuthenticateSDKService | $errorMessage",
|
|
325
|
+
level = SentryLogLevel.WARN,
|
|
326
|
+
throwable = e,
|
|
327
|
+
attributes = mapOf(
|
|
328
|
+
"error_message" to errorMessage,
|
|
329
|
+
"screen" to "AuthenticateSDKService",
|
|
330
|
+
"sensor_id" to sensorId,
|
|
331
|
+
),
|
|
332
|
+
logsOnly = true,
|
|
333
|
+
)
|
|
334
|
+
}
|
|
272
335
|
responseListener.onResponseFail()
|
|
273
336
|
e.printStackTrace()
|
|
274
337
|
Log.d("API Response", "Device Verification Exception: ${e.message}")
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
package com.mytatvarnsdk.utils
|
|
2
|
+
|
|
3
|
+
import android.util.Log
|
|
4
|
+
import com.mytatvarnsdk.CgmTrackyLibModule
|
|
5
|
+
import io.sentry.ScopeCallback
|
|
6
|
+
import io.sentry.Sentry
|
|
7
|
+
import io.sentry.SentryAttributes
|
|
8
|
+
import io.sentry.SentryLevel
|
|
9
|
+
import io.sentry.SentryLogLevel
|
|
10
|
+
import io.sentry.logger.SentryLogParameters
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Shared Sentry logging for [com.mytatvarnsdk.CgmTrackyLibModule] and journey activities.
|
|
14
|
+
*
|
|
15
|
+
* Use:
|
|
16
|
+
* ```
|
|
17
|
+
* safeLogModuleEvent {
|
|
18
|
+
* logModuleEvent("MyLocation", message = "...", level = SentryLogLevel.INFO)
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* Never throws — CGM flows must continue if logging fails.
|
|
23
|
+
*/
|
|
24
|
+
object CgmModuleSentryLog {
|
|
25
|
+
private const val MAX_SENTRY_DATA_EXTRA_CHARS = 16_384
|
|
26
|
+
private const val MAX_SENTRY_MESSAGE_DATA_CHARS = 2_000
|
|
27
|
+
|
|
28
|
+
private fun clipForSentry(text: String, maxChars: Int = MAX_SENTRY_DATA_EXTRA_CHARS): String =
|
|
29
|
+
try {
|
|
30
|
+
if (text.length <= maxChars) text else text.take(maxChars) + "…"
|
|
31
|
+
} catch (_: Throwable) {
|
|
32
|
+
""
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Wraps log preparation + emission so a bad payload cannot break CGM flows. */
|
|
36
|
+
inline fun safeLogModuleEvent(block: () -> Unit) {
|
|
37
|
+
try {
|
|
38
|
+
block()
|
|
39
|
+
} catch (t: Throwable) {
|
|
40
|
+
try {
|
|
41
|
+
Log.w("logModuleEvent", "Failed to prepare Sentry log: ${t.message}", t)
|
|
42
|
+
} catch (_: Throwable) {
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Structured Sentry log (like RN `Sentry.logger.info/warn/error`).
|
|
49
|
+
* Uses the host app's Sentry client (never call Sentry.init here).
|
|
50
|
+
*
|
|
51
|
+
* @param logsOnly When true, writes to Sentry Logs only — never creates Issues
|
|
52
|
+
* (use for journey QR/bind/scan errors shown to the user).
|
|
53
|
+
*/
|
|
54
|
+
fun logModuleEvent(
|
|
55
|
+
where: String,
|
|
56
|
+
message: String = "",
|
|
57
|
+
level: SentryLogLevel = SentryLogLevel.INFO,
|
|
58
|
+
jsonPayload: String? = null,
|
|
59
|
+
throwable: Throwable? = null,
|
|
60
|
+
attributes: Map<String, String> = emptyMap(),
|
|
61
|
+
logsOnly: Boolean = false,
|
|
62
|
+
) {
|
|
63
|
+
try {
|
|
64
|
+
if (!Sentry.isEnabled()) {
|
|
65
|
+
Log.w("logModuleEvent", "Sentry not initialized — skipping [$where]")
|
|
66
|
+
return
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
val resolvedMessage = when {
|
|
70
|
+
message.isNotEmpty() -> message
|
|
71
|
+
throwable != null -> {
|
|
72
|
+
val typeName = throwable.javaClass.simpleName ?: "Throwable"
|
|
73
|
+
"$typeName: ${throwable.message ?: ""}"
|
|
74
|
+
}
|
|
75
|
+
else -> where
|
|
76
|
+
}
|
|
77
|
+
val mergedAttributes = try {
|
|
78
|
+
attributes.toMutableMap()
|
|
79
|
+
} catch (_: Throwable) {
|
|
80
|
+
mutableMapOf()
|
|
81
|
+
}
|
|
82
|
+
throwable?.let {
|
|
83
|
+
mergedAttributes["exception"] = it.javaClass.simpleName ?: "Throwable"
|
|
84
|
+
mergedAttributes["exception_message"] = it.message ?: ""
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
val clippedJson = jsonPayload?.let { clipForSentry(it) }
|
|
88
|
+
val logMessage = clipForSentry(
|
|
89
|
+
"CgmTrackyLib: $where | $resolvedMessage",
|
|
90
|
+
MAX_SENTRY_MESSAGE_DATA_CHARS
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
val env = CgmTrackyLibModule.env
|
|
94
|
+
val sentryAttributes = mutableMapOf<String, Any>(
|
|
95
|
+
"cgm_tracky_lib" to "true",
|
|
96
|
+
"location" to where,
|
|
97
|
+
)
|
|
98
|
+
if (env.isNotEmpty()) {
|
|
99
|
+
sentryAttributes["tatva_env"] = env
|
|
100
|
+
}
|
|
101
|
+
clippedJson?.let { sentryAttributes["json"] = it }
|
|
102
|
+
mergedAttributes.forEach { (key, value) ->
|
|
103
|
+
try {
|
|
104
|
+
sentryAttributes[key] = clipForSentry(value, 500)
|
|
105
|
+
} catch (_: Throwable) {
|
|
106
|
+
sentryAttributes[key] = ""
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
val logsEnabled = try {
|
|
111
|
+
Sentry.getCurrentScopes()?.options?.logs?.isEnabled == true
|
|
112
|
+
} catch (_: Throwable) {
|
|
113
|
+
false
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (logsEnabled) {
|
|
117
|
+
val logParams = SentryLogParameters.create(
|
|
118
|
+
SentryAttributes.fromMap(sentryAttributes)
|
|
119
|
+
)
|
|
120
|
+
logParams.origin = "cgm-tracky-lib"
|
|
121
|
+
Sentry.logger().log(level, logParams, logMessage)
|
|
122
|
+
if (!logsOnly && throwable != null && level >= SentryLogLevel.ERROR) {
|
|
123
|
+
captureModuleException(where, throwable, sentryAttributes)
|
|
124
|
+
}
|
|
125
|
+
} else if (!logsOnly) {
|
|
126
|
+
captureModuleEventFallback(where, logMessage, level, throwable, sentryAttributes)
|
|
127
|
+
} else {
|
|
128
|
+
Log.w("logModuleEvent", "[$where] $logMessage (native Sentry Logs disabled)")
|
|
129
|
+
}
|
|
130
|
+
} catch (sentryEx: Throwable) {
|
|
131
|
+
try {
|
|
132
|
+
Log.w(
|
|
133
|
+
"logModuleEvent",
|
|
134
|
+
"Sentry logger failed for [$where]: ${sentryEx.message}",
|
|
135
|
+
sentryEx
|
|
136
|
+
)
|
|
137
|
+
Log.e("CgmTrackyLib", "[$where]", throwable ?: sentryEx)
|
|
138
|
+
} catch (_: Throwable) {
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
private fun mapLogLevelToEventLevel(level: SentryLogLevel): SentryLevel = when (level) {
|
|
144
|
+
SentryLogLevel.TRACE, SentryLogLevel.DEBUG -> SentryLevel.DEBUG
|
|
145
|
+
SentryLogLevel.INFO -> SentryLevel.INFO
|
|
146
|
+
SentryLogLevel.WARN -> SentryLevel.WARNING
|
|
147
|
+
SentryLogLevel.ERROR -> SentryLevel.ERROR
|
|
148
|
+
SentryLogLevel.FATAL -> SentryLevel.FATAL
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
private fun applyModuleScopeExtras(
|
|
152
|
+
where: String,
|
|
153
|
+
attributes: Map<String, Any>
|
|
154
|
+
): ScopeCallback = ScopeCallback { scope ->
|
|
155
|
+
scope.setTag("cgm_tracky_lib", "true")
|
|
156
|
+
scope.setTag("location", where)
|
|
157
|
+
val env = CgmTrackyLibModule.env
|
|
158
|
+
if (env.isNotEmpty()) {
|
|
159
|
+
scope.setTag("tatva_env", env)
|
|
160
|
+
}
|
|
161
|
+
attributes.forEach { (key, value) ->
|
|
162
|
+
try {
|
|
163
|
+
scope.setExtra(key, value.toString())
|
|
164
|
+
} catch (_: Throwable) {
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
private fun captureModuleEventFallback(
|
|
170
|
+
where: String,
|
|
171
|
+
message: String,
|
|
172
|
+
level: SentryLogLevel,
|
|
173
|
+
throwable: Throwable?,
|
|
174
|
+
attributes: Map<String, Any>
|
|
175
|
+
) {
|
|
176
|
+
try {
|
|
177
|
+
val scopeCallback = applyModuleScopeExtras(where, attributes)
|
|
178
|
+
if (throwable != null) {
|
|
179
|
+
Sentry.captureException(throwable, scopeCallback)
|
|
180
|
+
} else {
|
|
181
|
+
Sentry.captureMessage(message, mapLogLevelToEventLevel(level), scopeCallback)
|
|
182
|
+
}
|
|
183
|
+
} catch (t: Throwable) {
|
|
184
|
+
try {
|
|
185
|
+
Log.w("logModuleEvent", "Sentry fallback capture failed for [$where]: ${t.message}", t)
|
|
186
|
+
} catch (_: Throwable) {
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
private fun captureModuleException(
|
|
192
|
+
where: String,
|
|
193
|
+
throwable: Throwable,
|
|
194
|
+
attributes: Map<String, Any>
|
|
195
|
+
) {
|
|
196
|
+
try {
|
|
197
|
+
Sentry.captureException(throwable, applyModuleScopeExtras(where, attributes))
|
|
198
|
+
} catch (t: Throwable) {
|
|
199
|
+
try {
|
|
200
|
+
Log.w("logModuleEvent", "Sentry captureException failed for [$where]: ${t.message}", t)
|
|
201
|
+
} catch (_: Throwable) {
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
package com.mytatvarnsdk.utils
|
|
2
|
+
|
|
3
|
+
import io.sentry.SentryLogLevel
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Thin compatibility wrapper for [com.mytatvarnsdk.CgmTrackyLibModule] journey launch calls.
|
|
7
|
+
* Journey activities should use [CgmModuleSentryLog.safeLogModuleEvent] + [CgmModuleSentryLog.logModuleEvent] directly.
|
|
8
|
+
*/
|
|
9
|
+
object CgmSentryLog {
|
|
10
|
+
fun logJourneyLaunch(where: String, isReconnect: Boolean, envType: String) {
|
|
11
|
+
try {
|
|
12
|
+
CgmModuleSentryLog.safeLogModuleEvent {
|
|
13
|
+
CgmModuleSentryLog.logModuleEvent(
|
|
14
|
+
where = where,
|
|
15
|
+
message = "CGM journey launched | isReconnect=$isReconnect | env=$envType",
|
|
16
|
+
level = SentryLogLevel.INFO,
|
|
17
|
+
attributes = mapOf(
|
|
18
|
+
"is_reconnect" to isReconnect.toString(),
|
|
19
|
+
"env_type" to envType,
|
|
20
|
+
),
|
|
21
|
+
logsOnly = true,
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
} catch (_: Throwable) {
|
|
25
|
+
// Never propagate — CGM launch must continue.
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|