Android ACTION_DATE_CHANGED broadcast
Asked Answered
C

5

16

I have a Nexus S, and when I change the date manually on the phone, ACTION_DATE_CHANGED is not always broadcasted. If I change the date from Feb 13, 2014 to Feb 14, 2014, I have not gotten an ACTION_DATE_CHANGED to work, but if I set it to several years in the future, I sometimes get it to fire.

I can (99%) assure you I'm not misusing IntentFilters, BroadcastReceivers, etc. I'm just curious as to why this broadcast is so poorly documented. A quick scan through SO & Google shows that people aren't sure if it happens when the user manually changes it, or when the date rolls over at 12:00am every day, or both. My experience shows that it's pretty inconsistent regarding user changes and I haven't tried system changes.

I'll grep through the AOSP code and isolate all of the points where this is fired and report back.

Edit: the question: Anyone have any idea what's going on here? :-)

Cam answered 13/2, 2014 at 15:19 Comment(5)
I saw this myself too, so most likely not your fault. Still, what's the question? :)Creativity
Good catch :-) More like a request for information than a true question, but I still think it's probably useful to have on SO.Cam
Oh, it was about why and not is there any workarounds :)Dickinson
Yeah, but your answer was still good (I was commenting on it!) Here is what I was going to say: I'm grepping through 3 source trees now so I'll poke around and see if I can isolate what's going on, but it's good to know that it's not just me having this issues (also ACTION_TIME_CHANGED does seem to fire every time the date changes, so that's probably a lower-cost workaround!). Also, I'm particularly targeting API 14+, so I'm searching through AOSP 4.0.3_r1, 4.2.2_r1, and some 4.4 branch, for those interested!Cam
Okay I took it back, it might be useful for someone. Those Intents sure are tricky and little mystery for many.Dickinson
C
14

Here is code from 4.0.3_r1 in frameworks/base/services/java/android/server/AlarmManagerService.java.

First, we create a PendingIntent mDateChangeSender;

private final PendingIntent mDateChangeSender;

Then, in the constructor of AlarmManagerService.java, we setup the PendingIntent:

Intent intent = new Intent(Intent.ACTION_DATE_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
mDateChangeSender = PendingIntent.getBroadcast(context, 0, intent, 0);

Then later in the constructor:

mClockReceiver.scheduleDateChangedEvent();

So what is mClockReceiver? Just a BroadcastReceiver listening for Intent.ACTION_TIME_TICK and Intent.ACTION_DATE_CHANGED. In it's onReceive():

...
else if (intent.getAction().equals(Intent.ACTION_DATE_CHANGED)) {
...
    scheduleDateChangedEvent();
}

Then, later we find the method scheduleDateChangedEvent():

public void scheduleDateChangedEvent() {
     Calendar calendar = Calendar.getInstance();
     calendar.setTimeInMillis(System.currentTimeMillis());
     calendar.set(Calendar.HOUR, 0);
     calendar.set(Calendar.MINUTE, 0);
     calendar.set(Calendar.SECOND, 0);
     calendar.set(Calendar.MILLISECOND, 0);
     calendar.add(Calendar.DAY_OF_MONTH, 1);
     set(AlarmManager.RTC, calendar.getTimeInMillis(), mDateChangeSender);
}

So it sets a one-shot alarm, starting with the current time, then setting hour/min/sec/milli to zero, then adding a day, so if it was 1:30pm today, the next time it will get fired would be in 10 hours and 30 minutes.

This isn't to say there aren't bugs or anything here, but it LOOKS like ACTION_DATE_CHANGED should fire at midnight every day.

NOW - if I were to change the date on the phone lets say 10 years into the future. The code to handle the change in time will fire the first ACTION_DATE_CHANGED event then schedule a new ACTION_DATE_CHANGED to get fired, at 10 years + some fraction of a day. Then if we change the date back 10 years, to the correct date, the alarm is still scheduled to be fired in 10 years, thuse ACTION_DATE_CHANGED will no longer get fired (unless you set the date further than 10 years from now - try it!).

tl;dr: This is a bug in Android.

Cam answered 13/2, 2014 at 15:57 Comment(1)
If I were to patch this, I'd probably set ClockReceiver to also receive ACTION_TIME_CHANGED, check if I need to remove the old DATE_CHANGED alarm, and if so, remove it and reset it. I'll try this on one of my own copies of AOSP when I have some free time. If you beat me to writing a patch for AOSP, then feel free to reference my post!Cam
M
3

Matching ZachM's research, https://code.google.com/p/android/issues/detail?id=2880 logs an AOSP bug where after the clock get set backwards, ACTION_DATE_CHANGED won't fire again until the clock catches up with what was going to be the next day.

(There's also a note there about multi-hour delays in this broadcast. A consequence of setting the clock for testing or of the date changing while the device is sleeping?)

Outside of the bug, ACTION_DATE_CHANGED indicates that the clock reached the next day, while ACTION_TIME_CHANGED (== "android.intent.action.TIME_SET") indicates that the clock was set (adjusted).

ZachM's "If I were to patch this..." sounds like a fine workaround, using such an alarm within an app (not broadcast).

EDIT

AOSP bug #2880 has a new comment pointing out a (another?) bug in scheduleDateChangedEvent(): Where it calls calendar.set(Calendar.HOUR, 0);, the first parameter ought to be HOUR_OF_DAY.

From java.util.Calendar:

HOUR is used for the 12-hour clock (0 - 11). Noon and midnight are represented by 0, not by 12. E.g., at 10:04:15.250 PM the HOUR is 10.

HOUR_OF_DAY is used for the 24-hour clock. E.g., at 10:04:15.250 PM the HOUR_OF_DAY is 22.

So if scheduleDateChangedEvent() runs during the PM half of the day, it will schedule the next alarm for noon rather than midnight.

Moonlit answered 24/2, 2014 at 6:26 Comment(2)
Until api23 still did not fix the problem. . .Firstrate
Wow they changed it to Obsolete/Won't Fix. Does anyone know the current status of this issue? I'm going to submit a patch if it's still broken...Cam
D
1

I also encountered the same issue. I noticed that even when using ACTION_TIME_CHANGED and ACTION_DATE_CHANGED together, I wasn't able to detect always when date changed. I think it's a bug in platform.

So I added receiver for ACTION_TIME_TICK and check in that callback when the date changed.

Dickinson answered 13/2, 2014 at 15:22 Comment(1)
Thanks! For others dealing with this issue, when using API 14 (running on a Nexus S running 4.0.3_r1), I successfully get ACTION_TIME_CHANGED and ACTION_TIMEZONE_CHANGED any and every time I change the time and timezone manually.Cam
S
0

You actually can use BroadcastReceiver. Just use ACTION_TIMEZONE_CHANGED too.

I've made a nice solution for this, here:

https://mcmap.net/q/750367/-android-system-date-changed-event

Sarraceniaceous answered 14/2, 2018 at 8:55 Comment(5)
That's a nice solution, but unless I understood the question wrong (4 years ago :-) ), the issue is not so much "how do I do this", but "why in earlier versions of Android does this Intent not get broadcast in a consistent way?"Cam
@Cam Really? On which Android versions? And does my solution work there?Sarraceniaceous
@Cam I've just tested on 4.4 emulator. Seems to work fine.Sarraceniaceous
Ah yeah I think I detailed that in a comment in another reply to this about running in in 4.0.3. Whoops!Cam
So from which version it works well, and from which it doesn't?Sarraceniaceous
J
0

Some changes for Android 12, tested on Google Pixel 4XL.

If set date manually then it is not work but you can receive ACTION_TIME_CHANGED.

It is works for start a new day (time 00.00) perfectly. Unfortunately this is not implicit broadcast, you have to register a Broadcast Receiver in code.

Jacki answered 19/1, 2022 at 11:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.