alarm manager sometimes firing at wrong times

342 views Asked by At

I'm Making an app which has 5 different notifications at different times every day. it works perfectly but after beta testing some users are complaining that some alarm fire again at wrong times I haven't faced this problem before and I don't know how to trace the problem so I can fix it. This is how I create the alarm:

Manager Class:(which has all the functions of the alarm)

public static Integer DEFAULT_SILENT_DURATION = 20 * 60 * 1000;
    public static Integer DEFAULT_SILENT_START= 2 * 60 * 1000;

    public Manager(Context applicationContext) {

        this.context = applicationContext;
    }

    public static void acquireScreen(Context context) {
        PowerManager pm = (PowerManager) context.getApplicationContext()
                .getSystemService(Context.POWER_SERVICE);
        WakeLock wakeLock = pm
                .newWakeLock(
                        (PowerManager.SCREEN_BRIGHT_WAKE_LOCK
                                | PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP),
                        "TAG");
        wakeLock.acquire();
        Log.v("Check Manager acquireScreen","YES");
    }

    public static void releaseScreen(Context context) {
        KeyguardManager keyguardManager = (KeyguardManager) context
                .getApplicationContext().getSystemService(
                        Context.KEYGUARD_SERVICE);
        KeyguardLock keyguardLock = keyguardManager.newKeyguardLock("TAG");
        keyguardLock.disableKeyguard();
        Log.v("Check Manager releaseScreen","YES");
    }

    public static void initPrayerAlarm(Service service,
            Class<PrayerReceiver> receiver) {

        Manager.prayerService = service; // we may need it ?
        Manager.prayerIntet = new Intent(service, receiver);
        Manager.prayerPendingIntent = PendingIntent
                .getBroadcast(service, 1234432, Manager.prayerIntet,
                        PendingIntent.FLAG_UPDATE_CURRENT);
        Manager.prayerAlarmManager = (AlarmManager) service
                .getSystemService(Context.ALARM_SERVICE);
        Manager.prayerAlarmManager.set(AlarmManager.RTC_WAKEUP,
                System.currentTimeMillis() + 1000, Manager.prayerPendingIntent);
        Log.v("Check Manager initPrayerAlarm",""+System.currentTimeMillis() + 1000);
    }

    public static void updatePrayerAlarm(long newTimeInterval) {

        Manager.prayerAlarmManager.set(AlarmManager.RTC_WAKEUP,
                System.currentTimeMillis() + newTimeInterval,
                Manager.prayerPendingIntent);
        Log.v("Check Manager updatePrayerAlarm",""+System.currentTimeMillis() + newTimeInterval);
    }

public void restartPrayerService(Activity activty) {

        Intent intent = new Intent(activty, PrayerService.class);
        context.startService(intent);
        Log.v("Check Manager restartPrayerService","YES");
    }
  • In my MainActivity I call Manager restartPrayerService function
  • In PrayerService I call as below:

Manager.initPrayerState(this); Manager.initPrayerAlarm(this, PrayerReceiver.class);

and then register the receiver.

PrayerReceiver:

public class PrayerReceiver extends BroadcastReceiver {

static PrayerState prayerState;
private AudioManager am;
private Context context;
private SharedPreferences pref;
private Editor editor;
private int silentDuration;
private int silentStart ;
private int delayMilliSeconds = 1000 * 60;  // one minute by default.
private Object obj;


@Override
public void onReceive(Context context, Intent intent) {
        this.context = context;
        pref = PreferenceManager.getDefaultSharedPreferences(this.context);

    Manager m = new Manager(context);
    Preference p = m.getPreference();
    this.silentDuration = p.getSilentDuration();
    this.silentStart = p.getSilentStart();
    editor = pref.edit();
    try {

        prayerState = Manager.getPrayerState();
        am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
        switch (prayerState.getCurrentState()) {

        case PrayerState.WAITING_AZAN:
            {
                Log.v("Check PrayerReceiver PrayerState","WAITING_AZAN");
                onWaitingAzan();

            }

            break;
        case PrayerState.DOING_AZAN:
            { 
                Log.v("Check PrayerReceiver PrayerState","DOING_AZAN");
                onDoingAzan();
            }
            break;

        case PrayerState.WAITING_PRAYER:
            {
                Log.v("Check PrayerReceiver PrayerState","WAITING_PRAYER");
                onWaitingPrayer();
            }

            break;

        }

    } catch (Exception e) {
        // TODO Auto-generated catch block

        Log.v("Check PrayerReceiver PrayerState","ERROR");
      }

    }


    public int getDelayMilliSeconds() {

        return delayMilliSeconds;
    }

    public void setDelayMilliSeconds(int delayMilliSeconds) {
          this.delayMilliSeconds = delayMilliSeconds;
    }

    private void onWaitingAzan() {
     try {


        boolean isRingerModeChangedToSilent = pref.getBoolean(
                "isRingerModeChangedToSilent", false);
        if (isRingerModeChangedToSilent == true) {
            am.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
            editor.putBoolean("isRingerModeChangedToSilent", false);
            editor.commit();
        }

        // What is the remaining time until the next prayer ?
        Date date = new Date();
        int dd = date.getDate();
        int mm = date.getMonth() + 1;
        int yy = date.getYear() + 1900;
        int h = date.getHours();
        int m = date.getMinutes();
        int s = date.getSeconds();
        int nearestPrayerTime = Manager.computeNearestPrayerTime(context,
                h, m, s, yy, mm, dd);
        int deffTime = TimeHelper.different((h * 3600 + m * 60 + s),
                nearestPrayerTime);
        deffTime = deffTime * 1000; // to milliseconds

        // ok , come back after X seconds to do the Azan
        prayerState.setNextState(PrayerState.DOING_AZAN);

        Manager.updatePrayerAlarm(deffTime);


    } catch (Exception e) {

        Log.v("Check PrayerReceiver onWaitingAzan","ERROR");
      }
    }

    private void onDoingAzan() {

    prayerState.setNextState(PrayerState.WAITING_PRAYER);
    int delay = this.silentStart;
    if(delay < 2000*60)
        delay =2000*60; // two minutes  - at lease  
    Log.v("Check PrayerReceiver onDoingAzan","delay "+delay);
    Manager.playAzanNotification(context);

    Manager.updatePrayerAlarm(delay);



    }

    private void onWaitingPrayer() {

    Manager manager = new Manager(this.context);
    Preference preference = manager.getPreference();
    AudioManager am = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
    if(am.getRingerMode() == AudioManager.RINGER_MODE_NORMAL && preference.isAutoSilentDisabled()==false ){
        am.setRingerMode(AudioManager.RINGER_MODE_SILENT);
        editor.putBoolean("isRingerModeChangedToSilent", true);
        editor.commit();
    }

    this.delayMilliSeconds = silentDuration;
    prayerState.setNextState(PrayerState.WAITING_AZAN);

    Manager.updatePrayerAlarm(delayMilliSeconds);

    }

Can some one please help me,exactly what am I doing wrong?

1

There are 1 answers

0
Robin Dijkhof On BEST ANSWER

Manager.prayerAlarmManager.set is not set exact on the specified time on api 19 and above. That is probably why "some" users complain.

Note: Beginning with API 19 (KITKAT) alarm delivery is inexact: the OS will shift alarms in order to minimize wakeups and battery use. There are new APIs to support applications which need strict delivery guarantees; see setWindow(int, long, long, PendingIntent) and setExact(int, long, PendingIntent). Applications whose targetSdkVersion is earlier than API 19 will continue to see the previous behavior in which all alarms are delivered exactly when requested.

On api 19 and above you need setExact to schedule at a specific time

You will need something like this:

if(android.os.Build.VERSION.SDK_INT >= 19) {
// setExact
}
else {
    //set
}