From 62bfbbb0644891e446dea6301537183f6ce67172 Mon Sep 17 00:00:00 2001 From: jens Date: Thu, 8 Feb 2024 20:25:54 +0100 Subject: [PATCH] date time repetition --- .../jens/automation2/AutomationService.java | 2 +- .../java/com/jens/automation2/Trigger.java | 280 +++++------------- .../receivers/DateTimeListener.java | 151 ++++++++-- .../receivers/TimeZoneListener.java | 4 +- 4 files changed, 198 insertions(+), 239 deletions(-) diff --git a/app/src/main/java/com/jens/automation2/AutomationService.java b/app/src/main/java/com/jens/automation2/AutomationService.java index cae6c32..5b25865 100644 --- a/app/src/main/java/com/jens/automation2/AutomationService.java +++ b/app/src/main/java/com/jens/automation2/AutomationService.java @@ -320,7 +320,7 @@ public class AutomationService extends Service implements OnInitListener ReceiverCoordinator.applySettingsAndRules(); - DateTimeListener.reloadAlarms(); + DateTimeListener.setOrResetAlarms(); CalendarReceiver.armOrRearmTimer(); } diff --git a/app/src/main/java/com/jens/automation2/Trigger.java b/app/src/main/java/com/jens/automation2/Trigger.java index 23f883f..62d19c7 100644 --- a/app/src/main/java/com/jens/automation2/Trigger.java +++ b/app/src/main/java/com/jens/automation2/Trigger.java @@ -17,6 +17,7 @@ import com.jens.automation2.receivers.BluetoothReceiver; import com.jens.automation2.receivers.BroadcastListener; import com.jens.automation2.receivers.CalendarReceiver; import com.jens.automation2.receivers.ConnectivityReceiver; +import com.jens.automation2.receivers.DateTimeListener; import com.jens.automation2.receivers.DeviceOrientationListener; import com.jens.automation2.receivers.HeadphoneJackListener; import com.jens.automation2.receivers.MediaPlayerListener; @@ -135,6 +136,35 @@ public class Trigger } }; + boolean triggerParameter; //if true->started event, if false->stopped + String triggerParameter2; + + public static final String triggerParameter2Split = "tp2split"; + + Trigger_Enum triggerType = null; + PointOfInterest pointOfInterest = null; + TimeFrame timeFrame; + + public static String triggerPhoneCallStateRinging = "ringing"; + public static String triggerPhoneCallStateStarted = "started"; + public static String triggerPhoneCallStateStopped = "stopped"; + public static String triggerPhoneCallDirectionIncoming = "incoming"; + public static String triggerPhoneCallDirectionOutgoing = "outgoing"; + public static String triggerPhoneCallDirectionAny = "any"; + public static String triggerPhoneCallNumberAny = "any"; + + double speed; //km/h + long noiseLevelDb; + String processName = null; + int batteryLevel; + int phoneDirection = 0; // 0=any, 1=incoming, 2=outgoing + String phoneNumber = null; + String nfcTagId = null; + String bluetoothEvent = null; + String bluetoothDeviceAddress = null; + int activityDetectionType = -1; + int headphoneType = -1; + public static enum subSystemStates { wifi, bluetooth }; Rule parentRule = null; @@ -1124,8 +1154,6 @@ public class Trigger // We are not at any POI. But if this trigger requires us NOT to be there, that may be fine. if(this.getPointOfInterest() != null) { -// if(activePoi.equals(oneTrigger.getPointOfInterest())) -// { if(!this.getTriggerParameter()) { Miscellaneous.logEvent("i", String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), this.getParentRule().getName()), "We are not at POI \"" + this.getPointOfInterest().getName() + "\". But since that's required by this rule that's fine.", 4); @@ -1135,7 +1163,6 @@ public class Trigger Miscellaneous.logEvent("i", String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), this.getParentRule().getName()), String.format("Rule \"%1$s\" doesn't apply. We're not at POI \"" + this.getPointOfInterest().getName() + "\".", getParentRule().getName()), 3); return false; } -// } } else if(this.getPointOfInterest() == null) { @@ -1224,7 +1251,7 @@ public class Trigger return false; } - public boolean checkDateTime(Object triggeringObject, boolean checkifStateChangedSinceLastRuleExecution) + public boolean checkDateTime(Object triggeringObject, boolean checkIfStateChangedSinceLastRuleExecution) { /* * Use format known from Automation @@ -1246,142 +1273,52 @@ public class Trigger { TimeFrame tf = new TimeFrame(getTriggerParameter2()); - if(tf.getDayList().contains(calNow.get(Calendar.DAY_OF_WEEK))) + if (DateTimeListener.areWeInTimeFrame(this, triggeringObject) != this.getTriggerParameter()) { - if( - // Regular case, start time is lower than end time - ( - Miscellaneous.compareTimes(tf.getTriggerTimeStart(), nowTime) >= 0 - && - Miscellaneous.compareTimes(nowTime, tf.getTriggerTimeStop()) > 0 - ) - || - // Other case, start time higher than end time, timeframe goes over midnight - ( - Miscellaneous.compareTimes(tf.getTriggerTimeStart(), tf.getTriggerTimeStop()) < 0 - && - (Miscellaneous.compareTimes(tf.getTriggerTimeStart(), nowTime) >= 0 - || - Miscellaneous.compareTimes(nowTime, tf.getTriggerTimeStop()) > 0) - ) - || - // further case: start and end times are identical, meaning a 24h window - ( - Miscellaneous.compareTimes(tf.getTriggerTimeStart(), tf.getTriggerTimeStop()) == 0 - ) - ) + if (triggerParameter) + Miscellaneous.logEvent("i", "Trigger", "TimeFrame: We're currently (" + calNow.getTime().toString() + ", Day: " + String.valueOf(calNow.get(Calendar.DAY_OF_WEEK)) + ") outside of the specified TimeFrame (" + tf.toString() + "), but demanded is inside.", 5); + else + Miscellaneous.logEvent("i", "Trigger", "TimeFrame: We're currently (" + calNow.getTime().toString() + ") in the specified TimeFrame (" + tf.toString() + "), but demanded is outside.", 4); + + return false; + } + + // We are inside or outside of the timeframe as demanded by the trigger + + if (tf.getRepetition() > 0) + { + if (!isSupposedToRepeatSinceLastExecution(Calendar.getInstance())) { - // We are in the timeframe - Miscellaneous.logEvent("i", "Trigger", "TimeFrame: We're currently (" + calNow.getTime().toString() + ") in the specified TimeFrame (" + tf.toString() + ").", 4); - if(getTriggerParameter()) - { - if(checkifStateChangedSinceLastRuleExecution) - { - /* - * Was there a target repetition time between last execution and now? - * If not -> return false. - */ - Calendar compareCal = Calendar.getInstance(); - compareCal.setTimeInMillis(triggeringTime.getTime()); - if(tf.getRepetition() > 0) - { - if(!isSupposedToRepeatSinceLastExecution(compareCal)) - { - Miscellaneous.logEvent("i", "TimeFrame", "TimeFrame: Trigger of rule " + this.getParentRule().getName() + " applies, but repeated execution is not due, yet.", 4); - return false; - } - } - else - { - /* - * This is not a repeating rule. Have we left - * the relevant timeframe since the last run? - * Determine if it has ran today already. If yes - * return false because every rule that is not - * repeating can only be executed once per day. - */ - - if( - getParentRule().getLastExecution().get(Calendar.YEAR) == calNow.get(Calendar.YEAR) - && - getParentRule().getLastExecution().get(Calendar.MONTH) == calNow.get(Calendar.MONTH) - && - getParentRule().getLastExecution().get(Calendar.DAY_OF_MONTH) == calNow.get(Calendar.DAY_OF_MONTH) - ) - { - Miscellaneous.logEvent("i", "TimeFrame", "TimeFrame: Trigger of rule " + this.getParentRule().getName() + " applies, but it was already executed today.", 4); - return false; - } - } - } - - Miscellaneous.logEvent("i", "Trigger", "TimeFrame: That's what's specified. Trigger of rule " + this.getParentRule().getName() + " applies.", 4); - return true; - } - else - { - Miscellaneous.logEvent("i", "Trigger", "TimeFrame: That's not what's specified. Trigger of rule " + this.getParentRule().getName() + " doesn't apply.", 4); - return false; - } + Miscellaneous.logEvent("i", "TimeFrame", "TimeFrame: Trigger of rule " + this.getParentRule().getName() + " applies, but repetition is not due, yet.", 4); + return false; } else - { - Miscellaneous.logEvent("i", "Trigger", "TimeFrame: We're currently (" + calNow.getTime().toString() + ", Day: " + String.valueOf(calNow.get(Calendar.DAY_OF_WEEK)) + ") not in the specified TimeFrame (" + tf.toString() + ") because of the time.", 5); - if(!getTriggerParameter()) - { - if(checkifStateChangedSinceLastRuleExecution) - { - /* - * Was there a target repetition time between last execution and now? - * If not -> return false. - */ - Calendar compareCal = Calendar.getInstance(); - compareCal.setTimeInMillis(triggeringTime.getTime()); - if(tf.getRepetition() > 0) - { - if(!isSupposedToRepeatSinceLastExecution(compareCal)) - { - Miscellaneous.logEvent("i", "Trigger", "TimeFrame: Trigger of rule " + this.getParentRule().getName() + " applies, but repeated execution is not due, yet.", 4); - return false; - } - } - else - { - /* - * This is not a repeating rule. Have we left - * the relevant timeframe since the last run? - * Determine if it has ran today already. If yes - * return false because every rule that is not - * repeating can only be executed once per day. - */ - - if( - getParentRule().getLastExecution().get(Calendar.YEAR) == calNow.get(Calendar.YEAR) - && - getParentRule().getLastExecution().get(Calendar.MONTH) == calNow.get(Calendar.MONTH) - && - getParentRule().getLastExecution().get(Calendar.DAY_OF_MONTH) == calNow.get(Calendar.DAY_OF_MONTH) - ) - { - Miscellaneous.logEvent("i", "Trigger", "TimeFrame: Trigger of rule " + this.getParentRule().getName() + " applies, but it was already executed today.", 4); - return false; - } - } - } - Miscellaneous.logEvent("i", "Trigger", "TimeFrame: That's what's specified. Trigger of rule " + this.getParentRule().getName() + " applies.", 5); - return true; - } - else - { - Miscellaneous.logEvent("i", "Trigger", "TimeFrame: That's not what's specified. Trigger of rule " + this.getParentRule().getName() + " doesn't apply.", 5); - return false; - } - } + Miscellaneous.logEvent("i", "TimeFrame", "TimeFrame: Trigger of rule " + this.getParentRule().getName() + " would apply because repetition is due.", 4); } else { - Miscellaneous.logEvent("i", "Trigger", "TimeFrame: We're currently (" + calNow.getTime().toString() + ", Day: " + String.valueOf(calNow.get(Calendar.DAY_OF_WEEK)) + ") not in the specified TimeFrame (" + tf.toString() + ") because of the day.", 5); - return false; + if (checkIfStateChangedSinceLastRuleExecution) + { + /* + * This is not a repeating rule. Have we left + * the relevant timeframe since the last run? + * Determine if it has ran today already. If yes + * return false because every rule that is not + * repeating can only be executed once per day. + */ + + if ( + getParentRule().getLastExecution().get(Calendar.YEAR) == calNow.get(Calendar.YEAR) + && + getParentRule().getLastExecution().get(Calendar.MONTH) == calNow.get(Calendar.MONTH) + && + getParentRule().getLastExecution().get(Calendar.DAY_OF_MONTH) == calNow.get(Calendar.DAY_OF_MONTH) + ) + { + Miscellaneous.logEvent("i", "TimeFrame", "TimeFrame: Trigger of rule " + this.getParentRule().getName() + " applies, but it was already executed today.", 4); + return false; + } + } } } catch(Exception e) @@ -1389,43 +1326,8 @@ public class Trigger Miscellaneous.logEvent("e", "Trigger", "There was an error while checking if the time based trigger applies: " + Log.getStackTraceString(e), 1); return false; } - } - public static Calendar getNextRepeatedExecutionAfter(Trigger trigger, Calendar now) - { - Calendar calSet; - TimeObject setTime; - TimeFrame tf = new TimeFrame(trigger.getTriggerParameter2()); - - if(tf.getRepetition() > 0) - { - if(trigger.getTriggerParameter()) - setTime = tf.getTriggerTimeStart(); - else - 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); - - // If the starting time is a day ahead remove 1 day. - if(calSet.getTimeInMillis() > now.getTimeInMillis()) - calSet.add(Calendar.DAY_OF_MONTH, -1); - - long differenceInSeconds = Math.abs(now.getTimeInMillis() - calSet.getTimeInMillis()) / 1000; - long nextExecutionMultiplier = Math.floorDiv(differenceInSeconds, tf.getRepetition()) + 1; - long nextScheduleTimestamp = (calSet.getTimeInMillis() / 1000) + (nextExecutionMultiplier * tf.getRepetition()); - Calendar calSchedule = Calendar.getInstance(); - calSchedule.setTimeInMillis(nextScheduleTimestamp * 1000); - - return calSchedule; - } - else - Miscellaneous.logEvent("i", "Trigger", "Trigger " + trigger.toString() + " is not executed repeatedly.", 5); - - return null; + return true; } boolean isSupposedToRepeatSinceLastExecution(Calendar now) @@ -1435,7 +1337,7 @@ public class Trigger // the simple stuff: - if(lastExec == null) // rule never run, go any way + if(lastExec == null) // rule never run, go in any case return true; else if(tf.getRepetition() <= 0) // is not set to repeat at all return false; @@ -1446,50 +1348,16 @@ public class Trigger * we're inside the specified timeframe. */ - Calendar timeSupposedToRunNext = getNextRepeatedExecutionAfter(this, lastExec); + Calendar timeSupposedToRunNext = DateTimeListener.getNextRepeatedExecutionAfter(this, lastExec); 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); + Miscellaneous.logEvent("i", "isSupposedToRepeatSinceLastExecution()", "Next execution would be: " + Miscellaneous.formatDate(timeSupposedToRunNext.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; } - - boolean triggerParameter; //if true->started event, if false->stopped - String triggerParameter2; - - public static final String triggerParameter2Split = "tp2split"; - - Trigger_Enum triggerType = null; - PointOfInterest pointOfInterest = null; - TimeFrame timeFrame; - - public static String triggerPhoneCallStateRinging = "ringing"; - public static String triggerPhoneCallStateStarted = "started"; - public static String triggerPhoneCallStateStopped = "stopped"; - public static String triggerPhoneCallDirectionIncoming = "incoming"; - public static String triggerPhoneCallDirectionOutgoing = "outgoing"; - public static String triggerPhoneCallDirectionAny = "any"; - public static String triggerPhoneCallNumberAny = "any"; - - double speed; //km/h - long noiseLevelDb; - String processName = null; - int batteryLevel; - int phoneDirection = 0; // 0=any, 1=incoming, 2=outgoing - String phoneNumber = null; - String nfcTagId = null; - String bluetoothEvent = null; - String bluetoothDeviceAddress = null; - int activityDetectionType = -1; - int headphoneType = -1; public int getHeadphoneType() { 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 7541b85..4610e12 100644 --- a/app/src/main/java/com/jens/automation2/receivers/DateTimeListener.java +++ b/app/src/main/java/com/jens/automation2/receivers/DateTimeListener.java @@ -8,10 +8,10 @@ import android.content.Intent; import android.os.Build; import android.util.Log; +import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import com.jens.automation2.AutomationService; -import com.jens.automation2.BuildConfig; import com.jens.automation2.Miscellaneous; import com.jens.automation2.Rule; import com.jens.automation2.TimeFrame; @@ -19,7 +19,6 @@ import com.jens.automation2.TimeObject; import com.jens.automation2.Trigger; import com.jens.automation2.Trigger.Trigger_Enum; -import java.sql.Time; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; @@ -60,11 +59,11 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis allRulesWithNowInTimeFrame.get(i).activate(automationServiceRef, false); } - setAlarms(); + setOrResetAlarms(); } @RequiresApi(api = Build.VERSION_CODES.KITKAT) - public static void setAlarms() + public static void setOrResetAlarms() { alarmCandidates.clear(); @@ -77,7 +76,7 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis ArrayList allRulesWithTimeFrames = new ArrayList(); allRulesWithTimeFrames = Rule.findRuleCandidates(Trigger_Enum.timeFrame); -// allRulesWithTimeFrames = Rule.findRuleCandidatesByTimeFrame(); + /* * Take care of regular executions, no repetitions in between. */ @@ -196,12 +195,12 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis if(tf.getRepetition() > 0) { - if(oneTrigger.applies(calNow, Miscellaneous.getAnyContext())) - { +// if(oneTrigger.applies(calNow, Miscellaneous.getAnyContext())) +// { Calendar calSchedule = getNextRepeatedExecutionAfter(oneTrigger, calNow); alarmCandidates.add(new ScheduleElement(calSchedule, "Rule " + oneRule.getName() + ", trigger " + oneTrigger.toString())); - } +// } } } } @@ -249,7 +248,10 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis else alarmPendingIntent = PendingIntent.getBroadcast(automationServiceRef, 0, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT); - centralAlarmManagerInstance.set(AlarmManager.RTC_WAKEUP, scheduleCandidate.time.getTimeInMillis(), alarmPendingIntent); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) + centralAlarmManagerInstance.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, scheduleCandidate.time.getTimeInMillis(), alarmPendingIntent); + else + centralAlarmManagerInstance.set(AlarmManager.RTC_WAKEUP, scheduleCandidate.time.getTimeInMillis(), alarmPendingIntent); SimpleDateFormat sdf = new SimpleDateFormat("E dd.MM.yyyy HH:mm:ss"); Calendar calendar = Calendar.getInstance(); @@ -260,14 +262,16 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis public static void clearAlarms() { Miscellaneous.logEvent("i", "AlarmManager", "Clearing possibly standing alarms.", 4); + for(int requestCode : requestCodeList) { 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(); } @@ -278,11 +282,10 @@ 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(); + DateTimeListener.setOrResetAlarms(); // // get a Calendar object with current time // Calendar cal = Calendar.getInstance(); @@ -306,10 +309,7 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis else Miscellaneous.logEvent("i", "AlarmListener", "Request to stop AlarmListener. But it's not running.", 5); } - public static void reloadAlarms() - { - DateTimeListener.setAlarms(); - } + @Override public void startListener(AutomationService automationService) { @@ -367,9 +367,11 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis } } + @Nullable @RequiresApi(api = Build.VERSION_CODES.N) - public static Calendar getNextRepeatedExecutionAfter(Trigger trigger, Calendar now) + public static Calendar getNextRepeatedExecutionAfter(Trigger trigger, Calendar repetitionSearchStartPoint) { +// Miscellaneous.logEvent("i", "DateTimeListener", "Checking for next repetition execution after " + Miscellaneous.formatDate(now.getTime()), 5); Calendar calculationStart; TimeObject setTime; TimeFrame tf = new TimeFrame(trigger.getTriggerParameter2()); @@ -378,36 +380,67 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis { 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(); + + if(areWeInTimeFrame(trigger, new Date()) != trigger.getTriggerParameter()) + { + if(trigger.getTriggerParameter()) + { + calculationStart = (Calendar) repetitionSearchStartPoint.clone(); + calculationStart.set(Calendar.HOUR_OF_DAY, tf.getTriggerTimeStart().getHours()); + calculationStart.set(Calendar.MINUTE, tf.getTriggerTimeStart().getMinutes()); + calculationStart.set(Calendar.SECOND, tf.getTriggerTimeStart().getSeconds()); + calculationStart.set(Calendar.MILLISECOND, 0); + calculationStart.add(Calendar.SECOND, (int) tf.getRepetition()); + + if(calculationStart.getTimeInMillis() < repetitionSearchStartPoint.getTimeInMillis() && !areWeInTimeFrame(trigger, new Date())) + calculationStart.add(Calendar.DAY_OF_MONTH, 1); + } + else + { + calculationStart = (Calendar) repetitionSearchStartPoint.clone(); + calculationStart.set(Calendar.HOUR_OF_DAY, tf.getTriggerTimeStop().getHours()); + calculationStart.set(Calendar.MINUTE, tf.getTriggerTimeStop().getMinutes()); + calculationStart.set(Calendar.SECOND, tf.getTriggerTimeStop().getSeconds()); + calculationStart.set(Calendar.MILLISECOND, 0); + calculationStart.add(Calendar.SECOND, (int) tf.getRepetition()); + + if(calculationStart.getTimeInMillis() < repetitionSearchStartPoint.getTimeInMillis() && !areWeInTimeFrame(trigger, new Date())) + calculationStart.add(Calendar.DAY_OF_MONTH, 1); + } + } } else { if(trigger.getTriggerParameter()) { - Miscellaneous.logEvent("i", "DateTimeListener", "Chose start of next interval of trigger in rule " + trigger.getParentRule().getName() + " as calculation start.", 5); +// 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); +// Miscellaneous.logEvent("i", "DateTimeListener", "Chose end of next interval of trigger in rule " + trigger.getParentRule().getName() + " as calculation start.", 5); setTime = tf.getTriggerTimeStop(); } - calculationStart = (Calendar) now.clone(); + calculationStart = (Calendar) repetitionSearchStartPoint.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); + calculationStart.set(Calendar.SECOND, setTime.getSeconds()); + + if(calculationStart.getTimeInMillis() < repetitionSearchStartPoint.getTimeInMillis() && areWeInTimeFrame(trigger, new Date())) + calculationStart.add(Calendar.DAY_OF_MONTH, 1); } + calculationStart.set(Calendar.MILLISECOND, 0); - // If the starting time is a day ahead remove 1 day. - if(calculationStart.getTimeInMillis() > now.getTimeInMillis()) - calculationStart.add(Calendar.DAY_OF_MONTH, -1); + Miscellaneous.logEvent("i", "getNextRepeatedExecutionAfter()", "calcStart: " + Miscellaneous.formatDate(calculationStart.getTime()) + ", now: " + Miscellaneous.formatDate(repetitionSearchStartPoint.getTime()), 5); - Miscellaneous.logEvent("i", "getNextRepeatedExecutionAfter()", "Chose " + Miscellaneous.formatDate(calculationStart.getTime()) + " as calculation start.", 5); +// Miscellaneous.logEvent("i", "getNextRepeatedExecutionAfter()", "Chose " + Miscellaneous.formatDate(calculationStart.getTime()) + " as calculation start.", 5); - long differenceInSeconds = Math.abs(now.getTimeInMillis() - calculationStart.getTimeInMillis()) / 1000; + + Miscellaneous.logEvent("i", "getNextRepeatedExecutionAfter()", "calcStartAfterDayAdd " + Miscellaneous.formatDate(calculationStart.getTime()) + " as calculation start.", 5); + + long differenceInSeconds = Math.abs(repetitionSearchStartPoint.getTimeInMillis() - calculationStart.getTimeInMillis()) / 1000; long nextExecutionMultiplier = Math.floorDiv(differenceInSeconds, tf.getRepetition()) + 1; long nextScheduleTimestamp = (calculationStart.getTimeInMillis() / 1000) + (nextExecutionMultiplier * tf.getRepetition()); Calendar calSchedule = Calendar.getInstance(); @@ -418,8 +451,66 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis return calSchedule; } else - Miscellaneous.logEvent("i", "getNextRepeatedExecutionAfter()", "Trigger " + trigger.toString() + " is not executed repeatedly.", 5); + Miscellaneous.logEvent("i", "getNextRepeatedExecutionAfter()", "Trigger " + trigger.toString() + " is not configured to repeat.", 5); return null; } + + public static boolean areWeInTimeFrame(Trigger trigger, Object triggeringObject) + { + /* + * Use format known from Automation + * 07:30:00/17:30:00/23456/300 <-- last parameter is optional: repetition in seconds + * Also required: inside or outside that interval + */ + + Date triggeringTime; +// if(triggeringObject instanceof Date) +// triggeringTime = (Date)triggeringObject; +// else + triggeringTime = new Date(); + + String timeString = String.valueOf(triggeringTime.getHours()) + ":" + String.valueOf(triggeringTime.getMinutes()) + ":" + String.valueOf(triggeringTime.getSeconds()); + TimeObject nowTime = TimeObject.valueOf(timeString); + Calendar calNow = Calendar.getInstance(); + + try + { + TimeFrame tf = new TimeFrame(trigger.getTriggerParameter2()); + + if(tf.getDayList().contains(calNow.get(Calendar.DAY_OF_WEEK))) + { + if( + // Regular case, start time is lower than end time + ( + Miscellaneous.compareTimes(tf.getTriggerTimeStart(), nowTime) >= 0 + && + Miscellaneous.compareTimes(nowTime, tf.getTriggerTimeStop()) > 0 + ) + || + // Other case, start time higher than end time, timeframe goes over midnight + ( + Miscellaneous.compareTimes(tf.getTriggerTimeStart(), tf.getTriggerTimeStop()) < 0 + && + (Miscellaneous.compareTimes(tf.getTriggerTimeStart(), nowTime) >= 0 + || + Miscellaneous.compareTimes(nowTime, tf.getTriggerTimeStop()) > 0) + ) + || + // further case: start and end times are identical, meaning a 24h window + ( + Miscellaneous.compareTimes(tf.getTriggerTimeStart(), tf.getTriggerTimeStop()) == 0 + ) + ) + return true; + } + } + catch(Exception e) + { + Miscellaneous.logEvent("e", "Trigger", "There was an error while checking if the time based trigger applies: " + Log.getStackTraceString(e), 1); + return false; + } + + return false; + } } \ No newline at end of file diff --git a/app/src/main/java/com/jens/automation2/receivers/TimeZoneListener.java b/app/src/main/java/com/jens/automation2/receivers/TimeZoneListener.java index 4d55a9d..3e5ea9b 100644 --- a/app/src/main/java/com/jens/automation2/receivers/TimeZoneListener.java +++ b/app/src/main/java/com/jens/automation2/receivers/TimeZoneListener.java @@ -76,12 +76,12 @@ public class TimeZoneListener extends BroadcastReceiver implements AutomationLis if(action.equals(Intent.ACTION_TIMEZONE_CHANGED)) { Miscellaneous.logEvent("i", "TimeZoneListener", "Device timezone changed. Reloading alarms.", 3); - DateTimeListener.reloadAlarms(); + DateTimeListener.setOrResetAlarms(); } else if(action.equals(Intent.ACTION_TIME_CHANGED)) { Miscellaneous.logEvent("i", "TimeZoneListener", "Device time changed. Reloading alarms.", 3); - DateTimeListener.reloadAlarms(); + DateTimeListener.setOrResetAlarms(); } } @Override