In my app I want alarms for several times which will be set by the user.
But if I set the alarm for a different date and time it only responds on the last set-up time.
Such as if I set alarm for date 20-01-2017 time 10.10 am,
20-01-2017 time 10.20 am, 20-01-2017 time 10.30 am,
and so on it only gives the alarm for last selected date & Time.
But doesn't give alarm at 20-01-2017 time 10.10 am, 20-01-2017 time 10.20 am, or other selected times.
How can I get alarm at all selected times?
Here is my code:
public void setDate(View view) {
DialogFragment newFragment = new DatePickerFragment();
newFragment.show(getSupportFragmentManager(), "datePicker");
}
public void setTime(View view) {
DialogFragment newFragment = new TimePickerFragment();
newFragment.show(getSupportFragmentManager(), "timePicker");
}
public void setAlarm(View view) {
Calendar calNow = Calendar.getInstance();
Calendar calSet = (Calendar) calNow.clone();
calSet.set(Calendar.HOUR_OF_DAY, alarmHour);
calSet.set(Calendar.MINUTE, alarmMin);
calSet.set(Calendar.DAY_OF_MONTH, alarmDay);
calSet.set(Calendar.YEAR, alarmYear);
calSet.set(Calendar.MONTH, alarmMonth);
setAlarmN(calSet);
}
private void setAlarmN(Calendar targetCal) {
makeText(this, "Alarm is set at" + targetCal.getTime(),
LENGTH_LONG).show();
Intent intent = new Intent(getBaseContext(), AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
getBaseContext(), RQS_1, intent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, targetCal.getTimeInMillis(),
pendingIntent);
}
//date picker fragment
public static class DatePickerFragment extends DialogFragment
implements DatePickerDialog.OnDateSetListener {
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Use the current date as the default date in the picker
final Calendar c = Calendar.getInstance();
int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH);
int day = c.get(Calendar.DAY_OF_MONTH);
// Create a new instance of DatePickerDialog and return it
return new DatePickerDialog(getActivity(), this, year, month, day);
}
public void onDateSet(DatePicker view, int year, int month, int day) {
// Do something with the date chosen by the user
alarmDay = day;
alarmYear = year;
alarmMonth = month;
}
}
//Time picker fragment
public static class TimePickerFragment extends DialogFragment
implements TimePickerDialog.OnTimeSetListener {
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Use the current time as the default values for the picker
final Calendar c = Calendar.getInstance();
int hour = c.get(Calendar.HOUR_OF_DAY);
int minute = c.get(Calendar.MINUTE);
// Create a new instance of TimePickerDialog and return it
return new TimePickerDialog(getActivity(), this, hour, minute,
DateFormat.is24HourFormat(getActivity()));
}
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
// Do something with the time chosen by the user
alarmHour = hourOfDay;
alarmMin = minute;
}
}
Problem is in your void setAlarmN() method. You can't generate alarm notification with the same id. That should mean that notification before gets cancel and override. Try to set unique id for RQS_1 each time PendingIntent.getBroadcast() gets called. Probably you have to declare private variable and increment it.
Related
I want to add a function in my main activity that the application will fetch device time. If time is More than 2:00 PM in Device time or Less than 08:00 AM in Device time. A Popup will show after splash screen "Sorry Time UP, Please Order Tomorrow from 08:00 AM to 02:00 PM". And an Ok button to exit the application.
After Answer I Updated my Splash Activity. And nothing happened.
`public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// **************** ORDER SLOT ******************* //
Calendar finalTime = Calendar.getInstance();
Calendar mCalendarOpeningTime = Calendar.getInstance();
mCalendarOpeningTime.set(Calendar.HOUR, 10);
mCalendarOpeningTime.set(Calendar.MINUTE, 59);
mCalendarOpeningTime.set(Calendar.AM_PM, Calendar.AM);
Calendar mCalendarClosingTime = Calendar.getInstance();
mCalendarClosingTime = Calendar.getInstance();
mCalendarClosingTime.set(Calendar.HOUR, 11);
mCalendarClosingTime.set(Calendar.MINUTE, 00);
mCalendarClosingTime.set(Calendar.AM_PM, Calendar.AM);
if (finalTime.after(mCalendarOpeningTime)&&finalTime.before(mCalendarClosingTime)){
// show the dialog
AlertDialog.Builder builder = new AlertDialog.Builder(SplashScreen.this);
builder.setTitle(R.string.app_name);
builder.setIcon(R.mipmap.ic_launcher);
builder.setMessage("Order Full, Please Order Tomorrow before 02:00PM")
.setCancelable(false)
.setPositiveButton("Exit", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
finish();
}
});
}
Well, there are too many ways to do this. If you want to get time from the internet you can use TrueTime. As per your request, You can use Date instances :
private void setOpeningAndClosingTimes() {
//current time
Calendar finalTime = Calendar.getInstance();
Calendar mCalendarOpeningTime = Calendar.getInstance();
mCalendarOpeningTime.set(Calendar.HOUR, 8);
mCalendarOpeningTime.set(Calendar.MINUTE, 0);
mCalendarOpeningTime.set(Calendar.AM_PM, Calendar.AM);
Calendar mCalendarClosingTime = Calendar.getInstance();
mCalendarClosingTime = Calendar.getInstance();
mCalendarClosingTime.set(Calendar.HOUR, 2);
mCalendarClosingTime.set(Calendar.MINUTE, 00);
mCalendarClosingTime.set(Calendar.AM_PM, Calendar.PM);
if (finalTime.after(mCalendarOpeningTime)&&finalTime.before(mCalendarClosingTime)){
// show the dialog
Toast.makeText(this,"Time is 8Am to 2PM",Toast.LENGTH_LONG).show();
}else {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle(R.string.app_name);
builder.setIcon(R.mipmap.ic_launcher);
builder.setMessage("Order Full, Please Order Tomorrow before 02:00PM")
.setCancelable(false)
.setPositiveButton("Exit", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
finish();
}
});
builder.show();
}
Now call this method in onCreate() or onStart() so that the values are assigned to the respective "times" before you start using them:
I'm trying to create 3 notifications after the desired date and time is selected from a datepicker and a timepicker. I want to send notifications for the last 3 days for the selected value. But after the 3 notifications I want to cancel the notification process. I set up my pending notification and an alarm manager from my activity like
TimePickerDialog.OnTimeSetListener mTimeSetListener = new TimePickerDialog.OnTimeSetListener() {
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
//last 3 days add notification
Calendar calendar = Calendar.getInstance();
calendar.set(year, month, day, hourOfDay, minute, 0);
long when = calendar.getTimeInMillis();
when = when -3*(24*60*60*1000)+3000; //set startup time 3 days before
GetTime(when);
long diff = when - Calendar.getInstance().getTimeInMillis();
while (diff < 0){
when+= (24*60*60*1000); //increment 24h if selected time is closer then 3 days
diff = when - Calendar.getInstance().getTimeInMillis();
GetTime(when);
}
if (diff >0) {
Intent notifyIntent = new Intent(getApplicationContext() ,NotificationReceiver.class);
notifyIntent.putExtra("ctg", categorySelected);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), new Utils().getIdForCategory(categorySelected), notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, when, 60*1000, pendingIntent); //setting for testing purposes for 60 seconds
}
}
};
My receiver class is :
protected void onHandleIntent(Intent intent) {
String categorySelected = intent.getStringExtra("ctg");
SharedPreference pref = new SharedPreference(getApplicationContext());
int alarmCount = pref.getAlarmCount(categorySelected);
if (alarmCount<=3){
Log.d("alarmCount", String.valueOf(alarmCount));
pref.saveAlarmCount(categorySelected,alarmCount+1);
showNotification(intent);
}
else //we reached the 3 times
{
new Utils().clearAllPendingIntent(getApplicationContext(),categorySelected);
}
}
and my clear method
public void clearAllPendingIntent(Context context, String categorySelected){
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent notifyIntent = new Intent(context ,NotificationReceiver.class);
notifyIntent.putExtra("ctg",categorySelected);
PendingIntent pendingUpdateIntent = PendingIntent.getBroadcast(context, new Utils().getIdForCategory(categorySelected), notifyIntent, PendingIntent.FLAG_CANCEL_CURRENT);
SharedPreference pref = new SharedPreference(context);
pref.saveAlarmCount(categorySelected,1);
// Cancel alarms
try {
alarmManager.cancel(pendingUpdateIntent);
} catch (Exception e) {
}
}
My problem is that the pending intent is not canceled after 3 times, which means I get notification each minute. What am I doing wrong?
The actual problem was with my new Utils().getIdForCategory(categorySelected) function which should return a specific value based on the category.
public int getIdForCategory(String category){
if (category.equals("A")) return 1; //before it was category=="A"
if (category.equals("B")) return 2;
if (category.equals("C")) return 3;
if (category.equals("D")) return 4;
if (category.equals("E")) return 5;
return 0;
}
I am doing a time table project for my college, in which I want to generate notification on each hour using AlarmManager, I almost got the solution, but the alarm gets triggered during random time, like between hours. What I want is to trigger alarm manger messages on exactly each hour, like 7.00am,8.00am, and so on on everyday. My code is given below.
MainActivity.java
public class MainActivity extends AppCompatActivity {
DatabaseHelper2 db = new DatabaseHelper2(this);
private PendingIntent pendingIntent;
private AlarmManager alarmManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
Cursor resService = db.getAllData();
int pref = 0;
if(resService.getCount()!=0){
Date date2 = new Date();
int h=date2.getHours();
int m = date2.getMinutes();
int s = date2.getSeconds();
Intent alarmIntent = new Intent(this,AlarmReceiver.class);
pendingIntent = PendingIntent.getBroadcast(this,0,alarmIntent,0);
alarmManager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
//int interval = 60 * 60 * 10000;
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,System.currentTimeMillis(),AlarmManager.INTERVAL_HOUR,pendingIntent);
Toast.makeText(this,"Alarm set at "+h+" : "+m+" : "+s,Toast.LENGTH_LONG).show();
}
}
AlarmReciever.java
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Date d = new Date();
Toast.makeText(context,"Broadcast message triggered at "+d.getHours()+":"+d.getMinutes()+":"+d.getSeconds() ,Toast.LENGTH_SHORT).show();
Intent service1 = new Intent(context, MyService.class);
context.startService(service1);
}
}
MyService.java
public class MyService extends Service {
DatabaseHelper2 db = new DatabaseHelper2(this);
String sub;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Date date = new Date();
int now=date.getHours();
SimpleDateFormat sdf = new SimpleDateFormat("EEEE");
String dayOfWeek = sdf.format(date);
Cursor resNow = db.getNowSub(now,dayOfWeek);
if(resNow.getCount()!=0){
if(resNow.moveToNext()){
sub = resNow.getString(3);
}
NotificationManager notif = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
Notification notify = new Notification.Builder
(getApplicationContext()).setContentTitle("NowSub").setContentText("Now:"+sub+ " at "+date.getHours()+":"+date.getMinutes()+":"+date.getSeconds()).setContentTitle("currenet subject").setSmallIcon(R.mipmap.ic_launcher).build();
notify.flags |= Notification.FLAG_AUTO_CANCEL;
notif.notify(0, notify);
}
return START_STICKY;
}
I spent more than a week for this particular problem, hope someone will help.
Thanks in advance.
As in the description of AlarmManager:
Note: Beginning with API 19 (KITKAT) alarm delivery is inexact: the OS
will shift alarms in order to minimize wakeups and battery use. There
are new APIs to support applications which need strict delivery
guarantees; see setWindow(int, long, long, PendingIntent) and
setExact(int, long, PendingIntent). Applications whose
targetSdkVersion is earlier than API 19 will continue to see the
previous behavior in which all alarms are delivered exactly when
requested.
I suggest to use setExact instead of setRepeating to be waked up at an exact time.
Also, check out JobScheduler as stated here: Android AlarmManager setExact() is not exact
Instead of this:
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,System.currentTimeMillis(),AlarmManager.INTERVAL_HOUR,pendingIntent);
You need to pass an actual time when you want this to wake up, not System.currentTimeMillis()
So something like
Calendar calendar = Calendar.getInstance();
Date newDate = calendar.setTime(date2);
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME,calendar.getTimeInMillis(),AlarmManager.INTERVAL_HOUR,pendingIntent);
Try this instead. I change to AlarmManager.ELAPSED_REALTIME
I am trying to get start time and stop time from user using Time Picker in one class and then passing this time to the broadcast class.
But when I am checking whether the values of the start time and stop time is reached in the Broadcast Receiver class by using a toast message, I am not able to get the required start time or stop time that is passed.
CODE [Main Class]:
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.setting);
initialize();
alarmIntent = new Intent(Settings.this, AlarmReceiver.class);
pendingIntent = PendingIntent.getBroadcast(Settings.this, 0, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);
alarmRepeat();
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
Calendar c = Calendar.getInstance();
switch(v.getId()){
case R.id.startTime :
// Process to get Current Time
startHour = c.get(Calendar.HOUR_OF_DAY);
startMinute = c.get(Calendar.MINUTE);
// Launch Time Picker Dialog
TimePickerDialog tpd1 = new TimePickerDialog(this,
new TimePickerDialog.OnTimeSetListener() {
#Override
public void onTimeSet(TimePicker view, int hourOfDay,
int minute) {
// Display Selected time in textbox
eStart.setText(hourOfDay + ":" + minute);
startHour = hourOfDay;
startMinute = minute;
alarmIntent.putExtra("startHour", startHour);
alarmIntent.putExtra("startMinute", startMinute);//passing these variables to Broadcast class
}
}, startHour, startMinute, false);
tpd1.show();
public void alarmRepeat(){
Calendar cal = Calendar.getInstance();
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
manager.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 1000, pendingIntent);
}
Broadcast Class :
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
startHour = intent.getIntExtra("startHour", 0);
stopHour = intent.getIntExtra("StopHour", 0);
Toast.makeText(context, startHour + ":" + startMinute, Toast.LENGTH_LONG).show();
Program explanation: I have passed startHour and startMinute from the onTimeSet method in the main class to broadcast class.
In the Broadcast Class I am storing this startHour and StopMinute in the variables as defined above.
The problem here is that you are creating the alarm in onCreate and then updating your information in onClick. I'm pretty sure your pendingIntent declaration needs to be after you've supplied the information to alarmIntent.
Edit: I would recreate pendingIntent immediately after updating alarmIntent and then call alarmRepeat() again. Personally, I would put the assignment of pendingIntent inside the alarm method and pass alarmIntent in as a parameter, but that's a stylistic choice.
As long as the pending intents are the same (not including extras added to the intent inside it) alarmmanager will override any existing alarm with the new alarm
I am having some problem with alarm manager in Android. So what I am trying to do is set the alarm to repeat to run the DB insertion every day around 12.01AM.
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 0 );
calendar.set(Calendar.MINUTE, 1);
notificationCount = notificationCount + 1;
AlarmManager mgr = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
Intent notificationIntent = new Intent(context,
ReminderAlarm.class);
notificationIntent.putExtra("NotifyCount", notificationCount);
PendingIntent pi = PendingIntent.getBroadcast(context,
notificationCount, notificationIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
mgr.setInexactRepeating(AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pi);
So basically I've came up with these code. However, the alarm manager execute again after the minute I set it.
Let's say I run the apps on 01/10/2014 5.48PM. I wanted this to run the DB insertion when onReceive every day after I set it around 12.01AM only. But somehow, the alarm manager execute at 01/10/2014 5.49PM which is one minute after I set it and it stopped working.
I wonder which part I did wrongly.
Thanks in advance.
EDIT
Recurring class
For this class, it will trigger the alarm manager everyday and pass the variables along to reminder alarm class for DB insertion.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.recurring);
context = this;
buildListView();
if(!alarmInitialized(this)) {
scheduleAlarms(this);
}
}
// And the few methods you suggested to schedule the alarm
public static void scheduleAlarms(Context context) {
Calendar calendar = Calendar.getInstance();
if (hasRunnedToday(context)) { // if the alarm has run this day
calendar.add(Calendar.DATE, 1); // schedule it to run again starting
// tomorrow
}
long firstRunTime = calendar.getTimeInMillis();
AlarmManager mgr = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
Intent notificationIntent = new Intent(context, ReminderAlarm.class);
PendingIntent pi = PendingIntent.getActivity(context, 0,
notificationIntent, 0);
mgr.setInexactRepeating(AlarmManager.RTC_WAKEUP, firstRunTime,
AlarmManager.INTERVAL_DAY, pi);
ComponentName receiver = new ComponentName(context, BootReceiver.class);
PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(receiver,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
}
BootReceiver class
public void onReceive(Context context, Intent i) {
if (i.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
Recurring.scheduleAlarms(context);
}
}
ReminderAlarm class
Basically for this class it just grab the variable passed from Recurring class and execute the DB insertion. I did inserted some Toast.makeText to test if it is retrieving but no luck by testing it.
public class ReminderAlarm extends BroadcastReceiver {
private NotificationManager mNotificationManager;
private Notification notification;
#Override
public void onReceive(Context context, Intent intent) {
String recurID = null;
String recurStartDate = null;
String currentDate = null;
String description = null;
String type = null;
String amount = null;
String categoryName = null;
String frequencyStr = null;
String nextPaymentDate = null;
SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
DatabaseAdapter mDbHelper = new DatabaseAdapter(context);
mDbHelper.createDatabase();
mDbHelper.open();
RecurringController rc = new RecurringController(mDbHelper.open());
ArrayList<RecurringModel> recur_list = rc.getAllRecurring();
// THIS PART TO GET DATA FROM DATABASE
for (int i = 0; i < recur_list.size(); i++) {
recurID = recur_list.get(i).getRecurringID();
recurStartDate = recur_list.get(i).getRecurringStartDate();
currentDate = dateFormat.format(new Date());
description = recur_list.get(i).getRecurringDesc();
type = recur_list.get(i).getRecurringType();
amount = Float.toString(recur_list.get(i).getRecurringAmount());
categoryName = recur_list.get(i).getCategoryID();
frequencyStr = recur_list.get(i).getFrequency();
Toast.makeText(context,
description, Toast.LENGTH_LONG)
.show();
Toast.makeText(context,
recurStartDate Toast.LENGTH_LONG)
.show();
Calendar cal = Calendar.getInstance();
try {
cal.setTime(dateFormat.parse(recurStartDate));
if (frequencyStr.equals("Daily")) {
cal.add(Calendar.DAY_OF_MONTH, 1);
nextPaymentDate = dateFormat.format(cal.getTimeInMillis());
cal.add(Calendar.DAY_OF_MONTH, -1);
} else if (frequencyStr.equals("Weekly")) {
cal.add(Calendar.WEEK_OF_YEAR, 1);
nextPaymentDate = dateFormat.format(cal.getTimeInMillis());
cal.add(Calendar.WEEK_OF_YEAR, -1);
} else if (frequencyStr.equals("Monthly")) {
cal.add(Calendar.MONTH, 1);
nextPaymentDate = dateFormat.format(cal.getTimeInMillis());
cal.add(Calendar.MONTH, -1);
} else if (frequencyStr.equals("Yearly")) {
cal.add(Calendar.YEAR, 1);
nextPaymentDate = dateFormat.format(cal.getTimeInMillis());
cal.add(Calendar.YEAR, -1);
}
} catch (ParseException e) {
e.printStackTrace();
}
// If dates match then execute the SQL statements
if (currentDate.equals(nextPaymentDate)) {
// mDbHelper.createDatabase();
// mDbHelper.open();
TransactionRecModel trm = new TransactionRecModel();
CategoryController cc = new CategoryController(mDbHelper.open());
trm.setDate(currentDate);
trm.setTransDescription(description);
trm.setType(type);
trm.setAmount(Float.parseFloat(amount));
// Get the categoryID based on categoryName
String catID = cc.getCatIDByName(categoryName);
trm.setCategory(catID);
// Check if the recurring record exists before insert new
// transaction record
boolean recurExist = rc.checkRecurExist(recurStartDate,
description, catID);
if (recurExist == true) {
TransactionRecController trc = new TransactionRecController(
mDbHelper.open());
// Check if the transaction record exists to prevent
// duplication
boolean moveNext = trc.checkTransExist(trm);
if (moveNext == false) {
if (trc.addTransactionRec(trm)) {
// Update recurring start date after insertion of
// transaction
RecurringModel rm = new RecurringModel();
rm.setRecurringID(recurID);
rm.setRecurringStartDate(currentDate);
if (rc.updateRecurringDate(rm)) {
mNotificationManager = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
PendingIntent contentIntent = PendingIntent
.getActivity(
context,
Integer.parseInt(intent
.getExtras()
.get("NotifyCount")
.toString()),
new Intent(), 0);
notification = new Notification(
R.drawable.ic_launcher, "Notification",
System.currentTimeMillis());
notification.setLatestEventInfo(context,
description, nextPaymentDate,
contentIntent);
mNotificationManager
.notify(Integer.parseInt(intent
.getExtras().get("NotifyCount")
.toString()), notification);
mDbHelper.close();
}
}
}
}
mDbHelper.close();
}
}
mDbHelper.close();
Recurring.updateAlarmLastRun(context);
}
}
I've added this part of codes in the part you suggested to schedule the alarm to call the BootReceiver class. Then from BootReceiver class, I will call back to the Recurring class and Reminder Alarm class:
ComponentName receiver = new ComponentName(context, BootReceiver.class);
PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(receiver,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
The problem is in calendar.getTimeInMillis() in
mgr.setInexactRepeating(AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pi);
The second argument to setInexactRepeating quoting the doc
triggerAtMillis time in milliseconds that the alarm should first go off, using the appropriate clock (depending on the alarm type). This is inexact: the alarm will not fire before this time, but there may be a delay of almost an entire alarm interval before the first invocation of the alarm.
Meaning it will run the first time aproximally one minute after you set it because of
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 0 );
calendar.set(Calendar.MINUTE, 1);
If you wan't the first run of the alarm to be the next day do a
calendar.add(Calendar. DATE, 1);`
As to the it stopped working, did you reboot de device ?
AlarmCalendar alarms don't persist to device reboot, you can register a BroadcastReceiver to receive BOOT_COMPLETED event and register the alarm again check
does Alarm Manager persist even after reboot?
Update: as you requested here is some help after reviewing your code
In your BOOT_COMPLETED Receiver class:
public void onReceive(Context context, Intent i) {
if (i.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
ReminderAlarm.scheduleAlarms(this);
}
}
In your ReminderAlarm class
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.recurring);
if(!alarmInitialized(this) {
scheduleAlarms(this);
}
}
public static void scheduleAlarms(Context context) {
Calendar calendar = Calendar.getInstance();
if(hasRunnedToday(context)) { //if the alarm has run this day
calendar.add(Calendar.DATE, 1); //schedule it to run again starting tomorrow
}
long firstRunTime = calendar.getTimeInMillis();
AlarmManager mgr = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
Intent notificationIntent = new Intent(context, ReminderAlarm.class);
PendingIntent pi = PendingIntent.getActivity(context, 0,
notificationIntent, 0);
mgr.setInexactRepeating(AlarmManager.RTC_WAKEUP,
firstRunTime, AlarmManager.INTERVAL_DAY, pi);
}
public static boolean alarmInitialized(Context context) {
SharedPreferences preferences = context.getSharedPreferences("alarm_prefs", MODE_PRIVATE);
long alarmLastRun = preferences.getLong("AlarmLastRun", -1);
return alarmLastRun != -1;
}
public static void updateAlarmLastRun(Context context) {
SharedPreferences preferences = context.getSharedPreferences("alarm_prefs", MODE_PRIVATE);
preferences.edit()
.putLong("AlarmLastRun", new Date().getTime())
.apply();
}
public static boolean hasRunnedToday(Context context) {
SharedPreferences preferences = context.getSharedPreferences("alarm_prefs", MODE_PRIVATE);
long alarmLastRun = preferences.getLong("AlarmLastRun", -1);
if(alarmLastRun == -1) {
return false;
}
//check by comparing day, month and year
Date now = new Date();
Date lastRun = new Date(alarmLastRun);
return now.getTime() - lastRun.getTime() < TimeUnit.DAYS.toMillis(1);
}
Each time your Reminder class alarm runs you should call updateAlarmLastRun to update the last time the alarm has run, this is necessary because the alarm may be schedule to be run on a day and the user reboots the device before the alarm has run in that case we don't want to
use calendar.add(Calendar.DATE, 1); since that would skip a day.
On your Manifest.xml
<receiver android:name=".BootReceiver" android:enabled="true" android:exported="false" android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
Notes:
You shouldn't do context = this if context is a class field since the object holds a reference to its field context and context field holds a reference to the object that would leak
Your Receiver 'onReceive` doesn't has the extras you assumed to have like "notificationCount" onReceive by the system when your device finish boot.
Once your alarm runs call updateAlarmLastRun
Hope any of this helps