Compare commits
15 Commits
5ca7295c30
...
9f36411511
Author | SHA1 | Date | |
---|---|---|---|
9f36411511 | |||
eb893a7f21 | |||
8788a89e48 | |||
bb10620883 | |||
3e29054f82 | |||
9d5f0a3cef | |||
695b1f2481 | |||
d7357b0b0f | |||
e272338cc6 | |||
3dd84220a3 | |||
4bc2781ee7 | |||
62bfbbb064 | |||
31d167a93f | |||
500610fb98 | |||
6e73c74b60 |
@ -11,8 +11,8 @@ android {
|
|||||||
compileSdkVersion 33
|
compileSdkVersion 33
|
||||||
buildToolsVersion '29.0.2'
|
buildToolsVersion '29.0.2'
|
||||||
useLibrary 'org.apache.http.legacy'
|
useLibrary 'org.apache.http.legacy'
|
||||||
versionCode 138
|
versionCode 142
|
||||||
versionName "1.8"
|
versionName "1.8.1"
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,6 @@
|
|||||||
<uses-permission android:name="com.wireguard.android.permission.CONTROL_TUNNELS"/>
|
<uses-permission android:name="com.wireguard.android.permission.CONTROL_TUNNELS"/>
|
||||||
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
|
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
|
||||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||||
<uses-permission android:name="android.permission.READ_CALENDAR" />
|
|
||||||
<uses-permission
|
<uses-permission
|
||||||
android:name="android.permission.WRITE_SECURE_SETTINGS"
|
android:name="android.permission.WRITE_SECURE_SETTINGS"
|
||||||
tools:ignore="ProtectedPermissions" />
|
tools:ignore="ProtectedPermissions" />
|
||||||
@ -258,18 +257,6 @@
|
|||||||
android:exported="true"
|
android:exported="true"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<service android:name=".MyAccessibilityService"
|
|
||||||
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
|
|
||||||
android:exported="true">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.accessibilityservice.AccessibilityService" />
|
|
||||||
</intent-filter>
|
|
||||||
|
|
||||||
<meta-data
|
|
||||||
android:name="android.accessibilityservice"
|
|
||||||
android:resource="@xml/config_accessibility_service" />
|
|
||||||
</service>
|
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
@ -1107,7 +1107,13 @@ public class Actions
|
|||||||
externalApplicationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
externalApplicationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
|
||||||
// Pack intents
|
// Pack intents
|
||||||
externalApplicationIntent = packParametersIntoIntent(externalApplicationIntent, params, 3);
|
if(params.length >= 4)
|
||||||
|
{
|
||||||
|
if(Miscellaneous.isNumeric(params[3]))
|
||||||
|
externalApplicationIntent = packParametersIntoIntent(externalApplicationIntent, params, 4);
|
||||||
|
else
|
||||||
|
externalApplicationIntent = packParametersIntoIntent(externalApplicationIntent, params, 3);
|
||||||
|
}
|
||||||
|
|
||||||
if (params[2].equals(ActivityManageActionStartActivity.startByActivityString))
|
if (params[2].equals(ActivityManageActionStartActivity.startByActivityString))
|
||||||
automationServerRef.startActivity(externalApplicationIntent);
|
automationServerRef.startActivity(externalApplicationIntent);
|
||||||
@ -2353,7 +2359,8 @@ public class Actions
|
|||||||
{
|
{
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
|
||||||
{
|
{
|
||||||
MyAccessibilityService.getInstance().performGlobalAction(AccessibilityService.GLOBAL_ACTION_TAKE_SCREENSHOT);
|
if(!BuildConfig.FLAVOR.equals(AutomationService.flavor_name_googleplay))
|
||||||
|
MyAccessibilityService.getInstance().performGlobalAction(AccessibilityService.GLOBAL_ACTION_TAKE_SCREENSHOT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -622,7 +622,7 @@ public class ActivityManageRule extends Activity
|
|||||||
items.add(new Item(typesLong[i].toString(), R.drawable.megaphone));
|
items.add(new Item(typesLong[i].toString(), R.drawable.megaphone));
|
||||||
else if(types[i].toString().equals(Trigger_Enum.phoneCall.toString()))
|
else if(types[i].toString().equals(Trigger_Enum.phoneCall.toString()))
|
||||||
{
|
{
|
||||||
if(ActivityPermissions.isPermissionDeclaratedInManifest(ActivityManageRule.this, "android.permission.SEND_SMS"))
|
if(ActivityPermissions.isPermissionDeclaratedInManifest(ActivityManageRule.this, Manifest.permission.SEND_SMS))
|
||||||
items.add(new Item(typesLong[i].toString(), R.drawable.phone));
|
items.add(new Item(typesLong[i].toString(), R.drawable.phone));
|
||||||
}
|
}
|
||||||
else if(types[i].toString().equals(Trigger_Enum.nfcTag.toString()))
|
else if(types[i].toString().equals(Trigger_Enum.nfcTag.toString()))
|
||||||
@ -654,7 +654,10 @@ public class ActivityManageRule extends Activity
|
|||||||
else if(types[i].toString().equals(Trigger_Enum.checkVariable.toString()))
|
else if(types[i].toString().equals(Trigger_Enum.checkVariable.toString()))
|
||||||
items.add(new Item(typesLong[i].toString(), R.drawable.variable));
|
items.add(new Item(typesLong[i].toString(), R.drawable.variable));
|
||||||
else if(types[i].toString().equals(Trigger_Enum.calendarEvent.toString()))
|
else if(types[i].toString().equals(Trigger_Enum.calendarEvent.toString()))
|
||||||
items.add(new Item(typesLong[i].toString(), R.drawable.calendar));
|
{
|
||||||
|
if(ActivityPermissions.isPermissionDeclaratedInManifest(ActivityManageRule.this, Manifest.permission.READ_CALENDAR))
|
||||||
|
items.add(new Item(typesLong[i].toString(), R.drawable.calendar));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
items.add(new Item(typesLong[i].toString(), R.drawable.placeholder));
|
items.add(new Item(typesLong[i].toString(), R.drawable.placeholder));
|
||||||
}
|
}
|
||||||
@ -2250,12 +2253,15 @@ public class ActivityManageRule extends Activity
|
|||||||
}
|
}
|
||||||
else if(types[i].toString().equals(Action_Enum.copyToClipboard.toString()))
|
else if(types[i].toString().equals(Action_Enum.copyToClipboard.toString()))
|
||||||
items.add(new Item(typesLong[i].toString(), R.drawable.clipboard));
|
items.add(new Item(typesLong[i].toString(), R.drawable.clipboard));
|
||||||
else if(types[i].toString().equals(Action_Enum.takeScreenshot.toString()))
|
|
||||||
items.add(new Item(typesLong[i].toString(), R.drawable.copier));
|
|
||||||
else if(types[i].toString().equals(Action_Enum.setVariable.toString()))
|
else if(types[i].toString().equals(Action_Enum.setVariable.toString()))
|
||||||
items.add(new Item(typesLong[i].toString(), R.drawable.variable));
|
items.add(new Item(typesLong[i].toString(), R.drawable.variable));
|
||||||
else if(types[i].toString().equals(Action_Enum.setLocationService.toString()))
|
else if(types[i].toString().equals(Action_Enum.setLocationService.toString()))
|
||||||
items.add(new Item(typesLong[i].toString(), R.drawable.compass_small));
|
items.add(new Item(typesLong[i].toString(), R.drawable.compass_small));
|
||||||
|
else if(types[i].toString().equals(Action_Enum.takeScreenshot.toString()))
|
||||||
|
{
|
||||||
|
if(ActivityPermissions.isPermissionDeclaratedInManifest(ActivityManageRule.this, Manifest.permission.BIND_ACCESSIBILITY_SERVICE))
|
||||||
|
items.add(new Item(typesLong[i].toString(), R.drawable.copier));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
items.add(new Item(typesLong[i].toString(), R.drawable.placeholder));
|
items.add(new Item(typesLong[i].toString(), R.drawable.placeholder));
|
||||||
}
|
}
|
||||||
|
@ -320,8 +320,10 @@ public class AutomationService extends Service implements OnInitListener
|
|||||||
|
|
||||||
ReceiverCoordinator.applySettingsAndRules();
|
ReceiverCoordinator.applySettingsAndRules();
|
||||||
|
|
||||||
DateTimeListener.reloadAlarms();
|
DateTimeListener.setOrResetAlarms();
|
||||||
CalendarReceiver.armOrRearmTimer();
|
|
||||||
|
if(Rule.isAnyRuleUsing(Trigger.Trigger_Enum.calendarEvent) && ActivityPermissions.isPermissionDeclaratedInManifest(AutomationService.getInstance(), Manifest.permission.READ_CALENDAR) && ActivityPermissions.havePermission(Manifest.permission.READ_CALENDAR, AutomationService.getInstance()))
|
||||||
|
CalendarReceiver.armOrRearmTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -585,7 +585,45 @@ public class Miscellaneous extends Service
|
|||||||
|
|
||||||
Miscellaneous.logEvent("i", "TimeCompare", "Default return code. Shouldn't be here.", 5);
|
Miscellaneous.logEvent("i", "TimeCompare", "Default return code. Shouldn't be here.", 5);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int compareTimes(Calendar calOne, Calendar calTwo)
|
||||||
|
{
|
||||||
|
if(calOne.get(Calendar.HOUR_OF_DAY) == calTwo.get(Calendar.HOUR_OF_DAY) && calOne.get(Calendar.MINUTE) == calTwo.get((Calendar.MINUTE)))
|
||||||
|
{
|
||||||
|
// Miscellaneous.logEvent("i", "TimeCompare", "Times are equal.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(calOne.get(Calendar.HOUR_OF_DAY) > calTwo.get(Calendar.HOUR_OF_DAY))
|
||||||
|
{
|
||||||
|
// Miscellaneous.logEvent("i", "TimeCompare", "Time1 is bigger/later by hours.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(calOne.get(Calendar.HOUR_OF_DAY) < calTwo.get(Calendar.HOUR_OF_DAY))
|
||||||
|
{
|
||||||
|
// Miscellaneous.logEvent("i", "TimeCompare", "Time2 is bigger/later by hours.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(calOne.get(Calendar.HOUR_OF_DAY) == calTwo.get(Calendar.HOUR_OF_DAY))
|
||||||
|
{
|
||||||
|
if(calOne.get(Calendar.MINUTE) < calTwo.get(Calendar.MINUTE))
|
||||||
|
{
|
||||||
|
// Miscellaneous.logEvent("i", "TimeCompare", "Hours are equal. Time2 is bigger/later by minutes.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(calOne.get(Calendar.MINUTE) > calTwo.get(Calendar.MINUTE))
|
||||||
|
{
|
||||||
|
// Miscellaneous.logEvent("i", "TimeCompare", "Hours are equal. Time1 is bigger/later by minutes.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Miscellaneous.logEvent("i", "TimeCompare", "Default return code. Shouldn't be here.", 5);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String convertStreamToString(InputStream is)
|
public static String convertStreamToString(InputStream is)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.jens.automation2;
|
package com.jens.automation2;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
@ -212,7 +213,7 @@ public class ReceiverCoordinator
|
|||||||
if(Rule.isAnyRuleUsing(Trigger.Trigger_Enum.screenState))
|
if(Rule.isAnyRuleUsing(Trigger.Trigger_Enum.screenState))
|
||||||
ScreenStateReceiver.startScreenStateReceiver(AutomationService.getInstance());
|
ScreenStateReceiver.startScreenStateReceiver(AutomationService.getInstance());
|
||||||
|
|
||||||
if(Rule.isAnyRuleUsing(Trigger.Trigger_Enum.calendarEvent))
|
if(Rule.isAnyRuleUsing(Trigger.Trigger_Enum.calendarEvent) && ActivityPermissions.isPermissionDeclaratedInManifest(AutomationService.getInstance(), Manifest.permission.READ_CALENDAR) && ActivityPermissions.havePermission(Manifest.permission.READ_CALENDAR, AutomationService.getInstance()))
|
||||||
CalendarReceiver.startCalendarReceiver(AutomationService.getInstance());
|
CalendarReceiver.startCalendarReceiver(AutomationService.getInstance());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -469,7 +470,7 @@ public class ReceiverCoordinator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Rule.isAnyRuleUsing(Trigger.Trigger_Enum.calendarEvent))
|
if(Rule.isAnyRuleUsing(Trigger.Trigger_Enum.calendarEvent) && ActivityPermissions.isPermissionDeclaratedInManifest(AutomationService.getInstance(), Manifest.permission.READ_CALENDAR) && ActivityPermissions.havePermission(Manifest.permission.READ_CALENDAR, AutomationService.getInstance()))
|
||||||
{
|
{
|
||||||
if(!CalendarReceiver.getInstance().isListenerRunning())
|
if(!CalendarReceiver.getInstance().isListenerRunning())
|
||||||
CalendarReceiver.getInstance().startListener(AutomationService.getInstance());
|
CalendarReceiver.getInstance().startListener(AutomationService.getInstance());
|
||||||
|
@ -2,6 +2,7 @@ package com.jens.automation2;
|
|||||||
|
|
||||||
import java.sql.Time;
|
import java.sql.Time;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
public class TimeFrame
|
public class TimeFrame
|
||||||
{
|
{
|
||||||
@ -20,18 +21,19 @@ public class TimeFrame
|
|||||||
public void setDayList(ArrayList<Integer> dayList)
|
public void setDayList(ArrayList<Integer> dayList)
|
||||||
{
|
{
|
||||||
this.dayList = dayList;
|
this.dayList = dayList;
|
||||||
|
Collections.sort(dayList);
|
||||||
}
|
}
|
||||||
public void setDayListFromString(String dayListString)
|
public void setDayListFromString(String dayListString)
|
||||||
{
|
{
|
||||||
// Log.i("Parsing", "Full string: " + dayListString);
|
|
||||||
char[] dayListCharArray = dayListString.toCharArray();
|
char[] dayListCharArray = dayListString.toCharArray();
|
||||||
|
|
||||||
dayList = new ArrayList<Integer>();
|
dayList = new ArrayList<Integer>();
|
||||||
for(char item : dayListCharArray)
|
for(char item : dayListCharArray)
|
||||||
{
|
{
|
||||||
// Log.i("Parsing", String.valueOf(item));
|
|
||||||
dayList.add(Integer.parseInt(String.valueOf(item)));
|
dayList.add(Integer.parseInt(String.valueOf(item)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Collections.sort(dayList);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TimeObject getTriggerTimeStart()
|
public TimeObject getTriggerTimeStart()
|
||||||
|
@ -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,142 +1273,52 @@ 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
|
return false;
|
||||||
)
|
}
|
||||||
||
|
|
||||||
// Other case, start time higher than end time, timeframe goes over midnight
|
// We are inside or outside of the timeframe as demanded by the trigger
|
||||||
(
|
|
||||||
Miscellaneous.compareTimes(tf.getTriggerTimeStart(), tf.getTriggerTimeStop()) < 0
|
if (tf.getRepetition() > 0)
|
||||||
&&
|
{
|
||||||
(Miscellaneous.compareTimes(tf.getTriggerTimeStart(), nowTime) >= 0
|
if (!isSupposedToRepeatSinceLastExecution(Calendar.getInstance()))
|
||||||
||
|
|
||||||
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", "TimeFrame", "TimeFrame: Trigger of rule " + this.getParentRule().getName() + " applies, but repetition is not due, yet.", 4);
|
||||||
Miscellaneous.logEvent("i", "Trigger", "TimeFrame: We're currently (" + calNow.getTime().toString() + ") in the specified TimeFrame (" + tf.toString() + ").", 4);
|
return false;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
Miscellaneous.logEvent("i", "TimeFrame", "TimeFrame: Trigger of rule " + this.getParentRule().getName() + " would apply because repetition is due.", 4);
|
||||||
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
|
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);
|
if (checkIfStateChangedSinceLastRuleExecution)
|
||||||
return false;
|
{
|
||||||
|
/*
|
||||||
|
* 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)
|
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);
|
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 ran, 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,41 +1348,17 @@ public class Trigger
|
|||||||
* we're inside the specified timeframe.
|
* we're inside the specified timeframe.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Calendar timeSupposedToRunNext = getNextRepeatedExecutionAfter(this, lastExec);
|
Calendar lastRepetitionNotExecutedYet = DateTimeListener.getNextRepeatedExecution(this);
|
||||||
if(now.getTimeInMillis() > timeSupposedToRunNext.getTimeInMillis())
|
lastRepetitionNotExecutedYet.add(Calendar.SECOND, (int) -(tf.getRepetition()));
|
||||||
|
|
||||||
|
Miscellaneous.logEvent("i", "isSupposedToRepeatSinceLastExecution()", "Last execution: " + Miscellaneous.formatDate(lastExec.getTime()), 5);
|
||||||
|
Miscellaneous.logEvent("i", "isSupposedToRepeatSinceLastExecution()", "lastRepetitionNotExecutedYet: " + Miscellaneous.formatDate(lastRepetitionNotExecutedYet.getTime()), 5);
|
||||||
|
|
||||||
|
if(now.getTimeInMillis() > lastRepetitionNotExecutedYet.getTimeInMillis())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
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()
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
@ -30,13 +29,13 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis
|
|||||||
{
|
{
|
||||||
private static AutomationService automationServiceRef;
|
private static AutomationService automationServiceRef;
|
||||||
private static AlarmManager centralAlarmManagerInstance;
|
private static AlarmManager centralAlarmManagerInstance;
|
||||||
private static boolean alarmListenerActive = false;
|
private static boolean alarmListenerActive=false;
|
||||||
private static ArrayList<ScheduleElement> alarmCandidates = new ArrayList<>();
|
private static ArrayList<ScheduleElement> alarmCandidates = new ArrayList<>();
|
||||||
private static ArrayList<Integer> requestCodeList = new ArrayList<Integer>();
|
private static ArrayList<Integer> requestCodeList = new ArrayList<Integer>();
|
||||||
static PendingIntent alarmPendingIntent = null;
|
static PendingIntent alarmPendingIntent = null;
|
||||||
|
|
||||||
public static void startAlarmListener(final AutomationService automationServiceRef)
|
public static void startAlarmListener(final AutomationService automationServiceRef)
|
||||||
{
|
{
|
||||||
DateTimeListener.startAlarmListenerInternal(automationServiceRef);
|
DateTimeListener.startAlarmListenerInternal(automationServiceRef);
|
||||||
}
|
}
|
||||||
public static void stopAlarmListener(Context context)
|
public static void stopAlarmListener(Context context)
|
||||||
@ -48,37 +47,37 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis
|
|||||||
{
|
{
|
||||||
return alarmListenerActive;
|
return alarmListenerActive;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent)
|
public void onReceive(Context context, Intent intent)
|
||||||
{
|
{
|
||||||
Miscellaneous.logEvent("i", "AlarmListener", "Alarm received", 2);
|
Miscellaneous.logEvent("i", "AlarmListener", "Alarm received", 2);
|
||||||
|
|
||||||
ArrayList<Rule> allRulesWithNowInTimeFrame = Rule.findRuleCandidates(Trigger_Enum.timeFrame);
|
ArrayList<Rule> allRulesWithTimeFrame = Rule.findRuleCandidates(Trigger_Enum.timeFrame);
|
||||||
for(int i=0; i < allRulesWithNowInTimeFrame.size(); i++)
|
for(int i=0; i < allRulesWithTimeFrame.size(); i++)
|
||||||
{
|
{
|
||||||
if(allRulesWithNowInTimeFrame.get(i).getsGreenLight(context))
|
if(allRulesWithTimeFrame.get(i).getsGreenLight(context))
|
||||||
allRulesWithNowInTimeFrame.get(i).activate(automationServiceRef, false);
|
allRulesWithTimeFrame.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();
|
||||||
|
|
||||||
Calendar calNow = Calendar.getInstance();
|
Calendar calNow = Calendar.getInstance();
|
||||||
SimpleDateFormat sdf = new SimpleDateFormat("E dd.MM.yyyy HH:mm");
|
SimpleDateFormat sdf = new SimpleDateFormat("E dd.MM.yyyy HH:mm");
|
||||||
|
|
||||||
clearAlarms();
|
clearAlarms();
|
||||||
|
|
||||||
int i=0;
|
int i=0;
|
||||||
|
|
||||||
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.
|
||||||
*/
|
*/
|
||||||
@ -192,18 +191,17 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis
|
|||||||
* 4. Take div result +1 and add this on top of starting time
|
* 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
|
* 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());
|
TimeFrame tf = new TimeFrame(oneTrigger.getTriggerParameter2());
|
||||||
|
|
||||||
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 = getNextRepeatedExecution(oneTrigger);
|
||||||
|
|
||||||
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,39 +212,58 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
scheduleNextAlarm();
|
scheduleNextAlarm();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void scheduleNextAlarm()
|
private static void scheduleNextAlarm()
|
||||||
{
|
{
|
||||||
|
Long currentTime = System.currentTimeMillis();
|
||||||
|
ScheduleElement scheduleCandidate = null;
|
||||||
|
|
||||||
if(alarmCandidates.size() == 0)
|
if(alarmCandidates.size() == 0)
|
||||||
{
|
{
|
||||||
Miscellaneous.logEvent("i", "AlarmManager", "No alarms to be scheduled.", 3);
|
Miscellaneous.logEvent("i", "AlarmManager", "No alarms to be scheduled.", 3);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else
|
else if(alarmCandidates.size() == 1)
|
||||||
{
|
{
|
||||||
Collections.sort(alarmCandidates);
|
// only one alarm, schedule that
|
||||||
|
scheduleCandidate = alarmCandidates.get(0);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
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);
|
||||||
|
|
||||||
|
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();
|
||||||
|
calendar.setTimeInMillis(scheduleCandidate.time.getTimeInMillis());
|
||||||
|
Miscellaneous.logEvent("i", "AlarmManager", "Chose " + sdf.format(calendar.getTime()) + " as next scheduled alarm.", 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
@ -255,9 +272,10 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis
|
|||||||
|
|
||||||
centralAlarmManagerInstance.cancel(alarmPendingIntent);
|
centralAlarmManagerInstance.cancel(alarmPendingIntent);
|
||||||
}
|
}
|
||||||
|
|
||||||
requestCodeList.clear();
|
requestCodeList.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void startAlarmListenerInternal(AutomationService givenAutomationServiceRef)
|
private static void startAlarmListenerInternal(AutomationService givenAutomationServiceRef)
|
||||||
{
|
{
|
||||||
if(!alarmListenerActive)
|
if(!alarmListenerActive)
|
||||||
@ -265,29 +283,34 @@ 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);
|
||||||
|
|
||||||
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
|
||||||
|
// 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
|
else
|
||||||
Miscellaneous.logEvent("i", "AlarmListener", "Request to start AlarmListener. But it's already active.", 5);
|
Miscellaneous.logEvent("i", "AlarmListener", "Request to start AlarmListener. But it's already active.", 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void stopAlarmListenerInternal()
|
private static void stopAlarmListenerInternal()
|
||||||
{
|
{
|
||||||
if(alarmListenerActive)
|
if(alarmListenerActive)
|
||||||
{
|
{
|
||||||
Miscellaneous.logEvent("i", "AlarmListener", "Stopping alarm listener.", 4);
|
Miscellaneous.logEvent("i", "AlarmListener", "Stopping alarm listener.", 4);
|
||||||
clearAlarms();
|
clearAlarms();
|
||||||
|
centralAlarmManagerInstance.cancel(alarmPendingIntent);
|
||||||
alarmListenerActive = false;
|
alarmListenerActive = false;
|
||||||
}
|
}
|
||||||
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)
|
||||||
{
|
{
|
||||||
@ -345,41 +368,217 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.N)
|
static int getNextDayIntForExecution(Trigger trigger)
|
||||||
public static Calendar getNextRepeatedExecutionAfter(Trigger trigger, Calendar now)
|
|
||||||
{
|
{
|
||||||
Calendar calSet;
|
TimeFrame tf = new TimeFrame(trigger.getTriggerParameter2());
|
||||||
TimeObject setTime;
|
Calendar now = Calendar.getInstance();
|
||||||
|
|
||||||
|
if(tf.getDayList().contains(now.get(Calendar.DAY_OF_WEEK)))
|
||||||
|
return now.get(Calendar.DAY_OF_WEEK);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int dayNumberOfNextExecution = now.get(Calendar.DAY_OF_WEEK);
|
||||||
|
|
||||||
|
while(!tf.getDayList().contains(dayNumberOfNextExecution))
|
||||||
|
{
|
||||||
|
dayNumberOfNextExecution++;
|
||||||
|
if(dayNumberOfNextExecution > 6)
|
||||||
|
dayNumberOfNextExecution = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dayNumberOfNextExecution;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getDayDelta(Calendar now, int dayNumberOfNextExecution)
|
||||||
|
{
|
||||||
|
int result = dayNumberOfNextExecution - now.get(Calendar.DAY_OF_WEEK);
|
||||||
|
|
||||||
|
if(result >= 0)
|
||||||
|
return result;
|
||||||
|
else
|
||||||
|
return 6 + result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@RequiresApi(api = Build.VERSION_CODES.N)
|
||||||
|
public static Calendar getNextRepeatedExecution(Trigger trigger)
|
||||||
|
{
|
||||||
|
Calendar now = Calendar.getInstance();
|
||||||
|
Miscellaneous.logEvent("i", "DateTimeListener", "Checking for next repetition execution after " + Miscellaneous.formatDate(now.getTime()), 5);
|
||||||
|
Calendar calculationStart, calSchedule = null;
|
||||||
TimeFrame tf = new TimeFrame(trigger.getTriggerParameter2());
|
TimeFrame tf = new TimeFrame(trigger.getTriggerParameter2());
|
||||||
|
|
||||||
if(tf.getRepetition() > 0)
|
if(tf.getRepetition() > 0)
|
||||||
{
|
{
|
||||||
if(trigger.getTriggerParameter())
|
/*
|
||||||
setTime = tf.getTriggerTimeStart();
|
Are we inside of the timeframe or outside?
|
||||||
else
|
|
||||||
setTime = tf.getTriggerTimeStop();
|
|
||||||
|
|
||||||
calSet = (Calendar) now.clone();
|
Inside -> is this demanded?
|
||||||
calSet.set(Calendar.HOUR_OF_DAY, setTime.getHours());
|
Yes:
|
||||||
calSet.set(Calendar.MINUTE, setTime.getMinutes());
|
If last execution known, calculate from it
|
||||||
calSet.set(Calendar.SECOND, 0);
|
If not known, calculate from start of timeframe
|
||||||
calSet.set(Calendar.MILLISECOND, 0);
|
No:
|
||||||
|
Use end-time and add repetition
|
||||||
|
|
||||||
// If the starting time is a day ahead remove 1 day.
|
Outside? -> is this demanded?
|
||||||
if(calSet.getTimeInMillis() > now.getTimeInMillis())
|
Yes:
|
||||||
calSet.add(Calendar.DAY_OF_MONTH, -1);
|
If last execution known, calculate from it
|
||||||
|
If not known, calculate from end of timeframe
|
||||||
|
No:
|
||||||
|
Use start-time and add repetition
|
||||||
|
*/
|
||||||
|
|
||||||
long differenceInSeconds = Math.abs(now.getTimeInMillis() - calSet.getTimeInMillis()) / 1000;
|
if(areWeInTimeFrame(trigger, new Date()))
|
||||||
long nextExecutionMultiplier = Math.floorDiv(differenceInSeconds, tf.getRepetition()) + 1;
|
{
|
||||||
long nextScheduleTimestamp = (calSet.getTimeInMillis() / 1000) + (nextExecutionMultiplier * tf.getRepetition());
|
if(trigger.getTriggerParameter())
|
||||||
Calendar calSchedule = Calendar.getInstance();
|
{
|
||||||
calSchedule.setTimeInMillis(nextScheduleTimestamp * 1000);
|
if(trigger.getParentRule().getLastExecution() != null)
|
||||||
|
{
|
||||||
|
calculationStart = (Calendar) trigger.getParentRule().getLastExecution().clone();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
calculationStart = (Calendar) now.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);
|
||||||
|
}
|
||||||
|
long differenceInSeconds = Math.abs(now.getTimeInMillis() - calculationStart.getTimeInMillis()) / 1000;
|
||||||
|
long nextExecutionMultiplier = Math.floorDiv(differenceInSeconds, tf.getRepetition()) + 1;
|
||||||
|
calSchedule = (Calendar) calculationStart.clone();
|
||||||
|
calSchedule.add(Calendar.SECOND, (int) (nextExecutionMultiplier * tf.getRepetition()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
calculationStart = (Calendar) now.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);
|
||||||
|
calSchedule = (Calendar) calculationStart.clone();
|
||||||
|
calSchedule.add(Calendar.SECOND, (int) tf.getRepetition());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // not in timeframe
|
||||||
|
{
|
||||||
|
if (!trigger.getTriggerParameter())
|
||||||
|
{
|
||||||
|
if (trigger.getParentRule().getLastExecution() != null)
|
||||||
|
{
|
||||||
|
calculationStart = (Calendar) trigger.getParentRule().getLastExecution().clone();
|
||||||
|
long differenceInSeconds = Math.abs(now.getTimeInMillis() - calculationStart.getTimeInMillis()) / 1000;
|
||||||
|
long nextExecutionMultiplier = Math.floorDiv(differenceInSeconds, tf.getRepetition()) + 1;
|
||||||
|
calSchedule = (Calendar) calculationStart.clone();
|
||||||
|
calSchedule.add(Calendar.SECOND, (int) (nextExecutionMultiplier * tf.getRepetition()));
|
||||||
|
Miscellaneous.logEvent("i", "getNextRepeatedExecutionAfter()", "Chose " + Miscellaneous.formatDate(calSchedule.getTime()) + " as next repeated execution time.", 5);
|
||||||
|
return calSchedule;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
calculationStart = (Calendar) now.clone();
|
||||||
|
if(tf.getDayList().contains(now.get(Calendar.DAY_OF_WEEK)))
|
||||||
|
{
|
||||||
|
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());
|
||||||
|
|
||||||
return calSchedule;
|
int dayDelta = getDayDelta(now, getNextDayIntForExecution(trigger));
|
||||||
|
calculationStart.add(Calendar.DAY_OF_WEEK, dayDelta);
|
||||||
|
}
|
||||||
|
calSchedule = (Calendar) calculationStart.clone();
|
||||||
|
Miscellaneous.logEvent("i", "getNextRepeatedExecutionAfter()", "Chose " + Miscellaneous.formatDate(calSchedule.getTime()) + " as next repeated execution time.", 5);
|
||||||
|
return calSchedule;
|
||||||
|
}
|
||||||
|
/*long differenceInSeconds = Math.abs(now.getTimeInMillis() - calculationStart.getTimeInMillis()) / 1000;
|
||||||
|
long nextExecutionMultiplier = Math.floorDiv(differenceInSeconds, tf.getRepetition()) + 1;
|
||||||
|
calSchedule = (Calendar) calculationStart.clone();
|
||||||
|
calSchedule.add(Calendar.SECOND, (int) (nextExecutionMultiplier * tf.getRepetition()));*/
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
calculationStart = (Calendar) now.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);
|
||||||
|
calSchedule = (Calendar) calculationStart.clone();
|
||||||
|
calSchedule.add(Calendar.SECOND, (int) (tf.getRepetition()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Miscellaneous.compareTimes(calSchedule, now) > 0)
|
||||||
|
calSchedule.add(Calendar.DAY_OF_MONTH, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int dayDelta = getDayDelta(now, getNextDayIntForExecution(trigger));
|
||||||
|
calSchedule.add(Calendar.DAY_OF_WEEK, dayDelta);
|
||||||
|
|
||||||
|
Miscellaneous.logEvent("i", "getNextRepeatedExecutionAfter()", "Chose " + Miscellaneous.formatDate(calSchedule.getTime()) + " as next repeated execution time.", 5);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Miscellaneous.logEvent("i", "DateTimeListener", "Trigger " + trigger.toString() + " is not executed repeatedly.", 5);
|
Miscellaneous.logEvent("i", "getNextRepeatedExecutionAfter()", "Trigger " + trigger.toString() + " is not configured to repeat.", 5);
|
||||||
|
|
||||||
return null;
|
return calSchedule;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
12
fastlane/metadata/android/de-DE/changelogs/139.txt
Normal file
12
fastlane/metadata/android/de-DE/changelogs/139.txt
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
* Behoben: Overlay-Berechtigung zum Starten einer anderen Programmaktion nur erforderlich, wenn startByActivity() ausgewählt ist
|
||||||
|
* Behoben: Broadcast-Receiver-Trigger löste nichts aus, stürzte aber ab * Behoben: Fehler in Android 14 (nicht in Automation!!) erforderte eine Änderung beim Wählen von MMI-Codes, die ein #-Zeichen enthalten.
|
||||||
|
* Behoben: Speicherberechtigung wurde möglicherweise als nicht erteilt angezeigt, auch wenn sie
|
||||||
|
* Behoben: Ein sehr alter Bugfix wurde auch auf F-Droid- und Google-Play-Editionen angewendet, die irrtümlicherweise nur in der APK-Edition implementiert waren (TimeFrame-Trigger mit Wiederholungen)
|
||||||
|
* Behoben: Seltener Absturz beim Starten des Dienstes
|
||||||
|
* Behoben: Kompensiert für Android-Änderungen, zeitbasierte Trigger sind nun wieder präzise
|
||||||
|
* Hinzugefügt: neue Aktion -> Screenshot machen * Hinzugefügt: Der Ortungsdienst (GPS) kann zwischen den Zuständen umgeschaltet werden, wenn WRITE_SECURE_SETTINGS von einem Computer aus erteilt wurde
|
||||||
|
* Hinzugefügt: triggerUrl-Aktion kann jetzt mit POST und Parametern verwendet werden
|
||||||
|
* Hinzugefügt: Das Ergebnis der triggerUrl-Aktion wird jetzt in einer Variablen gespeichert, wenn Sie es überprüfen möchten
|
||||||
|
* Hinzugefügt: Neuer Auslöser: Kalenderereignisse
|
||||||
|
* Hinzugefügt: Das Ergebnis der runExecutable-Aktion wird jetzt in einer Variablen gespeichert, wenn Sie es überprüfen möchten
|
||||||
|
* Hinzugefügt: Ladeauslöser kann nun zwischen Typen unterscheiden (AC, USB, kabellos)
|
1
fastlane/metadata/android/de-DE/changelogs/141.txt
Normal file
1
fastlane/metadata/android/de-DE/changelogs/141.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
* Kalendar Funktion aus Google Version entfernt
|
3
fastlane/metadata/android/de-DE/changelogs/142.txt
Normal file
3
fastlane/metadata/android/de-DE/changelogs/142.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
* Behoben: Kalender Auslöser wird jetzt in Play Version verborgen
|
||||||
|
* Behoben: Parameter wurde beim Starten anderer Apps nicht korrekt übergeben
|
||||||
|
* Behoben: Absturz beim Verlassen der Einstellungen
|
1
fastlane/metadata/android/en-US/changelogs/137.txt
Normal file
1
fastlane/metadata/android/en-US/changelogs/137.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
* Fixed: Corrected multiple code points that caused crashes when targetApk > 31 (affected only Google Play version)
|
1
fastlane/metadata/android/en-US/changelogs/141.txt
Normal file
1
fastlane/metadata/android/en-US/changelogs/141.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
* Calendar trigger removed from Google version
|
3
fastlane/metadata/android/en-US/changelogs/142.txt
Normal file
3
fastlane/metadata/android/en-US/changelogs/142.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
* Fixed: Calendar trigger hidden from Play version
|
||||||
|
* Fixed: Parameters not correctly supplied when starting other apps
|
||||||
|
* Fixed: Crash when exiting settings while service is running
|
14
fastlane/metadata/android/es-ES/changelogs/139.txt
Normal file
14
fastlane/metadata/android/es-ES/changelogs/139.txt
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
* Corregido: El permiso de superposición para iniciar otra acción del programa solo se requiere si se selecciona startByActivity()
|
||||||
|
* Corregido: El disparador del receptor de transmisión no activaba nada, pero se bloqueaba
|
||||||
|
* Corregido: El error en Android 14 (no en Automatización!!) requería un cambio al marcar códigos MMI que contenían un carácter #.
|
||||||
|
* Corregido: El permiso de almacenamiento podía mostrarse como no concedido incluso si se
|
||||||
|
* Corregido: Se aplicó una corrección de errores muy antigua también a las ediciones F-Droid y Google-Play que por error se había implementado solo en la edición APK (disparador de timeFrame con repeticiones)
|
||||||
|
* Corregido: Raro bloqueo al iniciar el servicio
|
||||||
|
* Corregido: Compensado por los cambios de Android, los disparadores basados en el tiempo ahora son precisos nuevamente
|
||||||
|
* Añadido: nueva acción -> tomar captura de pantalla
|
||||||
|
* Agregado: El servicio de ubicación (GPS) se puede alternar entre estados si WRITE_SECURE_SETTINGS se ha otorgado desde una computadora
|
||||||
|
* Añadido: la acción triggerUrl ahora se puede usar con POST y parámetros
|
||||||
|
* Añadido: El resultado de la acción triggerUrl ahora se almacena en una variable si desea verificarlo
|
||||||
|
* Añadido: Nuevo activador: Eventos de calendario
|
||||||
|
* Añadido: El resultado de la acción runExecutable ahora se almacena en una variable si desea comprobarlo
|
||||||
|
* Añadido: El gatillo de carga ahora puede diferenciar entre tipos (CA, USB, de forma inalámbrica)
|
1
fastlane/metadata/android/es-ES/changelogs/141.txt
Normal file
1
fastlane/metadata/android/es-ES/changelogs/141.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
* Eliminado el activador de calendario de la versión de Google
|
3
fastlane/metadata/android/es-ES/changelogs/142.txt
Normal file
3
fastlane/metadata/android/es-ES/changelogs/142.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
* Corregido: Condición de calendario ahora es oculto en la versión Play
|
||||||
|
* Corregido: Los parámetros no se suministran correctamente al iniciar otras aplicaciones
|
||||||
|
* Corregido: Bloqueo al salir de la configuración mientras el servicio se está ejecutando
|
12
fastlane/metadata/android/fr-FR/changelogs/139.txt
Normal file
12
fastlane/metadata/android/fr-FR/changelogs/139.txt
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
* Corrigé : Autorisation de superposition pour démarrer une autre action de programme requise uniquement si startByActivity() est sélectionnée
|
||||||
|
* Corrigé : Le déclenchement du récepteur de diffusion ne déclenchait rien, mais plantait
|
||||||
|
* Corrigé : Un bug dans Android 14 (pas dans Automation !!) nécessitait un changement lors de la composition des codes MMI contenant un caractère #.
|
||||||
|
* Résolu : L'autorisation de stockage pouvait être affichée comme n'ayant pas été accordée, même si elle l'était
|
||||||
|
* Corrigé : Correction d'un très ancien bug également sur les éditions F-Droid et Google-Play qui n'avait été implémenté par erreur que dans l'édition APK (déclencheur timeFrame avec répétitions)
|
||||||
|
* Corrigé : Crash rare lors du démarrage du service
|
||||||
|
* Corrigé : Corrigé des changements d'Android, les déclencheurs basés sur le temps sont à nouveau précis
|
||||||
|
* Ajouté : nouvelle action > prendre une capture d'écran * Ajouté : Le service de localisation (GPS) peut être basculé entre les états s'WRITE_SECURE_SETTINGS a été accordé à partir d'un ordinateur
|
||||||
|
* Ajout : l'action triggerUrl peut maintenant être utilisée avec l'auto-test de démarrage (POST) et les paramètres
|
||||||
|
* Ajouté : Le résultat de l'action triggerUrl est maintenant stocké dans une variable si vous souhaitez le vérifier
|
||||||
|
* Ajout : Nouveau déclencheur : Événements de calendrier * Ajouté : Le résultat de l'action runExecutable est maintenant stocké dans une variable si vous souhaitez le vérifier
|
||||||
|
* Ajouté : La gâchette de charge peut désormais différencier les types (AC, USB, sans fil)
|
1
fastlane/metadata/android/fr-FR/changelogs/141.txt
Normal file
1
fastlane/metadata/android/fr-FR/changelogs/141.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
* Déclencheur d'agenda supprimé de la version Google
|
3
fastlane/metadata/android/fr-FR/changelogs/142.txt
Normal file
3
fastlane/metadata/android/fr-FR/changelogs/142.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
* Correction : Déclencheur de calendrier caché dans la version Play
|
||||||
|
* Correction : Les paramètres n'étaient pas correctement fournis lors du démarrage d'autres applications
|
||||||
|
* Correction : Plantage lors de la fermeture des paramètres pendant l'exécution du service
|
14
fastlane/metadata/android/it-IT/changelogs/139.txt
Normal file
14
fastlane/metadata/android/it-IT/changelogs/139.txt
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
* Risolto: l'autorizzazione di sovrapposizione per l'avvio di un'altra azione del programma è richiesta solo se è selezionato startByActivity()
|
||||||
|
* Risolto: il trigger del ricevitore di trasmissione non attivava nulla, ma si bloccava
|
||||||
|
* Risolto: un bug in Android 14 (non in Automazione!!) richiedeva una modifica durante la composizione dei codici MMI contenenti un carattere #.
|
||||||
|
* Risolto: l'autorizzazione di archiviazione poteva essere visualizzata come non concessa anche se lo era
|
||||||
|
* Risolto: Applicato un bug molto vecchio anche alle edizioni F-Droid e Google-Play che per errore era stato implementato solo nell'edizione APK (trigger timeFrame con ripetizioni)
|
||||||
|
* Risolto: raro crash durante l'avvio del servizio
|
||||||
|
* Risolto: compensato per le modifiche di Android, i trigger basati sul tempo ora sono di nuovo precisi
|
||||||
|
* Aggiunto: nuova azione -> fai screenshot
|
||||||
|
* Aggiunto: il servizio di localizzazione (GPS) può essere commutato tra gli stati se WRITE_SECURE_SETTINGS è stato concesso da un computer
|
||||||
|
* Aggiunto: l'azione triggerUrl può ora essere utilizzata con POST e parametri
|
||||||
|
* Aggiunto: il risultato dell'azione triggerUrl è ora memorizzato in una variabile se si desidera controllarlo
|
||||||
|
* Aggiunto: Nuovo trigger: Eventi del calendario
|
||||||
|
* Aggiunto: il risultato dell'azione runExecutable è ora memorizzato in una variabile se si desidera controllarlo
|
||||||
|
* Aggiunto: il trigger di ricarica ora può distinguere tra i tipi (AC, USB, wireless)
|
1
fastlane/metadata/android/it-IT/changelogs/141.txt
Normal file
1
fastlane/metadata/android/it-IT/changelogs/141.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
* Il trigger del calendario è stato rimosso dalla versione Google
|
3
fastlane/metadata/android/it-IT/changelogs/142.txt
Normal file
3
fastlane/metadata/android/it-IT/changelogs/142.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
* Risolto: trigger del calendario nascosto dalla versione Play
|
||||||
|
* Risolto: parametri non forniti correttamente all'avvio di altre app
|
||||||
|
* Risolto: arresto anomalo quando si esce dalle impostazioni mentre il servizio è in esecuzione
|
14
fastlane/metadata/android/nl-NL/changelogs/139.txt
Normal file
14
fastlane/metadata/android/nl-NL/changelogs/139.txt
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
* Opgelost: overlay-toestemming voor het starten van een andere programmaactie is alleen vereist als startByActivity() is geselecteerd
|
||||||
|
* Opgelost: de trigger van de uitzendontvanger zou niets activeren, maar crashen
|
||||||
|
* Opgelost: bug in Android 14 (niet in Automation!!) vereiste een wijziging bij het kiezen van MMI-codes met een #-teken.
|
||||||
|
* Opgelost: opslagtoestemming kan worden weergegeven als niet verleend, zelfs als dit wel het geval was
|
||||||
|
* Opgelost: een zeer oude bugfix ook toegepast op F-Droid- en Google-Play-edities die per ongeluk alleen in de APK-editie waren geïmplementeerd (timeFrame-trigger met herhalingen)
|
||||||
|
* Opgelost: zeldzame crash tijdens het starten van de service
|
||||||
|
* Opgelost: gecompenseerd voor Android-wijzigingen, op tijd gebaseerde triggers zijn nu weer nauwkeurig
|
||||||
|
* Toegevoegd: nieuwe actie > screenshot maken
|
||||||
|
* Toegevoegd: Locatieservice (GPS) kan worden omgeschakeld tussen staten als WRITE_SECURE_SETTINGS is verleend vanaf een computer
|
||||||
|
* Toegevoegd: triggerUrl-actie kan nu worden gebruikt met POST en parameters
|
||||||
|
* Toegevoegd: Resultaat van triggerUrl-actie wordt nu opgeslagen in een variabele als u deze wilt controleren
|
||||||
|
* Toegevoegd: Nieuwe trigger: Agenda-afspraken
|
||||||
|
* Toegevoegd: Resultaat van runExecutable actie wordt nu opgeslagen in een variabele als u deze wilt controleren
|
||||||
|
* Toegevoegd: oplaadtrigger kan nu onderscheid maken tussen typen (AC, USB, draadloos)
|
1
fastlane/metadata/android/nl-NL/changelogs/141.txt
Normal file
1
fastlane/metadata/android/nl-NL/changelogs/141.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
* Agendatrigger verwijderd uit Google-versie
|
3
fastlane/metadata/android/nl-NL/changelogs/142.txt
Normal file
3
fastlane/metadata/android/nl-NL/changelogs/142.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
* Opgelost: kalendertrigger verborgen voor Play-versie
|
||||||
|
* Opgelost: parameters worden niet correct opgegeven bij het starten van andere apps
|
||||||
|
* Opgelost: crash bij het afsluiten van instellingen terwijl de service actief is
|
14
fastlane/metadata/android/pl-PL/changelogs/139.txt
Normal file
14
fastlane/metadata/android/pl-PL/changelogs/139.txt
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
* Naprawiono: Uprawnienie nakładki do uruchamiania innej akcji programu jest wymagane tylko wtedy, gdy wybrano startByActivity()
|
||||||
|
* Naprawiono: Wyzwalacz odbiornika transmisji nie uruchamiał niczego, ale zawieszał się
|
||||||
|
* Naprawiono: Błąd w Androidzie 14 (nie w Automation!!) wymagał zmiany podczas wybierania kodów MMI zawierających znak #.
|
||||||
|
* Naprawiono: Uprawnienie do przechowywania może być wyświetlane jako nieprzyznane, nawet jeśli było
|
||||||
|
* Naprawiono: Zastosowano bardzo starą poprawkę błędu również do edycji F-Droid i Google-Play, która przez pomyłkę została zaimplementowana tylko w edycji APK (wyzwalacz timeFrame z powtórzeniami)
|
||||||
|
* Naprawiono: Rzadka awaria podczas uruchamiania usługi
|
||||||
|
* Naprawiono: Zrekompensowano zmiany w Androidzie, wyzwalacze oparte na czasie są teraz ponownie precyzyjne
|
||||||
|
* Dodano: nowa akcja -> zrób zrzut ekranu
|
||||||
|
* Dodano: Usługa lokalizacyjna (GPS) może być przełączana między stanami, jeśli WRITE_SECURE_SETTINGS została przyznana z komputera
|
||||||
|
* Dodano: akcja triggerUrl może być teraz używana z POST i parametrami
|
||||||
|
* Dodano: Wynik akcji triggerUrl jest teraz przechowywany w zmiennej, jeśli chcesz to sprawdzić
|
||||||
|
* Dodano: Nowy wyzwalacz: Wydarzenia w kalendarzu
|
||||||
|
* Dodano: Wynik akcji runExecutable jest teraz przechowywany w zmiennej, jeśli chcesz to sprawdzić
|
||||||
|
* Dodano: Wyzwalacz ładowania może teraz rozróżniać typy (AC, USB, bezprzewodowo)
|
1
fastlane/metadata/android/pl-PL/changelogs/141.txt
Normal file
1
fastlane/metadata/android/pl-PL/changelogs/141.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
* Wyzwalacz kalendarza usunięty z wersji Google
|
3
fastlane/metadata/android/pl-PL/changelogs/142.txt
Normal file
3
fastlane/metadata/android/pl-PL/changelogs/142.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
* Naprawiono: Wyzwalacz kalendarza ukryty w wersji Play
|
||||||
|
* Naprawiono: Parametry nie są poprawnie dostarczane podczas uruchamiania innych aplikacji
|
||||||
|
* Naprawiono: Awaria podczas wychodzenia z ustawień, gdy usługa jest uruchomiona
|
14
fastlane/metadata/android/ru-RU/changelogs/139.txt
Normal file
14
fastlane/metadata/android/ru-RU/changelogs/139.txt
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
* Исправлено: Разрешение на оверлей для запуска других действий программы требуется только в том случае, если выбран startByActivity()
|
||||||
|
* Исправлено: Триггер широковещательного приемника не вызывал ничего, кроме сбоя.
|
||||||
|
* Исправлено: Ошибка в Android 14 (не в Automation!!) требовала изменения при наборе кодов MMI, содержащих символ #.
|
||||||
|
* Исправлено: Разрешение на хранение могло отображаться как не предоставленное, даже если оно было
|
||||||
|
* Исправлено: Применено очень старое исправление ошибки также к редакциям F-Droid и Google-Play, которые по ошибке были реализованы только в редакции APK (триггер timeFrame с повторами)
|
||||||
|
* Исправлено: редкий сбой при запуске сервиса.
|
||||||
|
* Исправлено: Компенсированы изменения Android, триггеры, основанные на времени, теперь снова точны
|
||||||
|
* Добавлено: новое действие -> сделать скриншот
|
||||||
|
* Добавлено: Служба определения местоположения (GPS) может переключаться между состояниями, если WRITE_SECURE_SETTINGS было предоставлено с компьютера.
|
||||||
|
* Добавлено: действие triggerUrl теперь можно использовать с POST и параметрами
|
||||||
|
* Добавлено: Результат действия triggerUrl теперь сохраняется в переменной, если вы хотите проверить это
|
||||||
|
* Добавлено: Новый триггер: События календаря
|
||||||
|
* Добавлено: Результат действия runExecutable теперь сохраняется в переменной, если вы хотите проверить это
|
||||||
|
* Добавлено: Триггер зарядки теперь может различать типы (переменный ток, USB, беспроводная связь)
|
1
fastlane/metadata/android/ru-RU/changelogs/141.txt
Normal file
1
fastlane/metadata/android/ru-RU/changelogs/141.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
* Триггер календаря удален из версии Google
|
3
fastlane/metadata/android/ru-RU/changelogs/142.txt
Normal file
3
fastlane/metadata/android/ru-RU/changelogs/142.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
* Исправлено: Триггер календаря скрыт в игровой версии
|
||||||
|
* Исправлено: Параметры неправильно указываются при запуске других приложений.
|
||||||
|
* Исправлено: Сбой при выходе из настроек во время работы сервиса
|
13
fastlane/metadata/android/zh-CN/changelogs/139.txt
Normal file
13
fastlane/metadata/android/zh-CN/changelogs/139.txt
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
* 修复:只有在选择了 startByActivity() 时才需要启动其他程序操作的叠加权限
|
||||||
|
* 修复:广播接收机触发不会触发任何内容,但会崩溃
|
||||||
|
* 已修复:Android 14(不在 Automation!! 中)中的错误在拨打包含 # 字符的 MMI 代码时需要更改。
|
||||||
|
* 修复:存储权限可能显示为未授予,即使已授予
|
||||||
|
* 修复:将一个非常古老的错误修复也应用于 F-Droid 和 Google-Play 版本,这些版本错误地仅在 APK 版本中实现(具有重复的 timeFrame 触发器)
|
||||||
|
* 修复:启动服务时罕见崩溃
|
||||||
|
* 已修复:补偿了 Android 更改,基于时间的触发器现在再次精确
|
||||||
|
* 新增:新动作 ->截图 * 新增:定位服务 (GPS) 可以在各州之间切换,前提是已从计算机授予WRITE_SECURE_SETTINGS
|
||||||
|
* 新增:triggerUrl 操作现在可以与 POST 和参数一起使用
|
||||||
|
* 新增:triggerUrl 操作的结果现在存储在变量中,如果您想检查它
|
||||||
|
* 新增:新触发器:日历事件
|
||||||
|
* 新增:runExecutable 操作的结果现在存储在变量中,如果您想检查它
|
||||||
|
* 新增:充电触发器现在可以区分类型(交流、USB、无线)
|
1
fastlane/metadata/android/zh-CN/changelogs/141.txt
Normal file
1
fastlane/metadata/android/zh-CN/changelogs/141.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
* 日历触发器已从 Google 版本中删除
|
3
fastlane/metadata/android/zh-CN/changelogs/142.txt
Normal file
3
fastlane/metadata/android/zh-CN/changelogs/142.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
* 修复:播放版本中隐藏的日历触发器
|
||||||
|
* 修复:启动其他应用程序时未正确提供参数的问题
|
||||||
|
* 修复:服务运行时退出设置时崩溃
|
Loading…
Reference in New Issue
Block a user