I am having some problem with Alarm Manager in Android. I am setting the alarm manager to execute every midnight at 12am. Here are my codes:
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 0 );
notificationCount = notificationCount + 1;
AlarmManager mgr = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
Intent notificationIntent = new Intent(context,
ReminderAlarm.class);
notificationIntent.putExtra("RecurID", recurID);
notificationIntent.putExtra("RecurStartDate", _recurlist.get(position)
.getRecurringStartDate());
notificationIntent.putExtra("Date", dateFormat.format(new Date()));
notificationIntent.putExtra("Type", _recurlist.get(position).getRecurringType());
notificationIntent.putExtra("Amount", formatAmount);
notificationIntent.putExtra("NextPaymentDate", viewHolder.txt_ddate.getText());
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);
ComponentName receiver = new ComponentName(context, BootReceiver.class);
PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(receiver,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
return convertView;
And when onReceive, the program will execute the insert and update SQL statement if it matches the conditions:
ReminderAlarm class
public void onReceive(Context context, Intent intent) {
SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
String recurID = intent.getStringExtra("RecurID");
String recurStartDate = intent.getStringExtra("RecurStartDate");
String date = intent.getStringExtra("Date");
String type = intent.getStringExtra("Type");
String amount = intent.getStringExtra("Amount");
String nextPaymentDate = intent.getStringExtra("NextPaymentDate");
String currentDate = "Next Payment On: "
+ dateFormat.format(new Date());
// If dates match then execute the SQL statements
if (currentDate.equals(nextPaymentDate)) {
DatabaseAdapter mDbHelper = new DatabaseAdapter(
context.getApplicationContext());
mDbHelper.createDatabase();
mDbHelper.open();
TransactionRecModel trm = new TransactionRecModel();
CategoryController cc = new CategoryController(mDbHelper.open());
trm.setDate(date);
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
RecurringController rc1 = new RecurringController(mDbHelper.open());
boolean recurExist = rc1.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(date);
RecurringController rc = new RecurringController(
mDbHelper.open());
if (rc.updateRecurringDate(rm)) {
mDbHelper.close();
}
}
}
}
}
In my manifest file:
<receiver android:name="ReminderAlarm"></receiver>
<receiver
android:name="BootReceiver"
android:enabled="false" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" >
</action>
</intent-filter>
</receiver>
Boot Receiver class:
public void onReceive(Context context, Intent i) {
scheduleAlarms(context);
}
static void scheduleAlarms(Context context) {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 1);
AlarmManager mgr = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
Intent notificationIntent = new Intent(context, ReminderAlarm.class);
PendingIntent pi = PendingIntent.getService(context, 0,
notificationIntent, 0);
mgr.setInexactRepeating(AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pi);
}
However, the alarm manager does not execute when it get passed 12am everyday. The insert and update SQL statement will only be execute when I run the applications.
Any ideas? Thanks in advance.
Problem is in setting time for alarm to execute. replace the top three lines with this code
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 1);
Change your calendar value to Calendar calendar = Calendar.getInstance();
calendar .set(Calendar.HOUR_OF_DAY, 0);
calendar .set(Calendar.MINUTE, 0);
calendar .set(Calendar.SECOND, 0); and set alarm.
Related
I'm trying to make alarms using the times provided in the sqlite database for the reminders. however I can't seem to be getting it right. the code I have so far is: (in my mainactivity oncreate)
for (int i = 0; i < allRems.size(); i++) {
int mHour = 0, mMin = 0;
String mAlarmTime = allRems.get(i).getRemTime();
int mID = allRems.get(i).getRemId();
if (!(mAlarmTime == null)) {
String[] time = mAlarmTime.split(":");
mHour = Integer.parseInt(time[0].trim());
mMin = Integer.parseInt(time[1].trim());
}
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, mHour);
calendar.set(Calendar.MINUTE, mMin);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
AlarmManager alarmMgr = (AlarmManager) getSystemService(ALARM_SERVICE);
Intent alarmIntent = new Intent(getApplicationContext(), AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(MainActivity.this, mID, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent);
}
}
and my alarm receiver class is
#Override
public void onReceive(Context context, Intent intent) {
Log.e("onReceive", "--------------------------------------------------------");
Toast.makeText(context, "OnReceive alarm test", Toast.LENGTH_LONG).show();
if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
Log.e("DEVICE: ", "Device Rebooted");
}
}
i want to be able to set reminders for the specific time for the reminders in the database
I want to track the tower location of the user hourly. So for that I am now using an alarm manager. With alarm manager sometimes the alarm is getting triggered sometimes it does not.
Also there is problem in xiomi devices, if the app is killed from ram then the alarm does not trigger.
Is there any other way to do this? Can I run a service continuous and track the location hourly?
I want a solution where in a service I should be able to run this task hourly, may be using an handler or timer??
How can I use Job Scheduler for this?
Right Now my attempt with alarm manager :
public static boolean setAlarm(Context context) {
Calendar calendarNow = Calendar.getInstance();
Intent intent = new Intent(context, SaveLocationReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 1321, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendarNow.getTimeInMillis(), AlarmManager.INTERVAL_FIFTEEN_MINUTES, pendingIntent);
ComponentName receiver = new ComponentName(context, SaveLocationReceiver.class);
PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(receiver,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
return true;
}
SaveLocationReceiver.java:
public class SaveLocationReceiver extends BroadcastReceiver {
private SharedPreferences preferences;
String networkSubType="";
SessionData mSessionData;
#Override
public void onReceive(final Context context, Intent intent) {
Log.d("myapp", "service started");
mSessionData = new SessionData(context);
if(ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
&& ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED)
{
Calendar calendarSet = Calendar.getInstance();
Calendar calendarNow = Calendar.getInstance();
calendarSet.set(Calendar.HOUR_OF_DAY, 7); // hour
calendarSet.set(Calendar.MINUTE, 00); // minute
calendarSet.set(Calendar.SECOND, 0); // second
Calendar calendarEnd = Calendar.getInstance();
calendarEnd.set(Calendar.HOUR_OF_DAY, 20); // hour
calendarEnd.set(Calendar.MINUTE, 00); // minute
calendarEnd.set(Calendar.SECOND, 0); // second
SimpleDateFormat format1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(calendarNow.getTime());
// Output "Wed Sep 26 14:23:28 EST 2012"
String currentTime = format1.format(calendarNow.getTime());
System.out.println(currentTime);
if (calendarNow.compareTo(calendarSet) >= 0 && calendarNow.compareTo(calendarEnd) <= 0) {
TelephonyManager telephonyManager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
GsmCellLocation cellLocation = (GsmCellLocation) telephonyManager.getCellLocation();
ConnectivityManager connectivityManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);//?????????
NetworkInfo activeNetInfo = connectivityManager.getActiveNetworkInfo();
if (cellLocation != null) {
int cellid = cellLocation.getCid();
int celllac = cellLocation.getLac();
if(activeNetInfo != null) {
networkSubType = activeNetInfo.getSubtypeName();
}
String networkOperator = telephonyManager.getNetworkOperator();
int mcc = Integer.parseInt(networkOperator.substring(0, 3));
int mnc = Integer.parseInt(networkOperator.substring(3));
String networkOperatorName = telephonyManager.getNetworkOperatorName();
int type = telephonyManager.getNetworkType();
Log.d("CellLocation", cellLocation.toString());
Log.d("GSM CELL ID", String.valueOf(cellid));
Log.d("GSM Location Code", String.valueOf(celllac));
Log.d("MCC", String.valueOf(mcc));
Log.d("MNC", String.valueOf(mnc));
Log.d("NetworkOperatorName", networkOperatorName);
Log.d("radioType", String.valueOf(type));
Log.d("Network subtype name", networkSubType);
AddLocationAsyncTask addLocationAsyncTask = new AddLocationAsyncTask(context);
addLocationAsyncTask.execute(mSessionData.getString("user_id",""), String.valueOf(cellid), String.valueOf(celllac), String.valueOf(mcc), String.valueOf(mnc),
networkOperatorName, networkSubType, currentTime);
}
}
}
}
}
So I want above task of fetching the location to run exactly after half an hour without miss for any reason.
I need to reset an integer "daily" at a set specific time of day. In my activity, I write the value of daily into Shared preferences, then with an alarm manager and broadcast receiver try to set it to zero. everything works, besides the shared preferences and the value still remains what it was. I think that I need to import a different context for the shared prefs. Any help is welcomed.
The receiver:
public void onReceive(Context context, Intent intent) {
final SharedPreferences shared = context.getSharedPreferences("Mydata", MODE_PRIVATE);
final SharedPreferences.Editor editor = shared.edit();
int sum = shared.getInt("data1", 0);
Calendar c = Calendar.getInstance();
String date = String.valueOf(c.get(Calendar.DATE));
mainData.insert_data(date, sum);
int zero = 0;
editor.putInt("data1", zero);
editor.apply();
}
The alarm manager:
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 22);
calendar.set(Calendar.MINUTE, 45);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
final Context context = this.getContext();
PendingIntent pi = PendingIntent.getService(context, 0,
new Intent(context, MyAppReciever.class),PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
am.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, pi);
The Shared preferences in the Main Activity:
final SharedPreferences shared = this.getContext().getSharedPreferences("Mydata", MODE_PRIVATE);
final SharedPreferences.Editor editor = shared.edit();
editor.putInt("data1", 0);
editor.putInt("month", 0);
final int today212 = shared.getInt("data1", 0);
final int mesec212 = shared.getInt("month", 0);
final int limit212 = shared.getInt("budget", 0);
So I made a few changes to the code and added a PendingIntent requestCode.
The code looks like this
The place where you set up your Alarm:
public void scheduleTestAlarmReceiver(Context context) {
Intent receiverIntent = new Intent(context, MyAppReciever.class);
PendingIntent sender = PendingIntent.getBroadcast(context, 123456789, receiverIntent, 0);
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 23);
calendar.set(Calendar.MINUTE, 58);
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, sender);
}
and the place where you schedule it (say onClick):
Context cn= this.getContext();
scheduleTestAlarmReceiver(cn);
the Broadcast receiver should be the same as above.
And also do not forget to add the receiver to the manifest:
<receiver android:name=".MyAppReciever"></receiver>
I am setting notifications using alarm manager and broadcast receiver. I have tried to use setInexactRepeating method of an alarm manager but it dose not raise alarms at exact time above API 19.
So I got a suggestion to use setExact method and set alarms manually. I don't know how can I do this. Do I need to calculate dates for every week for a year?
Also the alarms I am creating I want to delete the same if the event is deleted. How can I cancel this? Using cancel method I have tried to cancel the alarm. For test I tried to set multiple alarms and delete it.
If I delete one event so the respected alarm of that event should get cancel but may be all alarms are getting cancel as I do not get any notification after deleting an event.
I have used unique Id for this. As final static int RQS_1 = 1; for setting alarm.
Can Anyone help me with this please?
Setting alarms:
public void setNotificationTime(Calendar c)
{
Date dateFrom = new Date();
df = new SimpleDateFormat("E MMM dd hh:mm:ss zzzz yyyy");
try {
dateFrom = df.parse(startTime);
}
catch (ParseException ex) {
}
dateFrom.getTime();
c.setTime(dateFrom);
hour = c.get(Calendar.HOUR_OF_DAY);
minute = c.get(Calendar.MINUTE);
if(notificationTime.equals("10 Minutes Before"))
{
c.set(Calendar.HOUR_OF_DAY, hour);
c.set(Calendar.MINUTE, minute - 10);
c.set(Calendar.SECOND, 0);
c.set(Calendar.MILLISECOND, 0);
c.set(Calendar.DATE, day);
// c.set(Calendar.DAY_OF_WEEK,);
SetDay(c);
notification = c.getTime();
notificationTime = df.format(notification);
Toast.makeText(getApplicationContext(),notificationTime,Toast.LENGTH_SHORT).show();
intent = new Intent(getBaseContext(),NotificationReceiver.class);
pendingIntent = PendingIntent.getBroadcast(getBaseContext(),RQS_1, intent, 0);
alarmManager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(), AlarmManager.INTERVAL_DAY * 7, pendingIntent);
}
else if(notificationTime.equals("30 Minutes Before"))
{
c.set(Calendar.HOUR_OF_DAY, hour);
c.set(Calendar.MINUTE, minute - 30);
c.set(Calendar.SECOND, 0);
c.set(Calendar.MILLISECOND, 0);
c.set(Calendar.DATE, day);
// c.set(Calendar.DAY_OF_WEEK,);
SetDay(c);
notification = c.getTime();
notificationTime = df.format(notification);
Toast.makeText(getApplicationContext(),notificationTime,Toast.LENGTH_SHORT).show();
intent = new Intent(getBaseContext(),NotificationReceiver.class);
pendingIntent = PendingIntent.getBroadcast(getBaseContext(),RQS_1, intent, 0);
alarmManager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(), AlarmManager.INTERVAL_DAY * 7, pendingIntent);
}
}
setDay method I have created to set the day which has been choosen by user from a dialog and set day.
setDay function:
public void SetDay(Calendar c)
{
switch (dayOfWeek)
{
case "Mon":
c.set(Calendar.DAY_OF_WEEK, 2);
c.getTime();
Toast.makeText(getApplicationContext(),dayOfWeek,Toast.LENGTH_SHORT).show();
break;
case "Tue":
c.set(Calendar.DAY_OF_WEEK, 3);
c.getTime();
Toast.makeText(getApplicationContext(),dayOfWeek,Toast.LENGTH_SHORT).show();
break;
}
Notification Receiver
public class NotificationReceiver extends BroadcastReceiver {
public static int MY_NOTIFICATION_ID = 0;
NotificationManager notificationManager;
Notification myNotification;
EventTableHelper db;
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Time is set", Toast.LENGTH_LONG).show();
db = new EventTableHelper(context);
List<EventData> testSavings = db.getAllEvents();
for (EventData ts : testSavings) {
String log = "from date:" + ts.getFromDate()
+ " ,to date: " + ts.getToDate()
+ " ,location: " + ts.getLocation()
+ " ,title " + ts.getTitle();
Calendar c = Calendar.getInstance();
Date date = new Date();
Date date1 = new Date();
Log.d("Result: ", log);
SimpleDateFormat df = new SimpleDateFormat("E MMM dd hh:mm:ss zzzz yyyy");
SimpleDateFormat df2 = new SimpleDateFormat("hh:mm a");
try {
date = df.parse(ts.getFromDate());
date1 = df.parse(ts.getToDate());
} catch (ParseException ex) {
}
String timeFrom = df2.format(date);
// String startTime = String.valueOf(timeFrom);
String timeTo = df2.format(date1);
// String endTime = String.valueOf(timeTo);
String location = ts.getLocation();
String title = ts.getTitle();
Intent myIntent = new Intent(context, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(
context,
0,
myIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
if(location.equals(""))
{
String msg = "From : " + timeFrom + "\nTo : " + timeTo;
myNotification = new NotificationCompat.Builder(context)
.setContentTitle("Event : " + title)
.setContentText(msg)
.setWhen(System.currentTimeMillis())
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.setSmallIcon(R.drawable.eventicon)
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
.setStyle(new NotificationCompat.BigTextStyle().bigText(msg))
.setDefaults(Notification.DEFAULT_SOUND)
.build();
}
else
{
String msg = "From : " + timeFrom + "\nTo : " + timeTo + "\nAt : " + location;
myNotification = new NotificationCompat.Builder(context)
.setContentTitle("Event : " + title)
.setContentText(msg)
.setWhen(System.currentTimeMillis())
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.setSmallIcon(R.drawable.eventicon)
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
.setStyle(new NotificationCompat.BigTextStyle().bigText(msg))
.setDefaults(Notification.DEFAULT_SOUND)
.build();
}
Log.i("Notify", "Notification");
notificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(MY_NOTIFICATION_ID, myNotification);
myNotification.flags=Notification.FLAG_AUTO_CANCEL;
}
}
}
Yes forgot to add code of cancel:
alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
intent = new Intent(getApplicationContext(), NotificationReceiver.class);
pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), RQS_1, intent, 0);
alarmManager.cancel(pendingIntent);
Thank you..
Like this,
pendingIntent = PendingIntent.getBroadcast(getBaseContext(),RQS_1, intent, 0);
alarmManager.cancel(pendingIntent); //Remove any alarms with a matching Intent
for more info AlarmManager
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