Why my Alarm is fired earlier than my set time? - android

I'm currently trying to make an alarm app that will mute all audio volume at the user-defined day and time. However, the alarm seems not fired at the correct time. I found that the alarm is always fired earlier.
This is my set alarm code:
public static void setAlarm(Context context, String time, int day, int reqCode) {
String[] timeSplit = time.split(":");
Calendar calendar = Calendar.getInstance();
int hour = Integer.parseInt(timeSplit[0]);
int minute = Integer.parseInt(timeSplit[1]);
int days = (day-calendar.get(Calendar.DAY_OF_WEEK) + calendar.get(Calendar.DAY_OF_MONTH));
calendar.set(
calendar.get(Calendar.YEAR),
calendar.get(Calendar.MONTH),
days,
hour,
minute,
0
);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, RuleAlarm.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, reqCode, intent, 0);
// Set the alarm to be fired every week on the selected day
alarmManager.setRepeating(AlarmManager.RTC, calendar.getTimeInMillis(), 7 * 24 * 60 * 60 * 1000, pendingIntent);
Toast.makeText(context, "Alarm is set", Toast.LENGTH_SHORT).show();
}
I have tried to change setRepeating() to setInexactRepeating() but nothing changed.

AlarmManger is inexact to save battery by combining wakeup calls.
https://developer.android.com/reference/android/app/AlarmManager.html

Try this
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 7 * 24 * 60 * 60 * 1000, pendingIntent);
The problem is that if you are creating PendingIntent for an alarm for past time it will be fired immediately.If you would like to prevent that happening, then simply do not set alarms with a past trigger time . Use BroadcastReceiver for receiving alarm.
Update :
Check we aren't setting it in the past which would trigger it to fire instantly
if(calendar.getTimeInMillis() < System.currentTimeMillis()) {
calendar.add(Calendar.DAY_OF_YEAR, 7);
}

I finally find out the problem. It lies on the day params. What I pass to day params is my Spinner selected position which starts from zero while the Calendar days starts from one (SUNDAY = 1, MONDAY = 2, so on). So, the alarm will always be set in the past days. I plus one to the day params and it's worked.
This is my piece of code where the startAlarm() function got called.
String ruleStartTime = rule_startTime.getText().toString();
// Spinner index starts from zero,
// to match with the Calendar day indexing, we need to plus it one
int dayIdx = day.getSelectedItemPosition()+1;
Alarm.setAlarm(getApplicationContext(), ruleStartTime,
dayIdx, 0);

Related

Detect alarm in onReceive() method and match with Room Database

I have two alarm which fires at an interval of 3 min. What will I store in the Room database so that I can know which alarm is firing? I am using TIME_ONE and TIME_TWO to pass a value and detecting in the receiver end. But I think it is bad practice for large number of alarms. It would be better it I can match the id of the alarm that will fire with the stored id in the Room database. Or if I store store the requestcode in the db then how will I get the request code in the onReceive method. I have also tried alarmIntent.putExtra(TIME_ONE, 2); and alarmIntent.putExtra(TIME_ONE, 1); I am not sure if one name can hold two values and work fine. What will be the id of the alarm so that I can get the exact alarm in the onReceive method as it fires? If I pass the requestcode using putExtra should I use one tag (TIME_ONE) or multiple tags(TIME_ONE, TIME_TWO) to detect alarms? I don't want to use if else to check which one throwing 1 so that I can handle. How can I use intent of the onReceive method so that I can know directly which alarm is firing? You can imagine the scenario as two alarms set time to alarm and detect for which alarm the onReceive method is called.
private void setAlarm() {
Intent alarmIntent = new Intent(this, MyAlarmReceiver.class);
alarmIntent.putExtra(TIME_ONE, 1);
pendingIntent = PendingIntent.getBroadcast(this, 1, alarmIntent, 0);
manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
int interval = 1000 * 60 * 3; // 3 min
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 22);
calendar.set(Calendar.MINUTE, 1);
manager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), interval, pendingIntent);// repeat every two min interval
}
private void setSecAlarm() {
Intent alarmIntent = new Intent(this, MyAlarmReceiver.class);
alarmIntent.putExtra(TIME_TWO, 1);
pendingIntent = PendingIntent.getBroadcast(this, 2, alarmIntent, 0);
manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
int interval = 1000 * 60 * 3; // 3 min
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 22);
calendar.set(Calendar.MINUTE, 3);
manager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), interval, pendingIntent);// repeat every two min interval
}
The onReceive method:
Calendar instance = Calendar.getInstance();
#Override
public void onReceive(Context context, Intent intent) {
int hour = instance.get(Calendar.HOUR);
int minute = instance.get(Calendar.MINUTE);
int second = instance.get(Calendar.SECOND);
int which_one = intent.getIntExtra(TIME_ONE,0);
int which_two = intent.getIntExtra(TIME_TWO,0);
if(which_one == 1 && which_two == 0){
Log.d(MY_TAG, hour+":"+minute+":"+second+ " First alarm called");
}else if(which_one == 0 && which_two == 1){
Log.d(MY_TAG, hour+":"+minute+":"+second+" Second alarm called");
}else{
Log.d(MY_TAG, hour+":"+minute+":"+second+ " none of them");
}
}
Late answer, hope you've solved this already of course .
I 'd just pass an id of the database row in the alarm intent.
The Insert Dao will return an Id, use it as the alarm identifier, and in onreceive you directly get the relevant row.

Alarm Manager not scheduling alarm properly

I am setting alarm usng this
Calendar now = Calendar.getInstance();
Calendar alarm = Calendar.getInstance();
alarm.set(Calendar.HOUR_OF_DAY,21);
alarm.set(Calendar.MINUTE,30);
if (alarm.before(now)) {
alarm.add(Calendar.DAY_OF_MONTH, 1); //Add 1 day if time selected before now
}
AlarmManager alarmManager =(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context,Receiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context,(int)alarm.getTimeInMillis(),i,0);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, (int)alarm.getTimeInMillis(),AlarmManager.INTERVAL_DAY,pi);
But even if I schedule it for next day,it triggers immediately after saving alarm.
Dont know what the issue is have searched a lot but everyone else gets it working
You are casting a long timestamp to int thus losing bits and changing the actual timestamp value. You end up with a time that already has passed so it executes the intent immediately.
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, alarm.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pi);
Notice that I removed the (int) cast in the last line.

Run Alarm In Selected Days

I want to start alarm when i have selecting the days,hours,and minutes.
This is my code so far :
public void startAt() {
Intent alarmIntent = new Intent(backgroundApplication.this, AlarmReceiver.class);
pendingIntent = PendingIntent.getBroadcast(backgroundApplication.this, 0, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.DAY_OF_WEEK,calendar.WEDNESDAY);
calendar.set(Calendar.HOUR_OF_DAY,7);
calendar.set(Calendar.MINUTE,35);
manager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
1000 * 5, pendingIntent);
}
For the example i set the DAY_OF_WEEK is today(friday) it works great. But when i changed it into Wednesday, or other day before friday it still running.
Is there any other way to start in selected days ?
According to the documentation http://developer.android.com/reference/android/app/AlarmManager.html#setRepeating%28int,%20long,%20long,%20android.app.PendingIntent%29, the 2nd parameter is the trigger time in milliseconds and if you set it to a time in the past, the alarm will trigger immediately. If you want the alarm to only start from next Wednesday, then you have to advance your Calendar time to the next Wednesday with calendar.add(Calendar.WEEK_OF_MONTH, 1). By the way, in your code, you don't need to have calendar.setTimeInMillis(System.currentTimeMillis()).Calendar.getInstance() will return the current time by default. You should also use static field Calendar.WEDNESDAY.

Alarm is running immediately after it is created

I am trying to play a ringtone at exactly at 7 PM everyday but it is playing ringtone immediately after its pending intent is registering broadcast.
I called the service in the foreground on a button click and created pending intent there in onStartCommand:
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
startForeground(FOREGROUND_ID,
buildForegroundNotification("DummyApp"));
c = Calendar.getInstance();
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
int interval = 1000 * 60 * 60*24;
c.setTimeInMillis(System.currentTimeMillis());
c.set(Calendar.HOUR, 19);
c.set(Calendar.MINUTE,00);
manager.setRepeating(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(),
interval, pendingIntent);
Intent alarmIntent = new Intent(AlarmService.this, DataProcessor.class);
pendingIntent = PendingIntent.getBroadcast(AlarmService.this, 0,
alarmIntent, 0);
return START_STICKY;
}
Now I am playing a ringtone on receiving this broadcast in DataProcessor class the on Receive method of Data Processor class:
#Override
public void onReceive(Context ctx,Intent intent) {
playRIng(ctx);
}
But when I run this code,click the button,service is created but alarm is fired immediately after the AlarmService is called and ringtone is played also.How it is possible because I am giving the exact 7 O clock time when registering broadcast.?
Googled a lot but found the same code only and nothing else.Every code is able to play the ringtone on the time but it also plays the ringtone immediately after the broadcast is registered.
Why you don't use a condition?:
#Override
public void onReceive(Context ctx,Intent intent) {
Calendar c = Calendar.getInstance();
int hour = c.get(Calendar.HOUR);
if(hour==19)
{
playRIng(ctx);
}
}
If you ran that code at 9pm you would be telling the AlarmManager that the intent should have been run for the first time 2 hours ago.
You need to check if the Calendar time is behind the current time.
If it is you need to add a day to the calendar so that it first triggers tomorrow at 7pm.
Something like this might work:
c = Calendar.getInstance();
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
int interval = 1000 * 60 * 60 * 24;
// Not needed
// c.setTimeInMillis(System.currentTimeMillis());
c.set(Calendar.HOUR, 19);
c.set(Calendar.MINUTE, 00);
// ** Add this **
// Check if the Calendar 7pm is in the past
if (c.getTimeInMillis() < System.currentTimeMillis())
c.add(Calendar.DAY_OF_YEAR, 1); // It is so tell it to run tomorrow instead
manager.setRepeating(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(), interval, pendingIntent);
Intent alarmIntent = new Intent(AlarmService.this, DataProcessor.class);
pendingIntent = PendingIntent.getBroadcast(AlarmService.this, 0, alarmIntent, 0);
You can try the example at developers website understanding the samplecode available there.May be there is some programming mistake in your code but the sample code available there is working exactly you want.
Scheduling Repeating Alarms
Best way, Play with hour & mintue.
Note: Please check your time formate. In my case it's 24 hr formate
Example:
Calendar c = Calendar.getInstance();
//for 12 hr formate user int hour = c.get(Calendar.HOUR);
int hour = c.get(Calendar.HOUR_OF_DAY);
int minute = c.get(Calendar.MINUTE);
//Log.e("time",""+hour+":"+minute);
if (hour == 10 && minute == 0 ) {
}

AlarmManager fires alarm immediately (while it shouldn't)

I have a scheduleAlarm class which is supposed to set the alarm in a specific time, however the alarm is being fired immediately after the method is called. I've checked that provided time in milliseconds is fine, so I've no idea what's going on.
private void scheduleAlarm(int day, int startHour, int startMinute, String info) {
AlarmManager mAlarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
Calendar c = Calendar.getInstance();
c.set(Calendar.DAY_OF_WEEK, day);
c.set(Calendar.HOUR, startHour);
c.set(Calendar.MINUTE, startMinute);
Intent startIntent = new Intent(this, Recorder.class);
startIntent.putExtra("info", "someinfo");
Log.v("millis", String.valueOf(c.getTimeInMillis())); // time is okay
Random mRandom = new Random();
int randomInt = mRandom.nextInt();
PendingIntent pendingIntent = PendingIntent.getService(this, randomInt, startIntent,PendingIntent.FLAG_UPDATE_CURRENT);
mAlarmManager.set(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(), pendingIntent);
}
Just make sure that the time set for the alarm is after current time.
There is an easy way to check that.
just do
Calendar.getInstance().getTimeInMilis() - c.getTimeInMillis()
Log this result, and you can see if the second is before the first.
Lets say now is 4 o'clock, and you set the same day and 3 o'clock. it will get activated instantly.
Other than that i see no reason why it should fail.
Another way to test would be to use currentTime and add lets say 10k miliseconds and see if it activates in 10 seconds after you test it. Then you are sure that the time set is wrong in your case.

Categories

Resources