Alarm manager Not triggering with correct time - android

I know this is most common thread in SO but i didn't find any answer for my question . I want to trigger dynamic broadcast receiver at particular time. For this i am using below code
public void method1() {
br = new BroadcastReceiver() {
#Override
public void onReceive(Context c, Intent i) {
doTASK();
}
};
registerReceiver(br, new IntentFilter("com.XXXX.wakeup"));
pi = PendingIntent.getBroadcast(this, 0,
new Intent("com.xxxx.wakeup"), 0);
am = (AlarmManager) (this.getSystemService(Context.ALARM_SERVICE));
setAlarmManagerObject();
}
And setAlarmManagerObject() method is here
public void setAlarmManagerObject() {
Calendar cal = Calendar.getInstance();
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH);
int day = cal.get(Calendar.DAY_OF_MONTH);
cal.set(year, month, day
, com.XXXX.Constants.AlarmHour
, com.xxxx.Constants.AlarmMinute
, com.xxxx.AlarmSecond);
am.setRepeating(AlarmManager.ELAPSED_REALTIME, cal.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, pi);
}
My problem is that when i used AlarmManager.RTC_WAKEUP it wake up when device is off. I don't want this property in my app. So i used AlarmManager.ELAPSED_REALTIME, but with ELAPSED_REALTIME alarm manager is not triggering. I want that my alarm manager trigger exact at same time. If device is off or sleep condition then alarm manager will also off after device wake up.It should trigger at exact time. Any help will really appreciated.

You need to use something like this:-
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP (or AlarmManager.ELAPSED_REALTIME),
SystemClock.elapsedRealtime() + Constants.DELAY_IN_MILLIS,
pendingIntent);
You can calculate DELAY_IN_MILLIS which is time delay in milliseconds from current system time.
For repeating alarm you can have code something like this:-
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + Constants.DELAY_IN_MILLIS,
Constants.ONE_DAY_IN_MILLIS,
pendingIntent);

Related

Why my Alarm is fired earlier than my set time?

I'm currently trying to make an alarm app that will mute all audio volume at the user-defined day and time. However, the alarm seems not fired at the correct time. I found that the alarm is always fired earlier.
This is my set alarm code:
public static void setAlarm(Context context, String time, int day, int reqCode) {
String[] timeSplit = time.split(":");
Calendar calendar = Calendar.getInstance();
int hour = Integer.parseInt(timeSplit[0]);
int minute = Integer.parseInt(timeSplit[1]);
int days = (day-calendar.get(Calendar.DAY_OF_WEEK) + calendar.get(Calendar.DAY_OF_MONTH));
calendar.set(
calendar.get(Calendar.YEAR),
calendar.get(Calendar.MONTH),
days,
hour,
minute,
0
);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, RuleAlarm.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, reqCode, intent, 0);
// Set the alarm to be fired every week on the selected day
alarmManager.setRepeating(AlarmManager.RTC, calendar.getTimeInMillis(), 7 * 24 * 60 * 60 * 1000, pendingIntent);
Toast.makeText(context, "Alarm is set", Toast.LENGTH_SHORT).show();
}
I have tried to change setRepeating() to setInexactRepeating() but nothing changed.
AlarmManger is inexact to save battery by combining wakeup calls.
https://developer.android.com/reference/android/app/AlarmManager.html
Try this
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 7 * 24 * 60 * 60 * 1000, pendingIntent);
The problem is that if you are creating PendingIntent for an alarm for past time it will be fired immediately.If you would like to prevent that happening, then simply do not set alarms with a past trigger time . Use BroadcastReceiver for receiving alarm.
Update :
Check we aren't setting it in the past which would trigger it to fire instantly
if(calendar.getTimeInMillis() < System.currentTimeMillis()) {
calendar.add(Calendar.DAY_OF_YEAR, 7);
}
I finally find out the problem. It lies on the day params. What I pass to day params is my Spinner selected position which starts from zero while the Calendar days starts from one (SUNDAY = 1, MONDAY = 2, so on). So, the alarm will always be set in the past days. I plus one to the day params and it's worked.
This is my piece of code where the startAlarm() function got called.
String ruleStartTime = rule_startTime.getText().toString();
// Spinner index starts from zero,
// to match with the Calendar day indexing, we need to plus it one
int dayIdx = day.getSelectedItemPosition()+1;
Alarm.setAlarm(getApplicationContext(), ruleStartTime,
dayIdx, 0);

Alarm is not triggering on the same Date

I want to reboot device on particular time so i am using alarm manager for that.below is the code of my activity.
public class MainActivity extends AppCompatActivity {
private static int timeHour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
private static int timeMinute = Calendar.getInstance().get(Calendar.MINUTE);
AlarmManager alarmManager;
private PendingIntent pendingIntent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
Intent myIntent = new Intent(MainActivity.this, AlarmReceiver.class);
pendingIntent = PendingIntent.getBroadcast(MainActivity.this, 0, myIntent, 0);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 11);
calendar.set(Calendar.MINUTE, 02);
alarmManager.cancel(pendingIntent);
// if(Calendar.getInstance().after(calendar)){
// // Move to tomorrow
// calendar.add(Calendar.DATE, 1);
// }
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),AlarmManager.INTERVAL_DAY, pendingIntent);
//
// alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
// SystemClock.elapsedRealtime() + AlarmManager.INTERVAL_DAY,
// AlarmManager.INTERVAL_DAY, pendingIntent);
}
}
and this is my receiver
public class AlarmReceiver extends BroadcastReceiver {
public static void rebootDevice() {
try {
Process process = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(process.getOutputStream());
os.writeBytes("reboot \n");
} catch (Throwable t) {
t.printStackTrace();
}
}
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Triggered", Toast.LENGTH_SHORT).show();
Log.d("Gajanand", "onReceive: Triggered");
rebootDevice();
}
}
Yes code is working fine but not on the exact date.for example if i run the same code now. alarm not triggers if i change the date it triggers. i am not getting what is the problem with code and there is 10 seconds delay in triggering alarm. any help
There are two problems with your code:
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 11);
calendar.set(Calendar.MINUTE, 02);
Here you're setting HOUR_OF_DAY and MINUTE but the SECOND field still has its initial value, so the alarm won't be triggered exactly on the minute
(unless you called calendar.setTimeInMillis(System.currentTimeMillis()) exactly on the minute, which is quite unlikely).
Should be something like this:
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 11);
calendar.set(Calendar.MINUTE, 2);
calendar.set(Calendar.SECOND, 0); // setting seconds to 0
setRepeating() is inexact and doesn't work with Doze.
For exact trigger times you should use exact alarms, check this answer for an example.
This is from the documentation
Note: as of API 19, all repeating alarms are inexact. If your
application needs precise delivery times then it must use one-time
exact alarms, rescheduling each time as described above. Legacy applications
whose {#code targetSdkVersion} is earlier than API 19 will continue to have all
of their alarms, including repeating alarms, treated as exact.
Repeating alarms are always inexact so that they wont consume much battery. They may be fired a bit later than the expected time. If you want your alarm to exact, don't make it repeating. Set it again once you receive the alarm

start a service with Alarmmanager at specific date and time and Repeating

I want to create reminder app
I have searched a lot of places but couldnt find a clean sequential explanation of how to start a service (or if thats not possible then an activity) at a specific time daily using the AlarmManager?
i want start service at specific date and time and for example Six months after that date start the service again And continue this cycle
Calendar cur_cal = new GregorianCalendar();
cur_cal.setTimeInMillis(System.currentTimeMillis());//set the current time and date for this calendar
Calendar cal = new GregorianCalendar();
cal.add(Calendar.YEAR, 2018);
cal.set(Calendar.MONTH, 2);
cal.set(Calendar.DAY_OF_MONTH, 12);
cal.set(Calendar.HOUR_OF_DAY, 9);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
Intent intent = new Intent(ProfileList.this, BroadcastedReceiver.class);
PendingIntent pintent = PendingIntent.getService(ProfileList.this, 0, intent, 0);
AlarmManager alarm = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
alarm.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 1000, pintent);
i tried this code to activate the alarm at 2018-02/12 9:00... this is Works on this date but i have problem to repeating after for example six month...How do I change the codes to be start service every six months?
NOTE: Dates are stored in the database And they will be called from there
public class AddService extends Service
{
InterstitialAd mInterstitialAd;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//Your Logic
stopSelf();
return START_NOT_STICKY;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
AlarmManager alarmManager = (AlarmManager)getSystemService(ALARM_SERVICE);
alarmManager.set(alarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000*60*60),
PendingIntent.getService(this,0,new Intent(this,AddService.class),0));
}
}
// Here your service will call every 1 hour, you can change time according to that
it's better to use job scheduler or firebase dispatcher for your requirement
refer this links
https://medium.com/google-developers/scheduling-jobs-like-a-pro-with-jobscheduler-286ef8510129
https://github.com/firebase/firebase-jobdispatcher-android

Alarm is running immediately after it is created

I am trying to play a ringtone at exactly at 7 PM everyday but it is playing ringtone immediately after its pending intent is registering broadcast.
I called the service in the foreground on a button click and created pending intent there in onStartCommand:
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
startForeground(FOREGROUND_ID,
buildForegroundNotification("DummyApp"));
c = Calendar.getInstance();
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
int interval = 1000 * 60 * 60*24;
c.setTimeInMillis(System.currentTimeMillis());
c.set(Calendar.HOUR, 19);
c.set(Calendar.MINUTE,00);
manager.setRepeating(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(),
interval, pendingIntent);
Intent alarmIntent = new Intent(AlarmService.this, DataProcessor.class);
pendingIntent = PendingIntent.getBroadcast(AlarmService.this, 0,
alarmIntent, 0);
return START_STICKY;
}
Now I am playing a ringtone on receiving this broadcast in DataProcessor class the on Receive method of Data Processor class:
#Override
public void onReceive(Context ctx,Intent intent) {
playRIng(ctx);
}
But when I run this code,click the button,service is created but alarm is fired immediately after the AlarmService is called and ringtone is played also.How it is possible because I am giving the exact 7 O clock time when registering broadcast.?
Googled a lot but found the same code only and nothing else.Every code is able to play the ringtone on the time but it also plays the ringtone immediately after the broadcast is registered.
Why you don't use a condition?:
#Override
public void onReceive(Context ctx,Intent intent) {
Calendar c = Calendar.getInstance();
int hour = c.get(Calendar.HOUR);
if(hour==19)
{
playRIng(ctx);
}
}
If you ran that code at 9pm you would be telling the AlarmManager that the intent should have been run for the first time 2 hours ago.
You need to check if the Calendar time is behind the current time.
If it is you need to add a day to the calendar so that it first triggers tomorrow at 7pm.
Something like this might work:
c = Calendar.getInstance();
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
int interval = 1000 * 60 * 60 * 24;
// Not needed
// c.setTimeInMillis(System.currentTimeMillis());
c.set(Calendar.HOUR, 19);
c.set(Calendar.MINUTE, 00);
// ** Add this **
// Check if the Calendar 7pm is in the past
if (c.getTimeInMillis() < System.currentTimeMillis())
c.add(Calendar.DAY_OF_YEAR, 1); // It is so tell it to run tomorrow instead
manager.setRepeating(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(), interval, pendingIntent);
Intent alarmIntent = new Intent(AlarmService.this, DataProcessor.class);
pendingIntent = PendingIntent.getBroadcast(AlarmService.this, 0, alarmIntent, 0);
You can try the example at developers website understanding the samplecode available there.May be there is some programming mistake in your code but the sample code available there is working exactly you want.
Scheduling Repeating Alarms
Best way, Play with hour & mintue.
Note: Please check your time formate. In my case it's 24 hr formate
Example:
Calendar c = Calendar.getInstance();
//for 12 hr formate user int hour = c.get(Calendar.HOUR);
int hour = c.get(Calendar.HOUR_OF_DAY);
int minute = c.get(Calendar.MINUTE);
//Log.e("time",""+hour+":"+minute);
if (hour == 10 && minute == 0 ) {
}

Repeating alarms between two dates

I've searched for examples of how to implement such a problem but couldn't find anything that could solve my problem so I'm asking you for an advice how to solve it.
I have to implement an alarm that fires every day at a specific time during the period between two specified dates.
Up to now I have a repeating alarm firing every day at a specific time but not specified until when to repeat...
Any advice and ideas will be highly appreciated!
Suppose you want to set an repeating Alarm from Date1 to Date2.
For Date1, there is no problem for you since it is working.
Set an alarm for Date2 and when that alarm is fired cancel Date1 repeating alarm.
I do it like this:
Lets say you wanted to set a repeating alarm, that first triggered at a 'random' time between two hours (e.g. 0100 - 0500) in the day, and then always triggered at that same time of day again every 24 hours.
private long getTimeOfNextWidgetAutoUpdateInMilliseconds(Calendar now, int startHour, int endHour){
// calc the time diff in milliseconds from now until a 'random' time between startHour and endHour
// ensure to +1 day if the time has already passed
}
private void createAutoRefreshAlarm(Context context, long initialTriggerTimeInMillis,
long intervalInMillis) {
AlarmManager alarmManager = getAlarmManager(context);
PendingIntent widgetRefreshPi = getWidgetRefreshAlarmPendingIntent(context);
setRepeatingAlarm(initialTriggerTimeInMillis, intervalInMillis, widgetRefreshPi,
alarmManager);
ApplicationData.setAppDataBoolean(WIDGET_REFRESH_ALARM_SERVICE_INITITATED, true);
}
private static void setRepeatingAlarm(long initialTriggerTimeInMillis, long intervalInMillis,
PendingIntent widgetRefreshPi, AlarmManager alarmManager) {
alarmManager.setRepeating(
AlarmManager.RTC_WAKEUP,
initialTriggerTimeInMillis,
intervalInMillis,
widgetRefreshPi);
}
private PendingIntent getWidgetRefreshAlarmPendingIntent(Context context) {
Intent alarmIntent = new Intent(context, AlarmManagerBroadcastReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
return pendingIntent;
}
private static AlarmManager getAlarmManager(Context context) {
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
return alarmManager;
}
I would then have the following in the WidgetProvider class:
#Override
public void onEnabled(Context context) {
super.onEnabled(context);
int startHour = 1;
int endHour = 5;
long initialTriggerTimeInMillis = getTimeOfNextWidgetAutoUpdateInMilliseconds(
Calendar.getInstance(),
startHour,
endHour);
long intervalInMillis = 86400000; // 24 hours
createAutoRefreshAlarm(context, initialTriggerTimeInMillis, intervalInMillis);
}
This should get you going, I've cut+pasted from my own project, so there may be a few errors.
Also, remember to cancel your alram in the onDisabled() method of your `WidgetProvider.
There are other scenarios that delete the alarm that you should consider, e.g. ON BOOT

Categories

Resources