From 31fc266f9451db1cdd87aa6395fe56ef3ac33ec0 Mon Sep 17 00:00:00 2001 From: Davis Mosenkovs Date: Thu, 15 Feb 2024 22:07:08 +0200 Subject: [PATCH] Periodically sync time on all connected devices Sync time every 43 hours, 53 minutes and 23 seconds. Interval is a bit smaller than 2 days. Interval is a prime (in seconds) so time of sync will slide over time. If next DST change is less than 48 hours in future, wait for it. --- .../gadgetbridge/GBApplication.java | 2 +- .../externalevents/TimeChangeReceiver.java | 48 ++++++++++++------- .../service/DeviceCommunicationService.java | 2 +- 3 files changed, 32 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java index 6d8772419..dab02000a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java @@ -246,7 +246,7 @@ public class GBApplication extends Application { loadAppsPebbleBlackList(); PeriodicExporter.enablePeriodicExport(context); - TimeChangeReceiver.scheduleNextDstChange(context); + TimeChangeReceiver.scheduleNextDstChangeOrPeriodicSync(context); if (isRunningMarshmallowOrLater()) { notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/TimeChangeReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/TimeChangeReceiver.java index 8b6f566fe..79b4d9ade 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/TimeChangeReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/TimeChangeReceiver.java @@ -44,7 +44,9 @@ import nodomain.freeyourgadget.gadgetbridge.util.Prefs; public class TimeChangeReceiver extends BroadcastReceiver { private static final Logger LOG = LoggerFactory.getLogger(TimeChangeReceiver.class); - public static final String ACTION_DST_CHANGED = "nodomain.freeyourgadget.gadgetbridge.DST_CHANGED"; + public static final String ACTION_DST_CHANGED_OR_PERIODIC_SYNC = "nodomain.freeyourgadget.gadgetbridge.DST_CHANGED_OR_PERIODIC_SYNC"; + public static final long PERIODIC_SYNC_INTERVAL_MS = 158003000; // 43:53:23.000 + public static final long PERIODIC_SYNC_INTERVAL_MAX_MS = 172800000; // 48 hours @Override public void onReceive(Context context, Intent intent) { @@ -63,7 +65,7 @@ public class TimeChangeReceiver extends BroadcastReceiver { switch (action) { case Intent.ACTION_TIME_CHANGED: case Intent.ACTION_TIMEZONE_CHANGED: - case ACTION_DST_CHANGED: + case ACTION_DST_CHANGED_OR_PERIODIC_SYNC: // Continue after the switch break; default: @@ -72,38 +74,48 @@ public class TimeChangeReceiver extends BroadcastReceiver { } final Date newTime = GregorianCalendar.getInstance().getTime(); - LOG.info("Time or Timezone changed, syncing with device: {} ({}), {}", DateTimeUtils.formatDate(newTime), newTime.toGMTString(), intent.getAction()); + LOG.info("Time/Timezone changed or periodic sync, syncing with device: {} ({}), {}", DateTimeUtils.formatDate(newTime), newTime.toGMTString(), intent.getAction()); GBApplication.deviceService().onSetTime(); // Reschedule the next DST change, since the timezone may have changed - scheduleNextDstChange(context); + scheduleNextDstChangeOrPeriodicSync(context); } /** - * Schedule an alarm to trigger on the next DST change, since ACTION_TIMEZONE_CHANGED is not broadcast otherwise. + * Schedule an alarm to trigger on the next DST change, since ACTION_TIMEZONE_CHANGED is not broadcast otherwise + * or schedule an alarm to trigger after PERIODIC_SYNC_INTERVAL_MS (whichever is earlier). * * @param context the context */ - public static void scheduleNextDstChange(final Context context) { + public static void scheduleNextDstChangeOrPeriodicSync(final Context context) { final ZoneId zoneId = ZoneId.systemDefault(); final ZoneRules zoneRules = zoneId.getRules(); final Instant now = Instant.now(); final ZoneOffsetTransition transition = zoneRules.nextTransition(now); - if (transition == null) { - LOG.warn("No DST transition found for {}", zoneId); - return; - } - final long nextDstMillis = transition.getInstant().toEpochMilli(); - final long delayMillis = nextDstMillis - now.toEpochMilli() + 5000L; - - final Intent i = new Intent(ACTION_DST_CHANGED); + final Intent i = new Intent(ACTION_DST_CHANGED_OR_PERIODIC_SYNC); final PendingIntent pi = PendingIntentUtils.getBroadcast(context, 0, i, 0, false); final AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); - final boolean exactAlarm = canScheduleExactAlarms(context, am); - LOG.info("Scheduling next DST change: {} (in {} millis) (exact = {})", nextDstMillis, delayMillis, exactAlarm); + boolean exactAlarm = false; + long delayMillis = PERIODIC_SYNC_INTERVAL_MS; + + if (transition != null) { + final long nextDstMillis = transition.getInstant().toEpochMilli(); + final long dstDelayMillis = nextDstMillis - now.toEpochMilli() + 5000L; + if (dstDelayMillis < PERIODIC_SYNC_INTERVAL_MAX_MS) { + exactAlarm = canScheduleExactAlarms(context, am); + delayMillis = dstDelayMillis; + LOG.info("Scheduling next DST change: {} (in {} millis) (exact = {})", nextDstMillis, delayMillis, exactAlarm); + } + } else { + LOG.warn("No DST transition found for {}", zoneId); + } + + if (delayMillis == PERIODIC_SYNC_INTERVAL_MS) { + LOG.info("Scheduling next periodic time sync in {} millis (exact = {})", delayMillis, exactAlarm); + } am.cancel(pi); @@ -113,7 +125,7 @@ public class TimeChangeReceiver extends BroadcastReceiver { am.setExact(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + delayMillis, pi); scheduledExact = true; } catch (final Exception e) { - LOG.error("Failed to schedule exact alarm for next DST change", e); + LOG.error("Failed to schedule exact alarm for next DST change or periodic time sync", e); } } @@ -126,7 +138,7 @@ public class TimeChangeReceiver extends BroadcastReceiver { am.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + delayMillis, pi); } } catch (final Exception e) { - LOG.error("Failed to schedule inexact alarm next DST change", e); + LOG.error("Failed to schedule inexact alarm for next DST change or periodic time sync", e); } } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java index 6e28e1809..41324f009 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java @@ -1179,7 +1179,7 @@ public class DeviceCommunicationService extends Service implements SharedPrefere IntentFilter filter = new IntentFilter(); filter.addAction("android.intent.action.TIME_SET"); filter.addAction("android.intent.action.TIMEZONE_CHANGED"); - filter.addAction(TimeChangeReceiver.ACTION_DST_CHANGED); + filter.addAction(TimeChangeReceiver.ACTION_DST_CHANGED_OR_PERIODIC_SYNC); registerReceiver(mTimeChangeReceiver, filter); } if (mBlueToothPairingRequestReceiver == null) {