AlarmManager stops working in Android 4.4.2 (using SetExact()) - android

I'm setting in my code an alarm to go off in specific time.
The alarm mechanism works great on SDK < 19, but on 19 the alarms aren't fired.
Here is the code where I set the alarm :
public void SetAlarm(Context context, Long executionTime)
{
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmReciever.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Only one alarm can live, so cancel previous.
am.cancel(pi);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
am.set(AlarmManager.RTC_WAKEUP, executionTime, pi);
} else {
setAlarmFromKitkat(am, executionTime, pi);
}
}
Since I'm setting the alarm using a Service I use GetApplicationContext() as the context.
The onReceive() code :
#Override
public void onReceive(Context context, Intent intent) {
for (SchedulerListener listener : listeners) {
listener.fetchAndRebuildNotification();
}
}
Here is the declaration of the BroadcastReceiver :
<receiver
android:name="com.SagiL.myAppName.BroadCastReceivers.AlarmReciever" />
The callback runs a method in a service (which is still alive when the alarm supposed to fire, notice it doesn't starts one).
This whole thing is a library which is used in my app, and there I declare the receiver the same way.
Sometimes the alarm do fires once, but mostly it doesn't fire at all.
Has anyone experienced such a thing ?
I can't believe it's common to SDK 19 since a lot of apps are using AlarmManager and they will break too if it is common.

I had a similar problem with my application. I found out that using 0 ad the id in getBroadcast(...); didn't work very well and caused numerous problems.
Try changing the id from 0 to the alarm's real id.
From:
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
To:
PendingIntent pi = PendingIntent.getBroadcast(context, id, intent, PendingIntent.FLAG_UPDATE_CURRENT);

It´s a late answer, but may help. In Android KitKat 4.4.xx a battery manager is integrated (my device: Huawei Ascend Mate 7). There is an option to kill background process and services of an app in the battery manager. Don´t know if the options are named similar to the german options, so just try:
go to settings
select save energy
select detailed power consumption
select Screen off: perform further
enable Your app
It sounds simple, but that exactly was my problem. On Samsung Galaxy S3 with ICS everything worked like a charm. But bought a new device, the huawei, with Android 4.4.2, and suddenly my apps alarms didn´t work. After checking the system, I detected that option, enabled my app and now everything is fine. Not everything is a programming answer :) .
UPDATE
Since this answer was made, a lot happened in Android. For everybody with a similar problem: Since update to Marshmallow, there are two problems: first one is like described above, the second one is the doze mode:
Optimitzing Doze
Some devices, like my Huawei Ascend Mate 7, using both energy saving methods. So it isn´t enough to do what is described above. Also, you have to whitelist the app and use the new alarmManager methods setAllowWhileIdle(), setExactAndAllowWhileIdle() and setAlarmClock() .
Possible Problems
By whitelisting your app, you have to tell this the user. You can do it with a simple information at starting your app, for example a AlertDialog and/or you can use ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS intent to start the whitelisting screen. But be aware of this Action, because like reported from some developers, Google can suspend an app from playstore that is calling this action.
setAlarmClockshould also work, but if you do this, an alarm clock icon is on the top.
Testing
I have made some tests with that new documented doze mode and found out, that it usually works. But without whitelisting, the app falling to standby and ´alarmManager´ does not fire anymore, also not with that new methods. I tested it over night and the app is send to standby within about one hour. At a normal situation at day, where the user is active and often moves his device, it works without whitelisting.

Related

Is there a device-agnostic way to handle simple recurring push notifications in Android?

Push notifications are still working great on all my devices running anything under 8.0, but anything 8.0+ is a nightmare.
Let's say I want a simple daily notification to pop up. It goes off once a day at a certain time, even if the application is closed. Exact timing isn't relevant:
AlarmManager am =(AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, alarmnotify.class);
PendingIntent pi = PendingIntent.getBroadcast(context, ALARM_ID, i, PendingIntent.FLAG_UPDATE_CURRENT);
am.setRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime(), AlarmManager.INTERVAL_DAY, pi);
On many devices supporting Doze this doesn't work and I have to use setAndAllowWhileIdle() or setExactAndAllowWhileIdle() and refresh the alarm when it fires (annoying). But many more devices, this doesn't work either.
If the device is stock Android I can request an "ignore battery optimization privilege", but this isn't working for almost any of my testing devices because of some silly OEM battery manager that runs on top of the stock battery manager. Even Samsung has one of these now. And plus, Google does not recommend this approach, and it can get your app de-listed if they feel you don't need it.
Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse("package:" + packageName));
startActivity(intent);
Some devices are working if I use AlarmManager.setAlarmClock(), but this is silly, my app is not an alarm clock, I just want to display a notification.
I considered moving to FCM, but it's ridiculous to build client-server infrastructure over a simple once-daily alarm. Plus, that brings in numerous other considerations. The simplest: what if the user is offline?
I'm noticing this a major issue even in enterprise grade applications with millions of downloads. I have the same applications installed on a 7.0 and 9.0 device. The 7.0 device gets notifications and the 9.0 does not. What gives?
Is there a universal approach to handling alarms post-8.0, much like the first snippet was universal to all devices prior to 8.0?

AlarmManager not working on Samsung devices in Lollipop

I develop an app that uses AlarmManager to set a bunch alarms (usually around 50) that need to be fired at a certain time during the year.
This is the code I'm using since 4.4 kitkat changed the AlarmManager.
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
long setDate = fireDate.getTime(); // it's a calendar date defined above
Intent intent = new Intent(LOCAL_DISPLAY_MESSAGE_ACTION);
PendingIntent pending = PendingIntent.getBroadcast(ctx,
id, intent, PendingIntent.FLAG_UPDATE_CURRENT);
if (Build.VERSION.RELEASE.startsWith("6")) {
am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, setDate, pending);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
am.setExact(AlarmManager.RTC_WAKEUP, setDate, pending);
} else {
am.set(AlarmManager.RTC_WAKEUP, setDate, pending);
}
Apart from the code above I'm using a broadcast receiver properly defined in the manifest.
public class LocalReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
PushWakeLocker.acquire(context);
// do some stuff
PushWakeLocker.release();
}
}
More info thay might help.
<uses-sdk
android:minSdkVersion="10"
android:targetSdkVersion="19" />
Since a few months ago I've been getting bad reviews only from Samsung devices (5.0 /5.1 android version) that don't get their local notifications at all. I mean, it's not firing the alarm, it seems that the device skips it or does not wake up.
In the tests, mainly with a Samsung S4 with 5.0.1, I always get the alarms on time, so this is driving me crazy.
FYI this code has always worked pretty fine.
I researched a lot about this but unfortunately I got no helpful information. It's not that they get the alarm with delay (as I've read in some threads), it's that they don't get it at all. So this is not about the known issue in lollipop and alarmmanager.
I appreciate your time and any suggestion is welcomed!
Your problem (or nightmare) is the Samsung Smart Manager. This app comes pre-installed with all Samsung phones since 2015 and is supposed to deactivate Apps that are unused.
"How does it know which apps are not used?" You may ask - simple:
Every app that has not been launched by the user for 3 days gets deactivated.
All remaining AlarmManager entries - of course - also get deleted. You can read about it on their "Developer Forums". Feel free to follow here or here until these threads get deleted by the staff. I have yet to see someone from Samsung respond to the topic.
The only way to "fix" this is to inform the Users of your app about the situation and show them how to whitelist your app in Smart Manager. We've had to setup a website with step-by-step instructions showing how to do this for our users.
You may think about setting up a background service, or calling AlarmManager every six hours or so - none of these hacks will work.
When devices are re-starterd it clears alarms so your on boot alarm has to set them up again.

AlarmManager not working in several devices

My app uses AlarmManager and it has been working since 4 years ago. But I noticed it started failing in some devices.
I'm pretty sure code is right (I'm using WakefulBroadcastReceiver, and setExactAndAllowWhileIdle for devices with Doze) because it's working perfectly on Nexus devices, but it fails in devices of some manufacturers (Huawei, Xiaomi...).
Huawei devices, for example, have a kind of battery manager that kill apps, and when an app is killed, scheduled alarms are cancelled. So setting an app as "protected" in Huawei battery manager solves the problem.
But recently I noticed it's not working with more devices: Xiaomi, Samsung (maybe it's related to the new "Smart Manager"?)... It seems that this behavior is becoming a standard: to kill background apps.
Anyone know anything about it? Any way to ensure alarm is fired?
EDIT: This problem is caused by "battery savers" added by different manufacturers. More info here: https://dontkillmyapp.com/
I'm trying to solve it several weeks already. I found nothing. Huawei just kill all the alarms after some time. If I put the app to the protected app in their battery saver it does't help. But If I change package name of my app to contain words like alarm, clock or calendar, it works absolutely normal like on any other devices. I don't understand how Google can give certification for this crap. I think that OEM should not modify core platform in such way. I understand that they have own batter saver which kill the app after some time, when user don't use it. But this killing alarms also of protected apps.
Also setAlarmClock() for exact timing alarms helps. But it is not possible to use this for thinks like widget update.
Update: Protection by package name keywords is already not working on current Huawei devices, it was true in 2017.
The issue is Smart Manager. Samsung has a battery manager which at times disables certain apps from running in background. It tried to "resume" when going back to the app but completely disables the application or may resume every 5 mins or so (depending how Samsung has it).
This would work on stock versions of android as there is no Samsung Manager. You can also install custom version of android which has some features to enable SM (depending on the rom).
Most of modern Android devices come with an app or mechanism, which automagically tries to figure out how to save battery and as a result might kill certain 3rd party apps. This might result in removing scheduled tasks and jobs, (e.g. alarms not going off, push notification not working, etc.). In many cases this happens completely independent from battery saving mechanisms of Android, in my case i couldn't make more battery optimization when i detect some devices model, i redirect user to the start up manager to whitelist my application
You found in this link for every model the intent that you should invoke
https://android-arsenal.com/details/1/6771
This might be late but I hope it helps someone.
I was stuck on the same problem for so long. But now I konw how to solve this problem. This is for anyone who might have the same problem.
People keep saying that you have to enable AutoStart but I managed to it with out using auto start.
First of all, WakeFullBroadcastaReceiver is now deprecated and you should use BroadcastReceiver.
Second of all, you have to use the ForegroudService instead of BackgroundService.
I will give you the example in the following:
IntentService.class
public class NotificationService extends IntentService {
//In order to send notification when the app is close
//we use a foreground service, background service doesn't do the work.
public NotificationService() {
super("NotificationService");
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(#Nullable Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
//There is no difference in the result between start_sticky or start_not_sticky at the moment
return START_NOT_STICKY;
}
#Override
protected void onHandleIntent(#Nullable Intent intent) {
//TODO check if the app is in foreground or not, we can use activity lifecyclecallbacks for this
startForegroundServiceT();
sendNotification(intent);
stopSelf();
}
/***
* you have to show the notification to the user when running foreground service
* otherwise it will throw an exception
*/
private void startForegroundServiceT(){
if (Build.VERSION.SDK_INT >= 26) {
String CHANNEL_ID = "my_channel_01";
NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
"Channel human readable title",
NotificationManager.IMPORTANCE_DEFAULT);
((NotificationManager)
getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);
Notification notification = new Notification.Builder(this, CHANNEL_ID)
.setContentTitle("")
.setContentText("").build();
startForeground(1, notification);
}
}
private void sendNotification(Intent intent){
//Send notification
//Use notification channle for android O+
}
}
start the foreground service in BroadcastReceiver.class
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent service = new Intent(context, NotificationService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(service);
} else {
context.startService(service);
}
}
}
And the setAlarms like this:
public static void setAlarm(Context context, int requestCode, int hour, int minute){
AlarmManager alarmManager =( AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context//same activity should be used when canceling the alarm
, AlarmReceiver.class);
intent.setAction("android.intent.action.NOTIFY");
//setting FLAG_CANCEL_CURRENT makes some problems. and doest allow the cancelAlarm to work properly
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 1001, intent, 0);
Calendar time = getTime(hour, minute);
//set Alarm for different API levels
if (Build.VERSION.SDK_INT >= 23){
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,time.getTimeInMillis(),pendingIntent);
}
else{
alarmManager.set(AlarmManager.RTC_WAKEUP,time.getTimeInMillis(),pendingIntent);
}
Then you have to declare the receiver and the foregroundservice in the manifest.
<receiver android:name=".AlarmReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.NOTIFY">
</action>
</intent-filter>
</receiver>
<service
android:name=".NotificationService"
android:enabled="true"
android:exported="true"></service>
I hope this helps some one.
I also have an app that sets alarms.The solution is to use AlarmManager.setAlarmClock() on api >= 21. This is unaffected by doze afaik and has the added bonus of putting an alarm clock icon in the system tray.
Use AlarmManager for <5.0 devices, and JobScheduler for 5.0+ devices. I can't say for sure that JobScheduler will be unaffected by manufacturer shenanigans, but it would seem much less likely to me, given that Android is trying to move people away from AlarmManager and onto JobScheduler.
EDIT: Google has come out with a first-party solution to this problem called WorkManager. It abstracts multiple scheduling frameworks and uses the most appropriate one for the device.
most new phones nowadays are bundled with some kind of battery/power saving manager which do same thing you described. not counting duboosters and clean masters.
I think you need to put a disclaimer or faq in your app / play store listing stating that this app needs to be put into exception of your battery manager app in order to work properly.
i stopped using AlarmManager a while ago... a better and more stable alternative
create a service
register a BroadcastReceiver for BOOT_COMPLETED
fire your service from the receiver
start a new Handler inside your service that loop itself every X minutes (Android - running a method periodically using postDelayed() call)
check if time to execute the task has come: now - execution time > 0 (How to find the duration of difference between two dates in java?)
if so.. execute the task and stop the handler
yes.. it's a pain..but the job get done NO MATTER WHAT
Are you listening for BOOT_COMPLETED? You need to set alarms again when a device is rebooted.
What version of Android are these devices running?
As of API 23, the OS itself will go into a low-power idle mode when it's been unused for a while, and in that mode alarms will not be delivered. There is a way for apps to explicitly say "I need this alarm to go off at this time regardless of battery usage," however; the new AlarmManager methods called setAndAllowWhileIdle() and setExactAndAllowWhileIdle().
From your description it sounds like this might not be the particular cause of your issues on certain OEMs' devices, but this is something that all developers using the Alarm Manager ought to be aware of.
Finally, many usages of the Alarm Manager are better addressed using the Job Scheduler's mechanisms. For backwards compatibility the Play Services "GCM Network Manager" is actually very close to the Job Scheduler in functionality -- it uses the Job Scheduler internally on newer versions of Android -- and is not necessarily about networking, despite the class's name.
I don't think killing the app will prevent the alarm manager from waking your app.
Its only when you "force stop" or disable the app you don't receive call backs from alarm manager.
The root cause might be something else.
Also on M... setExactAndAllowWhileIdle does throttling...that is if u schedule an alarm every 2 mins it won't be triggered. ..There needs to be 15 mins window. .
For Xiaomi you may need to enable AutoStart for your app. I am trying do to a list of Android modifications(usually from phone's manufacturer) that may effect a background process. If you have something new please add an answer here List of Android task killers
We need to enable our app in autostart manager in app manager, some handsets like vivo v5,
In vivo v5, We can find out this menu in iManager-->App Manager--> Auto Start Manager. Enable our app here.
Then your alarm/ alarmmanager will trigger alarm if the app is killed or closed.
I were looking for an answer and after several hours I found this:
https://stackoverflow.com/a/35220476/3174791
In resume is way to know if your app was killed by 'Protected apps' and this only works on Huawei devices. let me know if there is any solution for other devices (Samsung,Sony,Xiaomi, etc).

Booting Android Device on AlarmManager Call

I am building an Android Alarm Applicaion, and used following code for Main Calling Class:
AlarmManager inst_alarm= (AlarmManager) getSystemService(ALARM_SERVICE);
Intent intent =new Intent(MainActivity.this,Alarm.class);
pintent= PendingIntent.getBroadcast(MainActivity.this, 0, intent, 0);
inst_alarm.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(),pintent);
//"cal" is reference of calendar class to get saved time in millisecond.
for Service Class:
public class Alarm extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context c, Intent i) {
Uri uri_alarm= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
if(uri_alarm==null)
{ uri_alarm=RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
}
Ringtone ringtone_alarm=RingtoneManager.getRingtone(c, uri_alarm);
ringtone_alarm.play();
}
}
This code work fine but i have few quesions.
Question: 1) Is it possible to alarm bell on scheduled time if android device is switched off(device get power on automatically to ring bell on saved time) as in default application of android device does.
2) Suppose i saved alarm after 8 minutes exactly and i restart my device then alarm start ringing immediately after boot(Because i have used "bootcomplete" for receiver in manifest) but i want to play alarm after 8 minutes exactly not on reboot.(I have saved alarm in shared-preference but how to use it on reboot)
EDIT: Can I use "Power Manager" class or any other class to handle above mentioned situation ?
1) Is it possible...
No, not from complete power off. You're most likely referring to screen being off and the device in low power state. If the device is turned completely off then alarms cannot wake it. The default Android clock app just wakes it from sleep. If you'd like to wake up the screen and play sound, you'll have to create a Service which can be activated via your WakefulBroadcastReceiver and have it start the appropriate UI. If you do not, then the system can go right back to seep when your onReceive() is done.
2) ...want to play 8 minutes after...
What you're likely seeing is a previous expiration of your Alarm firing and you're waking up the device (not powering it on.) Alarms are not retained across power cycles or reboots. If you wish to have them stick around after a true reboot, then you'd have to manage that yourself. The PowerManager and AlarmManager do not provide such a facility.
For (1), if you're talking about complete shutdowns, it's unfortunately impossible. There is no way to do this without specialized hardware (and its corresponding software interface to your app).
For (2), you can do something clever. For example, persistently store the timestamp whenever the device restarts/turns off (you can register a BroadcastReceiver for ACTION_SHUTDOWN in addition to your BOOT_COMPLETE) when you have a pending alarm bell, and use that information on reboot/boot to resume (or stop, depending on the time difference and the alarm bell's "timer") or otherwise re-sync your pending alarm bell logic.
And for your PowerManager question, again if we're talking about complete shutdowns, unfortunately the answer is no.
PowerManager is used to mainly prevent the device from going into deep sleep. Remember, Android devices turn off their CPU's some time after they are locked, preventing your app from doing calculations/processes. This is essentially what the notion of "wakelocks" is about.

AlarmManager Android 4.4.2 bug

In my app I have a service and I use AlarmManager in this way:
AlarmManager am =(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, getIntent(), PendingIntent.FLAG_UPDATE_CURRENT);
long mills = SystemClock.elapsedRealtime();
mills += time;
am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, mills, pi);
And here is the receiver for my intent of the am:
if (intent.getAction().equals(Timer3GOn.intentExtra)) {
//some code
}
Here is how my app works:
when screen goes on (i receive Intent.ACTION_USER_PRESENT ) i set an AlarmManager that after a certain amount of time sends my intent Timer3GOn.intentExtra that is received by my class.
All this works fine except in Android 4.4.2 (haven't tested in 4.4.1 yet, but in 4.4 it works well). Only in android 4.4.2 if I delete my app from the "recent app list" of the device, the am is set properly but the intent is never received by my app; plus all the code in the service remains like stuck. So my app stops working but service remains in the RAM.
The problem doesn't start when I delete my app from recent app list, but only after I do that and the AlarmManager is set. How to resolve the problem?
P.S. in my app i have a CountDownTimer in the same class with the same context and it works well!
P.P.S. I've noticed that whatsapp has the same problem, if you delete it from recent apps, all the incoming messages don't being delivered until i open the program. It's just me or this happens to all 4.4.2 android versions?
Starting android 4.4 you have to use setExact() in order to execute alarms in accurate time.
Otherwise it'z the OS decision when to execute your alarm.

Categories

Resources