Keep alarmmanager when app gets closed - android

Well i have searched about 5 hours but no answer seems to do the trick. My app will keep tracking postal objects from a website, and needs to make a refresh every X (user defines it) amount of time to check for updates on the site, so the user will be aware of it and even can turn this feature off if he wants (i will cancel the alarmmanagers manually if so).
What I need to do is something like whatsapp, facebook or gmail, that checks for messages even with the app closed, and send user some notification. But that just seems impossible... I checked with "adb shell dumpsys alarm" and the alarm is there, but only while the app is running. I know this is the exactly expected thing to happen, but how does these other apps always set their AlarmMannagers againd when app is closed?
My current code:
Manifest:
<service android:name="services.HelloService"
android:process=":remote"/>
<receiver android:name="entidade.NotificationPublisher">
<intent-filter>
<action android:name="IWillStartAuto" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
HelloService:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
System.out.println("Hello Service Starting...");
ArrayList<Objeto> list = new ObjetoDAO(this).getAllObjetos(); //Sets the alarms...
for(int i=0; i<list.size(); i++){
if(!list.get(i).isArquivado())
list.get(i).setAlarme(this);
}
return START_STICKY;
}
#Override
public void onDestroy() {
System.out.println("Hello Service Ending...");
sendBroadcast(new Intent("IWillStartAuto"));
}
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
sendBroadcast(new Intent("IWillStartAuto"));
}
NotificationPublisher:
public class NotificationPublisher extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
ArrayList<Objeto> lista = new ObjetoDAO(context).getAllObjetos(); //list of tracked objects
for(int i=0; i<lista.size(); i++){
if(!lista.get(i).isArquivado()) //sets the AlarmMannager if users want it...
lista.get(i).testeNotificacao(context);
}
}}
UPDATE: Code used to set the alarm...
AlarmManager:
public void setAlarme(Context context) {
if (!isArquivado()) {
int idDoAlarme = getId();
Calendar calendar = Calendar.getInstance();
long interval = AlarmManager.INTERVAL_FIFTEEN_MINUTES;
Intent notificationIntent = new Intent(context, NotificationPublisher.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, idDoAlarme, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), interval, pendingIntent);
}
}
Also noted something: tested the app on my old phone (LG E435f, with Android 4.1.2) and surprise, the Alarm is still set after the app gets closed. So, could it be something with my phone (Lenovo K5 A6020l36, with Android 5.1.1)? But in this case, how are whatsapp and gmail still running their alarms on this phone with the apps closed?

I notice in your question that you want to send notification from server to your user like whats-app, Facebook, etc. even when app is closed.
Have you read about Firebase Cloud Messaging (FCM) or Google Cloud Messaging (GCM), I think this would more suit to your problem. Click Here to know more about it.

Set up your AlarmManager to fire at your predetermined date\time.
When it fires, your code will run so just repeat step 1 to set up the next time you want it to fire and then perform whatever functions you need to in order to check your site (start a service that does this)
Repeat from step 2
Don't forget that alarms do not survive a reboot of the device so you will need to set it up again if the device restarts.

Well, if the user kills your app, than it depends on the manofacturer. Some kill only the process, others kill the process along with services, broadcasts, alarmmangers (etc.) associated with the process.
Maybe the GCM can survive this kill process, as you sayd that whatsapp does get its notifications...

Related

Chinese Android Devices Killing Background Service

I am trying to run a background service in an android application. I have tried the standard way of doing it and a lot of other tweaks. The problem is that when the application is closed from recent apps, the service gets killed. This only happens in Chinese Android devices like Oppo, Vivo, Xiomi, etc. It works fine on all other brands.
I have tried the following solutions.
Over-riding the OnStartCommand() of activity to return START_STICKY. This still not re-starts activity after the application is closed as expected.
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
Added the application to exceptions of battery saving, so that it doesn't close it to save battery in DOZE mode.
Gave the application permission to Auto-Start from the security settings of phone.
Started the service as a foreground service, including a persistent notification.
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
String input = intent.getStringExtra("inputExtra");
createNotificationChannel();
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Foreground Service")
.setContentText(input)
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentIntent(pendingIntent)
.build();
startForeground(1, notification);
//do heavy work on a background thread
//stopSelf();
return START_NOT_STICKY;
}
Implemented Alarm Manager approach of starting service after it gets killed in onTaskRemoved() and onDestroy() methods of service.
<service
android:name=".MyService"
android:enabled="true"
android:exported="true"
android:stopWithTask="false" />
#Override
public void onTaskRemoved(Intent rootIntent){
Log.d("Service:","I am being closed!");
Intent restartServiceIntent = new Intent(getApplicationContext(), this.getClass());
restartServiceIntent.setPackage(getPackageName());
PendingIntent restartServicePendingIntent = PendingIntent.getService(getApplicationContext(), 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
alarmService.set(
AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + 1000,
restartServicePendingIntent);
super.onTaskRemoved(rootIntent);
}
I have also tried using a broadcast manager to start my service receiving a broadcast from activity when it is closed.
<receiver
android:name=".SensorRestarterBroadcastReceiver"
android:enabled="true"
android:exported="true"
android:label="RestartServiceWhenStopped"
/>
public class SensorRestarterBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.i(SensorRestarterBroadcastReceiver.class.getSimpleName(), "Service Stops!");
context.startService(new Intent(context, MyService.class));;
}
}
However, the service is not started again in these chinese devices specifically. While background services of Whatsapp, Facebook and some famous apps return after a few minutes of closing the app. Please suggest the correct way to achieve this.
I have tried solutions provided at Background Service is not restarting after killed in oppo, vivo, mi android version 7.1.2 as also described above. It doesn't solve my problem.
This will happen mostly for optimizing battery and improving phone performance,
As you have tried my solution but still you are getting this issue in some devices,
so here is an alternate solution for killing app on swipe from recent app list,
Ask User to Swipe down the application which will lock application as white list and wont be killed
OR
Add below line for every activity in manifest, which will hide your app from recent app list. hence user cant swipe app from recent apps list.
android:excludeFromRecents="true"
These brands have a white list of apps that can survive normally. If your app not in white list os force stops any app that swiped at recents screen. You must tell user to add your app to whitelist manually.

How to ensure that an AlarmManager fires even if the android app is closed?

I have an app that should update/get data from a server every six hours. To do so I made an AlarmManager the following way:
public class Repository {
public static AlarmManager alarmManager;
public static void initAlarmManager(Context context){
//start the update alarm manager
Intent resultIntent = new Intent(context,AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, 0, 60 * 60 * 1000, pendingIntent);
}
My AlarmReceiver now has to look for updates and if there is new data of a specific condition it has to notify the user via a notification. This is a part of my AlarmReceiver:
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if(Repository.ddfDb == null){
Repository.initDdfDb(context);
}
if(Repository.alarmManager == null){
Repository.initAlarmManager(context);
}
for(Episode episode : Repository.ddfDb.getListOfNextEpisodes()){
Notification.showNotification(context,episode);
}
}
}
Since my AlarmManager should run all the time I let him start also when boot is completed. To do so I added the following to my manifest file:
<receiver android:name=".AlarmReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
I run the function initAlarmManager() in my onCreate() of the mainActivity. So if the app is started, the AlarmManager starts too and everything works fine. Even if I close my app via the home button or change to another app via the "change between recent apps" button, my AlarmManager still fires and I get the notifications although my app is in the background.
I also run the function initAlarmManager() in my AlarmReceiver. So if I reboot my phone, the receiver gets called, sees that my AlarmManager is null and inits it afterwards. So everything works fine here too.
But here is my problem: If I press the "change between recent apps" button and close my app with a swipe my AlarmManager stops and I won't get any further notifications. This is weird, since after a reboot my app also doesn't appear in the recent apps menu but there it works.
I googled a lot and some people say it is impossible, since if the user really wants to close the app, he has to be able to do so. I understand this, since it provides security against virus apps. But also I see apps like WhattsApp being able to always notify the user.
So is there really no way to accomplish my always running AlarmManager or if there is a way, how do I implement this?
Thank you in advance!
I solved this issue the following way:
I moved all operations I did in the BroadcastReceiver to an IntentService. All the BroadcastReceiver now does is starting this IntentService.
When the app is now closed by swiping it away from the recent apps menu, my notifications still pop up.
Thanks to Muthu for giving me the right hint!

How to automatically restart a service even if user force close it?

I want a service to run all the time in my application. So I want to restart it even if it is force closed by user. There is definitely a way to do it as apps like facebook are doing it. It's not done using push notification, facebook restarts its service even if internet is off.
First of all, it is really very bad pattern to run service forcefully against the user's willingness.
Anyways, you can restart it by using a BroadcastReceiver which handles the broadcast sent from onDestroy() of your service.
StickyService.java
public class StickyService extends Service
{
private static final String TAG = "StickyService";
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand");
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
sendBroadcast(new Intent("YouWillNeverKillMe"));
}
}
RestartServiceReceiver.java
public class RestartServiceReceiver extends BroadcastReceiver
{
private static final String TAG = "RestartServiceReceiver";
#Override
public void onReceive(Context context, Intent intent) {
Log.e(TAG, "onReceive");
context.startService(new Intent(context.getApplicationContext(), StickyService.class));
}
}
Declare the components in manifest file:
<service android:name=".StickyService" >
</service>
<receiver android:name=".RestartServiceReceiver" >
<intent-filter>
<action android:name="YouWillNeverKillMe" >
</action>
</intent-filter>
</receiver>
Start the StickyService in a Component (i.e. Application, Activity, Fragment):
startService(new Intent(this, StickyService.class));
OR
sendBroadcast(new Intent("YouWillNeverKillMe"));
You have to create a sticky service with overriding onTaskRemoved method, where you can set an alarm service to trigger your code again.
public class BackgroundService extends Service {
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
#Override
public void onTaskRemoved(Intent rootIntent) {
//create an intent that you want to start again.
Intent intent = new Intent(getApplicationContext(), BackgroundService.class);
PendingIntent pendingIntent = PendingIntent.getService(this, 1, intent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, SystemClock.elapsedRealtime() + 5000, pendingIntent);
super.onTaskRemoved(rootIntent);
}
}
Also in some devices like Xiaomi, Huwaei the app gets force closed once it's removed from recent apps. This is because the manufacturers have task manager features which improve ram/battery performance.
You can check this link for more information: https://stackoverflow.com/a/41360159/2798289
As per the Android document
Starting from Android 3.1, the system's package manager keeps track of applications
that are in a stopped state and provides a means of controlling their launch from
background processes and other applications.
Note that an application's stopped state is not the same as an Activity's stopped
state. The system manages those two stopped states separately.
FLAG_INCLUDE_STOPPED_PACKAGES — Include intent filters of stopped applications in the
list of potential targets to resolve against.
FLAG_EXCLUDE_STOPPED_PACKAGES — Exclude intent filters of stopped applications from the
list of potential targets.
When neither or both of these flags is defined in an intent, the default behavior is to
include filters of stopped applications in the list of potential targets.
Note that the system adds FLAG_EXCLUDE_STOPPED_PACKAGES to all broadcast intents.
It does this to prevent broadcasts from background services from inadvertently or
unnecessarily launching components of stopped applications. A background service
or application can override this behavior by adding the FLAG_INCLUDE_STOPPED_PACKAGES
flag to broadcast intents that should be allowed to activate stopped applications.
On Force stop of app, Android just kill the process ID. No warnings, callbacks are given to service/activities. As per the Android document, When the app is killed there are chances that it calls onPause().
When I tried in my app, even onPause() was not called. I think the only way is use to FLAG_INCLUDE_STOPPED_PACKAGES intent flag and send it from another app
If I understand correctly, then actually this is not possible, Android feature to force close application was designed to allow user to get rid of unwanted applications, so it disallows any activities from it until user again starts any of its Activity.
Restart the service even if app is force-stopped and Keep running service in background even after closing the app How?
Whenever a service is killed, its onDestroy method is always called.
Its better to use a BroadcastReceiver to start your service when it is killed.
Here is a sample code illustrating its implementation:-
#Override
public void onDestroy() {
Intent in = new Intent();
in.setAction("StartkilledService");
sendBroadcast(in);
Log.d("debug", "Service Killed");
}
Then register a receiver in AndroidManifest.xml:-
<receiver android:name=".app.ServiceDestroyReceiver" >
<intent-filter>
<action android:name="StartKilledService" >
</action>
</intent-filter>
</receiver>
Finally,create a BroadcastReceiver,and start your service in the onReceive method:-
#Override
public void onReceive(Context context, Intent intent) {
Log.d("debug", "ServeiceDestroy onReceive...");
Log.d("debug", "action:" + intent.getAction());
Log.d("debug", "Starting Service");
ServiceManager.startService();
}
Hope this helps.
on the service's startCommand method return START_STICKY. generally it tell the OS to start the service when it is killed.
If the situation allows to use 'root' it's usually possible to implement Humpty-Dumpty paradigm.
Your application (1st) installs another application (2nd, taking APK from assets) and runs the service of the 2nd app.
2nd app's service bind to the 1st app service and rebinds when disconnected. The 1st app does the same.
Sure it will not help when all apps are killed by some Free RAM or similar application but when Android kills either of those two, the other one will restart its counterpart.
The only real solution for keeping services alive ist to call Service.startForeground(...) with a provided Notification. This will be the only valid solution, every other one will be very dependent on how Google will change the behaviour of it's system. With every API update, Google could prevent every other hack.
This also keeps the user aware, that your app is performing some background task which will keep the app alive and the user has to stop this. If you provide the user the ability to stop it is part of your application, though.
See the Documentation:
void startForeground (int id, Notification notification)
Make this service run in the foreground, supplying the ongoing notification to be shown to the user while in this state. By default services are background, meaning that if the system needs to kill them to reclaim more memory (such as to display a large page in a web browser), they can be killed without too much harm. You can set this flag if killing your service would be disruptive to the user, such as if your service is performing background music playback, so the user would notice if their music stopped playing.
There is a very hacky solution to keep service running even you force stop it. I do not recommend that because it is against user willingness. You can define a broadcast receiver to receive intent with action X. onStartCommand handler of your service, broadcast X (if the service is not started yet). on broadcast receiver upon receipt of X, first start the service, then, sleep for some minutes, and finally re-broadcast X.
I think the only foolproof solution here is to have 2 services in separate processes (android:process="somecustomprocessname" in manifest, in the service entry) that both listen to broadcasts and restart each other, because currently the UI doesn't let users kill multiple processes in one action. You can then set up a pinger thread in each service that checks if the other service is running every 100 milliseconds or so, and if not, attempts to restart it. But this is starting to look more and more like malware...

Alarm doesn't trigger after reboot

I have an alarm to reset a data connection say every 15 minutes. The problem is, once the phone is rebooted, the application gets killed and the alarm (service) doesn't trigger anymore.
(This is not a duplicate, the other similar questions on SO do not solve my problem.)
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<receiver
android:name="com.sang.mobiledata.ResetBroadcastReceiver"
android:exported="false" >
<intent-filter>
<action android:name="com.sang.mobiledata.IntentAction.RECEIVE_RESETCONN_UPDATE" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
Broadcast Receiver:
public void onReceive(Context context, Intent intent) {
// if(CONN_ACTION.equals(intent.getAction())) {
if (intent.getAction().equalsIgnoreCase(
"com.sang.mobiledata.IntentAction.RECEIVE_RESETCONN_UPDATE")) {
MainActivity objMain = new MainActivity();
objNetwork.setMobileDataEnabled(context, false);
objNetwork.setMobileDataEnabled(context, true);
}
if (intent.getAction().equalsIgnoreCase(
"android.intent.action.BOOT_COMPLETED")) {
// code to restart/resume/retain alarm
Code to fire alarm (on the onClick):
Intent myIntent = new Intent(
"com.sang.mobiledata.IntentAction.RECEIVE_RESETCONN_UPDATE");
myIntent.putExtra("FLAG_KEY", false);
PendingIntent pi = PendingIntent.getBroadcast(this, 0, myIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) this
.getSystemService(Context.ALARM_SERVICE);
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, 10);
long interval = intHrs * 3600000 + intMins * 60000;
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(), interval, pi);
long mins = interval / 60000;
Toast.makeText(
MainActivity.this,
"Data Connection will be reset every " + mins
+ " minute(s).", Toast.LENGTH_SHORT).show();
}
Any suggestions please?
Read the AlarmManager document, there it is written, that AlarmManager will not hold alarms after reboot.
As per the Android Developers,
.... Registered alarms are retained while the device is asleep (and can optionally wake the device up if they go off during that time), but will be cleared if it is turned off and rebooted.
And regarding BOOT_COMPLETED, they write:
... This is broadcast once, after the system has finished booting. It can be used to perform application-specific initialization, such as installing alarms. You must hold the RECEIVE_BOOT_COMPLETED permission in order to receive this broadcast.
As for permission is concerned, you have already registered that. Well what probably happening is, the service BOOT_COMPLETED is being used locally, with the application. The reboot of the mobile is system activity, which is not overridden to accomplish re-registry of the alarms being saved. But I am not sure. So, you need to do something when execution comes in hand of BOOT_COMPLETED.
Read Automatically starting Services in Android after booting, this might help you with it.
What I did was, I registered all the alarms and formed a database, using SQLite; On restart, I use to reset all the alarms. Well that worked for me. If you want to go with my process then,
Make a database for your alarms, and save them there. Write your application in such a way that, when the phone restarts, the AlarmManager resets all the alarms. This is how it works.
In Automatically starting Services in Android After booting again. It is written:
Also note that as of Android 3.0 the user needs to have started the application at least once before your application can receive android.intent.action.BOOT_COMPLETED events.

android service stops working after application is not in use for awhile

I have a service for my application that runs fine, but when a user is not using there phone for while like 20 minutes the service just doesnt work any more. is there something i suppose to be doing like saving a state or something, i am lost at this point. I dont see why the service doest keep running, I look in the application>running services on my phone and it still says its running. Any suggestions?
I faced the same problem few time back. Then I started to use Android Alarm Service. That solved my problem. Here is a reference link http://android-er.blogspot.com/2010/10/simple-example-of-alarm-service-using.html
If you want to keep running in the background (e.g. downloading something), you need to grab a wakelock (http://developer.android.com/reference/android/os/PowerManager.html)
Also, look at the following if you happen to do downloads in the background:
http://developer.android.com/reference/android/net/ConnectivityManager.html#getBackgroundDataSetting()
You can use Broadcast receiver instead to use like service.
And it can be called same as Service with alarm manager.
Receiver:
public class CallListReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Call List receiver called", Toast.LENGTH_LONG)
.show();
}
}
You can continuously call it using:
public void startAlert(Context context) {
Intent call_intent = new Intent(this, CallListReceiver.class);
PendingIntent pendingCallIntent = PendingIntent.getBroadcast(context,
0, call_intent, 0);
AlarmManager call_alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
call_alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
System.currentTimeMillis(), (7 * 1000), pendingCallIntent);
}
This Android's behavior that A Service has maximum life of 20 minutes. After 20 Minutes, it will be automatically killed by Android OS. But i think that there is a solution. i dont have tested it yet. The Solution is:
In your onStartCommand(), put this code at the end of this method
return START_STICKY;

Categories

Resources