How to execute one task every hour? - java

I have been developing an Android application and I need to execute 1 task every hour. I uses the following code for it:
private static final long ALARM_PERIOD = 1000L;
public static void initAlarmManager(Context context) {
Editor editor=PreferenceManager.getDefaultSharedPreferences(context).edit();
editor.putBoolean(context.getString(R.string.terminate_key), true).commit();
AlarmManager manager = (AlarmManager) context.getSystemService(context.ALARM_SERVICE);
Intent i = new Intent(context, AlarmEventReceiver.class);
PendingIntent receiver = PendingIntent.getBroadcast(context, 0, i, 0);
manager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime(), ALARM_PERIOD, receiver);
}
It works for me, but my client tells me that the task works only 1 time and won't work 1 hour. Where have I made a mistake? Please, tell me. Thank you.

According to your code, ALARM_PERIOD is 1000L, as repeating interval. So I doubt the alarm will set of in every 1000 milliseconds.
if you are setting repeating interval for every hour, it should be 3600000L.
And take note that if the phone is restarted, your alarm manager will no longer work unless you start again.
Here is the my Code:
private void setAlarmManager() {
Intent intent = new Intent(this, AlarmReceiver.class);
PendingIntent sender = PendingIntent.getBroadcast(this, 2, intent, 0);
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
long l = new Date().getTime();
if (l < new Date().getTime()) {
l += 86400000; // start at next 24 hour
}
am.setRepeating(AlarmManager.RTC_WAKEUP, l, 86400000, sender); // 86400000
}

Have you added receiver tag in application tag in manifest.xml
<receiver android:name=".AlarmReceiver" android:process=":remote"/>

Instead of Alram-Manager I recommended you to use Android-TimerTask
The TimerTask class represents a task to run at a specified time. The task may be run once or repeatedly. Its perfect suits for your requirements.

Try by modifying your code by changing your setRepeating() method like this
manager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,SystemClock.elapsedRealtime(), SystemClock.elapsedRealtime()+(60*60*1000), receiver);
OR
Test this it is repeating for every minute
manager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,Calendar.getInstance().getTimeInMillis(), Calendar.getInstance().getTimeInMillis()+(1*60*1000), receiver);

Related

Android Studio AlarmManager.cancel() closes the App

I am making an alarm app in which the alarm can be set with a toggle button. The code works in ADV, but if I test it on a real device, the the App closes imediatly after settting the alarm once and then turning it off. Also the alarm does not turn off.
(button press alarmOn -> alarm is on,
button press alarmOff-> app closes + alarm is still on)
mStartBtn1.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
long time;
if (((ToggleButton) view).isChecked()){ //if button is on
Intent intent = new Intent(MainActivity.this, AlarmReceiverActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(MainActivity.this, 2, intent, PendingIntent.FLAG_CANCEL_CURRENT);
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, timePicker1.getCurrentHour());
calendar.set(Calendar.MINUTE, timePicker1.getCurrentMinute());
time = (calendar.getTimeInMillis() - (calendar.getTimeInMillis() % 60000));
if (System.currentTimeMillis() > time) {
if (calendar.AM_PM == 0)
time = time + (1000 * 60 * 60 * 12);
else
time = time + (1000 * 60 * 60 * 24);
}
am.set(AlarmManager.RTC_WAKEUP, time, pendingIntent); //sets the alarm
}else{ //if button is off
am.cancel(pendingIntent);
}
}
});
Thank you for helping,
Florian
Your app is basically crashing. Maybe because you are passing null to am.cancel(pendingIntent)//pendingIntent might be null here.
Try moving PendingIntent pendingIntent = PendingIntent.getActivity(MainActivity.this, 2, intent, PendingIntent.FLAG_CANCEL_CURRENT); outside the if condition. If that is not the case then check AlarmReceiverActivity for crashes.

How do You Track a Rouge Alarm?

I have this app release in Android that notifies the user everyday at specific time (for example 10:00 pm). I didn't use setRepeating as it was not recommended on higher APIs from 21 up. The following was the pseudo code I used to keep resetting the alarm.
AlarmController (set alarm)
Once time was met send to alarm receiver
Alarm receiver would call the Alarm Controller and Increase the day by 1 and set it again
At the same time Alarm receiver will fire up the Intentservice for notification and set notified **true** in DataBase
In theory it was supposed to work. I am using Joda Time here to easily increase the day by 1. But the problem was, the notification kept firing up at a random time, sometimes it will fire up 6, after it was last fire up, or most often every 1 hour or 30 mins. I don't get it. Now the pseudo code I provided was the basic one. On my real code I have two alarms, one for firing up the notification and set Notified to true and the other was to reset the notified to false once the day change.
My app has been released. I never expected this scenario to happen because the way I debug this was on genymotion, I move the time manually and everything seems to be working alright. I had to fire a log on fabric IO but it seems that the log would only show once you get an error. Anyone thanks
Here is my bare minimum code that I was using exactly:
Alarm Controller
public static void setAdaptiveReminder(Context context, long ALARM_ID, DateTime dateTime, boolean shouldsetAlarm) {
Intent myIntent = new Intent(context, AdaptiveReminderReceiver.class);
myIntent.putExtra("reminder", shouldsetAlarm);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, (int) ALARM_ID, myIntent, PendingIntent.FLAG_UPDATE_CURRENT);
ALARMMANAGER = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Log.d(TAG, "setAdaptiveReminder: " + dateTime.toLocalTime().toString() + " " + dateTime.toLocalDate().toString());
CrashUtility.LogErrorReportToFabric(TAG + " setAdaptiveReminder", dateTime.toLocalTime().toString() + " " + dateTime.toLocalDate().toString());
if (Utility.GetBuildVersion() >= 19 && Utility.GetBuildVersion() < 23) { // if lollipop
//ALARMMANAGER.setRepeating(AlarmManager.RTC_WAKEUP,System.currentTimeMillis() + 5000,1000,pendingIntent);
ALARMMANAGER.setExact(AlarmManager.RTC_WAKEUP, dateTime.toDate().getTime(), pendingIntent);
//ALARMMANAGER.setRepeating(AlarmManager.RTC_WAKEUP,dateTime.toDate().getTime(), AlarmManager.INTERVAL_DAY,pendingIntent);
} else if (Utility.GetBuildVersion() >= 23 || Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
//Log.d(TAG, "setTimeSinceLastUseReminder: android M and UP");
ALARMMANAGER.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, dateTime.toDate().getTime(), pendingIntent);
//ALARMMANAGER.setrep(AlarmManager.RTC_WAKEUP,dateTime.toDate().getTime(), AlarmManager.INTERVAL_DAY,pendingIntent);
}
}
AlarmPresenter
public void setAdaptiveReminder() {
//AlarmController.setAdaptiveReminder(context,778,d);
DateTime dateTime = TimeUtility.SetCorrectTimeInCorrectDate(settingsRepository.getAdaptiveReminderTime());
boolean isNotified = settingsRepository.isNotifiedReminder();
//Toast.makeText(context, "" + dateTime.toLocalTime().toString(), Toast.LENGTH_SHORT).show();
Log.d(TAG, "setAdaptiveReminder: gggfss " + TimeUtility.DateIsToday(dateTime) + " " + dateTime.toLocalTime().toString());
Log.d(TAG, "setAdaptiveReminder: " + isNotified);
if (TimeUtility.DateIsToday(dateTime) && !isNotified) {
dateTime = dateTime.plusDays(1);
CrashUtility.LogErrorReportToFabric(TAG + " setAdaptiveReminder", dateTime.toLocalTime().toString() + " " + dateTime.toLocalDate().toString());
AlarmController.setAdaptiveReminder(context, 778, dateTime, true);
Log.d(TAG, "setAdaptiveReminder: " + dateTime.toLocalDate() + " " + dateTime.toLocalTime().toString());
}
}
Receiver
public void onReceive(Context context, Intent intent) {
// TODO: This method is called when the BroadcastReceiver is receiving
// an Intent broadcast.
this.context = context;
alarmControllerPresenter = new AlarmControllerPresenter(context,settingsRepository,habitRepository);
alarmControllerPresenter.setAdaptiveReminder();
}
So the code I have provided was the exact same code I am using to set the alarm every day. I just did some cleaning up and that was about it.

How to delete or cancel all pendingIntent in alarmManager?

In my app, I would like to delete all pendingIntent in my alarmManager.
Is possible to do a for() to delete all?
Try this.
Android: Get all PendingIntents set with AlarmManager
To cancel all alarm, first you have to find all the pending intent for that and cancel alarm using that.
If it is helpful to you than don't miss to accept this as your answer.
// set up alarm
List<PendingIntent> mPendingIntentList = new ArrayList<PendingIntent>();
Intent alarmIntent = new Intent(getApplicationContext(),Receiver.class);
alarmIntent.setData(Uri.parse("custom://" + alarm.ID));
alarmIntent.setAction(String.valueOf(alarm.ID));
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
PendingIntent displayIntent = PendingIntent.getBroadcast(getContext(), 0, alarmIntent, 0);
// add pending intent in list
mPendingIntentList.add(displayIntent );
alarmManager.set(AlarmManager.RTC_WAKEUP, alarmDateTime, displayIntent);
//cancel all alarms
for(int idx = 0 ; idx < mPendingIntentList.size() ; idx++){
alarmManager .cancel(mPendingIntentList.get(idx));
}
See AlarmManager.cancel(PendingIntent)
Create a PendingIntent matching the intent(s) you wish to cancel. Calling the above function once, will cancel all matching alarms
.

Detect if current time is between two set up times

I've a program which includes service. This program has settings which allows user to set up, disable and enable time. Between these two times (if option is enabled of course), the program should not work.
I'm actually having hard time to do this. I've already sucessfully converted "disabled" and "enabled" time in milliseconds. I have following code but it doesn't work as expected. I want to detect if current time is between two set up times, so i can disable service at that time.
public boolean isCurrentTimeBetween_enableDisable() {
long sysTime = System.currentTimeMillis();
if((sysTime > disableTime && sysTime < enableTime)) {
return true;
}
return false;
}
Anyone can give me better hint?
UPDATE:
If user selects lets say
Disable hour: 15:00
Enable hour: 22:00
Then code work as expected.
But if user selects lets say:
Disable hour: 22:00
Enable hour: 06:00
Then its obviously that Enable hour is the NEXT day. So i wrote the following code:
if(todaysDisableDate(context).getTime() > enableAt.getTime()) {
enableCal.add(Calendar.DAY_OF_MONTH, 1);
enableAt = formatEnableDate.parse(enableCal.get(Calendar.DAY_OF_MONTH) + "-" +(enableCal.get(Calendar.MONTH)+1) + "-" + enableCal.get(Calendar.YEAR) + " " + endHours_string + ":" + endMinutes_string);
}
Code below is getting the actual date.
public Date todaysDisableDate(Context context) {
Calendar disableCal = Calendar.getInstance();
getTimeValues_preferences((ContextWrapper) context, true, false); // this only gets a string for hour and minute (which is set up in preferences )
Date disableAt = null;
try {
disableAt = formatDisableDate.parse(disableCal.get(Calendar.DAY_OF_MONTH)+"-"+(disableCal.get(Calendar.MONTH)+1)+"-"+disableCal.get(Calendar.YEAR)+" "+startHours_string+":"+startMinutes_string); // današnji datum z današnjo uro
} catch (ParseException e) {
e.printStackTrace();
}
return disableAt;
}
public Date todaysEnableDate(Context context) {
Calendar enableCal = Calendar.getInstance();
getTimeValues_preferences((ContextWrapper) context, false, true);
Date enableAt = null;
try {
enableAt = formatEnableDate.parse(enableCal.get(Calendar.DAY_OF_MONTH)+"-"+(enableCal.get(Calendar.MONTH)+1)+"-"+enableCal.get(Calendar.YEAR)+" "+endHours_string+":"+endMinutes_string); // današnji datum z današnjo uro
if(todaysDisableDate(context).getTime() > enableAt.getTime()) {
enableCal.add(Calendar.DAY_OF_MONTH, 1);
enableAt = formatEnableDate.parse(enableCal.get(Calendar.DAY_OF_MONTH)+"-"+(enableCal.get(Calendar.MONTH)+1)+"-"+enableCal.get(Calendar.YEAR)+" "+endHours_string+":"+endMinutes_string);
}
} catch (ParseException e) {
}
return enableAt;
}
Code is working fine if service starts before 00:00. But if the service starts after midnight (of next day), then i'm getting false from method isCurrentTimeBetween_enableDisable(), because methods todaysDisableDate(Context context) and todaysEnableDate(Context context) are pulling out the next day (the same day as system hour is in)
Do you have to compare dates in your code? If that's a project requirement then you can ignore the following.
Otherwise, I think you can use AlarmManager to create the feature without actually comparing the date. You can create a "Enable" intent and a "Disable" intent for the AlarmManager to fire at the scheduled time. Something like this:
Register your alarms when the user confirmed the time schedule.
Intent intent = new Intent(context, yourAlarmReceiver.class); //or implicit with action
PendingIntent pIntent = PendingIntent.getBroadcast(
context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.setRepeating (typeConstant, triggerAtMillis, intervalMillis, pIntent);
You just need to figure out what triggerAtMillis is to determine the first shot of that broadcast, and intervalMillis will be a full day, which is a constant in the AlarmManager class.
Setup your custom receiver class (which I wrote as yourAlarmReceiver) which should extend BroadcastReceiver, and register the receiver in your service. In the onReceive() you should perform the corresponding actions based on intent.getAction(). Don't forget to register your receiver with an intent filter if you want more customization.
#Override
public void onReceive(Context context, Intent intent) {
switch(intent.getAction()){
case "enable": //enable if not enabled
case "disable": //disable if not disabled
default: break;
}
}
In this way it may save you some time from struggling with comparing today and tomorrow. You can determine the time of the very first shot by getting the current system time, probably in 24-hour format, and determine if your intended time has already passed. Whether it's been passed, you just need to set the initial firing time to currentTime + difference.
Hope it will shed some light.
I would recommend you to use the start date and end date itself...and not convert them to miliseconds. But this is only if you're not sure.
private String compareStringOne = "9:45";
private String compareStringTwo = "1:45";
SimpleDateFormat inputParser = new SimpleDateFormat(inputFormat, Locale.US);
private void compareDates(){
Calendar now = Calendar.getInstance();
int hour = now.get(Calendar.HOUR);
int minute = now.get(Calendar.MINUTE);
date = parseDate(hour + ":" + minute);
dateCompareOne = parseDate(compareStringOne);
dateCompareTwo = parseDate(compareStringTwo);
if ( dateCompareOne.before( date ) && dateCompareTwo.after(date)) {
//This is where you determine if the date is inbetween
}
}
private Date parseDate(String date) {
try {
return inputParser.parse(date);
} catch (java.text.ParseException e) {
return new Date(0);
}
}

Proximity Alert Intent not putting or returning extras

What I'm doing is adding different proximity alerts with a unique ID as an extra and it's not working -
for (int i = 0; i < latArray.size(); i++)
{
Bundle extra = new Bundle();
extra.putInt("UID", i);
Intent intent = new Intent(IntentToFire);
intent.putExtra("Blob", extra);
PendingIntent proximityIntent = PendingIntent.getBroadcast(this,-1 , intent, 0);
LocationManager locationManager =
Log.i("Picture:","Location img:"+GetLocation.imgArray.get(i));
Log.i("Potatoo:", "Lat :"+latArray.get(i)+" Lng :"+lngArray.get(i));
locationManager.addProximityAlert(Double.valueOf(latArray.get(i)), Double.valueOf(lngArray.get(i)), radius,expiration,proximityIntent);
}
And then on the broadcast receiver I'm putting this code -
flag = intent.getBundleExtra("blob").getInt("UID");
Every time I got to print flag, I just get an error. An ideas?
Try to use the FLAG_UPDATE_CURRENT:
PendingIntent.getBroadcast(this,-1 , intent, PendingIntent.FLAG_UPDATE_CURRENT);
I found it easiest is to encode data in the data-uri with proximity alerts on the Intent that is included in the pending intent, e.x.:
geo:<lat>,<lon>?id=<your id>
You can use your own protocol part though (geo is used by google maps AFAIK). No caching problems for me (seems you get a cached/old/wrong PendingIntent).

Categories

Resources