I'm working on an event planner for Android (learning purposes), and want each event to have it's own reminder. I've got the alarms working and they successfully trigger and know how to check if the alarms exist, but I'm unable to find out how to get the time for each alarm.
I've managed to identify if the alarm exists using:
Intent i = new Intent(getApplicationContext(), NotificationReceiver.class);
pIntent = PendingIntent.getBroadcast(getApplicationContext(), (int) id, i, PendingIntent.FLAG_NO_CREATE);
And I've tried using
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
Calendar test = Calendar.getInstance();
test.setTimeInMillis(am.getNextAlarmClock().getTriggerTime());
Log.d(TAG, "getReminder: TRIGGER: " + test.getTime());
But the time displayed there doesn't even match any of my alarms when testing. Also this doesn't allow me to identify which event the alarm belongs to anyway.
This is where I create the reminders.
public void makeReminder(String event, long reminder){
Log.d(TAG, "makeReminder: Started");
Intent i = new Intent (getApplicationContext(), NotificationReceiver.class);
i.putExtra("id", event); // eventID
i.putExtra("reminder", reminder); // reminderKey
i.putExtra("reminderTime", reminderCal.getTimeInMillis()); // actual time for the reminder
i.putExtra("message", "You have an upcoming event on " + dateTimeFormat.format(startCal.getTime()));
i.putExtra("name", eventName);
i.putExtra("channel", "event");
PendingIntent nIntent = (PendingIntent) PendingIntent.getBroadcast(
getApplicationContext(),
(int)reminder, i,
PendingIntent.FLAG_CANCEL_CURRENT
);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.setExact(AlarmManager.RTC_WAKEUP, reminderCal.getTimeInMillis(), nIntent);
Log.d(TAG, "makeReminder: reminder set for " + reminderCal.getTime());
Log.d(TAG, "makeReminder: reminderID: " + reminder);
}
I'm not sure how to proceed to get the time, but I'm hoping that it would be possible to get the triggertime with the reminderKey or alternatively fetching the reminderTime from the intent before the event actually gets triggered. The point is for users to see if there's an alarm set, when it is and then I know how to cancel or change the alarm. Just can't find a good way of displaying it.
Hopefully something that's simple to achieve, that I've overlooked :/ but can't seem to solve this.
You can't get this information from AlarmManager. If you need this information, you will need to save it in some persistent storage (SQLite database, SharedPreferences, File, etc.) and manage it yourself.
Related
I've read about every similar question on here but cannot find an answer, so please forgive me if this has been answered before, I really tried to search.
I'm setting up an alarm to show a notification after a certain time. The time logic is definitely solid, I can tell by my log output, this is not the problem.
I create a Pending intent like so:
Intent alarmIntent = new Intent(c, AlarmReceiver.class);
alarmIntent.putExtra("title", name);
alarmIntent.putExtra("location", building);
PendingIntent pi = PendingIntent.getBroadcast(c, 0, alarmIntent, 0);
and then set the alarm to fire after millis milliseconds. In this instance, millis is 407603959 according to my log statements. It definitely should not be firing after one second.
alarm.set(AlarmManager.RTC_WAKEUP, millis, pi);
Log.i("Alarm", "Alarm: " + name + " is set for: "
+ untilAlarm.getDays() + " days, " + untilAlarm.getHours() + " hours, "
+ untilAlarm.getMinutes() + " minutes from now. Or, " + millis
+ " milliseconds");
It appears as though my PendingIntent is being started before the alarm is even set. I tried blocking an alarm from being created like so:
Intent alarmIntent = new Intent(c, AlarmReceiver.class);
alarmIntent.putExtra("title", name);
alarmIntent.putExtra("location", building);
PendingIntent pi = PendingIntent.getBroadcast(c, 0, alarmIntent,
PendingIntent.FLAG_ONE_SHOT);
if (!name.equals("test") {
alarm.set(AlarmManager.RTC_WAKEUP, millis, pi);
//Log statement...
}
and the alarm for test is still triggered, but the log statement is not printed to the console, meaning alarm.set was never called. The intent is still fired, and a notification is shown with the title "test".
Why is my PendingIntent being launched before the alarm is fired?
You are using an alarm type of AlarmManager.RTC_WAKEUP, which will set the alarm to start at a specified time, in your case millis.
To set the alarm to start at a certain amount of time in the future, you need to either use one of these types of elapsed-time alarms:
ELAPSED_REALTIME
Alarm time in SystemClock.elapsedRealtime() (time since boot,
including sleep). This alarm does not wake the device up; if it goes
off while the device is asleep, it will not be delivered until the
next time the device wakes up.
ELAPSED_REALTIME_WAKEUP
Alarm time in SystemClock.elapsedRealtime() (time since boot,
including sleep), which will wake up the device when it goes off.
Or use an RTC or RTC_WAKEUP with the current time plus the time to wait, like:
alarm.set(AlarmManager.RTC_WAKEUP, Calendar.getInstance().getTimeInMillis() + millis, pi);
I've got a problem with the AlarmManager. I'm able to set up the Alarm with this code
private void setAlarm(long when) {
Intent intent = new Intent(NoteActivity.this, AlarmReceiver.class);
intent.putExtra("ID", note.getId());
AlarmManager manager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, when, PendingIntent.getBroadcast(NoteActivity.this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT));
Toast.makeText(getApplicationContext(),"Reminder set up", Toast.LENGTH_SHORT).show();
}
This code works well if I set long when = 5 * 1000; \\For example 5secs later, but if I use this code
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
long selectedDate = date.getTime();
long timeSince1970 = System.currentTimeMillis();
long timeForAlarm = selectedDate - timeSince1970;
Intent intent = new Intent(NoteActivity.this, AlarmReceiver.class);
intent.putExtra("ID", note.getId());
AlarmManager manager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, timeForAlarm, PendingIntent.getBroadcast(NoteActivity.this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT));
Toast.makeText(getApplicationContext(),"Reminder set for "+calendar.getTime().toString(), Toast.LENGTH_SHORT).show();
my alarm triggerd 2secs later. What I'm doing wrong? :/
I've tried AlarmManager.ELAPSED_REALTIME_WAKEUP and AlarmManager.RTC_WAKEUP but nothing changed.
Please do not check my question as duplicated. I didn't find something to try that solved my problem.
Assuming that you are working in Android Studio (if not - you must switch), click F1 while your text pointer is on set method and read description of AlarmManager::set.
Note: Beginning in API 19, the trigger time passed to this method is
treated as inexact: the alarm will not be delivered before this time,
but may be deferred and delivered some time later. The OS will use
this policy in order to "batch" alarms together across the entire
system, minimizing the number of times the device needs to "wake up"
and minimizing battery use. In general, alarms scheduled in the near
future will not be deferred as long as alarms scheduled far in the
future.
Instead of set use setExact
manager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, timeForAlarm, PendingIntent.getBroadcast(NoteActivity.this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT));
I want to create three Alarm named as Reminder1, Reminder2, Reminder3.
I know that, I can create multiple alarm for three of the above using different requestCode. Corresponding code was embedded below
private void startReminderAlarm(int id, Calendar from_date, long interval) {
// TODO Auto-generated method stub
Intent remIntent;
PendingIntent pendingIntent;
AlarmManager manager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
remIntent = new Intent(mContext, ReminderReceiver.class);
remIntent.putExtra("ID", id);
pendingIntent = PendingIntent.getBroadcast(mContext, id, remIntent, 0);
manager.setInexactRepeating(AlarmManager.RTC_WAKEUP, from_date.getTimeInMillis(), interval, pendingIntent);
Toast.makeText(mContext, "Alarm Set for id" + id, Toast.LENGTH_SHORT).show();
Log.d(TAG, "Alarm Set for id: " + id);
}
Depending on the id of Reminder, I'm starting each alarm. This was working fine. My question is,
1) Reminder1 alarm to be set for daily morning.
2) Reminder2 to be set for Daily Twice.
3) Reminder3 to be set for Daily Thrice.
1st case, wont create a problem, because it shall be set only once with corresponding id.
2nd case, If I create two alarm with corresponding id, the last one only persists. First one will be discarded.
3rd case, If I create three alarm with corresponding id, the last one only persists. First and second will be discarded.
I want to create 2 or 3 separate alarms with particular id.
Please suggest me any solution to solve this.
Use intent.setData to distinguish the intents. That is
remIntent = new Intent(mContext, ReminderReceiver.class);
remIntent.putExtra("ID", id);
remIntent.setData(Uri.parse("reminder:"+id+"/"+from_date.getTimeInMillis()+"/"+interval));
I am creating a repeating alarm. This works fine using the following code:
Intent intent = new Intent(this.ctx, AlarmReceiver.class);
intent.setAction("" + notificationId);
intent.putExtra(AlarmReceiver.TITLE, alarmTitle);
intent.putExtra(AlarmReceiver.SUBTITLE, alarmSubTitle);
intent.putExtra(AlarmReceiver.TICKER_TEXT, alarmTicker);
intent.putExtra(AlarmReceiver.NOTIFICATION_ID, notificationId);
PendingIntent sender = PendingIntent.getBroadcast(this.ctx, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager am = getAlarmManager();
am.setRepeating(AlarmManager.RTC_WAKEUP, triggerTime, 60000, sender);
Now I want to cancel an existing notification message (which pops up every minute for testing purposes), I invoke the following code, passing it an identical notificationId:
Intent intent = new Intent(this.ctx, AlarmReceiver.class);
intent.setAction("" + notificationId);
PendingIntent pi = PendingIntent.getService(this.ctx, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager am = getAlarmManager();
try {
am.cancel(pi);
} catch (Exception e) {
Log.e(PLUGIN_NAME, "AlarmManager update was not canceled. " + e.toString());
}
I see that pi != null, however the notification keeps coming and is not being cancelled. Both code snippets reside in the same class.
Basically I have two questions:
- How can I cancel a single alarm using its unique ID?
- How can I cancel all alarms, regardless of the ID?
UPDATE: I found that posting my issue here helps to get my mind straight. Changing the cancel code from:
PendingIntent sender = PendingIntent.getService( ... )
To:
PendingIntent sender = PendingIntent.getBroadcast( ... )
Helps to solve question 1. However the code to cancel all events, still does not work:
Intent intent = new Intent(this.ctx, AlarmReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(this.ctx, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager am = getAlarmManager();
am.cancel(pi);
I'm a noob here. But I think if you want to cancel the alarm, you have to use the exact same instance of PendingIntent. That means "their action, data, type, class, and categories are the same" as defined by filterEquals(Intent) . Therefore, you need to use the same requestCode here, not 0. Maybe you could use a list to store the Notification Ids, and iterate them to cancel all alarms.
I think , you should use same AlarmManager object to cancel the alram and also try to use same PendingIntent.
I have a small application which can be used to set reminders for future events. The app uses an AlarmManager to set the time for when the user should be reminded. When the alarm goes off, a BroadcastReceiver registers this and in turn starts a service to notify the user via a toast and a notification in the status bar.
In order to display the correct information in the notification and toast, some extra information is passed along with the intent. The first time a reminder is registered, the info received by the BroadcastReceiver and passed on to the service is correct. But for each following reminder (i.e. each new intent received by the BroadcastReceiver) this information stays the same even when the information sent is different.
As an example, if the string "foo" is put as an extra with the first intent, "foo" is correctly extracted by the BroadcastReceiver. If "bar" is put as an extra in the second intent, "foo" is still extracted by the BroadcastReceiver.
This is the code that registers the alarm and passes the intent (main ui-class):
Intent intent = new Intent(ACTION_SET_ALARM);
intent.putExtra("desc", desc);
intent.putExtra("time", time);
intent.putExtra("dbId", dbId);
intent.putExtra("millis", millis);
PendingIntent pIntent = PendingIntent.getBroadcast(quickAlert.this, 0, intent, 0);
// Schedule the alarm!
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, millis, pIntent);
The onReceive()-method in the BroadcastReceiver class:
#Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context, AlertService.class);
String desc = intent.getStringExtra("desc").equals("") ? "": ": " + intent.getStringExtra("desc");
String time = intent.getStringExtra("time");
long dbId = intent.getLongExtra("dbId", -1);
long millis = intent.getLongExtra("millis", -1);
i.putExtra("desc", desc);
i.putExtra("time", time);
i.putExtra("dbId", dbId);
i.putExtra("millis", millis);
Log.d(TAG, "AlertReceiver: " + desc + ", " + time + ", " + dbId + ", " + millis);
Toast.makeText(context, "Reminder: " + desc, Toast.LENGTH_LONG).show();
context.startService(i);
}
The intent-filter in the manifest:
<receiver android:name=".AlertReceiver">
<intent-filter>
<action android:name="com.aspartame.quickAlert.ACTION_SET_ALARM" />
</intent-filter>
</receiver>
I've been stuck with this for some time now, so help is very much appreciated!
Try adding FLAG_UPDATE_CURRENT to your PendingIntent when you create it via getBroadcast().
The above answers are correct, but they lack an explanation. It's worth noting this part of the PendingIntent documentation:
A PendingIntent itself is simply a reference to a token maintained by the system describing the original data used to retrieve it. ... If the creating application later re-retrieves the same kind of PendingIntent (same operation, same Intent action, data, categories, and components, and same flags), it will receive a PendingIntent representing the same token
Note that "extra" data is specifically not included in the concept of PendingIntent-identity!
best Link I've found on this topic: http://alvinalexander.com/source-code/android/android-how-attach-extra-intent-pendingintent-notification-solution-example
this is the clue:
int uniqueInt = (int) (System.currentTimeMillis() & 0xfffffff);
PendingIntent.getService(context, uniqueInt, intent, 0)