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.
Related
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.
I have an Android app where I need to trigger reminders everyday at the same time. The alarm must repeat every 5 minutes if ignored. If the user declares he read the reminder, by clicking an OK button, the alarm must stop repeating, until it is triggered the day after.
So, I want the alarm to stop repeating after the user's confirmation, and I read that with AlarmManager I should use the cancel() method. But I don't want to delete the alarm for future days, I just want it to stop repeating until next trigger.
In other words, I don't want the cancel() method to unset the alarm for the future days. Is it the default behavior of the cancel() method or do I have to cancel the alarm and then re-set it every time?
This is my code for setting the alarm:
public class AlarmSettingManager
{
private static Context context;
// Constructor
public AlarmSettingManager(Context c)
{
context = c;
}
private static class PrescriptionAlarmSetter extends AsyncTask<String, Void, Boolean>
{
SharedPrefManager sharedPrefManager = SharedPrefManager.getInstance(context);
#Override
protected Boolean doInBackground(String... strings)
{
// Get the list of prescriptions from SharedPreferences
if(!sharedPrefManager.getPrescrizioneList().equals(""))
{
try
{
JSONArray responseJsonArray = new JSONArray(sharedPrefManager.getPrescrizioneList());
int currentID = Constants.PRESCRIZIONE_ALARM_ID;
for(int j=0; j<responseJsonArray.length(); j++)
{
JSONObject singlePrescription = responseJsonArray.getJSONObject(j);
Prescrizione prescrizione = new Prescrizione
(
singlePrescription.getInt("id_prescrizione"),
singlePrescription.getInt("id_medico"),
singlePrescription.getInt("id_farmaco"),
singlePrescription.getInt("numero_pasticche"),
singlePrescription.getInt("totale_compresse"),
singlePrescription.getString("nome"),
singlePrescription.getString("ora_assunzione"),
singlePrescription.getString("posologia"),
singlePrescription.getString("suggerimenti")
);
// Start setting the alarm for current prescription
Intent alarmIntent = new Intent(context, AlarmBroadcastReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast
(
context.getApplicationContext(),
currentID,
alarmIntent,
PendingIntent.FLAG_CANCEL_CURRENT
);
// put the RequestCode ID as extra in order to identify which alarm is triggered
alarmIntent.putExtra("id", currentID);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
// Specify the time to trigger the alarm
calendar.set(Calendar.HOUR_OF_DAY, prescrizione.getIntHour());
calendar.set(Calendar.MINUTE, prescrizione.getIntMinutes());
calendar.set(Calendar.SECOND, 0);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
// Set the time interval (in milliseconds) to repeat the alarm if the previous one was ignored
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 300000L, pendingIntent);
currentID++;
}
}
catch(JSONException e)
{
e.printStackTrace();
}
}
return false;
}
#Override
protected void onPostExecute(Boolean b)
{
super.onPostExecute(b);
}
}
public boolean setAlarms()
{
AlarmSettingManager.PrescriptionAlarmSetter prescriptionAlarmSetter = new AlarmSettingManager.PrescriptionAlarmSetter();
prescriptionAlarmSetter.execute();
return true;
}
}
And this is the piece of code I'm going to adapt in order to cancel the alarm repeating:
Intent alarmIntent = new Intent(context, AlarmBroadcastReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast
(
context.getApplicationContext(),
currentID,
alarmIntent,
0
);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
Thanks.
At the time of cancelling alarm schedule a new alarm for the next day.
The intention of the "cancel" option is to remove the alarm.
Your application should add a new alarm just as the original was setup.
You can find a nice example of implementing a full alarm in Android at the following link, including how to re-add it on device reboot.
Repeat Alarm Example In Android Using AlarmManager
I could not explain my problem in the Title..Here's the detailed explanation of my problem :
I have an application where arrival time of trains are displayed.
I want to add a feature where User can create an alert if the train is 10-5 minutes away from station.
A form is displayed to create an alert (all the values are stored in DB).
alertID = db.insert_alerts(name,starttime,endtime,booleanrepeat);
I am using alarm manager to create the notification :
if (is_repeat.equals("true")) {
new AlertsReceiver().setRepeatAlarm(getApplicationContext(), mCalendar, (int)alertID ,10000);
} else if (is_repeat.equals("false")) {
new AlertsReceiver().setAlarm(getApplicationContext(), mCalendar,(int)alertID);
}
below is the Receiver class :
public class AlertsReceiver extends WakefulBroadcastReceiver {
private int alertId;
AlarmManager mAlarmManager;
PendingIntent mPendingIntent;
#Override
public void onReceive(Context context, Intent intent) {
Bundle extras = intent.getExtras();
if(extras == null) {
Log.d("Service","null");
} else {
alertId= extras.getInt("alertId");
}
Intent intent1 = new Intent(context,MService.class);
intent1.putExtra("alertId", alertId);
context.startService(intent1);
}
public void setAlarm(Context context, Calendar calendar, int ID) {
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context,AlertsReceiver.class);
intent.putExtra("alertId", ID);
mPendingIntent = PendingIntent.getBroadcast(context, ID, intent, PendingIntent.FLAG_CANCEL_CURRENT);
// Calculate notification time
Calendar c = Calendar.getInstance();
long currentTime = c.getTimeInMillis();
long diffTime = calendar.getTimeInMillis() - currentTime;
// Start alarm using notification time
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + diffTime,
mPendingIntent);
}
public void setRepeatAlarm(Context context, Calendar calendar, int ID, long RepeatTime) {
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Log.e("asetRepeat",ID+"");
Intent intent = new Intent(context, AlertsReceiver.class);
intent.putExtra("alertId", ID);
mPendingIntent = PendingIntent.getBroadcast(context, ID, intent, PendingIntent.FLAG_CANCEL_CURRENT);
// 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);
}
public void cancelAlarm(Context context, int ID) {
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Toast.makeText(context,"Cancelled"+ID,Toast.LENGTH_LONG).show();
// Cancel Alarm using Reminder ID
mPendingIntent = PendingIntent.getBroadcast(context, ID, new Intent(context, RiderAlertsReceiver.class), 0);
mAlarmManager.cancel(mPendingIntent);
}
}
In receiver I am starting a service where I am making a webservice call :
Once an alarm manager is set..A webservice call is made in background service to check the minutes in which train will arrive :
if the minutes < 10 minutes notification is displayed else the webservice call should run again
So, i place the webservice in timer which runs every 1 minute.
The issue is how to stop the timer once the notification is received.
Also, the every time the receiver is starting the same service so only one alert is working at one time.
The user can create multiple alerts and all alerts are stored in DB.
Please can any one tell me the best way to implement this feature.
Appreciate Help...!
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
I need help. Im new to android coding.
I have made task list, which I want to do specific things at time written in task.
Here is my task item
private long id;
private int mon;
private int tues;
private int wednes;
private int thurs;
private int fri;
private int satur;
private int sun;
private int profile;
Where I have days (monday,tuesday etc) which holds amount of minutes (for 10:00 its 600).
Following some tutorials I have alarm reciever
public class AlarmReciever extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
try {
Bundle bundle = intent.getExtras();
String message = bundle.getString("alarm_message");
Intent newIntent = new Intent(context, AlarmActivity.class);
newIntent.putExtra("profile", message);
newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(newIntent);
} catch (Exception e) {
Toast.makeText(context, "There was an error somewhere, but we still received an alarm", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
Its still unedited...
And then there is code which calls to make new tasks in alarm manager
// get a Calendar object with current time
Calendar cal = Calendar.getInstance();
// add 5 minutes to the calendar object
cal.add(Calendar.MINUTE, 5);
Intent intent = new Intent(ctx, AlarmReceiver.class);
intent.putExtra("alarm_message", "O'Doyle Rules!");
// In reality, you would want to have a static variable for the request code instead of 192837
PendingIntent sender = PendingIntent.getBroadcast(this, 192837, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Get the AlarmManager service
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), sender);
I dont understand how to specify in calendar, that I need new task repeating (for example) every monday at 10:00, and that when this happens, it calls new function, giving it "profile" variable to work with.
private void setProfile(Integer profile)
{
// Doing things with profile
}
take a look at the following code:
alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent2 = new Intent(context, SampleAlarmReceiver.class);
alarmIntent = PendingIntent.getBroadcast(context, 0, intent2, 0);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
// Set the alarm's trigger time to item hour
calendar.set(Calendar.HOUR_OF_DAY, NuevoItemActivity.hora.getCurrentHour());
calendar.set(Calendar.MINUTE, NuevoItemActivity.hora.getCurrentMinute());
// Set the alarm to fire , according to the device's clock, and to repeat once a day.
alarmMgr.setInexactRepeating(AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, (PendingIntent) alarmIntent);
As you can see in last line, you are able to indicate AlarmManager.INTERVAL_DAY to repeat the PendingIntent.