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
Related
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);
So I am having an issue with AlarmManager. I am trying to run some code every 2 minutes, which works okay while the phone is awake, but not when the device goes to sleep - during sleep, the intervals are perfectly 5 minutes apart.
Since my desired interval is 2 minutes, this is roughly 250% off my target interval, which for my specific application is not acceptable.
I am aware of the changes in API 19, and have followed suggestions to re-schedule the alarm using setExact() within my BroadcastReceiver. Code is below:
The code used to trigger BroadcastReceiver:
Intent intent = new Intent(this, AlarmReceiver.class);
final PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
mAlarmManager = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 3000, pendingIntent);
And this code is in my BroadcastReceiver which re-schedules the alarm:
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "AlarmService Triggered.", Toast.LENGTH_SHORT).show();
Log.d(this.getClass().getSimpleName(), "Service triggered");
Intent newIntent = new Intent(context, this.getClass());
mPendingIntent = PendingIntent.getBroadcast(context, 0, newIntent, 0);
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
alarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 120000, mPendingIntent);
}
Does anyone have suggestions as to how I could fix this? It is very frustrating that AlarmManager is totally ignoring my wish to have an alarm fire at an exact time. Is there any alternative that will allow me to schedule code at 2 minute intervals like I want?
DEVICE: Samsung Galaxy S6, OS 5.1.1
As #Francesc suggested, it ended up being the Samsung device. Tried it on another phone, now it works flawlessly.
Let this be a lesson to you - don't buy Samsung, they do weird stuff, lol.
Replace ELAPSED_REALTIME_WAKEUP with RTC_WAKEUP.
This is how I schedule alarms:
mTargetTime = System.currentTimeMillis() + timeout * 1000L;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
alarmManager.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, mTargetTime, mPendingIntent);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, mTargetTime, mPendingIntent);
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP, mTargetTime, mPendingIntent);
}
I am trying to create a simple alarm application where alarm should go off on several days.
I have created a service which registers alarm manager based on data saved in preferences. Everything is working fine except that it does not trigger alarm when app is not running.
AlarmService.java
#Override
protected void onHandleIntent(Intent intent) {
Toast.makeText(this,"Service started",Toast.LENGTH_LONG);
//set separate pending intent values for all days
setIntents();
// register the alarm manager here
alarmManager = (AlarmManager)(getSystemService(Context.ALARM_SERVICE));
execute();
}
private void execute() {
prefs=getSharedPreferences("user_data_pref",Context.MODE_PRIVATE);
prefEditor=prefs.edit();
int hour=prefs.getInt("ALARM_HOUR",0);
int minute=prefs.getInt("ALARM_MINUTE",0);
if(prefs.getString("ALARM_STATUS","NOT_SET").equals("SET"))
isAlarmOn=true;
if(prefs.getString("NOTIFICATION_STATUS","NOT_SET").equals("SET"))
isNotificationOn=true;
if (prefs.getBoolean("MON_SET",false)) {
setAlarmFor(Calendar.MONDAY,hour,minute,mondayIntent,isAlarmOn,isNotificationOn);
}
if (prefs.getBoolean("TUE_SET",false)) {
setAlarmFor(Calendar.TUESDAY,hour,minute,tuesdayIntent,isAlarmOn,isNotificationOn);
}
if (prefs.getBoolean("WED_SET",false)) {
setAlarmFor(Calendar.WEDNESDAY,hour,minute,wednesdayIntent,isAlarmOn,isNotificationOn);
}
if (prefs.getBoolean("THU_SET",false)) {
setAlarmFor(Calendar.THURSDAY,hour,minute,thursdayIntent,isAlarmOn,isNotificationOn);
}
if (prefs.getBoolean("FRI_SET",false)) {
setAlarmFor(Calendar.FRIDAY,hour,minute,fridayIntent,isAlarmOn,isNotificationOn);
}
if (prefs.getBoolean("SAT_SET",false)) {
setAlarmFor(Calendar.SATURDAY,hour,minute,saturdayIntent,isAlarmOn,isNotificationOn);
}
if (prefs.getBoolean("SUN_SET",false)) {
setAlarmFor(Calendar.SUNDAY,hour,minute,sundayIntent,isAlarmOn,isNotificationOn);
}
}
private void setAlarmFor(int weekday, int hour, int minute, PendingIntent pendingIntent, boolean isAlarmOn, boolean isNotificationOn){
if(isAlarmOn){
prefEditor.putString("ALARM_STATUS","SET");
prefEditor.commit();
}
if(isNotificationOn){
prefEditor.putString("NOTIFICATION_STATUS","SET");
prefEditor.commit();
}
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.DAY_OF_WEEK,weekday);
calendar.set(Calendar.HOUR_OF_DAY, hour);
calendar.set(Calendar.MINUTE, minute);
calendar.set(Calendar.SECOND,0);
/* Repeating on every week interval */
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
7*24*60*60*1000, pendingIntent);
}
private void setIntents(){
Intent intent = new Intent(this,AlarmReceiver.class);
mondayIntent=PendingIntent.getBroadcast(this, Calendar.MONDAY, intent, 0);
tuesdayIntent=PendingIntent.getBroadcast(this, Calendar.TUESDAY, intent, 0);
wednesdayIntent=PendingIntent.getBroadcast(this, Calendar.WEDNESDAY, intent, 0);
thursdayIntent=PendingIntent.getBroadcast(this, Calendar.THURSDAY, intent, 0);
fridayIntent=PendingIntent.getBroadcast(this, Calendar.FRIDAY, intent, 0);
saturdayIntent=PendingIntent.getBroadcast(this, Calendar.SATURDAY, intent, 0);
sundayIntent=PendingIntent.getBroadcast(this, Calendar.SUNDAY, intent, 0);
}
It should trigger AlarmReceiver class that displays alarm.
AlarmReceiver.java
#Override
public void onReceive(Context context, Intent intent) {
prefs=context.getSharedPreferences("user_data_pref",Context.MODE_PRIVATE);
//Get Status of currently set alarm and notification
alarmStatus=prefs.getString("ALARM_STATUS","NOT_SET");
notificationStatus=prefs.getString("NOTIFICATION_STATUS","NOT_SET");
//Send notification if the notification is set
if(notificationStatus.equals("SET")){
Toast.makeText(context, "NOTIFICATION START SUCCESSFUL", Toast.LENGTH_SHORT).show();
playNotificationSound(context,getNotificationSound());
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context)
.setContentTitle("") // title for notification
.setContentText("") // message for notification
.setAutoCancel(true); // clear notification after click
Intent intent_1 = new Intent(context, MainActivity.class);
PendingIntent pi = PendingIntent.getActivity(context, 11, intent_1, Intent.FLAG_ACTIVITY_NEW_TASK);
mBuilder.setContentIntent(pi);
NotificationManager mNotificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(0, mBuilder.build());
displayNotification(context);
}
//Fire Alarm if the Alarm is set
if(alarmStatus.equals("SET")){
Toast.makeText(context, "ALARM START SUCCESSFUL", Toast.LENGTH_SHORT).show();
/** Creating Alarm */
Intent i = new Intent(context,FitterfoxAlarmActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
}
AndroidManifest.xml
<receiver android:name=".OnBootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver android:name=".AlarmReceiver"></receiver>
<service android:name=".AlarmService"></service>
Try this set of code your service never going to stop it's works for me. "alarmManager.setRepeating" not working in many of the lollipop and marshmallows device once it started then lose control over the service this will help you out.
if (android.os.Build.VERSION.SDK_INT >= 23) {
piLR = PendingIntent.getBroadcast(context, 0, intentLR,
PendingIntent.FLAG_UPDATE_CURRENT);
amLR.setAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
interval, piLR);
} else if (android.os.Build.VERSION.SDK_INT >= 19
&& android.os.Build.VERSION.SDK_INT < 23) {
piLR = PendingIntent.getBroadcast(context, 0, intentLR,
PendingIntent.FLAG_UPDATE_CURRENT);
amLR.setInexactRepeating(AlarmManager.RTC_WAKEUP,
System.currentTimeMillis(), interval, piLR);
} else {
amLR.setRepeating(AlarmManager.RTC_WAKEUP,
System.currentTimeMillis(), interval, piLR);
}
Starting with KitKat, changes were made to the AlarmManager to improve device battery life. The time at which alarms fire is less exact. If you want your alarms to fire within minutes of the scheduled time, you will need to change the way you are using AlarmManager.
For KitKat (API 19) and later builds, the times specified in setRepeating() are inexact, as described in the documentation. The docs also note:
If your application needs precise delivery times then it must use
one-time exact alarms, rescheduling each time.
You indicate that the alarms do not fire when the app is not running. Because the period for your alarms is one week, there can be a large difference between the scheduled time and the actual time the alarm is fired. The documentation indicates:
Your alarm's first trigger will not be before the requested time, but
it might not occur for almost a full interval after that time.
I suspect that with your current code, you would eventually see the alarm fire, but might have to wait a very long time after the expected time.
Your revised code will probably need to use setWindow().
Marshmallow introduced Doze mode, which further changes alarm scheduling. As #Andy noted in his answer, to get the beavior you want on Marshmallow and later devices, you will need to use setExactAndAllowWhileIdle().
Two other things that need to be fixed. Your PendingIntents should probably use flag PendingIntent.FLAG_UPDATE_CURRENT. In your receiver, the flag Intent.FLAG_ACTIVITY_NEW_TASK belongs on intent_1, not pi.
I have some existing code that spawns a service intent which does a bunch of stuff in the background. This code does work...
Intent serviceIntent = new Intent(context, APMService.class);
serviceIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startService(serviceIntent);
My question is: how to change this to use the AlarmManager.setInexactRepeating(...) methods?
I have changed the above code to this:
Intent serviceIntent = new Intent(context, APMService.class);
serviceIntent.putExtra("STARTED_BY", starter);
serviceIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//Set up recurring alarm that restarts our service if
// it crashes or if it gets killed by the Android OS
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pi = PendingIntent.getService(context, 0, serviceIntent, 0);
//am.cancel(pi);
am.setInexactRepeating(
AlarmManager.ELAPSED_REALTIME_WAKEUP //wake up the phone if it's asleep
, cal.getTimeInMillis()
, 10000
, pi);
And I have added these permissions to AndroidManifest.xml...
<uses-permission android:name="com.android.alarm.permission.SET_ALARM"/>
<uses-permission android:name="com.android.alarm.permission.WAKE_LOCK"/>
My understanding is that this is supposed to start the service immediately and then try to restart it again every 10 seconds. But this code isn't working properly.
Using this new code, the service never starts at all and I cannot see why not. To complicate matters the debugger never seems to attach to the app in time to see what's going on.
Can anyone see what I'm doing wrong?
Put AlarmManager code under onDestroy() function of service to schedule start of service as below:
#Override
public void onDestroy() {
/**
* Flag to restart service if killed.
* This flag specify the time which is ued by
* alarm manager to fire action.
*/
final int TIME_TO_INVOKE = 5 * 1000; // try to re-start service in 5 seconds.
// get alarm manager
AlarmManager alarms = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AutoStartServiceReceiver.class);
PendingIntent pendingIntent = PendingIntent
.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
// set repeating alarm.
alarms.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() +
TIME_TO_INVOKE, TIME_TO_INVOKE, pendingIntent);
}
And handle starting of your service in AutoStartServiceReceiver as below:
public class AutoStartServiceReceiver extends BroadcastReceiver {
private static final String TAG = AutoStartServiceReceiver.class.getSimpleName();
#Override
public void onReceive(Context context, Intent intent) {
// check broadcast action whether action was
// boot completed or it was alarm action.
if (intent.getAction().equals(AppConstants.ACTION_ALARM_INTENT)) {
context.startActivity(new Intent(context, YourActivity.class));
// handle service restart event
LockerServiceHelper.handleServiceRestart(context);
}
}
}
Kindly note that, your service will not restart if you stop it manually from settings-apps-running apps-your app.
Your service is not starting because of AlarmManager.ELAPSED_REALTIME_WAKEUP, while it should be using AlarmManager.RTC_WAKEUP
If you want to run every 10s keep in mind that above API 21 alarm intervals below 60s are rounded up to 60s.
Also, consider using WakefulIntentService
https://github.com/commonsguy/cwac-wakeful
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);
}