My app is an alarm clock app, and I am setting an alarm in the following way:
PendingIntent pendingIntent = PendingIntent.getBroadcast(Activity_AlarmsList.this, alarmID, intent, 0);
ZonedDateTime zonedDateTime = ZonedDateTime.of(alarmDateTime.withSecond(0), ZoneId.systemDefault());
alarmManager.setAlarmClock(new AlarmManager.AlarmClockInfo(zonedDateTime.toEpochSecond() * 1000, pendingIntent), pendingIntent);
where alarmDateTime is a LocalDateTime object containing the alarm date and time.
On Android M and N (real devices), an alarm clock sign appears on the status bar as soon as an alarm is set. But on my Samsung Galaxy M31s (Android Q), no alarm sign appears! But the alarm clock sign appears when I run the app on an Android Q emulator.
In the Samsung Galaxy M31s, if I execute adb shell dumpsys alarm, I get the following output:
Next wake from idle: Alarm{c9c59a type 0 when 1603225320000 in.basulabs.shakealarmclock}
tag=*walarm*:in.basulabs.shakealarmclock.DELIVER_ALARM
type=0 expectedWhenElapsed=+48s986ms expectedMaxWhenElapsed=+48s986ms whenElapsed=+48s986ms maxWhenElapsed=+48s986ms when=2020-10-21 01:52:00.000
window=0 repeatInterval=0 count=0 flags=0x3
Alarm clock:
triggerTime=2020-10-21 01:52:00.000
showIntent=PendingIntent{f26a278: PendingIntentRecord{9c3ed51 in.basulabs.shakealarmclock broadcastIntent}}
operation=PendingIntent{860e9b6: PendingIntentRecord{9c3ed51 in.basulabs.shakealarmclock broadcastIntent}}
which is what I want. So the alarm is set, and indeed the alarm rings too, but no alarm clock sign appears.
What is the problem?
Inside my application I need to set alarms and when they fire I'm trying to trigger them in my Receiver.
In order to deal with Dozo mode from marshmallow 6.0, if the device version is greater or equal to 6.0 I'm using alarmManger.setAlarmClock() method. This works fine is almost all the devices except OPPO devices
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
final AlarmManager.AlarmClockInfo alarmClockInfo = new AlarmManager.AlarmClockInfo(fireDate.getTime(), pendingIntent);
alarmManager.setAlarmClock(alarmClockInfo, pendingIntent);
//alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, fireDate.getTime(), pendingIntent);
} else {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, fireDate.getTime(), pendingIntent);
}
======================================================================
from Terminal, I got logs using : adb shell dumpsys alarm.
1. for other brands (my app alarmManager.setAlarmClock() method result):
Batch{b778e8c num=1 start=35988972 end=35988972 flgs=0x3}:
RTC_WAKEUP #0: Alarm{b9e89d5 type 0 when 1547501400600 ######.######}
tag=*walarm*:######.######.Reminder
type=0 whenElapsed=+9h49m0s741ms when=2019-01-15 03:00:00
window=0 repeatInterval=0 count=0 flags=0x3
Alarm clock:
triggerTime=2019-01-15 03:00:00
showIntent=PendingIntent{3dc5ea: PendingIntentRecord{d66ec2a ######.###### broadcastIntent}}
operation=PendingIntent{996c0db: PendingIntentRecord{d66ec2a ######.###### broadcastIntent}}
the batch is unique and the flag value is set to 0x3, this is how it will be for alarmClocks.
For most of the brands the result is same, but in oppo the flag is set to 0x8
2. for oppo phone (my app alarmManager.setAlarmClock() method result ):
Batch{b778e8c num=1 start=35988972 end=35988972 flgs=0x8}:
RTC_WAKEUP #0: Alarm{b9e89d5 type 0 when 1547501400600 ######.######}
tag=*walarm*:######.######.Reminder
type=0 whenElapsed=+9h49m0s741ms when=2019-01-15 03:00:00
window=0 repeatInterval=0 count=0 flags=0x8
Alarm clock:
triggerTime=2019-01-15 03:00:00
showIntent=PendingIntent{3dc5ea: PendingIntentRecord{d66ec2a ######.###### broadcastIntent}}
operation=PendingIntent{996c0db: PendingIntentRecord{d66ec2a ######.###### broadcastIntent}}
3. for oppo phone (oppo default alarm app):
Batch{3450b8d num=1 start=464582537 end=464582537 flgs=0x9}:
RTC_WAKEUP #0: Alarm{32536c5 type 0 when 1547690400000 ######.###### whenElapsed 464582537 windowLength 0 maxWhenElapsed 464582537 repeatInterval 0 action }
tag=*walarm*:######.######.ALARM_ALERT
type=0 whenElapsed=+17h4m45s187ms when=2019-01-17 07:30:00
window=0 repeatInterval=0 count=0 flags=0x9
Alarm clock:
triggerTime=2019-01-17 07:30:00
showIntent=PendingIntent{ee6881a: PendingIntentRecord{97c18f0 ######.###### startActivity (whitelist: 902f275:+30s0ms)}}
operation=PendingIntent{3bc0f4b: PendingIntentRecord{2bd8d28 ######.###### broadcastIntent}}
Inside opp phones to get alarms it should be a single batch and flag should be set to 0x9
Conclusion
OTHER Phones: flag = 0x3 is required to trigger it as alarm, alarmManager.setAlarmClock() is setting the flag = 0x3, works fine.
OPPO Phones: flag =0x9 is required to trigger it as alarm. But, alarmManager.setAlarmClock() is setting the flag = 0x8.
What method should I call to make the flag = 0x9 in oppo devices?
I have set an alarm (in an alarm clock app we are developing) for 8:58 (in 24h format).
The alarm did not fire - alarm icon is still in status bar - and when I write adb shell dumpsys alarm I can see this:
Batch{6b33bdb num=1 start=99803288 end=99803288 flgs=0x3}:
RTC_WAKEUP #0: Alarm{3e3da2e type 0 when 1484078280736 my.app}
tag=*walarm*:my.app/md5f98255d9820be5cc9672d0645bf1ca12.RingBroadcastReceiver
type=0 whenElapsed=+11h1m53s125ms when=2017-01-10 20:58:00
window=0 repeatInterval=0 count=0 flags=0x3
Alarm clock:
triggerTime=2017-01-10 08:58:00
showIntent=PendingIntent{21219cf: PendingIntentRecord{aac3f5c my.app startActivity}}
operation=PendingIntent{ecde88f: PendingIntentRecord{821c71c my.app broadcastIntent}}
Next wake from idle: Alarm{3e3da2e type 0 when 1484078280736 my.app}
tag=*walarm*:my.app/md5f98255d9820be5cc9672d0645bf1ca12.RingBroadcastReceiver
type=0 whenElapsed=+11h1m53s125ms when=2017-01-10 20:58:00
window=0 repeatInterval=0 count=0 flags=0x3
Alarm clock:
triggerTime=2017-01-10 08:58:00
showIntent=PendingIntent{21219cf: PendingIntentRecord{aac3f5c my.app startActivity}}
operation=PendingIntent{ecde88f: PendingIntentRecord{821c71c my.app broadcastIntent}}
THE QUESTION IS: How is it possible that when is 12 hours after triggerTime?
It seems like 12/24 hour format issue, but my device and also my app and its time picker are all set to 24 hour format. This issue happened just once. When I set a new alarm, it works as expected.
Any ideas?
UPDATE:
We are using this code to set the alarm (sorry for Xamarin syntax) and I have tested that the alarmEntity is returning correct time. The problem must be in this code or in the device/android/system stuff. From the triggerTime=2017-01-10 08:58:00 it seems to me that the code is OK and there is some issue in the system or alarm manager.
DateTime closestTrigger = alarmEntity.GetTime();
Calendar calendar = Calendar.Instance;
calendar.Set(CalendarField.Year, closestTrigger.Year);
calendar.Set(CalendarField.Month, closestTrigger.Month - 1);
calendar.Set(CalendarField.DayOfMonth, closestTrigger.Day);
calendar.Set(CalendarField.HourOfDay, closestTrigger.Hour);
calendar.Set(CalendarField.Minute, closestTrigger.Minute);
calendar.Set(CalendarField.Second, closestTrigger.Second);
var alarmInfo = new AlarmManager.AlarmClockInfo(calendar.TimeInMillis, mainPendingIntent);
manager.SetAlarmClock(alarmInfo, ringPendingIntent);
UPDATE 2:
I've found one more important line in the same dumpsys alarm log:
Next alarm clock information:
user:0 pendingSend:false time:1484035080736 = 2017-01-10 08:58:00 = -58m6s876ms
..which means the alarm was missed, but the system didn't even try to present it, the logcat didn't show any activity at all around the 8:58. And still not clear why would the system reschedule the alarm to 20:58.
I have got a problem with alarmservice - it's set up to go off every hour and it works perfectly fine on my galaxy SII - however, on the wildfire and wildfire S the app hogs the whole system.
After looking at logs, it seems that alarm is added and trigered a few times every second.
I really don't understand why this is happening and more than that it bothers me, how could this problem be device specifc?
Here is what the log says:
V/AlarmManager( 103): Adding Alarm{44cf66f8 type 0 weat.heria.app} Jan 12 04:43:35 pm
V/AlarmManager( 103): Alarm triggering: Alarm{44cf66f8 type 0 weat.heria.app}
V/AlarmManager( 103): Adding Alarm{44cf66f8 type 0 weat.heria.app} Jan 12 04:43:35 pm
V/AlarmManager( 103): Alarm triggering: Alarm{44cf66f8 type 0 weat.heria.app}
V/AlarmManager( 103): Adding Alarm{44cf66f8 type 0 weat.heria.app} Jan 12 04:43:36 pm
V/AlarmManager( 103): Alarm triggering: Alarm{44cf66f8 type 0 weat.heria.app}
Please help me regarding this.
Edit: here is the code setting the alarm
public void setAlarm(int refreshRate) {
Intent myIntent = new Intent(WeatheriaActivity.this, AlarmService.class);
pendingIntent = PendingIntent.getService(WeatheriaActivity.this, 0,
myIntent, 0);
AlarmManager alarmManager = (AlarmManager)getSystemService(ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, 10);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.
getTimeInMillis(), refreshRate, pendingIntent);
}
PendingIntent.getService() should be passed a flag for its last parameter, not 0. I'd try fixing that first.
Can someone explain to me the difference between AlarmManager.RTC_WAKEUP and AlarmManager.ELAPSED_REALTIME_WAKEUP? I have read the documentation but still don't really understand the implication of using one over the other.
Example code:
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
scheduledAlarmTime,
pendingIntent);
alarmManager.set(AlarmManager.RTC_WAKEUP,
scheduledAlarmTime,
pendingIntent);
How different will the two lines of code execute? When will those two lines of code execute relative to each other?
I appreciate your help.
AlarmManager.ELAPSED_REALTIME_WAKEUP type is used to trigger the alarm since boot time:
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 600000, pendingIntent);
will actually make the alarm go off 10 min after the device boots.
There is a timer that starts running when the device boots up to measure the uptime of the device and this is the type that triggers your alarm according to the uptime of the device.
Whereas, AlarmManager.RTC_WAKEUP will trigger the alarm according to the time of the clock. For example if you do:
long thirtySecondsFromNow = System.currentTimeMillis() + 30 * 1000;
alarmManager.set(AlarmManager.RTC_WAKEUP, thirtySecondsFromNow , pendingIntent);
this, on the other hand, will trigger the alarm 30 seconds from now.
AlarmManager.ELAPSED_REALTIME_WAKEUP type is rarely used compared to AlarmManager.RTC_WAKEUP.
Despite the currently accepted and up-voted answer, AlarmManager.ELAPSED_REALTIME* types along with SystemClock.elapsedRealtime() has always been more reliable than the RTC clocks for alarms and timing.
Using ELAPSED_REALTIME_WAKEUP with AlarmManager will rely on a monotonic clock starting from boot time "and continues to tick even when the CPU is in power saving modes, so is the recommend basis for general purpose interval timing". So,
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime()
+ 60*1000, pendingIntent);
will make your PendingIntent fire in 1 min (60*1000 milliseconds).
Whereas, AlarmManager.RTC_WAKEUP is for the the standard "wall" time in milliseconds since the epoch. So,
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
+ 60*10000, pendingIntent);
may also trigger the alarm 60 seconds from now, but not reliably, because as noted in the SystemClock documentation:
The wall clock can be set by the user or the phone network (see
setCurrentTimeMillis(long)), so the time may jump backwards or
forwards unpredictably. This clock should only be used when
correspondence with real-world dates and times is important, such as
in a calendar or alarm clock application. Interval or elapsed time
measurements should use a different clock. If you are using
System.currentTimeMillis(), consider listening to the
ACTION_TIME_TICK, ACTION_TIME_CHANGED and ACTION_TIMEZONE_CHANGED
Intent broadcasts to find out when the time changes.
Also, the question only referenced only the *_WAKEUP alarms but see also the AlarmManager documentation on that to make sure you understand what the wakeup vs non-wakeup alarms provide.
Just a note. You can get the uptime millis calling:
long uptimeMillis = SystemClock.elapsedRealtime();
So if you want to fire the alarm 30 seconds from now, and you want to use the uptime clock instead of the normal clock, you can do:
long thirtySecondsFromNow = SystemClock.elapsedRealtime() + 30 * 1000;
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, thirtySecondsFromNow, pendingIntent);
Whenever you want to check for some elapsed time instead of a specific date/time, it's best to use the uptime. That's because the current time set by the user in the device can change if the user changes it using the settings.
I programmed this problem in my own project this way. in below code i am using
AlarmManager.ELAPSED_REALTIME_WAKEUP
to set alarm at a specific time.
the variable 'intentName' is used in the intentFilter to receiver this alarm. because i am firing many alarms of this type. when i cancel all alarms. i use the method cancel. given at bottom.
//to hold alarms and cancel when needed
public static ArrayList<String> alarmIntens = new ArrayList<String>();
//
public static String setAlarm(int hour, int minutes, long repeatInterval,
final Context c) {
/*
* to use elapsed realTime monotonic clock, and fire alarm at a specific time
* we need to know the span between current time and the time of alarm.
* then we can add this span to 'elapsedRealTime' to fire the alarm at that time
* this way we can get alarms even when device is in sleep mood
*/
Time nowTime = new Time();
nowTime.setToNow();
Time startTime = new Time(nowTime);
startTime.hour = hour;
startTime.minute = minutes;
//get the span from current time to alarm time 'startTime'
long spanToStart = TimeUtils.spanInMillis(nowTime, startTime);
//
intentName = "AlarmBroadcast_" + nowTime.toString();
Intent intent = new Intent(intentName);
alarmIntens.add(intentName);
PendingIntent pi = PendingIntent.getBroadcast(c, alarms++, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
//
AlarmManager am = (AlarmManager) c
.getSystemService(Context.ALARM_SERVICE);
//adding span to elapsedRealTime
long elapsedRealTime = SystemClock.elapsedRealtime();
Time t1 = new Time();
t1.set(elapsedRealTime);
t1.second=0;//cut inexact timings, seconds etc
elapsedRealTime = t1.toMillis(true);
if (!(repeatInterval == -1))
am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
elapsedRealTime + spanToStart, repeatInterval, pi);
else
am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, elapsedRealTime
+ spanToStart, pi);
where span function is this:
public static long spanInMillis(Time startTime, Time endTime) {
long diff = endTime.toMillis(true) - startTime.toMillis(true);
if (diff >= 0)
return diff;
else
return AlarmManager.INTERVAL_DAY - Math.abs(diff);
}
alarm cancel function is this.
public static void cancel(Context c) {
AlarmManager am = (AlarmManager) c
.getSystemService(Context.ALARM_SERVICE);
// cancel all alarms
for (Iterator<String> iterator = alarmIntens.iterator(); iterator
.hasNext();) {
String intentName = (String) iterator.next();
// cancel
Intent intent = new Intent(intentName);
PendingIntent pi = PendingIntent.getBroadcast(c, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
am.cancel(pi);
//
iterator.remove();
}
}
Some important notes when choosing which alarm to use:(for whom who already read the upvoted votes)
The RTC_WAKEUP death valley - time change:
If the user has manually change time to the past the alarm won't go off, and future will cause the alarm to go off immediately if it past the RTC timestamp. Do not use this alarm to do any client side verification / important jobs because it have a chance to fail.
The WAKEUP meaning (Marshmallow and above)
In general - not much. Will not wakeup the device when idle or while in doze, for that alarmManager.setExactAndAllowWhileIdle or alarmManager.setAndAllowWhileIdle (Doze & Idle)