Is there a way to detect when the Android system clock has been reset by the user in Android?
I\'m designing an app which uses system time to determ
If you don't mind your app to throw cheats in case of user's clock will get updated due to *DT/*ST shifts, occasional time syncs with NTP sources that can rewind your clock, your own process's stalling, you can implement a "consequential" check on system time so that if time went "back" you assume it's a "cheat". Otherwise, you have to rely on the server which will be your source of "valid" time. And even then, your server's time can too go backwards occasionally.
The system time (System.currentTimeMillis()
) would change if the user adjusted the clock, but the elapsed time since boot (SystemClock.elapsedRealtime()
) hopefully would not. By tracking the differential between these two, it would be possible to detect major changes to the system clock by the user.
It would be important not to track small changes that might be caused by the network updating the system clock. I'm going to assume that for my purposes, any change under about a half hour is irrelevant; the system time shouldn't change on the Locale
country changing but that might be worth eliminating also.
The elapsed realtime would obviously reset on boot so I should include a BroadcastReceiver
to reset the differential on receiving android.intent.action.BOOT_COMPLETED
.
We can use both TIME_SET
and TIMEZONE_CHANGED
.
<application
...>
<receiver android:name=".TimeChangedReceiver">
<intent-filter>
<action android:name="android.intent.action.TIME_SET"/>
<action android:name="android.intent.action.TIMEZONE_CHANGED"/>
</intent-filter>
</receiver>
</application>
TimeChangedReceiver.java
public class TimeChangedReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "time change " + intent.getAction(), Toast.LENGTH_SHORT).show();
}
}
Yes, there is. The ACTION_TIME_CHANGED Intent is broadcast when the device time is changed, and you can have a method which will trigger when this Intent is detected.
This intent has been in Android since API level 1, so it should work on any platform you might need to be compatible with.
You'll need to handle the Broadcast with a BroadcastReceiver:
public class TimeChangedReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//Do whatever you need to
}
}
You'll also need to add something like this to your Manifest:
<receiver android:name=".TimeChangedReceiver">
<intent-filter>
<action android:name="android.intent.action.TIME_SET" />
</intent-filter>
</receiver>
This will let Android know to trigger your receiver when this type of intent is detected.
It appears as though this doesn't care who edits the time, but also does not trigger on automatic adjustments when you are synced with the network. If you lose network and regain it, though, this will likely fire since your time will be slightly different (assuming you are using automatic network time).
However, while the clocks on cell phones are not particularly accurate (since they generally rely on syncing with time signals they receive) in my experience they absolutely should not lose more than about 30 seconds or a minute per hour, at the absolute maximum, so if the time change is small you can perhaps assume it was automatic. Leap seconds, when they are added, will also likely produce a time change message, although these are obviously small and infrequent.
You can use ConnectivityManager to keep track of whether the phone has a connection or not and you can change the behavior based on that (i.e. as long as network connectivity is there, and the time is automatic/network time, ignore time changes or something) but I can't find any intents regarding losing/regaining network connectivity so you will probably have to use a polling method.
A little notice to the answer of matt5784: I found out that on Android 4.1.2 the intent action is not available, don´t know if this is for all android versions or just at mine. Instead of
"android.intent.action.ACTION_TIME_CHANGED"
use
"android.intent.action.TIME_SET"