I have pending intent that sets alarm and it takes parameters such as row id and time from a database. I want to cancel alarm so i would do that by sending another pending intent with the same info and then cancel(i want to cancel it from different file). I only allow one alarm to be set at anyone time because that's the way my app works, because there is only one alarm set from that pending intent is there anyway i can just do cancel all for that intent?
Since I believe in code samples to get the point across, see below:
/*
* An alarm can invoke a broadcast request
* starting at a specified time and at
* regular intervals.
*/
public void sendRepeatingAlarm()
{
Calendar cal = Utils.getTimeAfterInSecs(30);
String s = Utils.getDateTimeString(cal);
this.mReportTo.reportBack(tag, "Schdeduling Repeating alarm in 5 sec interval starting at: " + s);
//Get an intent to invoke TestReceiver class
Intent intent = new Intent(this, TestReceiver.class);
intent.putExtra("message", "Repeating Alarm");
PendingIntent pi = this.getDistinctPendingIntent(intent, 2);
// Schedule the alarm!
AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
am.setRepeating(AlarmManager.RTC_WAKEUP,
cal.getTimeInMillis(),
5*1000, //5 secs
pi);
}
protected PendingIntent getDistinctPendingIntent(Intent intent, int requestId)
{
PendingIntent pi =
PendingIntent.getBroadcast(
this, //context
requestId, //request id
intent, //intent to be delivered
0);
//pending intent flags
//PendingIntent.FLAG_ONE_SHOT);
return pi;
}
/*
* An alarm can be stopped by canceling the intent.
* You will need to have a copy of the intent
* to cancel it.
*
* The intent needs to have the same signature
* and request id.
*/
public void cancelRepeatingAlarm()
{
//Get an intent to invoke TestReceiver class
Intent intent = new Intent(this, TestReceiver.class);
//To cancel, extra is not necessary to be filled in
//intent.putExtra("message", "Repeating Alarm");
PendingIntent pi = this.getDistinctPendingIntent(intent, 2);
// Schedule the alarm!
AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
am.cancel(pi);
}
I have pending intent that sets alarm and it takes parameters such as row id and time from a database.
There are no "parameters" on a PendingIntent. I am going to interpret this as meaning "extras".
I want to cancel alarm so i would do that by sending another pending intent with the same info and then cancel(i want to cancel it from different file).
It's not "sending" but "creating". Otherwise, yes, this is correct.
i can just do cancel all for that intent?
There is only one alarm.
Extras do not matter in terms of alarm scheduling. If you have an Intent (I1) wrapped in a PendingIntent (PI1) and use that to schedule an alarm, and later if you create an Intent (I2) with the same component/action/data/type, wrap that in a PendingIntent (PI2) and cancel() the alarm, it will cancel the PI1 alarm. Similarly, if you use PI2 to schedule a new alarm, it will remove the old PI1 alarm.
Related
My code
public class BackgroundIntentService extends IntentService {
public BackgroundIntentService() {
super("BackgroundIntentService");
}
#Override
protected void onHandleIntent(Intent intent) {
scheduleNextUpdate();
Log.w("Blabla", "asldad111");
Log.w("Blabla", "asldad");
Log.w("Blabla", "asldad");
Log.w("Blabla", "asldad555");
}
private void scheduleNextUpdate() {
Intent intent = new Intent(this, this.getClass());
PendingIntent pendingIntent =
PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// The update frequency should often be user configurable. This is not.
AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarm.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 5000, pendingIntent);
}
}
To start the service
Intent serviceIntent = new Intent(this, BackgroundIntentService.class);
startService(serviceIntent);
In the MainActivity.
The problem is that I can see in the logcat those logs spamming, not every 5 seconds but twice a second or more.
Where I'm wrong?
The flag you are using PendingIntent.FLAG_UPDATE_CURRENT in
PendingIntent pendingIntent =
PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
should be PendingIntent.FLAG_CANCEL_CURRENT
as quoted on the developer docs
FLAG_CANCEL_CURRENT - Flag indicating that if the described PendingIntent already exists, the current one should be canceled before generating a new one.
FLAG_UPDATE_CURRENT - Flag indicating that if the described PendingIntent already exists, then keep it but replace its extra data with what is in this new Intent.
so in your case the current pending intent exists and the new one updates it and fires at the exact moment it is updating the existing pending since you have defined the trigger time to be at System.currentTimeMillis()
So what is happening is that the current Pending intent is firing up before the new pending intent updates it ..and once it does that works as per the alarm logic , after the 5000ms interval the pending intent is fired. So there is a race condition here with interleaved alarm triggers and updates via the pending intents.
I want to set up a repeating alarm which sends on its first trigger with Bundles the string "test".
Is it possible on the next trigger to have another string like "test2" ?
Alarm manager:
// Enable the scheduled alarm to send notifications
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent alarmIntent = new Intent(this, Service.class);
Bundle extras = new Bundle();
extras.putString("test", "test");
alarmIntent.putExtras(extras);
PendingIntent alarmPendingIntent = PendingIntent.getService(this, 0, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
// Set the alarm in 30 minutes and repeat it every 30 minutes.
alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + 1000,
1000,
alarmPendingIntent);
IntentService:
public class Service extends IntentService {
public Service() {
super("service");
}
#Override
protected void onHandleIntent(Intent intent) {
String test = intent.getStringExtra("test");
// update the bundle data
Log.i("result", test);
// how to update here the string to "test2" ?
}
}
I want on the second trigger the value of String test to be test2.
But I always get the original value from the first trigger.
You will need separate alarms and separate PendingIntents. You can either set them up at the same time, or set an alarm that does not repeat and have the service set the following alarm whenever it runs.
Note that if you set the two alarms at the same time, you need something other than the extras to be different because Android does not compare intent extras when it checks for an existing PendingIntent for the given Intent. One way to do this is like so:
Intent alarmIntent = new Intent(this, Service.class);
...
alarmIntent.putExtras(extras);
alarmIntent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
in my task application, i want to create alarm service for multiple items. Here is the code i followed to create service. Lets assume, if there are more than 5 items present in list. then we will sent alarm service for 5 different times.
What if the user comes and edits the time?, how to update the system and make sure it triggers at new instance?. What if the user delete the task, how to quickly removes the registered alram for the deleted task?
What about uninstalling the app?, how to clear all the entries?, what if the system re-boots?
This is the code i'm following to register the task in alram services
Calendar Calendar_Object = Calendar.getInstance();
Calendar_Object.set(Calendar.MONTH, 8);
Calendar_Object.set(Calendar.YEAR, 2012);
Calendar_Object.set(Calendar.DAY_OF_MONTH, 6);
Calendar_Object.set(Calendar.HOUR_OF_DAY, 14);
Calendar_Object.set(Calendar.MINUTE, 25);
Calendar_Object.set(Calendar.SECOND, 0);
Step 2:
We need to create an alarm which help us to invoke the BroadCastReceiver on our specified time.
// MyView is my current Activity, and AlarmReceiver is the BoradCastReceiver
Intent myIntent = new Intent(MyView.this, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
MyView.this, 0, myIntent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
/*
The following sets the Alarm in the specific time by getting the long value of the alarm date time which is in calendar object by calling the getTimeInMillis(). Since Alarm supports only long value , we're using this method.
*/
alarmManager.set(AlarmManager.RTC, Calendar_Object.getTimeInMillis(),
pendingIntent);
Use this method to set Alarm :
public static void startAlarm(Context context, int alarm_code, String time) {
String[] arrTime = time.split(":");
intent = new Intent(context, AlarmReceiver.class);
intent.putExtra("CODE", alarm_code);
PendingIntent mAlarmSender = PendingIntent.getBroadcast(context,
alarm_code, intent, 0);
Calendar cal_alarm = Calendar.getInstance();
cal_alarm.setTimeZone(TimeZone.getDefault());
cal_alarm.set(Calendar.HOUR_OF_DAY, Integer.parseInt(arrTime[0]));
cal_alarm.set(Calendar.MINUTE, Integer.parseInt(arrTime[1]));
AlarmManager am = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
am.setRepeating(AlarmManager.RTC_WAKEUP, cal_alarm.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, mAlarmSender);
}
Here,"int alarm_code" is your unique code for particular item.
And for update alarm first cancel the existing alarm and set new alarm for new time.For that use this method :
public static void cancelAlarm(Context context, int alarm_code) {
AlarmManager am = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmReceiver.class);
intent.putExtra("CODE", alarm_code);
am.cancel(PendingIntent.getBroadcast(context, alarm_code, intent, 0));
}
Here,"int alarm_code" will be your unique code which you have used to set alarm.So that alarm with particular alarm_id will be cancel.You can also delete alarm with this method.
Same way you can clear all the alarms passing alarm_code to the given function.
You have to register receiver for system reboot and in onReceive of register you have to set all alarms again.
Hope this will help you.
Can a single alarm manager trigger at 2 different time intervals like first interval should be 1 minute and second interval should be something like 2 minutes
I was trying with following code but it is not working as i have expected :(
{
AlarmManager am=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmManagerBroadcastReceiver.class);
intent.putExtra(ONE_TIME, Boolean.FALSE);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000 * 60 *x, pi);
}
//Initialized x=1;
//In onReceive what i did was...
public void onReceive(Context context, Intent intent) {
if(x===1)
x=2;
else
x=1;
}
Is this wrong ?
From the Google developer document
A BroadcastReceiver object is only valid for the duration of the call toonReceive(Context, Intent). Once your code returns from this function, the system considers the object to be finished and no longer active.
So your x will be always 1. Make the x variable static.
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());
}
}