I am new to android developing, and i am working on Task Reminder App. I need to set repeating alarm for the task, and for that purpose, i am using Recurrence Picker Dialog.
But i don't know how to set multiple alarms based on the string returned by the recurrence picker dialog.
I am using the following recurrence picker dialog.
It returns a string in variable 'rrule', but i don't know how to use that string to set multiple alarms. Below is the code to set Listener for the picker.
recurrencePickerDialog.setOnRecurrenceSetListener(new RecurrencePickerDialog.OnRecurrenceSetListener() {
#Override
public void onRecurrenceSet(String rrule) {
}
});
recurrencePickerDialog.show(getSupportFragmentManager(),"recurrencePicker");
Anyone please help me. I would be thankful..
You can set alarms using Alarm Manager and a Custom Broadcast Receiver.
You can set your alarm like this.
#Override
public void onRecurrenceSet(String rrule) {
if (rrule != null && rrule.length() > 0) {
EventRecurrence recurrenceEvent = new EventRecurrence();
recurrenceEvent.setStartDate(new Time("" + new Date().getTime()));
recurrenceEvent.parse(rrule);
//Sets alarm
Intent intent=new Intent(this,MyBroadcastReceiver.class);
PendingIntent pendingIntent= PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager=(AlarmManager)getSystemService(ALARM_SERVICE);
long offset=getNextOccurence(recurrenceEvent);
alarmManager.set(AlarmManager.RTC_WAKEUP, Calendar.getInstance().getTimeInMillis()+offset,pendingIntent);
//Then save the rule somewhere.
} else {
Lod.d("TEST","No recurrence");
}
}
getNextOccurrence function
/**
* Get the milliseconds till next alarm
* #param e
* #return
*/
private long getNextOccurrence(EventRecurrence e) {
switch (e.freq) {
case EventRecurrence.HOURLY://When alarm is hourly
if(e.interval==0)//When set to 1 Hour
return 1000 * 60 * 60;
return 1000 * 60 * 60 * e.interval;
// TODO: Implement cases for other frequencies
}
return 0;
}
Then, in your Broacast Receiver, do the following:
Show Alarm
Set next alarm to be on next occurrence (based on saved rule)
Hope this helps you to get started.
Related
I have to run a receiver which receives action USER_PRESENT only for a particular duration on specific days of the week. Here the duration and weekdays are selected by user.
What I have tried is using Preferences with AlarmManager to achieve this and I would very much like to use something other than Alarms with Preferences to achieve this as It becomes too difficult to test alarms with weekly alarms that runs after user selected duration and for user selected week days.
Is there any other way I can do this work other than using Alarms and Preferences. A code sample would really helpful !!
For more details here is my approach using Alarms with Preferences :
Now Firstly I calculate the start time by letting user choose the hour and minutes through a DialogFragment where a TimePickerDialog is inflated so that user can choose the starting time and I get the hrs and min in the onTimeSet() callback and then I find out the start time for the receiver to go off.
Code Snippet goes something like this for calculating start time in millis from hrs and min:
Calendar calSet = Calendar.getInstance();
//setting alarm from current day so that it starts from today onwards
int day = calSet.get(Calendar.DAY_OF_WEEK);
calSet.set(Calendar.DAY_OF_WEEK, day);
calSet.set(Calendar.HOUR_OF_DAY, hrs);
calSet.set(Calendar.MINUTE, min);
calSet.set(Calendar.SECOND, 0);
calSet.set(Calendar.MILLISECOND, 0);
Long milliseconds = calSet.getTimeInMillis();
//check if the time is already passed
Long daily = 24L * 60L * 60L * 1000L;
if (milliseconds < System.currentTimeMillis()) {
//if already passed then push it for next day by adding just 24 hrs
milliseconds = milliseconds + daily;
}
And then I save this calculated time in millis in a preference say : SharedPreferences.Editor.putLong("PeriodicLockStartTimeInMillis", milliseconds);
Now I store the days user has selected using checkBoxes and setting preferences for each day's checkbox
SharedPreferences.Editor.putBoolean("DAYNAME", true);
also storing the duration for which the user wants the receiver to work:
SharedPreferences.Editor.putLong("LockDurationInMillis", minutesinmillis);
Then Using AlarmManager to set an alarm which will set a BroadcastReceiver whose name here is PeriodicLockServiceas an PendingIntent that will hit its receiver .
Code for setting alarm here :
Intent reminderIntent = new Intent(getActivity(), PeriodicLockService.class);
reminderIntent.setAction("ACTION_REPEATING_ALARM_RECEIVER");
pendingIntent = PendingIntent.getBroadcast(getActivity(), PeriodicLockService.REPEATING_ALARM_UNIQUE_ID, reminderIntent, PendingIntent.FLAG_UPDATE_CURRENT);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, milliseconds, pendingIntent);
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP, milliseconds, pendingIntent);
}
Now in PeriodicLockService when onReceive is hit then I firstly check if user had set things to run for today by using the preference as :
//Fetching today's day from Calendar to compare if user has set lock for today
Calendar calendar = Calendar.getInstance();
int day = calendar.get(Calendar.DAY_OF_WEEK);
switch (day) {
case Calendar.SUNDAY:
if (Preferences.getBooleanPreference(context, SUN_DAY)) {
startLockNow(context);
}
break;
case Calendar.MONDAY:
if (Preferences.getBooleanPreference(context, MON_DAY)) {
startLockNow(context);
}
break;
case Calendar.TUESDAY:
if (Preferences.getBooleanPreference(context, TUES_DAY)) {
startLockNow(context);
}
break;
case Calendar.WEDNESDAY:
if (Preferences.getBooleanPreference(context, WED_DAY)) {
startLockNow(context);
}
break;
case Calendar.THURSDAY:
if (Preferences.getBooleanPreference(context, THURS_DAY)) {
startLockNow(context);
}
break;
case Calendar.FRIDAY:
if (Preferences.getBooleanPreference(context, FRI_DAY)) {
startLockNow(context);
}
break;
case Calendar.SATURDAY:
if (Preferences.getBooleanPreference(context, SAT_DAY)) {
startLockNow(context);
}
break;
}
private void startLockNow(Context context) {
Long lockStartTimeInMillis = Preferences.getLongPreference(context, "PeriodicLockStartTimeInMillis");
//Update Unlock Time
Long LockDurationInMillis = Preferences.getLongPreference(context, "LockDurationInMillis"); //End time to stop the Receiver for action USER_PRESENT
Long newEndTime = lockStartTimeInMillis + LockDurationInMillis;
//Set Unlocked notification broadcast which also disables the receiver for action `USER_PRESENT`
Intent intent = new Intent(context, FinalUnlockedBroadcast.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, newEndTime + 1000, pendingIntent);
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP, newEndTime + 1000, pendingIntent);
}
//update the time for next lock by adding a day
milliseconds = Preferences.getLongPreference(context, "PeriodicLockStartTimeInMillis") + 24L * 60L * 60L * 1000L;
Intent reminderIntent = new Intent(context, PeriodicLockService.class);
reminderIntent.setAction("ACTION_REPEATING_ALARM_RECEIVER");
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, REPEATING_ALARM_UNIQUE_ID, reminderIntent, PendingIntent.FLAG_UPDATE_CURRENT);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, milliseconds , pendingIntent);
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP, milliseconds , pendingIntent);
}
}
But the thing is this doesn't always seem to work and its difficult to get logs from users devices running my app.
Is there any other way I can do this work other than using Alarms and Preferences
Android-Job Android-Job repo
Android-Job abstracts away which implementation you want to use to perform background work.
Depending on the requirements, this library decides which API to use to run your job.
It provides a superset of all the features from JobScheduler, GCMNetworkManager and AlarmManager.
All features from Android Nougat are backward compatible.
Less boilerplate.
Implementing Android-Job is super easy.
The API includes below classes/interfaces.
Job : Your jobs need to extend this class and override onRunJob method. The heavy lifting is done here. You must return a Result from this method so that the system knows whether to attempt to run your job at a later time.
JobRequest: You can schedule a Job by creating a JobRequest using its builder constructor and passing your Job tag.
JobCreator: JobCreator acts like a factory to provide a Job based on a job tag. Your concrete JobCreator class must implement the JobCreator interface and override the create method.
JobManager: The JobManager class serves as the entry point. Before using this class you must initialize this as singleton. JobManager takes a Context. After creating the instance, you have to add your JobCreator to JobManager.
if u interested to read more plz take alook to this awesome article Easy Job Scheduling with Android-Job
thanks for Rajesh Pattanaik the person who wrote this article
I would recommend you Firebase Job Dispatcher. It is a library for scheduling background jobs in your Android app. It provides a JobScheduler-compatible API that works on all recent versions of Android (API level 9+) that have Google Play services installed.
For instructions on how to use it in your app, click here.
You can use Job Scheduler
public class MyJobService extends JobService {
#Override
public boolean onStartJob(JobParameters params) {
Toast.makeText(this, "testing", Toast.LENGTH_LONG).show();
Log.i("sid", "Job scheduler called");
jobFinished(params, true);
return true;
}
#Override
public boolean onStopJob(JobParameters params) {
return false;
}
}
Call the below method in your activity
private void constructJob(){
JobInfo.Builder builder = new JobInfo.Builder(JOB_ID, new ComponentName(this, MyJobService.class));
builder.setMinimumLatency(60000)
.setBackoffCriteria(10000,JobInfo.BACKOFF_POLICY_LINEAR)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
.setPersisted(true);
mJobScheduler.schedule(builder.build());
}
Make sure you call builder.setPersisted(true) in order to run the service even after reboot. Another thing to have a look is that this code will work fine on Android N (API 24) or above APIs, however, for API 21 - 23 it call builder.setPeriodic(60000) instead of builder.setMinimumLatency(60000)
UPDATE
In order to run Job Scheduler on API 15 and above use JobSchedulerCompat.
Add below dependency in your gradle file -
compile 'me.tatarka.support:jobscheduler:0.1.1'
I need help in understanding the logic that I have implemented in my app using AlarmManager, since the logic is not working as I expected. I am new to Android development and a self-learner.
The Logic :
User selects a time in Main Activity using a button.
That time value is used for setting repeating alarm in Another activity.
When the alarm goes of A dialog box appears.
Main Activity:
static long ATfrom_to_millisec;
case R.id.ATfrom:
final Calendar ATfromC = Calendar.getInstance();
ATfromHour = ATfromC.get(Calendar.HOUR_OF_DAY);
ATfromMinute = ATfromC.get(Calendar.MINUTE);
// Launch Time Picker Dialog
TimePickerDialog ATfromtpd = new TimePickerDialog(MainActivity.this,
new TimePickerDialog.OnTimeSetListener() {
#Override
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
//Converting to milli seconds to use in AlarmManager
ATfrom_to_millisec = ((hourOfDay * 60 * 60 * 1000) + (minute * 60 * 1000));
String AM_PM;
if (hourOfDay < 12) {
AM_PM = "AM";
} else {
AM_PM = "PM";
if (hourOfDay > 12) {
hourOfDay = hourOfDay - 12;
}
}
if (minute < 10) {
ATfrom.setText(hourOfDay + ":0" + minute + " " + AM_PM);
} else {
ATfrom.setText(hourOfDay + ":" + minute + " " + AM_PM);
}
In the above logic the time selected by the user is converted to milliseconds and stored in a public static variable so that it can be used by other activities.
Alarm Activity :
public void onClick(View arg0) {
// TODO Auto-generated method stub
switch (arg0.getId()){
case R.id.bReminder:
try {
//Receiving the static variable's value from MainActivity
long AT_from = MainActivity.ATfrom_to_millisec;
float cov = (float)(AT_from/1000/60/60);
//Toast to check if the time value is passed correctly
toast.makeText(getApplicationContext(), String.valueOf(cov), toast.LENGTH_SHORT).show();
Intent intent = new Intent(this, Notifier.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this.getApplicationContext(),
12345, intent, 0);
//Logic for Repeating Alarm that uses the time value from MainActivty as starting time and repeating it every 10 seconds.
// i.e. the alarm should go off after 10 seconds from the use selected time and repeat after 10 seconds.
AlarmManager am =
(AlarmManager)getSystemService(Activity.ALARM_SERVICE);
am.setRepeating(AlarmManager.RTC_WAKEUP, AT_from + (10*1000), 10*1000, pendingIntent);
} catch (Exception e) {}
break;
case R.id.bReminderStop:
AlarmManager am =
(AlarmManager)getSystemService(Activity.ALARM_SERVICE);
am.cancel(pendingIntent);
break;
}
}
When alarm is set with the above implemented logic , The alarm goes of immediately once it is set and repeats with an interval of 1 minute.
But I implemented my logic expecting the alarm to go of 10 seconds from the time set by user and repeat after every 10 seconds
I am not able to understand the mistake implemented in my logic.
Also in the toast I am not getting the decimal value of float cov
(eg : 11:30 PM must be displayed as 23.5 .But it is displayed as 23.0)
Dialog Activity when Alarm goes off :
public class Notifier extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
alertDialogBuilder.setTitle("HydrateTime");
alertDialogBuilder.setMessage("Enter the amount of water");
alertDialogBuilder.setPositiveButton("Update", null);
AlertDialog alertDialog = alertDialogBuilder.create();
alertDialog.show();
}
}
I want the above Activity to be invoked when the Alarm goes off. Is the above implemented logic enough to make a Dialog window appear when an activity goes of?
Note : I am using a general activity definition in the Android Manifest.
like :
<activity
android:name=".Notifier"
android:label="#string/app_name">
</activity
Kindly request answers for the below questions :
Am I passing the time value set in the MainActivity to the AlarmManager in another activity correctly?
What is the mistake in my Alarm logic and how to rectify it such that the alarm goes of as per my requirement?
Is the definition for the dialog box correct? should there any more definitions in Manifest? should I create any layout file for the dialog activity? Should I extend my Notifier class with Dialog class instead of Activity class?
The logic has a minor flaw. You see, with alarms if the time to fire has already passed, then the alarm will fire immediately. For eg: if I set an alarm with milli seconds for 2 Jan 1983, it would fire immediately. If you notice, you are doing something similar.
To fix it, simply add this in your Alarm Activity:
// Will trigger after 10 secs from set time
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + AT_from + (10*1000), 10*1000, pendingIntent);
I am not sure what is causing the interval problem though. It seems fine to me.
I have done an application that fire an alarm in certain time, and i am stuck on implementing remind me after half an hour functionality
what can i do to implement receiver, or service or anything that runs after half an hour of clicking the button of reming me after half an hour
any suggestions ?
Edited the code from Android execute a function after 1 hour to half an hour.
// the scheduler
protected FunctionEveryHalfHour scheduler;
// method to schedule your actions
private void scheduleEveryHalfHour(){
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0,
new Intent(WAKE_UP_AFTER_HALF_HOUR),
PendingIntent.FLAG_UPDATE_CURRENT);
// wake up time every 1 hour
Calendar wakeUpTime = Calendar.getInstance();
wakeUpTime.add(Calendar.SECOND, 30 * 60);
AlarmManager aMgr = (AlarmManager) getSystemService(ALARM_SERVICE);
aMgr.set(AlarmManager.RTC_WAKEUP,
wakeUpTime.getTimeInMillis(),
pendingIntent);
}
//put this in the creation of service or if service is running long operations put this in onStartCommand
scheduler = new FunctionEveryHalfHour();
registerReceiver(scheduler , new IntentFilter(WAKE_UP_AFTER_HALF_HOUR));
// broadcastreceiver to handle your work
class FunctionEveryHalfHour extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
// if phone is lock use PowerManager to acquire lock
// your code to handle operations every half hour...
// after that call again your method to schedule again
// if you have boolean if the user doesnt want to continue
// create a Preference or store it and retrieve it here like
boolean mContinue = getUserPreference(USER_CONTINUE_OR_NOT);//
if(mContinue){
scheduleEveryHalfHour();
}
}
}
You can write a simple service with a timer and whenever the time is up.it can do your thing.all you need to do is start a service with a timer inside of it
I would like to execute a piece of code every 24 Hours however I'm not sure how to do this.
I have some code that sets the time that I would like the cycle to start but not sure how to execute the end time
int startDay = 00; // 12am
int end = 24; // 12 pm
int hours = (end - startDay) % 24; //difference will be 24 hours
Calendar calInstanceOne = Calendar.getInstance();
// set calendar to 12 am
calInstanceOne.set(Calendar.HOUR_OF_DAY, startDay);
calInstanceOne.set(Calendar.MINUTE, 0);
calInstanceOne.set(Calendar.SECOND, 0);
calInstanceOne.set(Calendar.MILLISECOND, 0);
Do I create another Calendar instance, set to 12pm? and compare the two? Would really appreciate any insight into this.
I would like to execute a piece of code every 24 Hours
Use AlarmManager, in conjunction with either WakefulBroadcastReceiver or my WakefulIntentService. Ideally, use setInexactRepeating() on AlarmManager for INTERVAL_DAY, to allow Android to slide the actual time around to best save battery for the user.
You can use AlarmManager to make actions periodically:
Intent intent = new Intent(this, MyStartServiceReceiver.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 5000, <24h in msecs>, pendingIntent);
Then you should register your BroadcastReceiver in the manifest and call the method you want to execute from this receiver.
First store your current time then whenever app will be open compare current time with previous store time if its greater or equal 24 hour
execute your code.
You may have several choices, let me outline the easiest one. The strategy is to simply use the system time to execute twenty four hours later:
package com.test;
import java.util.Calendar;
public class ExecuteCheck {
//Class fields
/* Number of milliseconds in a day
*
*/
private static final long C_DAY=24*60*60*1000;
//Object fields
/* Time last executed (or beginning of cycle), in milliseconds;
*
*/
private long lastExecuted = System.currentTimeMillis();
public ExecuteCheck() {
}
/** Set the current execution cycle time to now
*
*/
public void setExecutionTimeToNow() {
lastExecuted = System.currentTimeMillis();
}
/** Set the execution cycle time to be the value in the calendar argument.
* #param cal
*/
public void setExecutionTime(Calendar cal) {
lastExecuted = cal.getTimeInMillis();
}
/** Is it more than twenty-four hours since the last execution time?
* #return
*/
public boolean isTimeToExecute() {
return (System.currentTimeMillis() - lastExecuted) > C_DAY;
}
}
I am attempting to use CommonsWare's WakefulIntentService in a new application, specifically its ability to easily schedule the intent service to run at a later time.
I have a PreferenceActivity that allows the user to pick the schedule that the service is run (daily at 5am for example). Once the user makes a change to the preference value, I call:
AutoDownloadIntentServiceAlarmListener alarmListener = new AutoDownloadIntentServiceAlarmListener();
alarmListener.setForcedHour(5); // we want to schedule alarm for 5am everyday.
WakefulIntentService.scheduleAlarms(alarmListener, this, true);
For some reason, the desired IntentService (that extends WakefulIntentService) immediately starts up and performs its work.
Here is the implementation of of AutoDownloadIntentServiceAlarmListener:
public class AutoDownloadIntentServiceAlarmListener implements WakefulIntentService.AlarmListener {
private static final String TAG = "AutoDownloadIntentServiceAlarmListener";
private int mForcedHour = -1;
#Override
public long getMaxAge() {
return AlarmManager.INTERVAL_DAY * 2;
}
public void setForcedHour(int forcedHour) {
mForcedHour = forcedHour;
}
#Override
public void scheduleAlarms(AlarmManager alarmManager, PendingIntent pendingIntent, Context context) {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
String autoDownloadTimePref = MyApplication.getInstance().getPrefs().getString("autoDownloadEpisodesSchedule", "0");
int hourOfAlarm = Integer.parseInt(autoDownloadTimePref);
// if this class has been created with a specific hour
// use it instead of the value obtained from SharedPreferences above.
if (mForcedHour > -1) {
Log.w(TAG, "Forced hour has been set for this AlarmListener. " + mForcedHour);
hourOfAlarm = mForcedHour;
}
calendar.set(Calendar.HOUR_OF_DAY, hourOfAlarm);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent);
Log.d(TAG, String.format("Scheduled inexact alarm for %d", hourOfAlarm));
}
#Override
public void sendWakefulWork(Context context) {
Intent serviceIntent = new Intent(context, AutoDownloadIntentService.class);
WakefulIntentService.sendWakefulWork(context, serviceIntent);
}
}
It is my intention that the service does not startup as soon as it is scheduled, and instead starts up only at 5am the next day. (and continues to repeat on this schedule indefinitely, or until the user elects to disable or change its schedule)
What am I doing wrong?
It is my intention that the service does not startup as soon as it is scheduled, and instead starts up only at 5am the next day.
Except that's not what your code does, ~80% of the time. Your code says that it should run at 5am today, as you are getting the current time and not changing the day. Most of the time, 5am today is in the past, and so AlarmManager will immediately do its work.
You need to see if your calculated Calendar is older than now, and if so, add a day.