In service there is a receiver:
IntentFilter mFilter = new IntentFilter();
mFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
mFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
mFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
mFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION);
mFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
Service is a foreground service
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
...
startForeground(NOT_ID, getNotification(type));
return START_STICKY;
}
Service has notification running all time. When the service is "paused" notification is ok.
Problem:
When the USB charger is unplugged (The same thing happens connected to a PC or to a normal charger.) and the test is performed on Android 9 the receiver does not capture events, connection events, for example change Wi-Fi, connect by data or lose connection.
If I plug USB in, the events detectios works ok. To see the events I am using a test interface, not logcat.
I understand that this happens because I suppose in Android 9 the system pauses the services to save battery when the device is not plugged in.
Is there any way in Android 9 that the receiver is called when the USB is unpluged?
I tested in Android 8.1 and service is not paused.
Note: I can not declare the receiver in the manifest because from Android 6 it can not be done for battery reasons.
More info: To do the tests all the activities are completely closed and only the service and the notification is showing. If some activity is visible to user receiver works ok.
App is targeting to 27 and I am testing on android oreo 8.0 device.
compileSdkVersion 27
targetSdkVersion 27
When user clicks on the download button, app starts a foreground intent service and also notifies the user through a notification.
Within the onCreate of IntentService , app also fulfils the promise to call the startForeground(int id, Notification notification) method.
So,
//On click of download button
ContextCompat.startForegroundService(context, intent);
//Within the onCreate() of IntentService()
startForeground(id, notification);
In case when app is in foreground, everything works perfect. But when user swiped out and thus kills the app; I restart the download and it works, downloading starts; but android system displays a notification - "<#appname#> is running in background".
So user now can see two notification
one from my app showing the download progress and
another from android system, showing that my app is running in background.
Is this fine? How can I avoid the notification from android system?
Here is how I manage swipe out app kill:
#Override
public void onTaskRemoved(Intent rootIntent) {
Context localContext = getApplicationContext();
Intent restartServiceIntent = new Intent(localContext,
HandlePendingDownload.class);
restartServiceIntent.putExtra(DMConstants.ACTION_SWIPE_OUT, Boolean.TRUE);
restartServiceIntent.setPackage(getPackageName());
PendingIntent restartServicePendingIntent = PendingIntent.getBroadcast(
localContext, 1, restartServiceIntent,
PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmService = (AlarmManager) localContext
.getSystemService(Context.ALARM_SERVICE);
if (FWCompat.isKitKat_19_OrNewer()) {
alarmService.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + 1900,
restartServicePendingIntent);
} else {
alarmService.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + 1900,
restartServicePendingIntent);
}
super.onTaskRemoved(rootIntent);
}
Then later within onReceive() I call :
ContextCompat.startForegroundService(context, downloadIntent);
So to summarize,
Once the app is killed how to avoid the notification shown from android system, that the app is running in background? as I am already showing download notification to user, so the user is aware of that.
Also one more question, is there any way to get the intent withing onCreate() of IntentService?
I need to get the id of download content, which is passed in the intent as extra param. Cause based on this I can show the notification within onCreate()
As of now I am showing one "starting download" notification, then in onStartCommand() I clear that notification and create a new notification based on content Id.
From Android Documentation
Foreground
A foreground service performs some operation that is noticeable to the user. For example, an audio app would use a foreground service to play an audio track. Foreground services must display a Notification. Foreground services continue running even when the user isn't interacting with the app.
https://developer.android.com/guide/components/services.html
If the notification isn't properly started, then the service will be killed. Maybe you are looking for a different type of service. Maybe look into a bound service?
Bound A service is bound when an application component binds to it by
calling bindService(). A bound service offers a client-server
interface that allows components to interact with the service, send
requests, receive results, and even do so across processes with
interprocess communication (IPC). A bound service runs only as long as
another application component is bound to it. Multiple components can
bind to the service at once, but when all of them unbind, the service
is destroyed.
I am working on Android App which supports BLE devices.
In some mobile with Android 6. app is and ble service is killing by OS.
Is anyone having any idea how to keep running my app in background and after killing the app?
Using START_STICKY on service:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;}
Start your service in foreground by startForeground(), the in will be no affected by doze mode
I am trying to solve a problem similar to your. I think to have a Service always on you must acquire a wakeLock, see here: https://developer.android.com/reference/android/os/PowerManager.html
I'm working on location tracking application using FusedLocationProvider. I have a background service which tracks location of phone in every 5 minutes.
All works well with it, but once the phone goes idle then after 3 to 4 hours of time, the background service stops to take location. When user unlocks the phone the tracking start again.
Can someone please guide me what could be causing the issue?
One possibility could be Android M Doze Mode. When the device is unplugged and stationary for a period of time, the system attempts to conserve battery by restricting apps access to CPU-intensive services. Doze mode starts after about 1h of inactivity, periodic tasks etc. are then scheduled to maintenance windows. When the user unlocks the device, doze mode is turned off again.
You find more information about Doze Mode in the developer docs:
http://developer.android.com/training/monitoring-device-state/doze-standby.html
Maybe your service is being stopped because the phone needs to free up memory so it kills your service. Make sure your service is set as a foreground service.
A foreground service is a service that's considered to be something the user is actively aware of and thus not a candidate for the system to kill when low on memory. A foreground service must provide a notification for the status bar, which is placed under the "Ongoing" heading, which means that the notification cannot be dismissed unless the service is either stopped or removed from the foreground.
http://developer.android.com/guide/components/services.html
Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),
System.currentTimeMillis());
Intent notificationIntent = new Intent(this, ExampleActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, getText(R.string.notification_title),
getText(R.string.notification_message), pendingIntent);
startForeground(ONGOING_NOTIFICATION_ID, notification);
Android will put your service to sleep after being idle for a while. You can use WakeLock to prevent that from happening.
public int onStartCommand (Intent intent, int flags, int startId)
{
PowerManager mgr = (PowerManager)getSystemService(Context.POWER_SERVICE);
mWakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock");
mWakeLock.acquire();
...
return START_STICKY;
}
public void onDestroy(){
...
mWakeLock.release();
}
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).