I'm testing my application on Android P beta release 4. My app's targetSdkVersion is 27
It has been observed that alarm manager notifications are not working as expected. I'm using below code to set the notifications -
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
alarmManager.set(AlarmManager.RTC_WAKEUP, triggerAtMillis, AlarmIntentBuilder.buildPendingIntent(context, uri));
} else if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, triggerAtMillis, AlarmIntentBuilder.buildPendingIntent(context, uri));
} else {
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerAtMillis, AlarmIntentBuilder.buildPendingIntent(context, uri));
}
I tested the same logic on Android 8.0 but it's working fine. In Android 9.0, notifications are working but sometimes they did not work at all. Also, if they work they are not exact and takes too much time and this happens even if the application is in foreground.
The logic is, I've the repeating reminders which are set on specific time and those should repeat them-self on daily basis at the specified time. Also these are high priority reminders and should land at exact time so I'm using setExact and once the notification is received it's being display and new alarm for the next week of the same day is set.
I've checked the Android P API documents but could not find any link which has the impact on working of AlarmManager and Notifications. Only thing which I feel is causing the issue is Power management in Android P and the priority buckets. However notifications are not working properly even if application is in foreground.
Anything I'm missing here. Any help is much appreciated.
As you yourself mentioned the new App Standby Buckets feature of Power Management is likely to be the cause. The new documentation states:
If an app is in the frequent bucket [or below], the system imposes stronger restrictions on its ability to run jobs and trigger alarms
and
In particular, the bucket determines how frequently the app's jobs run, how often the app can trigger alarms
Additionally, if you view Power Details you can get a rough idea of the delay times.
Worth noting is that it appears your bucket is based on average usage (and machine learning) not on current usage - which means even if your app has just been in the foreground, the buckets play some role
This is happening because of Power management feature introduced in Android Pie.
In android P, strict restrictions are introduced on the apps running in background. These restrictions are explained here
As we can see in the above link, if we connect the device to charging there are no restrictions imposed on the device and notifications are working properly. However, if we remove the device then Android system adds the certain restrictions for the apps running in background.
We can turn off this restrictions by turning off battery optimization for our application from device settings. Search for battery optimization in settings and turn it off for our application.
Also, testing the notifications by changing the device date and time was a hack that worked fine till now but in Android P, we've to either test them in real time scenario or turn off battery optimization for our application to test them.
I hope this will clear our doubts.
Related
I am trying to run IntentService as such from AlarmManager setRepeating() for every half an hour. I want to send a to broadcast, from broad cast to intent service. In the service, some functionality will be done.
But, initially the AlarmManager in not triggering while the app is in closed state.
When my app is running or in background state the alarm is working fine and when I close the app the alarm is not working in some devices.
What should I do to run the alarm even if the app is closed?
From the documentation of setRepeating():
As of API 19, all repeating alarms are inexact.
Moreover, setRepeating() does not work with Doze.
You should use exact alarms (set by the appropriate AlarmManager method based on the API level of the device):
if (Build.VERSION.SDK_INT >= 23) {
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,
triggerTime, pendingIntent);
} else if (Build.VERSION.SDK_INT >= 19) {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent);
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent);
}
And reschedule them every time they fire.
For the rescheduling you could add the original trigger time to the Intent:
intent.putExtra(KEY_TRIGGER_TIME, triggerTime);
Then retrieve this extra in onReceive(), add your desired interval to it and reschedule the alarm using the new value:
#Override
public void onReceive(Context context, Intent intent) {
long triggerTime = intent
.getLongExtra(KEY_TRIGGER_TIME, System.currentTimeMillis());
// adding one day to the current trigger time
triggerTime += TimeUnit.DAYS.toMillis(1);
// set a new alarm using the new trigger time
// ...
}
NOTE: As #Opiatefuchs mentioned in the comment above, some manufacturers (such as Xiaomi or Huawei) may implement certain battery saver functions that can prevent alarms from being fired and cannot be bypassed programmatically.
Nowadays devices are coming with more security in context of Battery power consumption. By default devices keep almost all apps in power saving mode. It means in some devices your background work (Location, Alarm manager) won't work as soon as you come out from the app. In other devices background tasks won't work after a battery threshold limit (like 13%). So you need to keep out your app from this battery saving mode to run your app smoothly even in background. The way to achieve that behavior in these two manufacturers is:
Xiaomi
Go to the Battery => Power => App battery Saver => select your app and choose No restrictions (for Background settings), then Allow option for Background location.
To AutoStart your app after Boot: Go to the Security app => Permissions => Auto start and check your app.
Samsung
Samsung Smart Manager App used to stop all background work after 3 days if you don't come to your app. So the way to disable this feature is:
Go to Battery in the Settings => Unmonitored apps => Add your app to the whitelist. Some other Samsung versions may differ the place to disable it, like Battery => Detail => Select the app and "Don't optimize".
For other devices there should be same power options either in settings option directly or some app are given to handle it.
First, there is a bug with android studio. If you start the app from the android studio and then swipe it away from the recents, the alarms will be deleted. So after that, relaunch your app by clicking on the launcher Icon and then if you swipe it away, the alarm will be still there.
Second, on some devicrs with battery optimization stuff, you should start a foreground service and that works totally fine.
I could make it work using these two points and now it works like a charm.
The below behavior changed after a full charge. Previously, after disabling energy saving for this app, it displayed that there was no battery saving active etc, but only after a full charge (from very low battery state) did the device behave as it should. So change those settings for the app, then do a full recharge (maybe only after previously having low battery). This could fix it.
ZTE Blade L110
Even with the battery saver disabled (Settings -> Battery -> Options -> Battery Saver) and the app marked as important for messages (Settings -> Prompt & notification -> App notifications -> appname -> Priority) it seems like neither setExact nor setAlarmClock are triggering on time.
for Lenovo phone:-
you need to go in setting -> application->select app-> uncheck Restrict to launch
now it will be work in the background as killed state
Hi:
I'm curiously about how to show this dialog. When I press allow, the battery optimize is disabled for this app. Is it an new android api
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
String packageName = context.getPackageName();
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
if (!pm.isIgnoringBatteryOptimizations(packageName)) {
Intent intent = new Intent();
intent.setAction(android.provider.Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
intent.setData(Uri.parse("package:" + packageName));
context.startActivity(intent);
}
}
Also, you need to add the following permission in manifest
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
This is part of the new App Standby feature introduced with API 23 (Marshmallow) alongside Doze Battery Optimization aimed to optimize power and resource usage while the app is in background (App Standby) or when the device has long been in sleep (Doze).
Following is the explanation from the Android Developer's site page:
Specifically, in the App Standby mode, the system determines that an app is idle when the user is not actively using it. The system makes this determination when the user does not touch the app for a certain period of time and none of the following conditions applies:
The user explicitly launches the app.
The app has a process currently in the foreground (either as an activity or foreground service, or in use by another activity or foreground service).
The app generates a notification that users see on the lock screen or in the notification tray.
The app is an active device admin app (for example, a device policy controller). Although they generally run in the background, device admin apps never enter App Standby because they must remain available to receive policy from a server at any time.
When the user plugs the device into a power supply, the system releases apps from the standby state, allowing them to freely access the network and to execute any pending jobs and syncs. If the device is idle for long periods of time, the system allows idle apps network access around once a day.
So, this means that starting from API 23 (Marshmallow), the device may actively put your app on standby, preventing network access (say for task like sync) and limiting (or disabling) background executions. Now, for most of the apps this behavior is fine or you could easily optimize for such behavior, but for some apps out there this may cause some unexpected behavior, especially for apps that have been poorly optimized or use non-standard sync strategies or some other means of background sync/execution.
So to circumvent that, the user can explicitly mark the app as non-optimized and the system will fallback and not put the app to standby, although this leads to a poorer user experience and you should not be doing this for regular apps that could be optimized.
I started to test my app on Nexus 5x with Android O.
My targetSdkVersion is 22.
In the developer site I read about Background execution limits:
Where:
By default, these restrictions only apply to apps that target O. However, users can enable these restrictions for any app from the Settings screen, even if the app has not targetted O.
Where is these settings (to enforce Android O limitations)?
Whats is the best practice for these limitation while I still want
to keep lower targetSdkVersion?
I found the setting under App info > Battery usage although not all apps have this setting.
When this setting is OFF I see following logs:
W/BroadcastQueue: Background execution not allowed: receiving Intent { act=android.intent.action.$ACTION dat=package:$APP_PACKAGE flg=0x4000010 (has extras) } to $APP_PACKAGE/$APP_RECEIVER
[UPDATE Sep 27, 2017]
As described here:
However, developers cannot use the Settings app to apply this limitation, unless their app happens to be in the battery blame list, which ideally doesn’t happen.
This article offers undocumented way to test background limitations via following command (ignore and allow values are possible)
adb shell appops set your.application.id.here RUN_IN_BACKGROUND ignore
Best practices are
If you plan on sticking with a lower targetSdkVersion for a while, and you are really really sure that your app will not show up on the battery blame list, and you want to ignore the background limitations for now, that’s your decision to make.
If, however, you plan on sticking with a lower targetSdkVersion and your app does tend to consume a fair bit of battery life, you should test your app with the adb shell appops command cited above. If nothing else, you can identify the likely symptoms that users will experience if they limit your background work through the Battery screen in Settings. That way, if you get customer service calls/emails/texts/Play Store comments/candygrams about those symptoms, you can better advise users about what to do.
See also Android Oreo Background Execution Limits
I cannot find it either.
Best practise would be to develop this for API 26, although you are not targeting it. So starting your service(s) as foreground service. After that, your service should start a foreground Notification in the onCreate.
From the docs:
The new Context.startForegroundService() method starts a foreground service. The system allows apps to call Context.startForegroundService() even while the app is in the background. However, the app must call that service's startForeground() method within five seconds after the service is created. (startForeground pushes the notification)
App info > Battery usage
IMO best practice is unfortunately to target API 26... This default behaviour is there only for legacy apps (sitting in play store but not being updated anymore).
How do i detect if the app has been killed?
i have found a solution which is call activity on onDestroy
#Override
protected void onDestroy() {
super.onDestroy();
Intent intent = new Intent(this, ConnectionStablizer.class);
startActivity(intent);
// code here
}
it is working fine on galaxy note 3 (4.4.2) but not working on android emulator (android 4.2.2), galaxy y duos (2.3.6) and htc desire (4.0.2)
so i found another solution-
run a background service which detects when app gets destroyed and launch the activity again like this one
i have the exact implementation but it doesn't do anything? where am i wrong? my code is the same as in the link
where am I wrong
You are wrong trying to reopen your app once it's been destroyed. This is a hacky behavior...
Nevertheless, you can achieve your goal by using alarm manager and set an alarm for every second or so, to check if your app is alive if it's not you can bring it back.
Also, pay attention:
Beginning with API 19 (KITKAT) alarm delivery is inexact: the OS
will shift alarms in order to minimize wakeups and battery use. There
are new APIs to support applications which need strict delivery
guarantees; see setWindow(int, long, long, PendingIntent) and
setExact(int, long, PendingIntent). Applications whose
targetSdkVersion is earlier than API 19 will continue to see the
previous behavior in which all alarms are delivered exactly when
requested.
I strongly recommend to not use my solution, nor attempting to find one.
If the app is removed from recent apps by user then you can get a notification from OS by overriding onTaskRemoved method in your service and take respective action. In general Android never kills any app unless otherwise in a low memory condition. In such case callbacks will be given to save the state of your application provided you handle all such callbacks.
On some devices (even on some that, at least according to the manual, do not have a battery saver in the system, and the customers deny they installed one) the system broadcasts the Alarm Intent several hours later, only at the moment when the user switches the device on.
If the users set the alarm in a few minutes, it works. If it is set in a few hours, it might work, might be off by a few minutes or hours, most likely the latter.
This is getting on my nerves, as
I always get the complaints from the customers (understandably), and
I do not have a generic answer for them, as it might not be
obvious where the problem lies, where to exclude my app from that
"unexact" behaviour.
it is not even an 'about' time when it's several hours wrong!
I do target API >= 19/KitKat, so I distinguish already how to set the alarm:
PendingIntent pi = PendingIntent.getBroadcast(ctx, 1, i, PendingIntent.FLAG_UPDATE_CURRENT);
if (android.os.Build.VERSION.SDK_INT >= 19)
alarmManager.setExact(AlarmManager.RTC_WAKEUP, calSeqStart.getTimeInMillis(), pi);
else
alarmManager.set(AlarmManager.RTC_WAKEUP, calSeqStart.getTimeInMillis(), pi);
Often, and also in the latest case it's not even an API 19 device:
TCT ONE TOUCH TAB 7HD (TAB7HD)
OS API Level: 16
To the code: I am sure "calSeqStart"'s time is correct, this cannot be a problem.
It cannot be a WakeLock problem, as soon as the BroadcastReceiver gets the Intent, it logs a message, and that message also appears at the wrong time! So the broadcast is sent only at the time the user switches the device on.
At my place, and hundreds of others, it works without problems.
My questions:
How can an Alarm App tell the system forcibly it needs to be woken up and started at a certain time?!
Does anybody know whether it's possible to find an energy-saver-app like STAMINA (Sony Experia Z) so that the user can be warned?
ADDITION:
In my app, I do set alarms in the alarm manager as AlarmManager.RTC_WAKEUP type, but when I dump the alarms using adb, I see they are mapped to AlarmManager.RTC type.
This only happens on some (or at least one: Alcatel onetouch TAB 7D) device. On all others, the alarms set by my app do correctly wake up the device (and I see them as RTC_WAKEUP in the "adb shell dumpsys alarm" as expected).
As it is Android 4.1.1, it cannot be an AppOpps check, must be something else.
And using the ADB, I see that only deskclock can set the alarm as WAKEUP, all entries of other apps are non-WAKEUP alarms.