Search code examples
javaandroidalarmmanager

AlarmManager isn't working in correct schedule


In my app, i have 18 Checkboxes and if the user check it, the AlarmManager will start a notification in the time that CheckBox indicates. I tested the AlarmManager with just one alarm, and it works correctly.

But when i added all the schedules, it's not working correctly and the AlarmManager is starting the notification in an aleatory time, usually when i close the app.

MainFragment.class, in method onCreate. This is to save that the checkbox is marked and to call the method that will create the AlarmManager.

// isChecked?
        checkBoxesEvents.get(0).setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                savePreferences(0);
                if(isChecked) {
                    startAlarm(0);
                }
            }
        });
        checkBoxesEvents.get(1).setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                savePreferences(1);
                if(isChecked) {
                    startAlarm(1);
                }
            }
        });
        checkBoxesEvents.get(2).setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                savePreferences(2);
                if(isChecked) {
                    startAlarm(2);
                }
            }
        });
        checkBoxesEvents.get(3).setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                savePreferences(3);
                if(isChecked) {
                    startAlarm(3);
                }
            }
        });
        checkBoxesEvents.get(4).setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                savePreferences(4);
                if(isChecked) {
                    startAlarm(4);
                }
            }
        });
        checkBoxesEvents.get(5).setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                savePreferences(5);
                if(isChecked) {
                    startAlarm(5);
                }
            }
        });
        checkBoxesEvents.get(6).setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                savePreferences(6);
                if(isChecked) {
                    startAlarm(6);
                }
            }
        });
        checkBoxesEvents.get(7).setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                savePreferences(7);
                if(isChecked) {
                    startAlarm(7);
                }
            }
        });
        checkBoxesEvents.get(8).setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                savePreferences(8);
                if(isChecked) {
                    startAlarm(8);
                }
            }
        });
        checkBoxesEvents.get(9).setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                savePreferences(9);
                if(isChecked) {
                    startAlarm(9);
                }
            }
        });
        checkBoxesEvents.get(10).setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                savePreferences(10);
                if(isChecked) {
                    startAlarm(10);
                }
            }
        });
        checkBoxesEvents.get(11).setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                savePreferences(11);
                if(isChecked) {
                    startAlarm(11);
                }
            }
        });
        checkBoxesEvents.get(12).setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                savePreferences(12);
                if(isChecked) {
                    startAlarm(12);
                }
            }
        });
        checkBoxesEvents.get(13).setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                savePreferences(13);
                if(isChecked) {
                    startAlarm(13);
                }
            }
        });
        checkBoxesEvents.get(14).setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                savePreferences(14);
                if(isChecked) {
                    startAlarm(14);
                }
            }
        });
        checkBoxesEvents.get(15).setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                savePreferences(15);
                if(isChecked) {
                    startAlarm(15);
                }
            }
        });
        checkBoxesEvents.get(16).setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                savePreferences(16);
                if(isChecked) {
                    startAlarm(16);
                }
            }
        });
        checkBoxesEvents.get(17).setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                savePreferences(17);
                if(isChecked) {
                    startAlarm(17);
                }
            }
        });

MainFragment.class, this is the method to create the Alarm.

public void startAlarm(int eventID) {
        int[] HOUR_ARRAY =      {7, 20, 7,12,17 ,8,16, 8, 9,21, 9,19,12,13,13,14,15,15};
        int[] MINUTES_ARRAY =   {55,55,55,55,55,25,25,55,55,55,55,25,50,25,55,55,25,55};
        String[] NOTIFICATION_TITLES = {"Ocleera Rift", "Ocleera Rift", "Mistmerrow Conflict", "Mistmerrow Conflict",
        "Mistmerrow Conflict", "Freedich Gold Trader", "Freedich Gold Trader", "Nation Construction Quests", "Diamond Shores",
        "Diamond Shores", "Battle of the Golden Plains", "Battle of the Golden Plains", "Karkasse Ridgelands", "Kraken",
        "The Mirage Isle Fish Fest", "Red Dragon", "Abyssal Attack", "Lusca Awakening"};

        String notificationTitle = getString(R.string.contentTitle);
        String notificationText = NOTIFICATION_TITLES[eventID] + getString(R.string.contentNotificationText);

        Calendar calendar = Calendar.getInstance();
        Log.d("HOUR-BEFORE-SET", String.valueOf(calendar.get(Calendar.HOUR_OF_DAY)) + String.valueOf(calendar.get(Calendar.MINUTE)));
        calendar.set(Calendar.HOUR_OF_DAY, HOUR_ARRAY[eventID]);
        calendar.set(Calendar.MINUTE, MINUTES_ARRAY[eventID]);
        Log.d("HOUR-AFTER-SET", String.valueOf(calendar.get(Calendar.HOUR_OF_DAY)) + String.valueOf(calendar.get(Calendar.MINUTE)));

        Intent intent = new Intent(getActivity().getApplicationContext(), AlarmReceiver.class);
        intent.putExtra("contentTitle", notificationTitle);
        intent.putExtra("contentText", notificationText);

        PendingIntent pendingIntent = PendingIntent.getBroadcast(getActivity().getApplicationContext(), eventID, intent, PendingIntent.FLAG_UPDATE_CURRENT);

        AlarmManager alarmManager = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE);
        alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent);
    }

AlarmReceiver.class, and this is my BroadcastReceiver

public class AlarmReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

        NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context
        .NOTIFICATION_SERVICE);

        Intent repeatingIntent = new Intent(context,RepeatingActivity.class);
        repeatingIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

        PendingIntent pendingIntent = PendingIntent.getActivity(context,100,repeatingIntent,
                PendingIntent.FLAG_UPDATE_CURRENT);

        String contentTitle = intent.getStringExtra("contentTitle");
        String contentText = intent.getStringExtra("contentText");

        NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
                .setContentIntent(pendingIntent)
                .setSmallIcon(R.drawable.icon_notification)
                .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.icon_notification))
                .setContentTitle(contentTitle)
                .setContentText(contentText)
                .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
                .setVibrate(new long[]{800,500,600,300})
                .setLights(Color.GREEN, 500, 500)
                .setAutoCancel(true);

        notificationManager.notify(100,builder.build());

        // Light up the screen
        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
        boolean isScreenOn = false;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
            isScreenOn = pm.isInteractive();
        }
        else if(Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT_WATCH){
            isScreenOn = pm.isScreenOn();
        }

        if(isScreenOn==false)
        {
            PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK |PowerManager.ACQUIRE_CAUSES_WAKEUP |PowerManager.ON_AFTER_RELEASE,"MyLock");
            wl.acquire(10000);
            PowerManager.WakeLock wl_cpu = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"MyCpuLock");

            wl_cpu.acquire(10000);
        }
    }

}

Solution

  • The AlarmManager documentation says about setRepeating:

    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.

    My alarm was starting in wrong time because the time set is already passed. And have no relation with the multiple alarms.

    What i did to adjust it was put the alarm that has passed, to start just in the next day.

    Calendar actualTime = Calendar.getInstance();
    if(calendar.getTimeInMillis() < actualTime.getTimeInMillis()) {
        calendar.set(Calendar.DAY_OF_MONTH, 1);
    }
    

    I just added it to my code.