/* * Copyright (C) 2015 Actor LLC. <https://actor.im> */ package im.actor.runtime.android; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import im.actor.runtime.util.ExponentialBackoff; import im.actor.runtime.Runtime; import im.actor.runtime.actors.ThreadPriority; import im.actor.runtime.android.threading.AndroidDispatcher; import im.actor.runtime.android.threading.AndroidImmediateDispatcher; import im.actor.runtime.android.time.SntpClient; import im.actor.runtime.generic.GenericThreadingProvider; import im.actor.runtime.Log; import im.actor.runtime.threading.Dispatcher; import im.actor.runtime.threading.ImmediateDispatcher; public class AndroidThreadingProvider extends GenericThreadingProvider { private static final String PROPS = "time_sync.ini"; private SharedPreferences preference; private long syncDelta; private String serverHost; public AndroidThreadingProvider() { this.serverHost = "europe.pool.ntp.org"; Runtime.dispatch(() -> { this.preference = AndroidContext.getContext().getSharedPreferences(PROPS, Context.MODE_PRIVATE); this.syncDelta = preference.getLong("delta", syncDelta); invalidateSync(); IntentFilter timeChangedFilter = new IntentFilter(); timeChangedFilter.addAction(Intent.ACTION_TIME_CHANGED); timeChangedFilter.addAction(Intent.ACTION_DATE_CHANGED); AndroidContext.getContext().registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Log.d("AndroidClockSync", "Time changed: invalidating sync"); invalidateSync(); } }, timeChangedFilter); }); } // TODO: Better invalidation private void invalidateSync() { Log.d("AndroidClockSync", "Starting sync..."); new Thread() { @Override public void run() { SntpClient client = new SntpClient(); ExponentialBackoff exponentialBackoff = new ExponentialBackoff(); while (!client.requestTime(serverHost, 10000)) { exponentialBackoff.onFailure(); try { Thread.sleep(exponentialBackoff.exponentialWait()); } catch (InterruptedException e) { e.printStackTrace(); } } syncDelta = client.getClockOffset(); preference.edit().putLong("delta", syncDelta).commit(); Log.d("AndroidClockSync", "Synced. Time delta: " + syncDelta + " ms"); } }.start(); } @Override public long getSyncedCurrentTime() { return System.currentTimeMillis() + syncDelta; } @Override public Dispatcher createDispatcher(String name) { return new AndroidDispatcher(name); } @Override public ImmediateDispatcher createImmediateDispatcher(String name, ThreadPriority priority) { return new AndroidImmediateDispatcher(name, priority); } }