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.
This commit is contained in:
Davis Mosenkovs 2024-02-15 22:07:08 +02:00
parent 64c024a5ce
commit 2e9176560d
3 changed files with 32 additions and 20 deletions

View File

@ -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);

View File

@ -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);
}
}
}

View File

@ -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) {