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.
Related
I am having problems while doing work in the background in Android. I need to do a http request every 5s in a app of my own use (won't publish the app). I've seem that since version O Android had put limitations on the operational system and I'm doing what is recomended, that is, I'm creating a foreground service with a persistent notification to run this task. It works fine with the screen on, and even with the app closed, but after a while if the phone is locked it enters the Doze mode and lock my requests until I turn the screen on again. I've tried to mess with the power savings configurations of my phone with no luck.
Anyone have faced that issue?
Preferably without FCM (Firebase Cloud Messaging).
I am doing it on Xamarin.Forms, but if you have some example in Java that's ok, I'll get the idea.
You have to set REQUEST_IGNORE_BATTERY_OPTIMIZATIONS permission in your manifest.
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
Also you have to ask the user to put your app on the Battery_Optimization whitelist at runtime, like descriped here:
//check for ignoring battery optimization
PowerManager mPowerManager = (PowerManager) your_context.getSystemService(Context.POWER_SERVICE)
if (!mPowerManager.isIgnoringBatteryOptimization(your_context.getPackageName())) {
//ask for permission
Intent intent = new Intent(android.provider.Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse("package:" + your_context.getApplicationContext().getPackageName()));
startActivity(intent);
}
BUT your app is most likely not going to get approved by Google Play, when you try to release it to the PlayStore!
You should use FCM high-priority messages instead.
There aren't too many ways to do it on Android in nowadays.
Try to look at this Google tutorial and choose the right one.
Regarding the REQUEST_IGNORE_BATTERY_OPTIMIZATIONS permission, your app should fit these conditions.
You'll find more details here android-doze-standby.
Honestly if you need do a task every X seconds use an alarm broadcast:
https://developer.android.com/reference/android/app/AlarmManager
You just implement a receiver and you can perform the task. If you need it in a specific class implement the receiver as in inner class running on a new thread re-registering the alarm every time.
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.
my app has a proxy server in a native executable written by C, it always runs in the background, let's call it httpproxy.exe.
The main activity I use startForegroundService and startForeground with a persist notification to keep the app in the foreground avoid killing by system, then run the httpproxy.exe in the background.
my app works well on android 5 and older verisons, but on android 8.0, when the activity goes background after minutes, httpproxy.exe looks like getting suspended, so I have to bring my app up time after time, that's unacceptable.
I heard there are a so-called Background Execution Limits on android 8,
how can I have my app normally work like before?
Make sure, that your app is excluded from the Doze mode.
Checking:
PowerManager powerManager =
(PowerManager)getActivity().getSystemService(Activity.POWER_SERVICE);
powerManager.isIgnoringBatteryOptimizations(getActivity().getPackageName());
Asking the user to white-list your app:
Intent intent = new Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS);
startActivity(intent);
I am running service background to execute some tasks with some interval using AlaramManager (setExactAndAllowWhileIdle). If its connected the power charger its running. But if its unplugged device power after some i am loosing the network to my application.
Alaram is waking up the service even device is idle.But my app don't have network.
As per https://developer.android.com/training/monitoring-device-state/doze-standby.html# its restricting the network when phone is idle.I tested the same with applying phone idle ($ adb shell dumpsys battery unplug)
But is there any possible to get network access to my application even phone is idle mode.
Application is not of play store. Its really appropriated for suggestion.
I've used PowerManager.isDeviceIdleMode() in your running service to detect whether you're in Doze and if so just invoke setAlarmClock() method with 250 millis (for example) and random broadcast just to wake the device up, it'll completely wake up from doze and thus will get network access as usual. THe down side is that you lose the battery saving that comes with doze.. :D Please mark this as useful should it actually be usefull in your case.
Once your service (set up with setExactAndAllowWhileIdle()) you can go :
private boolean isDeviceInDozeMode() {
PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
return pm.isDeviceIdleMode();
So now you know that you're in DOZE or not.
Then you can just set up AlarmClock and set it with setAlarmClock(AlarmClockInfo a, PendingIntent p)
And you're out of Doze with normal network access.
NOTE: Please remember that using setExactAndAllowWhileIdle doesn't mean that your alarm will go off at specified time, it will go off sooner than normal set() method, but not exact (as the method name would suggest). Generally my way isn't perfect in terms of scheduling, but it does exit DOZE programmatically once it's detected on device.
Let me know should you need more update.
I tried many options but none of them works, But finally this works to me.It might help for others.
we can always ask the user to let your app ignore battery optimization functionality using
PowerManager powerManager = (PowerManager)
getSystemService(Context.POWER_SERVICE);
Intent intent=new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
if (powerManager.isIgnoringBatteryOptimizations(getPackageName())) {
intent.setAction(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS);
}
else {
intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse("package:" + getPackageName()));
startActivity(intent);
}
and in the manifest
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"></uses-permission>
But remember this might make your app not approved by Google Play
https://developer.android.com/training/monitoring-device-state/doze-standby.html#whitelisting-cases
Let's say the user open "Settings" application, is there a way to "intercept" this intent, from my app's service, in order to detect that "Settings" app is going to be openned?
For instance, in SOTI MobiControl app you can manage (from a web dashboard) the permissions of the user with the app installed (and enrolled to your server). If you don't allow one user to open Settings app, when he tries to open it, a toast appears saying "Unauthorized". How do they that?
Doing so is against Google Play Developer Program Policy, as it states in its System Interference section:
An app downloaded from Google Play (or its components or derivative
elements) must not make changes to the user’s device outside of the
app without the user’s knowledge and consent.
This includes behavior such as replacing or reordering the default
presentation of apps, widgets, or the settings on the device. If an
app makes such changes with the user’s knowledge and consent, it must
be clear to the user which app has made the change and the user must
be able to reverse the change easily, or by uninstalling the app
altogether.
Apps and their ads must not modify or add browser settings or
bookmarks, add homescreen shortcuts, or icons on the user’s device as
a service to third parties or for advertising purposes.
Apps and their ads must not display advertisements through system
level notifications on the user’s device, unless the notifications
derive from an integral feature provided by the installed app (e.g.,
an airline app that notifies users of special deals, or a game that
notifies users of in-game promotions).
Apps must not encourage, incentivize, or mislead users into removing
or disabling third-party apps except as part of a security service
provided by the app.
https://play.google.com/intl/ALL_us/about/developer-content-policy.html
Is there a way to "intercept" this intent, from my app's service, in
order to detect that "Settings" app is going to be opened?
As other mentioned before it's not possible to intercept a launch intent.
For instance, in SOTI MobiControl app you can manage (from a web
dashboard) the permissions of the user with the app installed (and
enrolled to your server). If you don't allow one user to open Settings
app, when he tries to open it, a toast appears saying "Unauthorized".
How do they that?
It's however possible to determine if an app is opened and "intercept" that call. By intercept I mean draw over the starting app's screen and present a login screen or a not authorized screen.
I haven't worked out a full sample that would work an any Android version but from my research with AppLocks, I'd say it works more or less like this:
On pre-Lollipop Android you'd use this to retrieve the running processes:
ActivityManager manager = (ActivityManager)getSystemService(ACTIVITY_SERVICE);
for (ActivityManager.RunningAppProcessInfo info : manager.getRunningAppProcesses()) {
Log.e("TAG", "Running process: " + info.processName);
if ("com.mycompany.mycoolapp".equals(info.processName)) {
// do stuff...
}
}
requires:
<uses-permission android:name="android.permission.GET_TASKS"/>
or alternatively:
for (ActivityManager.RunningTaskInfo recentTaskInfo : manager.getRunningTasks(100)) {
Log.e("TAG", "Recent tasks: " + recentTaskInfo.baseActivity.getPackageName());
}
On Lollipop and higher you'd use UsageStats to determine if an app is running:
UsageStatsManager usageStatsManager = (UsageStatsManager)getSystemService(USAGE_STATS_SERVICE);
Calendar cal = Calendar.getInstance();
cal.add(Calendar.YEAR, -1);
long start = cal.getTimeInMillis();
long end = System.currentTimeMillis();
List<UsageStats> queryUsageStats = usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, start, end);
for (UsageStats stats : queryUsageStats) {
Log.e("TAG", "Usage stats for: " + stats.getPackageName());
}
requires:
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
I would probably run both using the AlarmManager to perform that recurring task.
I'm fairly certain these are the two ways to get the list of running apps. If the permission for usage stats is denied to AppLock it's not working any more an Android 6.0 devices. On pre-M devices it however still works which is an indicator that the app has an alternative way to get the list of running apps (the first option described above).
Once it's determined an app has been started (it's running and hasn't been running the last time we checked), we can "take over" the screen. And that's how I'd do it: http://www.piwai.info/chatheads-basics/
Of course that's just the basic idea and I'm sure there are a couple of pitfalls when implementing a reliable solution but this should give you something to start with.
Let's say the user open "Settings" application, is there a way to "intercept" this intent, from my app's service, in order to detect that "Settings" app is going to be openned?
No, unless you are the one that is calling startActivity() to launch the application in the first place.