date time repetition
This commit is contained in:
parent
31d167a93f
commit
62bfbbb064
@ -320,7 +320,7 @@ public class AutomationService extends Service implements OnInitListener
|
|||||||
|
|
||||||
ReceiverCoordinator.applySettingsAndRules();
|
ReceiverCoordinator.applySettingsAndRules();
|
||||||
|
|
||||||
DateTimeListener.reloadAlarms();
|
DateTimeListener.setOrResetAlarms();
|
||||||
CalendarReceiver.armOrRearmTimer();
|
CalendarReceiver.armOrRearmTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ import com.jens.automation2.receivers.BluetoothReceiver;
|
|||||||
import com.jens.automation2.receivers.BroadcastListener;
|
import com.jens.automation2.receivers.BroadcastListener;
|
||||||
import com.jens.automation2.receivers.CalendarReceiver;
|
import com.jens.automation2.receivers.CalendarReceiver;
|
||||||
import com.jens.automation2.receivers.ConnectivityReceiver;
|
import com.jens.automation2.receivers.ConnectivityReceiver;
|
||||||
|
import com.jens.automation2.receivers.DateTimeListener;
|
||||||
import com.jens.automation2.receivers.DeviceOrientationListener;
|
import com.jens.automation2.receivers.DeviceOrientationListener;
|
||||||
import com.jens.automation2.receivers.HeadphoneJackListener;
|
import com.jens.automation2.receivers.HeadphoneJackListener;
|
||||||
import com.jens.automation2.receivers.MediaPlayerListener;
|
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 };
|
public static enum subSystemStates { wifi, bluetooth };
|
||||||
|
|
||||||
Rule parentRule = null;
|
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.
|
// 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(this.getPointOfInterest() != null)
|
||||||
{
|
{
|
||||||
// if(activePoi.equals(oneTrigger.getPointOfInterest()))
|
|
||||||
// {
|
|
||||||
if(!this.getTriggerParameter())
|
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);
|
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);
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
else if(this.getPointOfInterest() == null)
|
else if(this.getPointOfInterest() == null)
|
||||||
{
|
{
|
||||||
@ -1224,7 +1251,7 @@ public class Trigger
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean checkDateTime(Object triggeringObject, boolean checkifStateChangedSinceLastRuleExecution)
|
public boolean checkDateTime(Object triggeringObject, boolean checkIfStateChangedSinceLastRuleExecution)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Use format known from Automation
|
* Use format known from Automation
|
||||||
@ -1246,52 +1273,31 @@ public class Trigger
|
|||||||
{
|
{
|
||||||
TimeFrame tf = new TimeFrame(getTriggerParameter2());
|
TimeFrame tf = new TimeFrame(getTriggerParameter2());
|
||||||
|
|
||||||
if(tf.getDayList().contains(calNow.get(Calendar.DAY_OF_WEEK)))
|
if (DateTimeListener.areWeInTimeFrame(this, triggeringObject) != this.getTriggerParameter())
|
||||||
{
|
{
|
||||||
if(
|
if (triggerParameter)
|
||||||
// Regular case, start time is lower than end time
|
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.compareTimes(tf.getTriggerTimeStart(), nowTime) >= 0
|
Miscellaneous.logEvent("i", "Trigger", "TimeFrame: We're currently (" + calNow.getTime().toString() + ") in the specified TimeFrame (" + tf.toString() + "), but demanded is outside.", 4);
|
||||||
&&
|
|
||||||
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
|
|
||||||
)
|
|
||||||
)
|
|
||||||
{
|
|
||||||
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We are inside or outside of the timeframe as demanded by the trigger
|
||||||
|
|
||||||
|
if (tf.getRepetition() > 0)
|
||||||
|
{
|
||||||
|
if (!isSupposedToRepeatSinceLastExecution(Calendar.getInstance()))
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "TimeFrame", "TimeFrame: Trigger of rule " + this.getParentRule().getName() + " applies, but repetition is not due, yet.", 4);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
Miscellaneous.logEvent("i", "TimeFrame", "TimeFrame: Trigger of rule " + this.getParentRule().getName() + " would apply because repetition is due.", 4);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (checkIfStateChangedSinceLastRuleExecution)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* This is not a repeating rule. Have we left
|
* This is not a repeating rule. Have we left
|
||||||
@ -1314,118 +1320,14 @@ public class Trigger
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
catch(Exception e)
|
||||||
{
|
{
|
||||||
Miscellaneous.logEvent("e", "Trigger", "There was an error while checking if the time based trigger applies: " + Log.getStackTraceString(e), 1);
|
Miscellaneous.logEvent("e", "Trigger", "There was an error while checking if the time based trigger applies: " + Log.getStackTraceString(e), 1);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public static Calendar getNextRepeatedExecutionAfter(Trigger trigger, Calendar now)
|
return true;
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isSupposedToRepeatSinceLastExecution(Calendar now)
|
boolean isSupposedToRepeatSinceLastExecution(Calendar now)
|
||||||
@ -1435,7 +1337,7 @@ public class Trigger
|
|||||||
|
|
||||||
// the simple stuff:
|
// the simple stuff:
|
||||||
|
|
||||||
if(lastExec == null) // rule never run, go any way
|
if(lastExec == null) // rule never run, go in any case
|
||||||
return true;
|
return true;
|
||||||
else if(tf.getRepetition() <= 0) // is not set to repeat at all
|
else if(tf.getRepetition() <= 0) // is not set to repeat at all
|
||||||
return false;
|
return false;
|
||||||
@ -1446,51 +1348,17 @@ public class Trigger
|
|||||||
* we're inside the specified timeframe.
|
* 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()", "Last execution: " + Miscellaneous.formatDate(lastExec.getTime()), 5);
|
||||||
Miscellaneous.logEvent("i", "isSupposedToRepeatSinceLastExecution()", "Next execution: " + Miscellaneous.formatDate(timeSupposedToRunNext.getTime()), 5);
|
Miscellaneous.logEvent("i", "isSupposedToRepeatSinceLastExecution()", "Next execution would be: " + Miscellaneous.formatDate(timeSupposedToRunNext.getTime()), 5);
|
||||||
Miscellaneous.logEvent("i", "isSupposedToRepeatSinceLastExecution()", "Now: " + Miscellaneous.formatDate(now.getTime()), 5);
|
|
||||||
|
|
||||||
if(now.getTimeInMillis() > timeSupposedToRunNext.getTimeInMillis())
|
if(now.getTimeInMillis() > timeSupposedToRunNext.getTimeInMillis())
|
||||||
{
|
|
||||||
Miscellaneous.logEvent("i", "isSupposedToRepeatSinceLastExecution()", "Repetition due.", 5);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
Miscellaneous.logEvent("i", "isSupposedToRepeatSinceLastExecution()", "Repetition not due.", 5);
|
|
||||||
return false;
|
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()
|
public int getHeadphoneType()
|
||||||
{
|
{
|
||||||
return headphoneType;
|
return headphoneType;
|
||||||
|
@ -8,10 +8,10 @@ import android.content.Intent;
|
|||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.RequiresApi;
|
import androidx.annotation.RequiresApi;
|
||||||
|
|
||||||
import com.jens.automation2.AutomationService;
|
import com.jens.automation2.AutomationService;
|
||||||
import com.jens.automation2.BuildConfig;
|
|
||||||
import com.jens.automation2.Miscellaneous;
|
import com.jens.automation2.Miscellaneous;
|
||||||
import com.jens.automation2.Rule;
|
import com.jens.automation2.Rule;
|
||||||
import com.jens.automation2.TimeFrame;
|
import com.jens.automation2.TimeFrame;
|
||||||
@ -19,7 +19,6 @@ import com.jens.automation2.TimeObject;
|
|||||||
import com.jens.automation2.Trigger;
|
import com.jens.automation2.Trigger;
|
||||||
import com.jens.automation2.Trigger.Trigger_Enum;
|
import com.jens.automation2.Trigger.Trigger_Enum;
|
||||||
|
|
||||||
import java.sql.Time;
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
@ -60,11 +59,11 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis
|
|||||||
allRulesWithNowInTimeFrame.get(i).activate(automationServiceRef, false);
|
allRulesWithNowInTimeFrame.get(i).activate(automationServiceRef, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
setAlarms();
|
setOrResetAlarms();
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
||||||
public static void setAlarms()
|
public static void setOrResetAlarms()
|
||||||
{
|
{
|
||||||
alarmCandidates.clear();
|
alarmCandidates.clear();
|
||||||
|
|
||||||
@ -77,7 +76,7 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis
|
|||||||
|
|
||||||
ArrayList<Rule> allRulesWithTimeFrames = new ArrayList<Rule>();
|
ArrayList<Rule> allRulesWithTimeFrames = new ArrayList<Rule>();
|
||||||
allRulesWithTimeFrames = Rule.findRuleCandidates(Trigger_Enum.timeFrame);
|
allRulesWithTimeFrames = Rule.findRuleCandidates(Trigger_Enum.timeFrame);
|
||||||
// allRulesWithTimeFrames = Rule.findRuleCandidatesByTimeFrame();
|
|
||||||
/*
|
/*
|
||||||
* Take care of regular executions, no repetitions in between.
|
* 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(tf.getRepetition() > 0)
|
||||||
{
|
{
|
||||||
if(oneTrigger.applies(calNow, Miscellaneous.getAnyContext()))
|
// if(oneTrigger.applies(calNow, Miscellaneous.getAnyContext()))
|
||||||
{
|
// {
|
||||||
Calendar calSchedule = getNextRepeatedExecutionAfter(oneTrigger, calNow);
|
Calendar calSchedule = getNextRepeatedExecutionAfter(oneTrigger, calNow);
|
||||||
|
|
||||||
alarmCandidates.add(new ScheduleElement(calSchedule, "Rule " + oneRule.getName() + ", trigger " + oneTrigger.toString()));
|
alarmCandidates.add(new ScheduleElement(calSchedule, "Rule " + oneRule.getName() + ", trigger " + oneTrigger.toString()));
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -249,6 +248,9 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis
|
|||||||
else
|
else
|
||||||
alarmPendingIntent = PendingIntent.getBroadcast(automationServiceRef, 0, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
|
alarmPendingIntent = PendingIntent.getBroadcast(automationServiceRef, 0, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||||
|
|
||||||
|
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);
|
centralAlarmManagerInstance.set(AlarmManager.RTC_WAKEUP, scheduleCandidate.time.getTimeInMillis(), alarmPendingIntent);
|
||||||
|
|
||||||
SimpleDateFormat sdf = new SimpleDateFormat("E dd.MM.yyyy HH:mm:ss");
|
SimpleDateFormat sdf = new SimpleDateFormat("E dd.MM.yyyy HH:mm:ss");
|
||||||
@ -260,14 +262,16 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis
|
|||||||
public static void clearAlarms()
|
public static void clearAlarms()
|
||||||
{
|
{
|
||||||
Miscellaneous.logEvent("i", "AlarmManager", "Clearing possibly standing alarms.", 4);
|
Miscellaneous.logEvent("i", "AlarmManager", "Clearing possibly standing alarms.", 4);
|
||||||
|
|
||||||
for(int requestCode : requestCodeList)
|
for(int requestCode : requestCodeList)
|
||||||
{
|
{
|
||||||
Intent alarmIntent = new Intent(automationServiceRef, DateTimeListener.class);
|
Intent alarmIntent = new Intent(automationServiceRef, DateTimeListener.class);
|
||||||
if(alarmPendingIntent == null)
|
if(alarmPendingIntent == null)
|
||||||
alarmPendingIntent = PendingIntent.getBroadcast(automationServiceRef, requestCode, alarmIntent, 0);
|
alarmPendingIntent = PendingIntent.getBroadcast(automationServiceRef, requestCode, alarmIntent, 0);
|
||||||
// Miscellaneous.logEvent("i", "AlarmManager", "Clearing alarm with request code: " + String.valueOf(requestCode));
|
|
||||||
centralAlarmManagerInstance.cancel(alarmPendingIntent);
|
centralAlarmManagerInstance.cancel(alarmPendingIntent);
|
||||||
}
|
}
|
||||||
|
|
||||||
requestCodeList.clear();
|
requestCodeList.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,11 +282,10 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis
|
|||||||
Miscellaneous.logEvent("i", "AlarmListener", "Starting alarm listener.", 4);
|
Miscellaneous.logEvent("i", "AlarmListener", "Starting alarm listener.", 4);
|
||||||
DateTimeListener.automationServiceRef = givenAutomationServiceRef;
|
DateTimeListener.automationServiceRef = givenAutomationServiceRef;
|
||||||
centralAlarmManagerInstance = (AlarmManager)automationServiceRef.getSystemService(automationServiceRef.ALARM_SERVICE);
|
centralAlarmManagerInstance = (AlarmManager)automationServiceRef.getSystemService(automationServiceRef.ALARM_SERVICE);
|
||||||
// alarmIntent = new Intent(automationServiceRef, AlarmListener.class);
|
|
||||||
// alarmPendingIntent = PendingIntent.getBroadcast(automationServiceRef, 0, alarmIntent, 0);
|
|
||||||
alarmListenerActive = true;
|
alarmListenerActive = true;
|
||||||
Miscellaneous.logEvent("i", "AlarmListener", "Alarm listener started.", 4);
|
Miscellaneous.logEvent("i", "AlarmListener", "Alarm listener started.", 4);
|
||||||
DateTimeListener.setAlarms();
|
DateTimeListener.setOrResetAlarms();
|
||||||
|
|
||||||
// // get a Calendar object with current time
|
// // get a Calendar object with current time
|
||||||
// Calendar cal = Calendar.getInstance();
|
// Calendar cal = Calendar.getInstance();
|
||||||
@ -306,10 +309,7 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis
|
|||||||
else
|
else
|
||||||
Miscellaneous.logEvent("i", "AlarmListener", "Request to stop AlarmListener. But it's not running.", 5);
|
Miscellaneous.logEvent("i", "AlarmListener", "Request to stop AlarmListener. But it's not running.", 5);
|
||||||
}
|
}
|
||||||
public static void reloadAlarms()
|
|
||||||
{
|
|
||||||
DateTimeListener.setAlarms();
|
|
||||||
}
|
|
||||||
@Override
|
@Override
|
||||||
public void startListener(AutomationService automationService)
|
public void startListener(AutomationService automationService)
|
||||||
{
|
{
|
||||||
@ -367,9 +367,11 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
@RequiresApi(api = Build.VERSION_CODES.N)
|
@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;
|
Calendar calculationStart;
|
||||||
TimeObject setTime;
|
TimeObject setTime;
|
||||||
TimeFrame tf = new TimeFrame(trigger.getTriggerParameter2());
|
TimeFrame tf = new TimeFrame(trigger.getTriggerParameter2());
|
||||||
@ -378,36 +380,67 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis
|
|||||||
{
|
{
|
||||||
if(trigger.getParentRule().getLastExecution() != null)
|
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();
|
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
|
else
|
||||||
{
|
{
|
||||||
if(trigger.getTriggerParameter())
|
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();
|
setTime = tf.getTriggerTimeStart();
|
||||||
}
|
}
|
||||||
else
|
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();
|
setTime = tf.getTriggerTimeStop();
|
||||||
}
|
}
|
||||||
|
|
||||||
calculationStart = (Calendar) now.clone();
|
calculationStart = (Calendar) repetitionSearchStartPoint.clone();
|
||||||
calculationStart.set(Calendar.HOUR_OF_DAY, setTime.getHours());
|
calculationStart.set(Calendar.HOUR_OF_DAY, setTime.getHours());
|
||||||
calculationStart.set(Calendar.MINUTE, setTime.getMinutes());
|
calculationStart.set(Calendar.MINUTE, setTime.getMinutes());
|
||||||
calculationStart.set(Calendar.SECOND, 0);
|
calculationStart.set(Calendar.SECOND, setTime.getSeconds());
|
||||||
// calculationStart.set(Calendar.MILLISECOND, 0);
|
|
||||||
|
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.
|
Miscellaneous.logEvent("i", "getNextRepeatedExecutionAfter()", "calcStart: " + Miscellaneous.formatDate(calculationStart.getTime()) + ", now: " + Miscellaneous.formatDate(repetitionSearchStartPoint.getTime()), 5);
|
||||||
if(calculationStart.getTimeInMillis() > now.getTimeInMillis())
|
|
||||||
calculationStart.add(Calendar.DAY_OF_MONTH, -1);
|
|
||||||
|
|
||||||
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 nextExecutionMultiplier = Math.floorDiv(differenceInSeconds, tf.getRepetition()) + 1;
|
||||||
long nextScheduleTimestamp = (calculationStart.getTimeInMillis() / 1000) + (nextExecutionMultiplier * tf.getRepetition());
|
long nextScheduleTimestamp = (calculationStart.getTimeInMillis() / 1000) + (nextExecutionMultiplier * tf.getRepetition());
|
||||||
Calendar calSchedule = Calendar.getInstance();
|
Calendar calSchedule = Calendar.getInstance();
|
||||||
@ -418,8 +451,66 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis
|
|||||||
return calSchedule;
|
return calSchedule;
|
||||||
}
|
}
|
||||||
else
|
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;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
@ -76,12 +76,12 @@ public class TimeZoneListener extends BroadcastReceiver implements AutomationLis
|
|||||||
if(action.equals(Intent.ACTION_TIMEZONE_CHANGED))
|
if(action.equals(Intent.ACTION_TIMEZONE_CHANGED))
|
||||||
{
|
{
|
||||||
Miscellaneous.logEvent("i", "TimeZoneListener", "Device timezone changed. Reloading alarms.", 3);
|
Miscellaneous.logEvent("i", "TimeZoneListener", "Device timezone changed. Reloading alarms.", 3);
|
||||||
DateTimeListener.reloadAlarms();
|
DateTimeListener.setOrResetAlarms();
|
||||||
}
|
}
|
||||||
else if(action.equals(Intent.ACTION_TIME_CHANGED))
|
else if(action.equals(Intent.ACTION_TIME_CHANGED))
|
||||||
{
|
{
|
||||||
Miscellaneous.logEvent("i", "TimeZoneListener", "Device time changed. Reloading alarms.", 3);
|
Miscellaneous.logEvent("i", "TimeZoneListener", "Device time changed. Reloading alarms.", 3);
|
||||||
DateTimeListener.reloadAlarms();
|
DateTimeListener.setOrResetAlarms();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
|
Loading…
Reference in New Issue
Block a user