Create alarms in Android - android

i used below code to create alarm.
public static void RegisterForAlarmEvent(Context ct, long intervel)
{
Intent intent = new Intent(ct, AlarmReceiver.class);
PendingIntent mAlarmSender = PendingIntent.getBroadcast(ct,
constants.ALARM_ID, intent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager am = (AlarmManager) ct
.getSystemService(ct.ALARM_SERVICE);
Long totalTime = getCurrentTimeinMiliSeconds() + intervel;
am.set(AlarmManager.RTC, totalTime , mAlarmSender);
}
I need to check next time, if the alarm is already registered & its triggered. If its triggered then only i need to re-register.
So, i'm checking like this to know, if the alaram is already registered.
boolean alarmUp = (PendingIntent.getBroadcast(ct, id, intent, PendingIntent.FLAG_NO_CREATE)!= null);
If i call register using alaramevent method & check alarm is already registered i get NULL, literally it should return NULL, once the alarm is executed right?
How to check alarm is already fired or not?

According to docs FLAG_NO_CREATE:
Flag for use with getActivity, getBroadcast, and getService: if the described PendingIntent does not already exist, then simply return null instead of creating it.
So if the pending intent already created then it will return the reference to the previous pending intent. If not then it will return null.
And the answer to your question is maintain some shared preference value and change that value in broadcast receiver. Based on that value

Related

Multiple Alarm for multiple Alarm Manager Object

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));

Get list of registered Pending Intents in Android OS

I register alarms which I schedule to execute at given time, and it can be many alarms depending on the size of the scheduled list. But I have two questions which remains unclear to me:
1) How can I query the OS for the Pending Intents I registers? I need this for testing. The psudo code for what I want would be something like this:
List<PendingIntent> intentsInOS = context.getAllPendingIntentsOfType(AppConstants.INTENT_ALARM_SCHEDULE));
2) See the pending intent I create, I provide an action and extra data (the schedule id).
private Intent getSchedeuleIntent(Integer id) {
Intent intent = new Intent(AppConstants.INTENT_ALARM_SCHEDULE);
intent.putExtra(AppConstants.INTENT_ALARM_SCHEDULE_EXTRA, id);
return intent;
}
But we also say that the intent have FLAG_CANCEL_CURRENT. Will it cancel all pending intents with same action, or does it have to both same action AND extra data?
PendingIntent pendingIntent = PendingIntent.getBroadcast(context.getApplicationContext(), 0, getSchedeuleIntent(schedule.id), PendingIntent.FLAG_CANCEL_CURRENT);
My code
#Override
public void run() {
List<ScheduledLocation> schedules = dbManager.getScheduledLocations();
if(schedules == null || schedules.isEmpty()){
return;
}
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
//alarmManager.
// we need to get the number of milliseconds from current time till next hour:minute the next day.
for(ScheduledLocation schedule : schedules){
long triggerAtMillis = DateUtils.millisecondsBetweenNowAndNext(now, schedule.hour, schedule.minute, schedule.day);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context.getApplicationContext(), 0, getSchedeuleIntent(schedule.id), PendingIntent.FLAG_CANCEL_CURRENT);
alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtMillis, MILLISECONDS_IN_WEEK, pendingIntent);
}
// List<PendingIntent> intentsInOS = context.getAllPendingIntentsOfType(AppConstants.INTENT_ALARM_SCHEDULE));
}
private Intent getSchedeuleIntent(Integer id) {
Intent intent = new Intent(AppConstants.INTENT_ALARM_SCHEDULE);
intent.putExtra(AppConstants.INTENT_ALARM_SCHEDULE_EXTRA, id);
return intent;
}
1 How can I query the OS for the Pending Intents I registers?
I'm not sure you can, but you can check if a specific PendingIntent is registered or not like this :
private boolean checkIfPendingIntentIsRegistered() {
Intent intent = new Intent(context, RingReceiver.class);
// Build the exact same pending intent you want to check.
// Everything has to match except extras.
return (PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_NO_CREATE) != null);
}
2 Will it cancel all pending intents with same action, or does it have to both same action AND extra data?
It will cancel all the PendingIntent that are resolved to be equal.
What exactly does equal means ?
The java doc of android says:
Determine if two intents are the same for the purposes of intent
resolution (filtering). That is, if their action, data, type, class,
and categories are the same. This does not compare any extra
data included in the intents.
You can read at the 7391 line here : https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/content/Intent.java
To sum up, all PendingIntent that are build exactly the same except extras will be cancelled.

How to properly cancel pending alarms

I can't seem to find an answer to this, but what is the criteria for passing in a matching PendingIntent to be removed from an alarm? It it based on the just the name like com.blah.package.myclass or do the Extras matter?
For example, I'm doing something like this and all alarms fire the same intent:
public void setAlarm(Context context, long nextAlarmMillis) {
Intent intent = new Intent(context, AlarmReceiver.class);
intent.putExtra("alarm", this);
PendingIntent sender = PendingIntent.getBroadcast(context, 1234 /* unused */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Get the AlarmManager service
AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
am.cancel(sender);
am.set(AlarmManager.RTC_WAKEUP, nextAlarmMillis, sender);
}
What happens is that the Alarm class can be altered, etc and passed in as an Extra. I am canceling the previous alarm, but I'm not sure if it's doing anything or if any left over alarms will remain.
Anyone know for sure?
Following is mentioned in AlarmManager documentation
Any alarm, of any type, whose Intent matches this one (as defined by filterEquals(Intent)), will be canceled.
Which, the filterEquals() is defined as:
Determine if two intents are the same for the purposes of intent resolution (filtering). That is, if their action, data, type, class, and categories are the same. This does not compare any extra data included in the intents.
I think the easiest to do is you keep the reference of PendingIntent passed to AlarmManager, and pass it to cancel. Or have a factory method to construct such pi.

How to set multiple alarms using alarm manager in android

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);

Intent.putExtras not consistent

I have a weird situation with AlarmManager. I am scheduling an event with AlarmManager and passing in a string using intent.putExtra. The string is either silent or vibrate and when the receiver fires the phone should either turn of the ringer or set the phone to vibrate. The log statement correctly outputs the expected value each time.
Intent intent;
if (eventType.equals("start")) {
intent = new Intent(context, SReceiver.class);
} else {
intent = new Intent(context, EReceiver.class);
}
intent.setAction(eventType+Long.toString(newId));
Log.v("EditQT",ringerModeType.toUpperCase());
intent.putExtra("ringerModeType", ringerModeType.toUpperCase());
PendingIntent appIntent = PendingIntent.getBroadcast(context, 0,
intent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService (Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
appIntent);
The receiver that fires when the alarm executes also has a log statement and I can see the first time around that the statement outputs the expected string either SILENT or VIBRATE but for each subsequent execution the output shows the original value on the receiver end. The alarm executes and then I change the value for putExtra to opposite string and the receiver still displays the previous value event though the call from the code above shows that the new value was passed in. The value for setAction is the same each time.
audioManager = (AudioManager) context.getSystemService(Activity.AUDIO_SERVICE);
Log.v("Start",intent.getExtras().get("ringerModeType").toString());
if (intent.getExtras().get("ringerModeType").equals("SILENTMODE")) {
audioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
} else {
audioManager.setRingerMode(AudioManager.RINGER_MODE_VIBRATE);
}
Any thoughts?
Your very question was asked six hours ago.
If you will have multiple PendingIntents at the same time with different extras, you will need to vary something else in the Intents, like the action string or the Uri, as described in the linked-to issue above.
If you will only have one PendingIntent at a time, but your extra may vary, just use FLAG_UPDATE_CURRENT in your call to getBroadcast().
Multiple PendingIntents:
Intent notificationIntent = new Intent(this, Oconf.class);
notificationIntent.setData(Uri.parse("text"));
Then, onNewIntent(Intent intent):
String text = intent.getData().toString();

Categories

Resources