I'm building an alarm application. I have successfully implemented basic alarm functions.
Calendar calendar = Calendar.getInstance();
calendar.set(calendar.HOUR_OF_DAY, sHour);
calendar.set(calendar.MINUTE, sMin);
calendar.set(calendar.SECOND, 0);
calendar.set(calendar.MILLISECOND, 0);
long sdl = calendar.getTimeInMillis();
Intent intent = new Intent(AlarmList.this, AlarmReceiver.class);
PendingIntent sender = PendingIntent.getBroadcast(AlarmList.this, 0, intent,PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager ALARM1 = (AlarmManager)getSystemService(ALARM_SERVICE);
ALARM1.set(AlarmManager.RTC_WAKEUP, sdl, sender);
In my application, user can select days (sunday,monday...) to repeat the alarm weekly.
I'm trying to create multiple alarms to repeat weekly but don't know how to do it.
Can I create it using (repeat) interval or should I create multiple alarm managers?
You need to use different Broadcast id's for the pending intents. Something like
this:
Intent intent = new Intent(load.this, AlarmReceiver.class);
final int id = (int) System.currentTimeMillis();
PendingIntent appIntent = PendingIntent.getBroadcast(this, id, intent, PendingIntent.FLAG_ONE_SHOT);
Using the system time should be a unique identifier for every pending
intent you fire.
From the docs:
If there is already an alarm for this Intent scheduled (with the
equality of two intents being defined by filterEquals(Intent), then
it will be removed and replaced by this one
Multiple AlarmManagers would not resolve your issue. If they have multiple different alarms (different times and different days), then you would need to set the alarm within the BroadcastReceiver every time you fire off a previous alarm.
You would also need to hold RECEIVE_BOOT_COMPLETED and have a BroadcastReceiver to receive the boot so that if the phone is rebooted you can re-schedule your alarms.
To set multiple alarms you need to define your Intent each time so that it is distinguishable from the others. The easiest way I find to do this is to set the data field of your Intent something as follows:
// give your alarm an id and save it somewhere
// in case you want to cancel it in future
String myAlarmId = ...;
// create your Intent
Intent intent = new Intent(AlarmList.this, AlarmReceiver.class);
intent.setData(Uri.parse("myalarms://" + myAlarmId));
...
The rest of your code #Hassy31 is fine as is and remains unchanged.
Note that the requestCode parameter in the PendingIntent.getBroadcast() method (as suggested by #parag) is unused according to the documentation so this ain't the right way to go about it.
set Broadcast id for pendingIntent
for (int id = 0; id < 3; id++) {
// Define pendingintent
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, id,ntent, 0);
// set() schedules an alarm
alarmManager.set(AlarmManager.RTC_WAKEUP, alertTime, pendingIntent);
}
Set multiple alarms using android alarm manager
//RC_ARRAY is store all the code that generate when alarm is set
private lateinit var RC_ARRAY:ArrayList<Int>
//tick is just hold the request when new alarm set
private var tick :Int=0
//setAlarm method set alarm
fun setAlarm(c: Calendar, context: Context) {
val manager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
//when alarm store set the request assign to tick variable
tick = System.currentTimeMillis().toInt()
//Add all the alarm Request into RC_ARRAY for just cancel the alarm
RC_ARRAY.add(tick)
//Notification Broadcast intent
val intentAlarm = Intent(context, AlaramFireReceiver::class.java).let {
PendingIntent.getBroadcast(context, tick, it, PendingIntent.FLAG_ONE_SHOT)
}
//alarm fire next day if this condition is not statisfied
if (c.before(Calendar.getInstance())) {
c.add(Calendar.DATE, 1)
}
//set alarm
manager.setExact(AlarmManager.RTC_WAKEUP, c.timeInMillis, intentAlarm)
}
//remove specific alarm
private fun removeAlarm(context: Context) {
val manager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
//remove specific alarm according to alarm request code
for (i in RC_ARRAY){
val intentAlarm = Intent(context, AlaramFireReceiver::class.java).let {
PendingIntent.getBroadcast(context, i, it, 0)
}
//cancel alarm
manager.cancel(intentAlarm)
}
}
//delivers notification for alarm
class AlaramFireReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
//Notification ID
val channelid="channelId"
val manger=context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
//check for device only available for Oreo and above
if (Build.VERSION.SDK_INT >=Build.VERSION_CODES.O){
val channel= NotificationChannel(channelid,"alarm notification",NotificationManager.IMPORTANCE_HIGH)
channel.enableLights(true)
manger.createNotificationChannel(channel)
}
//build notification
val build=NotificationCompat.Builder(context,channelid)
.setSmallIcon(R.drawable.ic_access_time_black_24dp)
.setContentTitle("alarm")
.setContentTitle("time done")
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setColor(Color.RED)
//Deliver notification
manger.notify(0,build.build())
}
}
What I do is something similar to how you move to the next element in a linked list. I keep in database a ReminderEntity that has all the days of the week the user enabled the Alarm to go off.
Then I schedule the first day only. When the first day triggers then in that moment I schedule the next day and so on.
Same thing if the user deletes the first coming Alarm before it happens. In this case I clear the removed day from the entity and schedule an alarm for the next one available.
use different requestCode for the pending intents and use .FLAG_MUTABLE for type of Flag
int requestCode = (int) System.currentTimeMillis();
Intent intent = new Intent(load.this, AlarmReceiver.class);
return PendingIntent.getBroadcast(this, requestCode , intent, PendingIntent.FLAG_MUTABLE);
Related
I want to be able to set a variable alarm from the background whenever my service is run. I am using the following code:
...
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
...
Intent i = new Intent(AlarmClock.ACTION_SET_ALARM);
i.putExtra(AlarmClock.EXTRA_SKIP_UI, true);
i.putExtra(AlarmClock.EXTRA_HOUR, 9);
i.putExtra(AlarmClock.EXTRA_MINUTES, 9);
i.putExtra(AlarmClock.EXTRA_MESSAGE, "Good Morning");
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
}
...
I am aware that an activity cannot be started from the background. But is there any other way or a hack to be able to accomplish what I need to do here?
Looking at Schedule Repeating Alarms documentation, you could use AlarmManager with a PendingIntent as seen below.
When you start the service, you could always set up the alarm and set the alarm to trigger straight away using the current time.
When the alarm goes off, it sends out a intent to a Broadcast Reciever (which is AlarmReceiver in the case below - just make your own). You can then do whatever you want from AlarmReceiver.
It is probably worth running through the full documentation as I found it super useful. It will only take maximum 15 minutes, is really clear and it should meet your requirement.
private var alarmMgr: AlarmManager? = null
private lateinit var alarmIntent: PendingIntent
...
alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmIntent = Intent(context, AlarmReceiver::class.java).let { intent ->
PendingIntent.getBroadcast(context, 0, intent, 0)
}
// Set the alarm to start at 8:30 a.m.
val calendar: Calendar = Calendar.getInstance().apply {
timeInMillis = System.currentTimeMillis()
set(Calendar.HOUR_OF_DAY, 8)
set(Calendar.MINUTE, 30)
}
// setRepeating() lets you specify a precise custom interval--in this case,
// 20 minutes.
alarmMgr?.setRepeating(
AlarmManager.RTC_WAKEUP,
calendar.timeInMillis,
1000 * 60 * 20,
alarmIntent
)
i'm developing an application where i need to set multiple alarm in a day.
Every time my application receives Intent.ACTION_DATE_CHANGE or Intent.ACTION_BOOT_COMPLETED i schedule schedule the alarms for the current day.
Users from the application preferences can change if they want to receive alarm based reminders for each event category.
How can i cancel all the alarm just for a single category?
Actually I schedule events in this way:
AlarmManager alarmMan = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
for (MyCustomEvent evt : events) {
Intent intentEvt = new Intent(context, ReceiverNotificationPublisher.class);
// the id is long value
intentEvt.putExtra(ReceiverNotificationPublisher.ITEM_ID, evt.getId());
// the category is int value
intentEvt.putExtra(ReceiverNotificationPublisher.ITEM_CATEGORY, evt.getCategory());
// others values here
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, evt.getCategory(), intentEvt, PendingIntent.FLAG_UPDATE_CURRENT);
// set event
alarmMan.setExact(AlarmManager.RTC_WAKEUP, evt.getTimestampMillis(), pendingIntent);
}
Thanks to everyone in advance
I have to send 3 different notification(different content) at different time in a day.
Following the official documentation, https://developer.android.com/training/scheduling/alarms.html#type,
I was able to send notification at specified times, but having some trouble with changing the content of each notification. Following is the method to set notifications and is called in onCreate() method of MainActivity.
public void setNotification() {
Intent intent = new Intent(this, MyBroadcastReceiver.class);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
for (int id = 0; id < 3; id++) {
Calendar calendar = Calendar.getInstance();
// Defining different pendingIntent
switch (id){
case 0:
calendar.set(Calendar.HOUR_OF_DAY, 9);
break;
case 1:
calendar.set(Calendar.HOUR_OF_DAY, 14);
break;
case 2:
calendar.set(Calendar.HOUR_OF_DAY, 20);
break;
}
if(calendar.getTimeInMillis() < System.currentTimeMillis()){
calendar.add(Calendar.DATE, 1);
}
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, id, intent, 0);
// setRepeating() schedules an alarm
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent);
}
}
I am aware that I can use Intent.putExtra() features to send data, which can be used to identify the intent, but this data will be lost if app is killed.
I want this to work even if app is not running or app gets killed or device is booted. After some reading I found out that I can use a BOOT_COMPLETE listener to set alarms after device is booted. Because of setting notifications in onCreate() method, notification is appearing everytime I run the app, even though I tried to tackle this by using following code
if(calendar.getTimeInMillis() < System.currentTimeMillis()){
calendar.add(Calendar.DATE, 1);
}
Currently onReceive method looks like this
public void onReceive(Context context, Intent intent) {
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(context)
.setSmallIcon(R.mipmap.app_icon)
.setContentTitle("Title")
.setContentText("Message");
Intent resultIntent = new Intent(context, MainActivity.class);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
stackBuilder.addParentStack(MainActivity.class);
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(0, mBuilder.build());
}
I need help in deciding where should I put setNotification() method so that it registers all alarms once and how to identify which intent is coming so that appropriate actions can be taken. One way to go about it is to define 3 different broadcastReceivers with intent filters and set intent URI while creating them. Is it the correct way or is there any other simple solution?
notification is appearing everytime I run the app,
Keep a check using SharedPreference and set only once if not done.
Also your code
if(calendar.getTimeInMillis() < System.currentTimeMillis()){
calendar.add(Calendar.DATE, 1);
}
should be somewhat like this
Calendar calendar = Calendar.getInstance();
// Get the current time in millis
long currentTime = calendar.getTimeInMillis();
// Set the reminder times
switch(id) {
..
..
}
//Get the reminder time in millis
long intendedTime = calendar.getTimeInMillis();
if (intendedTime < currentTime) {
// Set from next day and to repeat once a day.
// you might consider using calendar.add() for adding one day to the current day
calendar.add(Calendar.DAY_OF_MONTH, 1);
intendedTime = calendar.getTimeInMillis();
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP,
intendedTime, AlarmManager.INTERVAL_DAY, pendingIntent);
} else {
// Set for today and to repeat once a day.
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, intendedTime,
AlarmManager.INTERVAL_DAY, pendingIntent);
}
how to identify which intent is coming so that appropriate actions can
be taken
You need to set an action to Intent in order to receive data in BroadcastReceiver
Intent intent = new Intent(this, MyBroadcastReceiver.class);
intent.setAction("THIS_IS_MY_ACTION");
Case of BOOT_COMPLETE
Cancel all the alarm on Boot, and reset them. To cancel an alarm Call cancel() on AlarmManager with an same PendingIntent which you have used while setting an alarm using setRepeating().
Take care of context and INTENT_FLAGS while working with AlarmManager.
Use getApplicationContext() for context and Keep records of request_code as they are going to be used while cancelling an alarm, use PendingIntent.FLAG_UPDATE_CURRENT
This might help:-
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), request_code, intent, PendingIntent.FLAG_UPDATE_CURRENT)
the app i'm doing have to schedule an notifications if the user choose to
every time the user close the app the must must check and make the notification based on the user choice
the problem is if the user choose to have notification every time he close the app my code will put new notification for the same the thing so when the notification is fired there will be many notification instead of just one
i need to know if i can check if there is scheduled notification just like the one that i'm trying to make to avoid duplication and have one notification only
here is my code:
private void createScheduledNotification(long dateop,int days,String vaa,String naa)
{
Calendar calendars = Calendar.getInstance();
calendars.setTimeInMillis(dateop);
if(days<30){
calendars.add(Calendar.HOUR_OF_DAY, days *24);
}
else{
calendars.add(Calendar.MONTH, days/30);
}
AlarmManager alarmManager = (AlarmManager) getApplicationContext().getSystemService(getBaseContext().ALARM_SERVICE);
int id = (int) System.currentTimeMillis();
Intent intent = new Intent(this, TimeReceiver.class);
intent.putExtra("username", naa);
intent.putExtra("vaccine", vaa);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), id, intent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.set(AlarmManager.RTC_WAKEUP, calendars.getTimeInMillis(), pendingIntent);
}
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.