I am trying to implement alarm that notify daily at the same time. It works fine. But when i set alarm again it notify me on the spot without waiting time to come, because time on which alarm is set has been passed. But when I change Calendar.DATE to Calendar.DAYS_OF_MONTH it does not notify me. So can any one help me where i am wrong. I am sharing my code below.
public void setNotification() {
PendingIntent pendingIntent = createPendingIntent();
Calendar calendarToSet=Calendar.getInstance();
Calendar currentTime=Calendar.getInstance();
calendarToSet.set(Calendar.HOUR,10);
calendarToSet.set(Calendar.MINUTE,0);
calendarToSet.set(Calendar.SECOND,0);
calendarToSet.set(Calendar.AM_PM,Calendar.AM);
if(calendarToSet.before(currentTime))
{
calendarToSet.set(Calendar.DATE,1);
}
AlarmManager alarmManager = (AlarmManager) MyAppManager.context.getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,calendarToSet.getTimeInMillis(),AlarmManager.INTERVAL_DAY,pendingIntent);
// Toast.makeText(MyAppManager.context, "set", Toast.LENGTH_LONG).show();
}
public PendingIntent createPendingIntent() {
Intent intent = new Intent(MyAppManager.context, TaffaquhFiddinBroadCastReceiver.class);
intent.putExtra("key", "What_to_say_upon_completing_ablution");
PendingIntent pendingIntent = PendingIntent.getBroadcast(MyAppManager.context, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
return pendingIntent;
}
What i am trying to do is to set alarm for the next day if the time is passed so please help.
Also what is the difference between Calendar.DATE and Calendar.DAYS_OF_MONTH?
The problem is you are setting the day field of your Calendar instance, instead of adding a day to it.
Change the following:
calendarToSet.set(Calendar.DATE, 1);
To this:
calendarToSet.add(Calendar.DATE, 1);
Also what is the difference between Calendar.DATE and
Calendar.DAYS_OF_MONTH?
They are the same, DATE is just a synonym for DAY_OF_MONTH.
From the source code of the Calendar class:
public static final int DATE = 5;
public static final int DAY_OF_MONTH = 5;
As you can see, they represent the same value.
Related
I've built one small reminder app demo. Now the problem is sometimes reminder coming or sometimes not? Now, I have this feature that user can set the alarm for day, month, week, year.
Now how can I check for the month or year that notification is coming or not?
Obviously, when I manually go and change the Android date and time settings, alarm not coming. (Even for some minutes also)
See: When I change Android phone date and time, notification not getting, otherwise, if I do nothing, I get notification on time
Edit:
Code:
public void setRepeatAlarm(Context context, Calendar calendar, int ID, long RepeatTime, int requestCode) {
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
// Put Reminder ID in Intent Extra
Intent intent = new Intent(context, AlarmReceiver.class);
intent.putExtra(REMINDER_ID, Integer.toString(ID));
mPendingIntent = PendingIntent.getBroadcast(context, ID, intent, PendingIntent.FLAG_CANCEL_CURRENT);
mPendingIntent = PendingIntent.getBroadcast(context, requestCode, new Intent(context, AlarmReceiver.class),
PendingIntent.FLAG_NO_CREATE);
isAlarmSet = (mPendingIntent != null);
if (isAlarmSet) {
showLog("isAlarmSet: " + isAlarmSet);
} else {
showLog("isAlarmSet: " + isAlarmSet);
}
// Calculate notification timein
Calendar c = Calendar.getInstance();
long currentTime = c.getTimeInMillis();
long diffTime = calendar.getTimeInMillis() - currentTime;
// Start alarm using initial notification time and repeat interval time
mAlarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + diffTime,
RepeatTime, mPendingIntent);
// Restart alarm if device is rebooted
ComponentName receiver = new ComponentName(context, BootReceiver.class);
PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(receiver,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
}
You can check for existing alarm using this :
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, requestCode,
new Intent(this, AlarmReceiver.class),
PendingIntent.FLAG_NO_CREATE);
boolean isAlarmSet = (pendingIntent!=null);
Note that the requestCode here should be the same one used while setting the alarm. Also, AlarmReceiver is your BroadcastReceiver class for alarm
I have not tested this in the scenario you mentioned (changing the phone time), but you can refer this and set your alarm again according to the new time and cancel the previous one.
You have pretty knowledge about Design Pattern. Please follow the Observer Pattern to mange below thing and get always new time when you change time manually or not. It will check current time is changed or not. More details Please read Observer Pattern Documentation.
// Calculate notification timein
Calendar c = Calendar.getInstance();
long currentTime = c.getTimeInMillis();
long diffTime = calendar.getTimeInMillis() - currentTime;
You should listen to time changes in the android system and act accordingly
<receiver android:name=".TimeChangedReceiver">
<intent-filter >
<action android:name="android.intent.action.TIME_SET"/>
</intent-filter>
</receiver>
Broadcast receiver class
public class TimeChangedReceiver extends BroadcastReceiver{
#Override
public void onReceive(final Context arg0, Intent arg1) {
//Call your Alarm setting code
// change your alarm accordingly
}
}
I have used AlarmManager to set the alarm and passed the time from timePicker.
I want to set alarm at the given time but if the time(that I am going to set) has been passed then the alarm triggers immediately .
Example:- If the current time is 9:00 PM and I set alarm for 7:00PM then the alarm triggers immediately.
Below is my code
public void startAlarm(Calendar c, int id){
Toast.makeText(this, "Alarm in on", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(this,AlarmReciever.class);
intent.putExtra("id",id);
//int _id = (int)System.currentTimeMillis();
PendingIntent pendingIntent = PendingIntent.getBroadcast(this,id,intent,PendingIntent.FLAG_ONE_SHOT);
alarmManager = (AlarmManager)getSystemService(ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,c.getTimeInMillis(), 1000*60,pendingIntent);
//alarmManager.set(AlarmManager.RTC_WAKEUP,c.getTimeInMillis(),pendingIntent);
}
How to control the triggering of alarm if the time for which we are setting alarm has been passed?
You will need to detect if the calendar time is in the past and adjust it accordingly. Like so:
public void startAlarm(Calendar c, int id){
Toast.makeText(this, "Alarm in on", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(this,AlarmReciever.class);
intent.putExtra("id",id);
//Check if calendar is set in the past
if (c.getTimeInMillis() < System.currentTimeMillis()) {
//Add one day to the calendar (or whatever repeat interval you would like)
c.add(Calendar.DAY_OF_YEAR, 1);
}
//int _id = (int)System.currentTimeMillis();
PendingIntent pendingIntent = PendingIntent.getBroadcast(this,id,intent,PendingIntent.FLAG_ONE_SHOT);
alarmManager = (AlarmManager)getSystemService(ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,c.getTimeInMillis(), 1000*60,pendingIntent);
//alarmManager.set(AlarmManager.RTC_WAKEUP,c.getTimeInMillis(),pendingIntent);
}
As I'm not sure how you are allowing the user to set the time I'm not sure if the addition of one day will always do the trick. For instance, if you allow the user to pick a date from a calendar it may be years in the past. You will need to adjust how much time you add based on your desired repeat interval and how you are allowing the user to set the time.
TL;DR - AlarmManager .setRepeating is starting immediately instead of the desired future time.. (for example 5 minutes from now)
So basically I am starting an alarm manager and i'm giving it the time left to operate and for some reason it is firing instantly.. the user is choosing a time from a time picker, and I set this time for the next alarm.
code below:
-this method get's the time left until the alarm, this is used as the triggerInMillis for the alarmManager.
/** calculate the time left until the alarm with calendar */
private static long getTimeFromCalendar(final int hourOfDay, final int minute) {
Date dat = new Date();//initializes to now
Calendar cal_alarm = Calendar.getInstance();
Calendar cal_now = Calendar.getInstance();
cal_now.setTime(dat);
cal_alarm.setTime(dat);
cal_alarm.set(Calendar.HOUR_OF_DAY,hourOfDay);
cal_alarm.set(Calendar.MINUTE, minute);
cal_alarm.set(Calendar.SECOND,0);
if(cal_alarm.before(cal_now)){
cal_alarm.add(Calendar.DATE,1);
}
long calAlarm = cal_alarm.getTimeInMillis();
long calNow = cal_now.getTimeInMillis();
long timeLeft = (calAlarm - calNow);
return timeLeft;
}
then I call the -startAlarm- method :
private static void startAlarm(final Enums typeToStart) {
final PendingIntent pendingIntent = GBAlarms.createPendingIntent(OnAlarmReceiver.class, Constants.typeEnum, typeToStart);
final long timeToAlarm = Utils.getTimeToAlarm(typeToStart);
long repeatTime = Constants._24hours;
GBAlarms.createRepeatingAlarm(timeToAlarm, repeatTime, pendingIntent);
}
and finally, my -GBAlarms.class- where i create my alarms and pending intents.
public class GBAlarms {
/** Define our AlarmManager */
private static AlarmManager mgr = (AlarmManager) BaseApplication.getAppContext().getSystemService(Context.ALARM_SERVICE);
/** Create a new PendingIntent */
public static PendingIntent createPendingIntent(final Class destination, #Nullable final String extra, Enums.TeaType type) {
Intent i = new Intent(BaseApplication.getAppContext(), destination);
if (extra != null && type != null) { i.putExtra(extra, type); }
PendingIntent pi = PendingIntent.getBroadcast(BaseApplication.getAppContext(), type.getValue() , i, 0);
return pi;
}
/** Create a new repeating Alarm */
public static void createRepeatingAlarm(final long time, final long repeatTime, final PendingIntent pi) {
mgr.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, time, repeatTime, pi);
}
}
I don't understand, for some reason the alarm pops right when I set it in the -createRepeatingAlarm- method, and I debugged of course, the time parameter looks legit.. if I set it to 3 minutes, 10 minutes, it puts that time left in the trigger..
can anyone spot my mistake? maybe I'm missing something?
thanks a lot for any help.
You are creating a "pending" alarm,
a alarm that repeats after a specific interval.
The trick is to cancel the current alarm in the moment you are starting.
Look at the code below: You have to call the method getBroadcast with the
flag PendingIntent.CANCEL_CURRENT
AlarmManager alarmMgr;
PendingIntent pendingIntent;
public void startAlarmManager()
{
Intent dialogIntent = new Intent(getBaseContext(), AlarmBroadcastReceiver.class);
alarmMgr = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
pendingIntent = PendingIntent.getBroadcast(this, 0, dialogIntent,PendingIntent.FLAG_CANCEL_CURRENT);
alarmMgr.setInexactRepeating(AlarmManager.RTC_WAKEUP,System.currentTimeMillis(), 10000, pendingIntent);
}
}
why are you using ELAPSED_TIME?
please try using RTC_WAKEUP and switch
long timeLeft = (calAlarm - calNow);
with just calAlarm
you don’t need to mills left, you need the mills that you want it to pop.
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.
I've searched for examples of how to implement such a problem but couldn't find anything that could solve my problem so I'm asking you for an advice how to solve it.
I have to implement an alarm that fires every day at a specific time during the period between two specified dates.
Up to now I have a repeating alarm firing every day at a specific time but not specified until when to repeat...
Any advice and ideas will be highly appreciated!
Suppose you want to set an repeating Alarm from Date1 to Date2.
For Date1, there is no problem for you since it is working.
Set an alarm for Date2 and when that alarm is fired cancel Date1 repeating alarm.
I do it like this:
Lets say you wanted to set a repeating alarm, that first triggered at a 'random' time between two hours (e.g. 0100 - 0500) in the day, and then always triggered at that same time of day again every 24 hours.
private long getTimeOfNextWidgetAutoUpdateInMilliseconds(Calendar now, int startHour, int endHour){
// calc the time diff in milliseconds from now until a 'random' time between startHour and endHour
// ensure to +1 day if the time has already passed
}
private void createAutoRefreshAlarm(Context context, long initialTriggerTimeInMillis,
long intervalInMillis) {
AlarmManager alarmManager = getAlarmManager(context);
PendingIntent widgetRefreshPi = getWidgetRefreshAlarmPendingIntent(context);
setRepeatingAlarm(initialTriggerTimeInMillis, intervalInMillis, widgetRefreshPi,
alarmManager);
ApplicationData.setAppDataBoolean(WIDGET_REFRESH_ALARM_SERVICE_INITITATED, true);
}
private static void setRepeatingAlarm(long initialTriggerTimeInMillis, long intervalInMillis,
PendingIntent widgetRefreshPi, AlarmManager alarmManager) {
alarmManager.setRepeating(
AlarmManager.RTC_WAKEUP,
initialTriggerTimeInMillis,
intervalInMillis,
widgetRefreshPi);
}
private PendingIntent getWidgetRefreshAlarmPendingIntent(Context context) {
Intent alarmIntent = new Intent(context, AlarmManagerBroadcastReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
return pendingIntent;
}
private static AlarmManager getAlarmManager(Context context) {
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
return alarmManager;
}
I would then have the following in the WidgetProvider class:
#Override
public void onEnabled(Context context) {
super.onEnabled(context);
int startHour = 1;
int endHour = 5;
long initialTriggerTimeInMillis = getTimeOfNextWidgetAutoUpdateInMilliseconds(
Calendar.getInstance(),
startHour,
endHour);
long intervalInMillis = 86400000; // 24 hours
createAutoRefreshAlarm(context, initialTriggerTimeInMillis, intervalInMillis);
}
This should get you going, I've cut+pasted from my own project, so there may be a few errors.
Also, remember to cancel your alram in the onDisabled() method of your `WidgetProvider.
There are other scenarios that delete the alarm that you should consider, e.g. ON BOOT