diff --git a/app/src/main/java/com/jens/automation2/Trigger.java b/app/src/main/java/com/jens/automation2/Trigger.java index 5277c56..23f883f 100644 --- a/app/src/main/java/com/jens/automation2/Trigger.java +++ b/app/src/main/java/com/jens/automation2/Trigger.java @@ -1447,9 +1447,18 @@ public class Trigger */ Calendar timeSupposedToRunNext = getNextRepeatedExecutionAfter(this, lastExec); - if(now.getTimeInMillis() > timeSupposedToRunNext.getTimeInMillis()) - return true; + Miscellaneous.logEvent("i", "isSupposedToRepeatSinceLastExecution()", "Last execution: " + Miscellaneous.formatDate(lastExec.getTime()), 5); + Miscellaneous.logEvent("i", "isSupposedToRepeatSinceLastExecution()", "Next execution: " + Miscellaneous.formatDate(timeSupposedToRunNext.getTime()), 5); + Miscellaneous.logEvent("i", "isSupposedToRepeatSinceLastExecution()", "Now: " + Miscellaneous.formatDate(now.getTime()), 5); + + if(now.getTimeInMillis() > timeSupposedToRunNext.getTimeInMillis()) + { + Miscellaneous.logEvent("i", "isSupposedToRepeatSinceLastExecution()", "Repetition due.", 5); + return true; + } + + Miscellaneous.logEvent("i", "isSupposedToRepeatSinceLastExecution()", "Repetition not due.", 5); return false; } diff --git a/app/src/main/java/com/jens/automation2/receivers/DateTimeListener.java b/app/src/main/java/com/jens/automation2/receivers/DateTimeListener.java index f78ec62..7541b85 100644 --- a/app/src/main/java/com/jens/automation2/receivers/DateTimeListener.java +++ b/app/src/main/java/com/jens/automation2/receivers/DateTimeListener.java @@ -23,20 +23,19 @@ import java.sql.Time; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; -import java.util.Collections; import java.util.Date; public class DateTimeListener extends BroadcastReceiver implements AutomationListenerInterface { private static AutomationService automationServiceRef; private static AlarmManager centralAlarmManagerInstance; - private static boolean alarmListenerActive = false; + private static boolean alarmListenerActive=false; private static ArrayList alarmCandidates = new ArrayList<>(); private static ArrayList requestCodeList = new ArrayList(); static PendingIntent alarmPendingIntent = null; public static void startAlarmListener(final AutomationService automationServiceRef) - { + { DateTimeListener.startAlarmListenerInternal(automationServiceRef); } public static void stopAlarmListener(Context context) @@ -48,7 +47,7 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis { return alarmListenerActive; } - + @Override public void onReceive(Context context, Intent intent) { @@ -60,10 +59,10 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis if(allRulesWithNowInTimeFrame.get(i).getsGreenLight(context)) allRulesWithNowInTimeFrame.get(i).activate(automationServiceRef, false); } - + setAlarms(); } - + @RequiresApi(api = Build.VERSION_CODES.KITKAT) public static void setAlarms() { @@ -71,11 +70,11 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis Calendar calNow = Calendar.getInstance(); SimpleDateFormat sdf = new SimpleDateFormat("E dd.MM.yyyy HH:mm"); - + clearAlarms(); - + int i=0; - + ArrayList allRulesWithTimeFrames = new ArrayList(); allRulesWithTimeFrames = Rule.findRuleCandidates(Trigger_Enum.timeFrame); // allRulesWithTimeFrames = Rule.findRuleCandidatesByTimeFrame(); @@ -192,8 +191,7 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis * 4. Take div result +1 and add this on top of starting time * 5. Is this next possible execution still inside timeframe? Also consider timeframes spanning over midnight */ - Calendar calSet; - Time setTime; + TimeFrame tf = new TimeFrame(oneTrigger.getTriggerParameter2()); if(tf.getRepetition() > 0) @@ -202,7 +200,7 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis { Calendar calSchedule = getNextRepeatedExecutionAfter(oneTrigger, calNow); - alarmCandidates.add(new ScheduleElement(calSchedule, "Rule " + oneRule.getName() + ", repetition in trigger " + oneTrigger.toString())); + alarmCandidates.add(new ScheduleElement(calSchedule, "Rule " + oneRule.getName() + ", trigger " + oneTrigger.toString())); } } } @@ -214,36 +212,51 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis } } } - + scheduleNextAlarm(); } - + private static void scheduleNextAlarm() { + Long currentTime = System.currentTimeMillis(); + ScheduleElement scheduleCandidate = null; + if(alarmCandidates.size() == 0) { Miscellaneous.logEvent("i", "AlarmManager", "No alarms to be scheduled.", 3); + return; } - else + else if(alarmCandidates.size() == 1) { - Collections.sort(alarmCandidates); - - Miscellaneous.logEvent("i", "AlarmManager", "Chose this as next scheduled alarm: " + alarmCandidates.get(0), 4); - - Intent alarmIntent = new Intent(automationServiceRef, DateTimeListener.class); - - if(Miscellaneous.getAnyContext().getApplicationContext().getApplicationInfo().targetSdkVersion >= 31) - alarmPendingIntent = PendingIntent.getBroadcast(automationServiceRef, 0, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); - else - alarmPendingIntent = PendingIntent.getBroadcast(automationServiceRef, 0, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) - centralAlarmManagerInstance.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, alarmCandidates.get(0).time.getTimeInMillis(), alarmPendingIntent); - else - centralAlarmManagerInstance.set(AlarmManager.RTC_WAKEUP, alarmCandidates.get(0).time.getTimeInMillis(), alarmPendingIntent); + // only one alarm, schedule that + scheduleCandidate = alarmCandidates.get(0); } + else if(alarmCandidates.size() > 1) + { + scheduleCandidate = alarmCandidates.get(0); + + for(ScheduleElement alarmCandidate : alarmCandidates) + { + if(Math.abs(currentTime - alarmCandidate.time.getTimeInMillis()) < Math.abs(currentTime - scheduleCandidate.time.getTimeInMillis())) + scheduleCandidate = alarmCandidate; + } + } + + Intent alarmIntent = new Intent(automationServiceRef, DateTimeListener.class); + + if(Miscellaneous.getAnyContext().getApplicationContext().getApplicationInfo().targetSdkVersion >= 31) + alarmPendingIntent = PendingIntent.getBroadcast(automationServiceRef, 0, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); + else + alarmPendingIntent = PendingIntent.getBroadcast(automationServiceRef, 0, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT); + + centralAlarmManagerInstance.set(AlarmManager.RTC_WAKEUP, scheduleCandidate.time.getTimeInMillis(), alarmPendingIntent); + + SimpleDateFormat sdf = new SimpleDateFormat("E dd.MM.yyyy HH:mm:ss"); + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(scheduleCandidate.time.getTimeInMillis()); + Miscellaneous.logEvent("i", "AlarmManager", "Chose " + sdf.format(calendar.getTime()) + " as next scheduled alarm.", 4); } - + public static void clearAlarms() { Miscellaneous.logEvent("i", "AlarmManager", "Clearing possibly standing alarms.", 4); @@ -252,12 +265,12 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis Intent alarmIntent = new Intent(automationServiceRef, DateTimeListener.class); if(alarmPendingIntent == null) alarmPendingIntent = PendingIntent.getBroadcast(automationServiceRef, requestCode, alarmIntent, 0); - +// Miscellaneous.logEvent("i", "AlarmManager", "Clearing alarm with request code: " + String.valueOf(requestCode)); centralAlarmManagerInstance.cancel(alarmPendingIntent); } requestCodeList.clear(); } - + private static void startAlarmListenerInternal(AutomationService givenAutomationServiceRef) { if(!alarmListenerActive) @@ -265,20 +278,29 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis Miscellaneous.logEvent("i", "AlarmListener", "Starting alarm listener.", 4); DateTimeListener.automationServiceRef = givenAutomationServiceRef; centralAlarmManagerInstance = (AlarmManager)automationServiceRef.getSystemService(automationServiceRef.ALARM_SERVICE); +// alarmIntent = new Intent(automationServiceRef, AlarmListener.class); +// alarmPendingIntent = PendingIntent.getBroadcast(automationServiceRef, 0, alarmIntent, 0); alarmListenerActive = true; Miscellaneous.logEvent("i", "AlarmListener", "Alarm listener started.", 4); DateTimeListener.setAlarms(); + +// // get a Calendar object with current time +// Calendar cal = Calendar.getInstance(); +// // add 5 minutes to the calendar object +// cal.add(Calendar.SECOND, 10); +// centralAlarmManagerInstance.setInexactRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 5000, alarmPendingIntent); } else Miscellaneous.logEvent("i", "AlarmListener", "Request to start AlarmListener. But it's already active.", 5); } - + private static void stopAlarmListenerInternal() { if(alarmListenerActive) { Miscellaneous.logEvent("i", "AlarmListener", "Stopping alarm listener.", 4); clearAlarms(); + centralAlarmManagerInstance.cancel(alarmPendingIntent); alarmListenerActive = false; } else @@ -348,37 +370,55 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis @RequiresApi(api = Build.VERSION_CODES.N) public static Calendar getNextRepeatedExecutionAfter(Trigger trigger, Calendar now) { - Calendar calSet; + Calendar calculationStart; TimeObject setTime; TimeFrame tf = new TimeFrame(trigger.getTriggerParameter2()); if(tf.getRepetition() > 0) { - if(trigger.getTriggerParameter()) - setTime = tf.getTriggerTimeStart(); + if(trigger.getParentRule().getLastExecution() != null) + { + Miscellaneous.logEvent("i", "DateTimeListener", "Chose last runtime of rule " + trigger.getParentRule().getName() + " as calculation start.", 5); + calculationStart = trigger.getParentRule().getLastExecution(); + } else - setTime = tf.getTriggerTimeStop(); + { + if(trigger.getTriggerParameter()) + { + Miscellaneous.logEvent("i", "DateTimeListener", "Chose start of next interval of trigger in rule " + trigger.getParentRule().getName() + " as calculation start.", 5); + setTime = tf.getTriggerTimeStart(); + } + else + { + Miscellaneous.logEvent("i", "DateTimeListener", "Chose end of next interval of trigger in rule " + trigger.getParentRule().getName() + " as calculation start.", 5); + setTime = tf.getTriggerTimeStop(); + } - calSet = (Calendar) now.clone(); - calSet.set(Calendar.HOUR_OF_DAY, setTime.getHours()); - calSet.set(Calendar.MINUTE, setTime.getMinutes()); - calSet.set(Calendar.SECOND, 0); - calSet.set(Calendar.MILLISECOND, 0); + calculationStart = (Calendar) now.clone(); + calculationStart.set(Calendar.HOUR_OF_DAY, setTime.getHours()); + calculationStart.set(Calendar.MINUTE, setTime.getMinutes()); + calculationStart.set(Calendar.SECOND, 0); +// calculationStart.set(Calendar.MILLISECOND, 0); + } // If the starting time is a day ahead remove 1 day. - if(calSet.getTimeInMillis() > now.getTimeInMillis()) - calSet.add(Calendar.DAY_OF_MONTH, -1); + if(calculationStart.getTimeInMillis() > now.getTimeInMillis()) + calculationStart.add(Calendar.DAY_OF_MONTH, -1); - long differenceInSeconds = Math.abs(now.getTimeInMillis() - calSet.getTimeInMillis()) / 1000; + Miscellaneous.logEvent("i", "getNextRepeatedExecutionAfter()", "Chose " + Miscellaneous.formatDate(calculationStart.getTime()) + " as calculation start.", 5); + + long differenceInSeconds = Math.abs(now.getTimeInMillis() - calculationStart.getTimeInMillis()) / 1000; long nextExecutionMultiplier = Math.floorDiv(differenceInSeconds, tf.getRepetition()) + 1; - long nextScheduleTimestamp = (calSet.getTimeInMillis() / 1000) + (nextExecutionMultiplier * tf.getRepetition()); + long nextScheduleTimestamp = (calculationStart.getTimeInMillis() / 1000) + (nextExecutionMultiplier * tf.getRepetition()); Calendar calSchedule = Calendar.getInstance(); calSchedule.setTimeInMillis(nextScheduleTimestamp * 1000); + Miscellaneous.logEvent("i", "getNextRepeatedExecutionAfter()", "Chose " + Miscellaneous.formatDate(calSchedule.getTime()) + " as next repeated execution time.", 5); + return calSchedule; } else - Miscellaneous.logEvent("i", "DateTimeListener", "Trigger " + trigger.toString() + " is not executed repeatedly.", 5); + Miscellaneous.logEvent("i", "getNextRepeatedExecutionAfter()", "Trigger " + trigger.toString() + " is not executed repeatedly.", 5); return null; }