Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android AlarmManager: how to avoid to going off of past alarms

Hi and thank you for your help.

I have an application that uses AlarmManager to set one alarm a day for the next weeks, months...

  • I set one alarm for each day of the week to start the Activity

and

  • one alarm for each day of the week for stopping the Activity after some time

I have the following problem that I will try to explain in the following lines:

Today is Wednesday,

I open the application and set my alarms for MON, TUE, WED, THU, FRI, SAT, SUN... as soon as I set the alarms:

ALL the alarms for MON and TUE go immediately off I end up with 4 instances of the Activity !!!!

Please how do I avoid this???

Please see a piece of my code:

        // SET THE ALARM FOR STARTING THE ACTIVITY 
        Intent smon = new Intent(ctxt, VideoActivty.class);
        smon.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        PendingIntent psmon = PendingIntent.getActivity(ctxt, 0, smon, 0);

        Calendar calSet = Calendar.getInstance();
        calSet.set(Calendar.DAY_OF_WEEK, 2);
        calSet.set(Calendar.HOUR_OF_DAY, hsmon);
        calSet.set(Calendar.MINUTE, msmon);
        calSet.set(Calendar.SECOND, 0);
        calSet.set(Calendar.MILLISECOND, 0);

        mgr.setRepeating(AlarmManager.RTC_WAKEUP, calSet.getTimeInMillis(),
                7 * 24 * 60 * 60 * 1000, psmon);

        // SET THE ALARM FOR KILLING THE ACTIVITY 
        Intent fmon = new Intent(ctxt, VideoActivty.class);
        fmon.putExtra("finish", true);
        PendingIntent pfmon = PendingIntent.getActivity(ctxt, 0, fmon, 0);

        calSet.set(Calendar.DAY_OF_WEEK, 2);
        calSet.set(Calendar.HOUR_OF_DAY, hfmon);
        calSet.set(Calendar.MINUTE, mfmon);
        calSet.set(Calendar.SECOND, 0);
        calSet.set(Calendar.MILLISECOND, 0);

        mgr.setRepeating(AlarmManager.RTC_WAKEUP, calSet.getTimeInMillis(),
                7 * 24 * 60 * 60 * 1000, pfmon);

This is the Activity:

public class VideoActivty extends Activity {
private VideoView video;
private MediaController ctlr;
private PowerManager.WakeLock wl;
private KeyguardLock keyguard;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //
    PowerManager pm = (PowerManager) this
            .getSystemService(this.POWER_SERVICE);
    wl = pm.newWakeLock(
            PowerManager.PARTIAL_WAKE_LOCK, "");
    wl.acquire();

    KeyguardManager km = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
    keyguard = km.newKeyguardLock("MyApp");
    keyguard.disableKeyguard();

    getWindow().setFormat(PixelFormat.TRANSLUCENT);
    VideoView videoHolder = new VideoView(this);
    //if you want the controls to appear
    videoHolder.setMediaController(new MediaController(this));
    Uri video = Uri.parse("android.resource://" + getPackageName() + "/" 
    + R.raw.ingress); //do not add any extension
    //if your file is named sherif.mp4 and placed in /raw
    //use R.raw.sherif
    videoHolder.setVideoURI(video);
    setContentView(videoHolder);

    videoHolder.start();
    videoHolder.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {

        @Override
        public void onCompletion(MediaPlayer mp) {

                        mp.start();
        }
    });
}


@Override
protected void onNewIntent (Intent i){


  if( i.getBooleanExtra("finish",false) ){
      wl.release();
      keyguard.reenableKeyguard();
      finish();
  }
}


}
like image 612
Lisa Anne Avatar asked Dec 27 '22 00:12

Lisa Anne


1 Answers

As the API page of AlarmManager states regarding the set(...) and setRepeating(...) methods:

"If the stated trigger time is in the past, the alarm will be triggered immediately, with an alarm count depending on how far in the past the trigger time is relative to the repeat interval."

So, if for example you are on Wednesday, then the AlarmManager will fire the events of: Sunday, Monday, Tuesday and (possibly) Wednesday. It will actually fire only one for all of them.

Here is how I avoid this. Not sure it is the best way, but it works smoothly.

Let's say that you store the day of the week, the hour and the minute of the day in which you want to fire your AlarmManager in the following variables:

final int myAlarmDayOfTheWeek = ...;
final int myAlarmHour = ...;
final int myAlarmMinute = ...;

Of course, here I'm assuming you store the day of the week with the same convention of the Calendar class, i.e.:

Sunday = Calendar.SUNDAY = 1

Monday = Calendar.MONDAY = 2

... ... ...

Saturday = Calendar.SATURDAY = 7

Then:

Calendar timestamp = Calendar.getInstance();

//Check whether the day of the week was earlier in the week:
if( myAlarmDayOfTheWeek > timestamp.get(Calendar.DAY_OF_WEEK) ) {
    //Set the day of the AlarmManager:
    time.add(Calendar.DAY_OF_YEAR, (myAlarmDayOfTheWeek - timestamp.get(Calendar.DAY_OF_WEEK)));
}
else {
    if( myAlarmDayOfTheWeek < timestamp.get(Calendar.DAY_OF_WEEK) ) {
        //Set the day of the AlarmManager:
        timestamp.add(Calendar.DAY_OF_YEAR, (7 - (timestamp.get(Calendar.DAY_OF_WEEK) - myAlarmDayOfTheWeek)));
    }
    else {  // myAlarmDayOfTheWeek == time.get(Calendar.DAY_OF_WEEK)
        //Check whether the time has already gone:
        if ( (myAlarmHour < timestamp.get(Calendar.HOUR_OF_DAY)) || ((myAlarmHour == timestamp.get(Calendar.HOUR_OF_DAY)) && (myAlarmMinute < timestamp.get(Calendar.MINUTE))) ) {
            //Set the day of the AlarmManager:
            timestamp.add(Calendar.DAY_OF_YEAR, 7);
        }
    }
}

//Set the time of the AlarmManager:
timestamp.set(Calendar.HOUR_OF_DAY, myAlarmHour);
timestamp.set(Calendar.MINUTE, myAlarmMinute);
timestamp.set(Calendar.SECOND, 0);

Note that by using Calendar.DAY_OF_YEAR in the Calendar.add(...), you don't even need to take care of the change of the month...

If you are in the first condition (i.e. myAlarmDayOfTheWeek > timestamp.get(Calendar.DAY_OF_WEEK)), you can also just use Calendar.set(...) with Calendar.DAY_OF_WEEK as field and myAlarmDayOfTheWeek as value.

Now, you just need to setup your AlarmManager. For example:

final AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, timestamp.getTimeInMillis(), AlarmManager.INTERVAL_DAY * 7, myAlarmPendingIntent);

Please, also avoid calculating the day interval (i.e. 24 * 60 * 60 * 1000) every time, but use AlarmManager.INTERVAL_DAY (or at most 86400000) instead.

like image 188
Paolo Rovelli Avatar answered Mar 15 '23 11:03

Paolo Rovelli