Android AlarmService repeating alarm repeats once more after cancel is called - android

First off,this site is great and everyone is so helpfull. This is my first post so forgive me if i have ommited anything.
I create an alarm like so:
private void startLocation() {
AlarmManager alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, MyWeatherUpdateService.class);
PendingIntent service = PendingIntent.getService(context, 0, i,
PendingIntent.FLAG_CANCEL_CURRENT);
alarm.setRepeating(AlarmManager.RTC, SystemClock.elapsedRealtime() + (60 * 1000),
Long.parseLong(prefs.getString("listpref", "60000")), service);
}
In this method which is called inside a fragment, context is from getApplication (), listpref is a string update interval in milliseconds.
I cancel it by:
public void endLocation() {
Intent i = new Intent(context, MyWeatherUpdateService.class);
PendingIntent service = PendingIntent.getService(context, 0, i,
PendingIntent.FLAG_CANCEL_CURRENT);
alarm.cancel(service);
}
Ensuring that the intent/pending intent is the same.
Now i have 2 issues:
1) the alarm fires almost imediately after creation, even though i tell it to start after 1min.
2) when i call cancel, the alarm fires once more before the alarm is cancelled.
With question 1) why does the alarm fire so soon? And with 2) is this working as intended or should the alarm cancel immediately like i want it to.
If i have not supplied enough info, ill add more code if required.
Thanks in advance.

the alarm fires almost imediately after creation, even though i tell it to start after 1min
That is because you are using RTC with an elapsedRealtime() starting time. Those need to match. The simplest solution is to switch to ELAPSED_REALTIME.
when i call cancel, the alarm fires once more before the alarm is cancelled.
Try replacing PendingIntent.FLAG_CANCEL_CURRENT with 0, at least in the PendingIntent for your cancel() call.

Related

Use one alarm manager to cancel another

I am doing a reminder application. It will reminder for a duration at the interval of time. For example, remind every five minutes for an hour. In this case, I am trying to set two alarm. One is used to do the reminder for every five minutes, the other one is used to cancel the reminder alarm after one hour. Here is my codes.
private void createIntervalNotification(int reminder, int dhour, int dminute){ //reminder in min
int interval = (reminder)*60*1000;
AlarmManager am = (AlarmManager) MainActivity.this.getSystemService(MainActivity.this.ALARM_SERVICE);
am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime()+interval, interval, getPendingIntent(this,REMINDER_ID));
int duration = (dhour*60 + dminute)*60*1000;
am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime()+duration,getPendingIntent(this,CANCEL_REMINDER_ID));
}
private static PendingIntent getPendingIntent(Context ctxt, int id) {
Intent intent1 = new Intent(ctxt, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(ctxt, id,intent1, PendingIntent.FLAG_UPDATE_CURRENT);
return pendingIntent;
}
I have some questions to do this(Set reminder of 5 mins for duration of 1 hour).
1) Can I do this with my method? Use one alarm to cancel another?
2) Can both alarm share a broadcastReceiver? If yes, how to differentiate it is invoked by which alarm?
3) Is it any other method can do this?
Cancelling an alarm is pretty much exactly the same as setting an alarm. You just call a different method to cancel on the AlarmManager than you do to create. Just make sure that the pending intent in the AlarmManager and the broadcast ID is identical.
Differentiate alarms by setting Extras on the Intent.

how to set an Ending Point for Alarm Manager

I have an Alarm Manager that runs periodically , but I want to have a specific set of time that it will be running. For Example , lets say that we have a periodic Alarm Manager that is registered with a broadcast receiver and an Action is being performed every 30 minutes. The thing is that I want the Alarm Manager to be active for a specific time lets say 3 hours, so the Alarm manager should goes off 3 hours / 30 minutes or 6 times.
Code to start the define the Alarm Manager:
TimerPeriodic = (AlarmManager)getActivity().getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(getActivity(),AlarmReceiver.class);
intent.putExtra(Constants.ALARM_ID, Constants.TIMER_PERIODIC_ID);
TimerPeriodicPendingIntent = PendingIntent.getBroadcast(getActivity(), 0, intent, 0);
Fire Alarm Manager:
long start = TimeUnit.MINUTES.toMillis(StartMinutes);
TimerPeriodic.setRepeating(
AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + start, start, TimerPeriodicPendingIntent);
Also the alarm Manager should be active if the Application is killed.
Thank you for any help!
It can be acheived by using Sqlite Db. where you store the Alaram ID,count,and repeation (How many time you want to repeat).
when Alarm is trigger (AlarmReceiver.onReceive()) increment the count check with the condition with repeation. if it exceed just cancel it. Hope It will help :)
#Override
public void onReceive(Context context, Intent intent) {
AlarmManager alarmManager = (AlarmManager) context.getApplicationContext().getSystemService(
context.ALARM_SERVICE);
Intent myIntent = new Intent(context, AlarmReceiver.class);
cancelAlarm(reminder.getId(),myIntent,alarmManager);
}
private void cancelAlarm(int notiId,Intent myIntent,AlarmManager alarmManager) {
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, notiId, myIntent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.cancel(pendingIntent);
}

How to cancel and set AlarmManager at the same time

What I am doing at the moment is, using AlarmManager.SetAlarm(context) to enable and AlarmManager.CancelAlarm(context) to cancel it. I am using it with an IntentService.
What I want to do is cancel the alarm from triggered IntentService and then set it again such as:
#Override
protected void onHandleIntent(Intent intent) {
FooAlarmManager foo = new FooAlarmManager();
foo.CancelAlarm(FooClass.this);
//Do some stuff
foo.SetAlarm(FooClass.this);
}
Why I am doing this? Because within FooAlarmManager I am getting the time from a static class such as:
public void SetAlarm(Context context) {
Integer minutes = StaticValuePass.getMins();
AlarmManager am = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, FooAlarmManager.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
am.setInexactRepeating(AlarmManager.RTC_WAKEUP,
System.currentTimeMillis(), 1000 * minutes*60, pi);
}
And I am setting the value of time from onHandleIntent(). So basically I am doing some check within onHandleIntent() and determining when should be the next alarm.
Unfortunetely, my code above doesn't work, the reason is when you use setAlarm() it actually invokes onHandleIntent() immediately.
So I have two questions in this case,
1) Can I prevent setAlarm() to invoke onHandleIntent() when it is firstly created?
2) (Assuming the above doesn't work) How can I change the alarm interval time?
The second parameter, currently System.currentTimeMillis(), is the time at which you want the repeating alarm to first go off. So setting it to the current time will trigger the alarm immediately. Setting it to System.currentTimeMillis() + (1000 * minutes * 60) should fix your problem.
Please refer to the documentation: https://developer.android.com/reference/android/app/AlarmManager.html#setInexactRepeating(int,+long,+long,+android.app.PendingIntent)

AlarmManager not stopping previous PendingIntent

I have a function where I set a 15 minute repeating alarm to start my service, which calls a webservice, processes the result and closes. Simplified:
public static void setAlarm(Context cx) {
try{
//My service is running, no need to reset the alarm
if (isServiceRunning())
return;
Intent intent = new Intent(cx, ResultService.class);
PendingIntent sender = PendingIntent.getService(cx, 0, intent, PendingIntent.FLAG_NO_CREATE);
//My pending intent exists, no need to reset the alarm
if (sender!=null)
return;
sender = PendingIntent.getService(cx, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager am = (AlarmManager) cx.getSystemService(cx.ALARM_SERVICE);
//Cancel any previous alarms????
am.cancel(sender);
am.setRepeating(AlarmManager.RTC_WAKEUP, firstRun, interval, sender);
}catch (Exception e){
}
}
This is called by a BroadcastReceiver that listens for the following events
ACTION_SCREEN_ON
ACTION_BOOT_COMPLETED
CONNECTIVITY_ACTION
via
setAlarm(context.getApplicationContext());
It seems to work however I start seeing multiple calls to my webservice per second on random devices.
I have tried getting it to happen whilst debugging with no success.
What am I doing wrong here?
Update
I ran
adb shell dumpsys alarm > dump.txt
to check the alarm lock and I see the number of wakeups/alarms increases every time the alarm manager executes my PendingIntent:
com.x
279ms running, 22 wakeups
22 alarms: flg=0x4 cmp=com.x/.service.ResultService
Does it mean anything?
UPDATE 2
I tracked one of the offending devices.
It calls the web service as it should for most of the day, then suddenly at 19:53 last evening I get 330 extra calls from the device in 6 seconds.
Afterwards it runs fine until 06:50 this morning when I get 282 extra calls and on 06:55 I get another 130 extra calls.
int RQS=1;
//RQS- request id for starting the alram ,get the same request and cancel
// starting the alarm
intent = new Intent(getBaseContext(), Receiver.class);
pendingIntent = PendingIntent.getBroadcast(getBaseContext(), RQS,
intent, PendingIntent.FLAG_CANCEL_CURRENT);
alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, targetCal.getTimeInMillis(),
pendingIntent);
//cancelling the request
alarmManager.cancel(PendingIntent.getBroadcast(getBaseContext(), RQS, intent,
PendingIntent.FLAG_UPDATE_CURRENT));

Implementing Snooze in Android Notifications

What's the best way to implement snooze functionality in an Android notification. (i.e. I notify user of X [for arguments sake lets use the example of a text message], and he doesn't want to be bothered by it for now, yet at the same time he wants to make sure he doesn't forget. So he does want it to play the noise again, but at e.g. 5 minutes from now)
I saw the way the android alarm clock does it, but to me it seems messy (and usually not good) to popup a floating intent while the user might be doing something important.
On the other hand, it doesn't seem possible to put buttons inside the notification area. Or am I wrong?
What would you suggest?
Add a snooze button:
Button snooze = (Button) findViewById(R.id.snooze);
snooze.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View arg0, MotionEvent arg1) {
mMediaPlayer.stop();
finish();
return true;
}
});
Then before where you call the alarm, update the time
Intent intent = new Intent(this, this.getClass());
PendingIntent pendingIntent =
PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
long currentTimeMillis = System.currentTimeMillis();
long nextUpdateTimeMillis = currentTimeMillis + 5 * DateUtils.MINUTE_IN_MILLIS;
Time nextUpdateTime = new Time();
nextUpdateTime.set(nextUpdateTimeMillis);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC, nextUpdateTimeMillis, pendingIntent);
Call the alarm now.
A simple strategy may be as follows:
The notification text can be "1 new message. Click here to notify again in 5 mins".
If the user clears the notifications, nothing happens and notification is cleared.
If the user clicks on the notification, then clear the notification and set up a timer and post a new notification after 5 min.
Alternatively, clicking the notification can bring an activity to the foreground that will set up a timer if there's no other input from the user (e.g., clicking on a "dismiss" button).
Another, opposite approach, would be to set up a timer when the notification is sent, and after the snooze time, remove it and add a new one, with the corresponding noise and probably a text added saying how much time passed since the original notification. That can be done recursively until the user clears the notification or clicks on it.
The best strategy will depend on what the application does and what is the level of customization the user is able to do. I would not implement any snozze behavior that cannot be easily prevented by the user (can be very annoying if not).
I've done this exactly same way how i created first alarm-notification
private void startAlarm(Calendar calendar) {
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, AlertReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, Config.NOTIFICATION_REQUEST_CODE, intent, 0);
//Repeat every 24 hours
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 24*60*60*1000, pendingIntent);
}
So for snoozing notification or alarm i just created another alarm but that's not repeating alarm. that will trigger for only once
private void snoozeAlarm() {
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, AlertReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, Config.NOTIFICATION_REQUEST_CODE, intent, 0);
alarmManager.setExact(AlarmManager.RTC_WAKEUP,
Calendar.getInstance().getTimeInMillis() + 5 * 60000, //...start alarm again after 5 minutes
pendingIntent);
finish();
System.exit(0); //...exit the activity which displayed
}
if anyone need to take a look at AlertReceiver.class
public class AlertReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
intent = new Intent();
intent.setClass(context, DisplayedOnScreen.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
NotificationHelper notificationHelper = new NotificationHelper(context);
NotificationCompat.Builder notificationBuilder = notificationHelper.getNotification();
notificationHelper.getManager().notify(1, notificationBuilder.build());
}
}

Categories

Resources