@@ -71,6 +71,8 @@ public final class SystemEventsBreadcrumbsIntegration implements Integration, Cl
71
71
private volatile boolean isStopped = false ;
72
72
private volatile IntentFilter filter = null ;
73
73
private final @ NotNull AutoClosableReentrantLock receiverLock = new AutoClosableReentrantLock ();
74
+ // Track previous battery state to avoid duplicate breadcrumbs when values haven't changed
75
+ private @ Nullable BatteryState previousBatteryState ;
74
76
75
77
public SystemEventsBreadcrumbsIntegration (final @ NotNull Context context ) {
76
78
this (context , getDefaultActionsInternal ());
@@ -331,7 +333,7 @@ public void onStop(@NonNull LifecycleOwner owner) {
331
333
}
332
334
}
333
335
334
- static final class SystemEventsBroadcastReceiver extends BroadcastReceiver {
336
+ final class SystemEventsBroadcastReceiver extends BroadcastReceiver {
335
337
336
338
private static final long DEBOUNCE_WAIT_TIME_MS = 60 * 1000 ;
337
339
private final @ NotNull IScopes scopes ;
@@ -350,19 +352,36 @@ public void onReceive(final Context context, final @NotNull Intent intent) {
350
352
final @ Nullable String action = intent .getAction ();
351
353
final boolean isBatteryChanged = ACTION_BATTERY_CHANGED .equals (action );
352
354
353
- // aligning with iOS which only captures battery status changes every minute at maximum
354
- if (isBatteryChanged && batteryChangedDebouncer .checkForDebounce ()) {
355
- return ;
355
+ @ Nullable BatteryState batteryState = null ;
356
+ if (isBatteryChanged ) {
357
+ if (batteryChangedDebouncer .checkForDebounce ()) {
358
+ // aligning with iOS which only captures battery status changes every minute at maximum
359
+ return ;
360
+ }
361
+
362
+ // For battery changes, check if the actual values have changed
363
+ final @ Nullable Float batteryLevel = DeviceInfoUtil .getBatteryLevel (intent , options );
364
+ final @ Nullable Integer currentBatteryLevel =
365
+ batteryLevel != null ? batteryLevel .intValue () : null ;
366
+ final @ Nullable Boolean currentChargingState = DeviceInfoUtil .isCharging (intent , options );
367
+ batteryState = new BatteryState (currentBatteryLevel , currentChargingState );
368
+
369
+ // Only create breadcrumb if battery state has actually changed
370
+ if (batteryState .equals (previousBatteryState )) {
371
+ return ;
372
+ }
373
+
374
+ previousBatteryState = batteryState ;
356
375
}
357
376
377
+ final BatteryState state = batteryState ;
358
378
final long now = System .currentTimeMillis ();
359
379
try {
360
380
options
361
381
.getExecutorService ()
362
382
.submit (
363
383
() -> {
364
- final Breadcrumb breadcrumb =
365
- createBreadcrumb (now , intent , action , isBatteryChanged );
384
+ final Breadcrumb breadcrumb = createBreadcrumb (now , intent , action , state );
366
385
final Hint hint = new Hint ();
367
386
hint .set (ANDROID_INTENT , intent );
368
387
scopes .addBreadcrumb (breadcrumb , hint );
@@ -411,7 +430,7 @@ String getStringAfterDotFast(final @Nullable String str) {
411
430
final long timeMs ,
412
431
final @ NotNull Intent intent ,
413
432
final @ Nullable String action ,
414
- boolean isBatteryChanged ) {
433
+ final @ Nullable BatteryState batteryState ) {
415
434
final Breadcrumb breadcrumb = new Breadcrumb (timeMs );
416
435
breadcrumb .setType ("system" );
417
436
breadcrumb .setCategory ("device.event" );
@@ -420,14 +439,12 @@ String getStringAfterDotFast(final @Nullable String str) {
420
439
breadcrumb .setData ("action" , shortAction );
421
440
}
422
441
423
- if (isBatteryChanged ) {
424
- final Float batteryLevel = DeviceInfoUtil .getBatteryLevel (intent , options );
425
- if (batteryLevel != null ) {
426
- breadcrumb .setData ("level" , batteryLevel );
442
+ if (batteryState != null ) {
443
+ if (batteryState .level != null ) {
444
+ breadcrumb .setData ("level" , batteryState .level );
427
445
}
428
- final Boolean isCharging = DeviceInfoUtil .isCharging (intent , options );
429
- if (isCharging != null ) {
430
- breadcrumb .setData ("charging" , isCharging );
446
+ if (batteryState .charging != null ) {
447
+ breadcrumb .setData ("charging" , batteryState .charging );
431
448
}
432
449
} else {
433
450
final Bundle extras = intent .getExtras ();
@@ -458,4 +475,26 @@ String getStringAfterDotFast(final @Nullable String str) {
458
475
return breadcrumb ;
459
476
}
460
477
}
478
+
479
+ static final class BatteryState {
480
+ private final @ Nullable Integer level ;
481
+ private final @ Nullable Boolean charging ;
482
+
483
+ BatteryState (final @ Nullable Integer level , final @ Nullable Boolean charging ) {
484
+ this .level = level ;
485
+ this .charging = charging ;
486
+ }
487
+
488
+ @ Override
489
+ public boolean equals (final @ Nullable Object other ) {
490
+ if (!(other instanceof BatteryState )) return false ;
491
+ BatteryState that = (BatteryState ) other ;
492
+ return Objects .equals (level , that .level ) && Objects .equals (charging , that .charging );
493
+ }
494
+
495
+ @ Override
496
+ public int hashCode () {
497
+ return Objects .hash (level , charging );
498
+ }
499
+ }
461
500
}
0 commit comments