I want to start a Notification Service with an AlarmManager. However, it doesn't alyways work, when swiped the app in the recent tasks layer. I have also tried out JobIntentService and JobService with the propriate entries in the Manifest, everything resulted in the same problem: The Notification or also startActivity() don't get called (sometimes!, maybe when in doze mode?) after I closed the app.
Now, I thought to maybe go back to the AlarmManager, as it seems to work for other people here.
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
{
AlarmManager alarmManager = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(getActivity(), AlertReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getActivity(), 1, intent, 0);
if(Build.VERSION.SDK_INT <= 23)
{
alarmManager.setExact(AlarmManager.RTC_WAKEUP, timeForAlarm, pendingIntent);//Alarm with setExact and AlertReceiver should be better than the old Alarm Manager
}
else
{
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, timeForAlarm, pendingIntent);//Alarm with setExact and AlertReceiver should be better than the old Alarm Manager
}
}
else
{
final AlarmManager alarm = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(getActivity(), Service_Notification.class);
PendingIntent startPendingIntent = PendingIntent.getService(getActivity(), 0, intent, 0);
alarm.set(AlarmManager.RTC_WAKEUP, timeForAlarm, startPendingIntent);
}
This is my AlertReceiver for Versions above KitKat (I also tried extends BroadCastReceiver)
public class AlertReceiver extends WakefulBroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
context.startService(new Intent(context, Service_Notification.class));
}
}
So, what can I do now? Thank you in advance
I came across the same issue. It seems the policy for background task has been changed a lot since Oreo. You could check the WorkManager in Jetpack. It simplifies a lot the use cases across different OS version.
OneTimeWorkRequest.Builder ob = new OneTimeWorkRequest.Builder(YourWorker.class)
.setConstraints(constraints)
.setInitialDelay(delayed, TimeUnit.MILLISECONDS)
.addTag(yourWorkerTag);
WorkManager.getInstance().beginUniqueWork(orderTag, ExistingWorkPolicy.REPLACE, ob.build()).enqueue();
And then start your Notification Service in YourWorker. It's done!
Related
In my project I am using AlarmManager in order to trigger daily AlarmClock but when the time comes to start an alarm following toast message occurs:
Background activity start from com.example.nameOfApp blocked. See g.co/dev/bgblock
Updated code:
-------setAlarmClock method-------
private void setAlarmClock(Calendar calendar, int alarmId, String time, String timeOfTheDay, boolean action) {
AlarmManager manager = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(getActivity(), AlarmClockReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getActivity(), alarmId, intent, 0);
if (action) {
manager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, pendingIntent);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
manager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
}
} else {
manager.cancel(pendingIntent);
}
}
-------AlarmClockReceiver class-------
public class AlarmClockReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String alarmAction = AlarmClock.ACTION_SET_ALARM;
Intent i = new Intent(alarmAction);
i.putExtra(AlarmClock.EXTRA_SKIP_UI, true);
i.putExtra(AlarmClock.EXTRA_MESSAGE, "Time for taking medicine!");
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
}
Moreover in AndroidManifest I included following line:
<uses-permission android:name="com.android.alarm.permission.SET_ALARM"/>
I am aware that it's connected with new Android Q privacy change. From the aforementioned link it's said:
Apps running on Android Q can start activities only when one or more of the following conditions are met:
...
The app receives a notification PendingIntent from the system. In the case of pending intents for services and broadcast receivers, the app can start activities for a few seconds after the pending intent is sent.
If I understood it correctly this is exactly my case. Nevertheless aforementioned toast message occurs.
The PendingIntent is valid (in order to start an activity) only if you set the intent in a notification using the method setContentIntent. So what you can do is to post a notification instead of starting directly an activity. When the user tap on the notification the pending intent will be used to start the activity.
Edit: as alternative you need to ask the SYSTEM_ALERT_WINDOW permission but you won't be able to execute the app on Android Go because it's not possible to use this permission on that version.
I'd like to repeat an alarm every 20 minutes.
So I tried:
manifest:
<receiver android:name=".AlarmReceiver" />
AlarmReceiver.class
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent intent2 = new Intent(context, MainActivity.class);
showNotification(context, "text", "text", intent2);
Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Ringtone r = RingtoneManager.getRingtone(context, notification);
r.play();
}
#TargetApi(Build.VERSION_CODES.N)
public void showNotification(Context context, String title, String body, Intent intent) {
...
}
}
and in my main activity:
AlarmManager alarmMgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
Calendar time = Calendar.getInstance();
time.setTimeInMillis(System.currentTimeMillis());
time.add(Calendar.SECOND, 1200);
alarmMgr.set(AlarmManager.RTC_WAKEUP, time.getTimeInMillis(), pendingIntent);
It is working only the first time. I'd like to keep it repeating even when the app is not opening, any ideas?
Starting with KitKat (API 19), alarms are all inexact, meaning the system will batch alarms around similar times together. If you need exact timing, there are different APIs to call. Further complicating things, starting with Marshmallow, Android introduced the concept of Doze, which further restricts the when/how things can wake up the device. You can still use exact alarms, but need to use the API which allows it during idle (Doze) time: setAndAllowWhileIdle(). Bear in mind that when your alarm fires, you could be in a Doze window and your app will be restricted on what kinds of operations it can perform.
Try below for Repeating alarm on every 20 minutes interval
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, time.getTimeInMillis(),1000 * 60 * 20, pendingIntent);
Try to use android worker manager since it is working with doze mode as well. https://developer.android.com/reference/androidx/work/PeriodicWorkRequest#min_periodic_interval_millis
https://developer.android.com/reference/androidx/work/PeriodicWorkRequest
Since the introduction Doze Mode and App StandBy managing alarms have changed. The problem I'm facing is my alarm manager fires correctly on KitKat, Lolipop and Marshmellow devices but above API 23 it does not fire unless the app is in foreground or background. But if the app is killed, the alarms are stopped.
Checked out Google Keep Application on my Android 7, turns out it does the same.
But Google Calendar fires regardless of whether the app is killed or not.
Done some reading and found out setExactAndAllowWhileIdle method on the alarm manager ensures to break the doze mode and trigger your alarm.
But it does not work, is there anything I'm missing here?
Here's my code:
Intent alertIntent = new Intent(this, NotificationPublisher.class);
alertIntent.putExtra("Hello", "Meal Time");
AlarmManager alarmManager = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
int id = (int) System.currentTimeMillis();
if (Build.VERSION.SDK_INT < 23) {
if (Build.VERSION.SDK_INT >= 19) {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, delay, PendingIntent.getBroadcast(this, id, alertIntent, PendingIntent.FLAG_UPDATE_CURRENT));
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP, delay, PendingIntent.getBroadcast(this, id, alertIntent, PendingIntent.FLAG_UPDATE_CURRENT));
}
} else {
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, delay, PendingIntent.getBroadcast(this, id, alertIntent, PendingIntent.FLAG_UPDATE_CURRENT));
}
Broadcast Receiver:
public class NotificationPublisher extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String message = intent.getStringExtra("Hello");
Log.d("Called", "Meal Time");
}
Manifest:
<uses-permission android:name="android.permission.WAKE_LOCK" />
<receiver android:name=".NotificationPublisher" />
Because of battery optimisation it is not working,i turned off the battery optimisation of particular app, it is working fine in oneplus 3.
You wanna white-list your app from battery optimisation programatically, check this link stackoverflow.com/a/42651399/3752079
Try with adding below line for your alertIntent
myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0,myIntent, 0);
I used AlarmManager to set time and expect to do some work in the future. Almost case it work well without problem. But sometimes (just sometimes), the alarm not fired. It is difficult to reproduce the issue and I still do not know the reason.
I got this issue on several OS version : 4.4, 5.1, 6.0, 6.1, 7.0.
I already used WakefulBroadcastReceiver to start a service with Wakelock, but the issue still happen.
Below is my code to schedule a alarm.
Intent alarmIntent = new Intent(context, AlarmReceiver.class);
alarmIntent.putExtra("todo_id", myTodo.getId());
alarmIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, myTodo.getId(), alarmIntent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
AlarmManager.AlarmClockInfo alarmClockInfo = new AlarmManager.AlarmClockInfo(calendar.getTimeInMillis(), pendingIntent);
alarmManager.setAlarmClock(alarmClockInfo, pendingIntent);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
}
public class AlarmReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
LogUtil.debug("onReceive()");
if (null != intent.getExtras()) {
int id = intent.getIntExtra("todo_id", -1);
if (id != -1) {
Intent myIntent = new Intent(context, AlarmService.class);
myIntent.putExtra("todo_id", id);
LogUtil.debug("Receiver receive todo id: "+id );
startWakefulService(context, myIntent);
}
}
}
}
public class AlarmService extends Service {
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
LogUtil.debug("Service onStartCommand");
int id = intent.getIntExtra("todo_id", -1);
LogUtil.debug("Service receive todo id: " + id);
// do some stuff here
AlarmReceiver.completeWakefulIntent(intent);
return START_REDELIVER_INTENT;
}
Does anyone have the same issue like me ? And what is your solution ?
Maybe this issue come from Android SDK, they made AlarmManager work unstable.
I had the same issue , i solved this issue by doing all my logic in AlarmReceiver. I was also starting service in receiver which hold my alarm logic. But once i move my code into alarm receiver it works fine. Mine issue was i wasn't ending my service , it kept on running and causing some issue or might be other reasons but it solved my issue. You should try and let me know if this help.
I have a big problem with Android KitKat and Alarm Manager.
All my apps work with a service that always run in background without Android kill it.
Before Android 4.4 KitKat the solution I found was to start the service through a BroadcastReceiver triggered by an AlarmManager.
...
Intent intent = new Intent(c, MyReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(c, 0, intent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager am = (AlarmManager) c.getSystemService(Context.ALARM_SERVICE);
if (Build.VERSION.SDK_INT<Build.VERSION_CODES.KITKAT) {
am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), pendingIntent);
} else {
setAlarmFromKitkat(am, System.currentTimeMillis(), pendingIntent);
}
...
#TargetApi(19)
private static void setAlarmFromKitkat(AlarmManager am, long ms, PendingIntent pi){
am.setExact(AlarmManager.RTC_WAKEUP, ms, pi);
}
...
public class MyReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent service = new Intent(context, MyService.class);
context.startService(service);
}
}
On Android 4.4 KitKat by this solution I can start service but after some time Android kill it!
Is there a way to have a Service that works in background without Android 4.4 KitKat kill it?
Many Thanks
For Android Kitkat version
If your app uses AlarmManager...
When you set your app's targetSdkVersion to "19" or higher, alarms that you create using either set() or setRepeating() will be inexact.
To improve power efficiency, Android now batches together alarms from all apps that occur at reasonably similar times so the system wakes the device once instead of several times to handle each alarm.
If your alarm is not associated with an exact clock time, but it's still important that your alarm be invoked during a specific time range (such as between 2pm and 4pm), then you can use the new setWindow() method, which accepts an "earliest" time for the alarm and a "window" of time following the earliest time within which the system should invoke the alarm.
If your alarm must be pinned to an exact clock time (such as for a calendar event reminder), then you can use the new setExact() method.
This inexact batching behavior applies only to updated apps. If you've set the targetSdkVersion to "18" or lower, your alarms will continue behave as they have on previous versions when running on Android 4.4.
Original Source:
http://developer.android.com/about/versions/android-4.4.html
in kitkat,use the code snippet below to restart te service automatically:
#Override
public void onTaskRemoved(Intent rootIntent) {
// TODO Auto-generated method stub
Intent restartService = new Intent(getApplicationContext(),
this.getClass());
restartService.setPackage(getPackageName());
PendingIntent restartServicePI = PendingIntent.getService(
getApplicationContext(), 1, restartService,
PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmService = (AlarmManager)getApplicationContext().getSystemService(Context.ALARM_SERVICE);
alarmService.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() +1000, restartServicePI);
}