Compare commits

...

54 Commits

Author SHA1 Message Date
jens 5ca7295c30 date time repetition 2024-01-27 17:03:27 +01:00
jens e2027a457a Merge remote-tracking branch 'origin/development' into development 2024-01-25 16:54:00 +01:00
jens 6c31b67b14 Battery charging type differentiation and other fixes 2024-01-25 16:53:43 +01:00
jens 04fe674cf6 Battery charging type differentiation 2024-01-25 14:03:39 +01:00
Jens 17b3b8fafc New version prep, fix attempt in notification listener 2024-01-24 23:16:24 +01:00
Jens 0d38c8bbe0 New version prep, fix attempt in notification listener 2024-01-24 14:00:34 +01:00
Jens f7ff8a38e1 New version prep, fix attempt in notification listener 2024-01-21 23:46:08 +01:00
Jens b7677bdcce Calendar trigger 2024-01-20 23:47:32 +01:00
jens 1ff4a15818 Calendar trigger 2024-01-18 16:28:42 +01:00
jens bd42507521 Bugfix in triggerUrl action 2024-01-15 16:42:16 +01:00
Jens fe924f6fe9 Calendar trigger 2024-01-14 23:18:12 +01:00
jens dfe8594f06 Calendar trigger 2024-01-14 15:56:44 +01:00
jens 553d14b05f Calendar trigger 2024-01-10 20:01:24 +01:00
Jens b38ca31df5 Calendar trigger 2024-01-09 22:56:42 +01:00
Jens 6e566c664d Calendar trigger 2024-01-08 23:10:27 +01:00
Jens 8c4b75232e Calendar trigger 2024-01-07 23:56:55 +01:00
jens 4521bc7d4e Calendar trigger 2024-01-07 15:15:56 +01:00
Jens eaecf63724 Calendar trigger 2024-01-06 23:57:52 +01:00
jens ec62b91449 Calendar trigger 2024-01-06 17:25:27 +01:00
Jens 223cca442d wifi trigger 2024-01-06 11:49:49 +01:00
jens f3613f8eb0 triggerUrl with POST params 2024-01-03 16:24:21 +01:00
jens 8b193aa89c triggerUrl with POST params 2024-01-02 16:36:10 +01:00
jens 58ec35aae5 calendar trigger 2024-01-01 13:35:21 +01:00
jens c61c5ba14c if brackets 2023-12-31 16:53:59 +01:00
jens d75cf137ba Merge branch 'calendar_trigger' into development 2023-12-31 16:00:13 +01:00
jens 5e3d268815 date time trigger set to wakeup 2023-12-31 15:59:02 +01:00
jens 3bcf90277f calendar trigger 2023-12-31 15:54:24 +01:00
Jens 81a205a8db Calendar trigger 2023-12-30 23:26:27 +01:00
jens 97a3344e81 calendar trigger 2023-12-29 19:43:50 +01:00
jens cd47b33449 calendar trigger 2023-12-28 17:17:08 +01:00
Jens 2ba25a9e65 Calendar trigger 2023-12-28 00:25:55 +01:00
jens d2606b72cd calendar trigger 2023-12-27 14:48:27 +01:00
Jens 584495ef61 Calendar trigger 2023-12-27 13:33:09 +01:00
jens 9b28aeef8b calendar trigger 2023-12-26 11:56:02 +01:00
jens b6bf31589a calendar trigger 2023-12-25 14:28:48 +01:00
Jens 67238bd2f0 Calendar trigger 2023-12-25 11:57:55 +01:00
jens 5f278a6ba0 calendar trigger 2023-12-23 13:55:02 +01:00
Jens a21f90acb5 Wifi receiver 2023-12-21 23:16:21 +01:00
jens 5f8ed5765a TriggerUrl result stored in variable 2023-12-21 16:40:11 +01:00
jens 605f85d215 Howto for write_secure_settings linked and translations updated 2023-12-21 15:37:55 +01:00
Jens 21f4a7fd5c Set location service 2023-12-20 23:54:36 +01:00
Jens 2219164869 Set location service 2023-12-19 23:52:28 +01:00
jens a8646ef61d Merge branch 'accessibility_api' into development
# Conflicts:
#	app/src/main/java/com/jens/automation2/Actions.java
2023-12-19 16:54:52 +01:00
jens f641de9893 Take screenshot action added 2023-12-19 16:54:10 +01:00
Jens bca8b44ad6 Bugfix for Android 14 for auto dialing mmi codes 2023-12-18 23:13:18 +01:00
Jens c34dfa4af4 Bugfix for Android 14 for auto dialing mmi codes 2023-12-18 22:55:18 +01:00
jens 38644cee28 Take screenshot action added 2023-12-16 13:52:18 +01:00
jens 47898e84ea Comment added 2023-12-14 17:46:55 +01:00
Jens ac74b52aed Accessibility API 2023-12-14 00:15:59 +01:00
Jens 3f76813e80 Http method selectable 2023-12-12 23:40:12 +01:00
Jens 1b8dc5de5f Http method selectable 2023-12-11 22:50:07 +01:00
Jens 3c8c0f14f2 Fixed bug in broadcast receiver trigger 2023-12-06 23:44:40 +01:00
Jens 9ead47bdf7 Permissions for startActivity() reduced 2023-12-03 23:24:58 +01:00
Jens e4828a9720 Fixes for Google Play version 2023-11-30 00:00:34 +01:00
77 changed files with 4590 additions and 589 deletions

View File

@ -8,11 +8,11 @@ android {
defaultConfig {
applicationId "com.jens.automation2"
minSdkVersion 16
compileSdkVersion 31
compileSdkVersion 33
buildToolsVersion '29.0.2'
useLibrary 'org.apache.http.legacy'
versionCode 136
versionName "1.7.19"
versionCode 138
versionName "1.8"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

View File

@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<supports-screens
android:anyDensity="true"
@ -50,7 +52,6 @@
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<!-- <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />-->
<uses-permission android:name="android.permission.GET_TASKS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.NFC" />
@ -70,6 +71,14 @@
<uses-permission android:name="android.permission.ANSWER_PHONE_CALLS" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission
android:name="android.permission.WRITE_SECURE_SETTINGS"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
<!--android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />-->
<uses-feature
android:name="android.hardware.telephony"
@ -130,6 +139,7 @@
</intent-filter>
</receiver>
<receiver android:name=".receivers.PackageReplacedReceiver"
android:exported="true"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
@ -138,9 +148,11 @@
<receiver android:name=".receivers.DateTimeListener" />
<receiver android:name=".receivers.ConnectivityReceiver" />
<receiver android:name=".receivers.TimeZoneListener" />
<receiver android:name=".receivers.CalendarReceiver" />
<receiver
android:name=".DeviceAdmin"
android:exported="true"
android:description="@string/app_name"
android:label="@string/app_name"
android:permission= "android.permission.BIND_DEVICE_ADMIN" >
@ -179,9 +191,12 @@
<activity android:name=".ActivityManageActionSetVariable" />
<activity android:name=".ActivityManageTriggerCheckVariable" />
<activity android:name=".ActivityManageActionCopyToClipboard" />
<activity android:name=".ActivityManageActionLocationService" />
<activity android:name=".ActivityManageTriggerCharging" />
<activity
android:name=".ActivityMainTabLayout"
android:exported="true"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@ -227,9 +242,11 @@
<activity android:name=".ActivityVolumeTest" />
<activity android:name=".ActivityPermissions"></activity>
<activity android:name=".ActivityManageTriggerNotification" />
<activity android:name=".ActivityManageTriggerCalendar" />
<service
android:name=".receivers.NotificationListener"
android:exported="true"
android:label="@string/app_name"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE" >
<intent-filter>
@ -261,6 +278,17 @@
android:exported="true"
/>
<service android:name=".MyAccessibilityService"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
<meta-data
android:name="android.accessibilityservice"
android:resource="@xml/config_accessibility_service" />
</service>
</application>
</manifest>

View File

@ -18,7 +18,7 @@ public class MyGoogleApiClient
public com.google.android.gms.appindexing.Action getIndexApiAction()
{
Thing object = new Thing.Builder()
.setName("ActivityMainScreen Page") // TODO: Define a title for the content shown.
.setName("ActivityMainScreen Page")
// TODO: Make sure this auto-generated URL is correct.
.setUrl(Uri.parse("http://[ENTER-YOUR-URL-HERE]"))
.build();

View File

@ -10,9 +10,12 @@ import android.os.Looper;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.Nullable;
import com.google.android.gms.location.DetectedActivity;
import com.jens.automation2.receivers.ActivityDetectionReceiver;
import com.jens.automation2.receivers.BroadcastListener;
import com.jens.automation2.receivers.CalendarReceiver;
import java.util.ArrayList;
import java.util.Calendar;
@ -373,23 +376,28 @@ public class Rule implements Comparable<Rule>
{
if(hasNotAppliedSinceLastExecution())
{
Miscellaneous.logEvent("i", "getsGreenLight()", "Rule " + getName() + " applies and has flipped since its last execution.", 4);
Miscellaneous.logEvent("i", "getsGreenLight()", "Rule \"" + getName() + "\" applies and has flipped since its last execution.", 4);
return true;
}
else if(hasTriggerOfType(Trigger.Trigger_Enum.calendarEvent) && CalendarReceiver.mayRuleStillBeActivatedForPendingCalendarEvents(this))
{
Miscellaneous.logEvent("i", "getsGreenLight()", "Rule \"" + getName() + "\" applies, has not flipped since its last execution, but may still be executed for other calendar events.", 4);
return true;
}
else
Miscellaneous.logEvent("i", "getsGreenLight()", "Rule " + getName() + " has not flipped since its last execution.", 4);
Miscellaneous.logEvent("i", "getsGreenLight()", "Rule \"" + getName() + "\" has not flipped since its last execution.", 4);
}
else
Miscellaneous.logEvent("i", "getsGreenLight()", "Rule " + getName() + " does not apply.", 4);
Miscellaneous.logEvent("i", "getsGreenLight()", "Rule \"" + getName() + "\" does not apply.", 4);
return false;
}
public boolean applies(Context context)
{
if(AutomationService.getInstance() == null)
{
Miscellaneous.logEvent("i", "RuleCheck", "Automation service not running. Rule " + getName() + " cannot apply.", 3);
Miscellaneous.logEvent("i", "RuleCheck", "Automation service not running. Rule \"" + getName() + "\" cannot apply.", 3);
return false;
}
@ -401,7 +409,7 @@ public class Rule implements Comparable<Rule>
return false;
}
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), String.format("Rule %1$s generally applies currently. Checking if it's really due, yet will be done separately.", this.getName()), 3);
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), String.format("Rule \"%1$s\" generally applies currently. Checking if it's really due, yet will be done separately.", this.getName()), 3);
return true;
}
@ -507,7 +515,7 @@ public class Rule implements Comparable<Rule>
{
boolean isActuallyToggleable = isActuallyToggable();
boolean notLastActive = getLastActivatedRule() == null || !getLastActivatedRule().equals(Rule.this);
// boolean notLastActive = getLastActivatedRule() == null || !getLastActivatedRule().equals(Rule.this);
boolean doToggle = ruleToggle && isActuallyToggleable;
String message;
@ -521,6 +529,29 @@ public class Rule implements Comparable<Rule>
if(Settings.startNewThreadForRuleActivation)
publishProgress(message);
/*
Make a note of Rule/CalendarEvent executed combinations
*/
if(Rule.this.hasTriggerOfType(Trigger.Trigger_Enum.calendarEvent))
{
for(CalendarReceiver.CalendarEvent event : CalendarReceiver.getApplyingCalendarEvents(Rule.this))
{
if(!CalendarReceiver.hasEventBeenUsedInRule(Rule.this, event))
{
/*
Record only the first calendar event that matched because the rule may
be executed once for every matching event.
*/
Miscellaneous.logEvent("i", "Rule", "Executing this rule run for calender event: " + event, 5);
CalendarReceiver.addUsedPair(new CalendarReceiver.RuleEventPair(Rule.this, event));
break;
}
}
}
/*
Run actions one after another
*/
for(int i = 0; i< Rule.this.getActionSet().size(); i++)
{
try
@ -780,4 +811,71 @@ public class Rule implements Comparable<Rule>
return null;
}
@Override
public boolean equals(@Nullable Object obj)
{
return this.getName().equals(((Rule)obj).getName());
}
public boolean hasTriggerOfType(Trigger.Trigger_Enum queryType)
{
for(Trigger t : getTriggerSet())
{
if(t.getTriggerType().equals(queryType))
return true;
}
return false;
}
public boolean hasActionOfType(Action.Action_Enum queryType)
{
for(Action a : getActionSet())
{
if(a.getAction().equals(queryType))
return true;
}
return false;
}
public int getAmountOfTriggersForType(Trigger.Trigger_Enum type)
{
int amount = 0;
for(Trigger t : getTriggerSet())
{
if(t.getTriggerType().equals(type))
amount++;
}
return amount;
}
public int getAmountOfActionsForType(Action.Action_Enum type)
{
int amount = 0;
for(Action a : getActionSet())
{
if(a.getAction().equals(type))
amount++;
}
return amount;
}
public static int getAmountOfActivatedRules()
{
int amount = 0;
for(Rule r : Rule.getRuleCollection())
{
if(r.isRuleActive())
amount++;
}
return amount;
}
}

View File

@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<supports-screens
android:anyDensity="true"
@ -50,7 +52,6 @@
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<!-- <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />-->
<uses-permission android:name="android.permission.GET_TASKS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.NFC" />
@ -68,6 +69,13 @@
<uses-permission android:name="android.permission.ANSWER_PHONE_CALLS" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission
android:name="android.permission.WRITE_SECURE_SETTINGS"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
<!--android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />-->
<uses-feature
android:name="android.hardware.telephony"
@ -128,6 +136,7 @@
</intent-filter>
</receiver>
<receiver android:name=".receivers.PackageReplacedReceiver"
android:exported="true"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
@ -136,9 +145,11 @@
<receiver android:name=".receivers.DateTimeListener" />
<receiver android:name=".receivers.ConnectivityReceiver" />
<receiver android:name=".receivers.TimeZoneListener" />
<receiver android:name=".receivers.CalendarReceiver" />
<receiver
android:name=".DeviceAdmin"
android:exported="true"
android:description="@string/app_name"
android:label="@string/app_name"
android:permission= "android.permission.BIND_DEVICE_ADMIN" >
@ -177,8 +188,12 @@
<activity android:name=".ActivityManageActionSetVariable" />
<activity android:name=".ActivityManageTriggerCheckVariable" />
<activity android:name=".ActivityManageActionCopyToClipboard" />
<activity android:name=".ActivityManageActionLocationService" />
<activity android:name=".ActivityManageTriggerCharging" />
<activity
android:name=".ActivityMainTabLayout"
android:exported="true"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@ -224,9 +239,11 @@
<activity android:name=".ActivityVolumeTest" />
<activity android:name=".ActivityPermissions"></activity>
<activity android:name=".ActivityManageTriggerNotification" />
<activity android:name=".ActivityManageTriggerCalendar" />
<service
android:name=".receivers.NotificationListener"
android:exported="true"
android:label="@string/app_name"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE" >
<intent-filter>
@ -246,6 +263,17 @@
android:exported="true"
/>
<service android:name=".MyAccessibilityService"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
<meta-data
android:name="android.accessibilityservice"
android:resource="@xml/config_accessibility_service" />
</service>
</application>
</manifest>

View File

@ -10,7 +10,10 @@ import android.os.Looper;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.Nullable;
import com.jens.automation2.receivers.BroadcastListener;
import com.jens.automation2.receivers.CalendarReceiver;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
@ -344,7 +347,16 @@ public class Rule implements Comparable<Rule>
if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.timeFrame))
{
if(oneTrigger.getTimeFrame().repetition > 0)
return true;
{
if(this.getLastExecution() != null)
{
Calendar now = Calendar.getInstance();
if (this.getLastExecution().getTimeInMillis() + oneTrigger.getTimeFrame().getRepetition() * 1000 <= now.getTimeInMillis())
return true;
}
else
return true;
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.broadcastReceived))
{
@ -361,23 +373,28 @@ public class Rule implements Comparable<Rule>
{
if(hasNotAppliedSinceLastExecution())
{
Miscellaneous.logEvent("i", "getsGreenLight()", "Rule " + getName() + " applies and has flipped since its last execution.", 4);
Miscellaneous.logEvent("i", "getsGreenLight()", "Rule \"" + getName() + "\" applies and has flipped since its last execution.", 4);
return true;
}
else if(hasTriggerOfType(Trigger.Trigger_Enum.calendarEvent) && CalendarReceiver.mayRuleStillBeActivatedForPendingCalendarEvents(this))
{
Miscellaneous.logEvent("i", "getsGreenLight()", "Rule \"" + getName() + "\" applies, has not flipped since its last execution, but may still be executed for other calendar events.", 4);
return true;
}
else
Miscellaneous.logEvent("i", "getsGreenLight()", "Rule " + getName() + " has not flipped since its last execution.", 4);
Miscellaneous.logEvent("i", "getsGreenLight()", "Rule \"" + getName() + "\" has not flipped since its last execution.", 4);
}
else
Miscellaneous.logEvent("i", "getsGreenLight()", "Rule " + getName() + " does not apply.", 4);
Miscellaneous.logEvent("i", "getsGreenLight()", "Rule \"" + getName() + "\" does not apply.", 4);
return false;
}
public boolean applies(Context context)
{
if(AutomationService.getInstance() == null)
{
Miscellaneous.logEvent("i", "RuleCheck", "Automation service not running. Rule " + getName() + " cannot apply.", 3);
Miscellaneous.logEvent("i", "RuleCheck", "Automation service not running. Rule \"" + getName() + "\" cannot apply.", 3);
return false;
}
@ -389,7 +406,7 @@ public class Rule implements Comparable<Rule>
return false;
}
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), String.format("Rule %1$s generally applies currently. Checking if it's really due, yet will be done separately.", this.getName()), 3);
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), String.format("Rule \"%1$s\" generally applies currently. Checking if it's really due, yet will be done separately.", this.getName()), 3);
return true;
}
@ -471,7 +488,7 @@ public class Rule implements Comparable<Rule>
{
boolean isActuallyToggleable = isActuallyToggable();
boolean notLastActive = getLastActivatedRule() == null || !getLastActivatedRule().equals(Rule.this);
// boolean notLastActive = getLastActivatedRule() == null || !getLastActivatedRule().equals(Rule.this);
boolean doToggle = ruleToggle && isActuallyToggleable;
String message;
@ -485,6 +502,29 @@ public class Rule implements Comparable<Rule>
if(Settings.startNewThreadForRuleActivation)
publishProgress(message);
/*
Make a note of Rule/CalendarEvent executed combinations
*/
if(Rule.this.hasTriggerOfType(Trigger.Trigger_Enum.calendarEvent))
{
for(CalendarReceiver.CalendarEvent event : CalendarReceiver.getApplyingCalendarEvents(Rule.this))
{
if(!CalendarReceiver.hasEventBeenUsedInRule(Rule.this, event))
{
/*
Record only the first calendar event that matched because the rule may
be executed once for every matching event.
*/
Miscellaneous.logEvent("i", "Rule", "Executing this rule run for calender event: " + event, 5);
CalendarReceiver.addUsedPair(new CalendarReceiver.RuleEventPair(Rule.this, event));
break;
}
}
}
/*
Run actions one after another
*/
for(int i = 0; i< Rule.this.getActionSet().size(); i++)
{
try
@ -744,4 +784,71 @@ public class Rule implements Comparable<Rule>
return null;
}
@Override
public boolean equals(@Nullable Object obj)
{
return this.getName().equals(((Rule)obj).getName());
}
public boolean hasTriggerOfType(Trigger.Trigger_Enum queryType)
{
for(Trigger t : getTriggerSet())
{
if(t.getTriggerType().equals(queryType))
return true;
}
return false;
}
public boolean hasActionOfType(Action.Action_Enum queryType)
{
for(Action a : getActionSet())
{
if(a.getAction().equals(queryType))
return true;
}
return false;
}
public int getAmountOfTriggersForType(Trigger.Trigger_Enum type)
{
int amount = 0;
for(Trigger t : getTriggerSet())
{
if(t.getTriggerType().equals(type))
amount++;
}
return amount;
}
public int getAmountOfActionsForType(Action.Action_Enum type)
{
int amount = 0;
for(Action a : getActionSet())
{
if(a.getAction().equals(type))
amount++;
}
return amount;
}
public static int getAmountOfActivatedRules()
{
int amount = 0;
for(Rule r : Rule.getRuleCollection())
{
if(r.isRuleActive())
amount++;
}
return amount;
}
}

View File

@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<supports-screens
android:anyDensity="true"
@ -49,7 +51,6 @@
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<!-- <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />-->
<uses-permission android:name="android.permission.GET_TASKS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.NFC" />
@ -65,6 +66,14 @@
<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.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission
android:name="android.permission.WRITE_SECURE_SETTINGS"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<!--android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />-->
<application
android:allowBackup="true"
@ -99,7 +108,9 @@
android:exported="false"
android:label="@string/app_name" />
<receiver android:name=".receivers.StartupIntentReceiver" android:enabled="true" android:exported="true">
<receiver android:name=".receivers.StartupIntentReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<!--<action android:name="android.intent.action.SCREEN_ON" />-->
<!--<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />-->
@ -121,6 +132,7 @@
<receiver android:name=".receivers.DateTimeListener" />
<receiver android:name=".receivers.ConnectivityReceiver" />
<receiver android:name=".receivers.TimeZoneListener" />
<receiver android:name=".receivers.CalendarReceiver" />
<receiver
android:name=".DeviceAdmin"
@ -162,6 +174,9 @@
<activity android:name=".ActivityManageActionSetVariable" />
<activity android:name=".ActivityManageTriggerCheckVariable" />
<activity android:name=".ActivityManageActionCopyToClipboard" />
<activity android:name=".ActivityManageActionLocationService" />
<activity android:name=".ActivityManageTriggerCharging" />
<activity
android:name=".ActivityMainTabLayout"
android:exported="true"
@ -202,7 +217,6 @@
<activity android:name=".ActivityManageActionStartActivity" />
<activity android:name=".ActivityManageTriggerNfc" />
<activity android:name=".ActivityManageActionSpeakText" />
<activity android:name=".ActivityManageActionPlaySound" />
<activity android:name=".ActivityManageTriggerBluetooth" />
<activity android:name=".ActivityMainProfiles" />
<activity android:name=".ActivityManageProfile" />
@ -210,6 +224,7 @@
<activity android:name=".ActivityVolumeTest" />
<activity android:name=".ActivityPermissions"></activity>
<activity android:name=".ActivityManageTriggerNotification" />
<activity android:name=".ActivityManageTriggerCalendar" />
<service
android:name=".receivers.NotificationListener"
@ -222,8 +237,6 @@
</service>
<activity android:name=".ActivityPermissions" />
<!-- https://developer.android.com/about/versions/pie/android-9.0-changes-28#apache-p-->
<uses-library android:name="org.apache.http.legacy" android:required="false"/>
@ -245,6 +258,18 @@
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>
</manifest>

View File

@ -10,9 +10,12 @@ import android.os.Looper;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.Nullable;
import com.google.android.gms.location.DetectedActivity;
import com.jens.automation2.receivers.ActivityDetectionReceiver;
import com.jens.automation2.receivers.BroadcastListener;
import com.jens.automation2.receivers.CalendarReceiver;
import java.util.ArrayList;
import java.util.Calendar;
@ -347,7 +350,16 @@ public class Rule implements Comparable<Rule>
if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.timeFrame))
{
if(oneTrigger.getTimeFrame().repetition > 0)
return true;
{
if(this.getLastExecution() != null)
{
Calendar now = Calendar.getInstance();
if (this.getLastExecution().getTimeInMillis() + oneTrigger.getTimeFrame().getRepetition() * 1000 <= now.getTimeInMillis())
return true;
}
else
return true;
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.broadcastReceived))
{
@ -364,23 +376,28 @@ public class Rule implements Comparable<Rule>
{
if(hasNotAppliedSinceLastExecution())
{
Miscellaneous.logEvent("i", "getsGreenLight()", "Rule " + getName() + " applies and has flipped since its last execution.", 4);
Miscellaneous.logEvent("i", "getsGreenLight()", "Rule \"" + getName() + "\" applies and has flipped since its last execution.", 4);
return true;
}
else if(hasTriggerOfType(Trigger.Trigger_Enum.calendarEvent) && CalendarReceiver.mayRuleStillBeActivatedForPendingCalendarEvents(this))
{
Miscellaneous.logEvent("i", "getsGreenLight()", "Rule \"" + getName() + "\" applies, has not flipped since its last execution, but may still be executed for other calendar events.", 4);
return true;
}
else
Miscellaneous.logEvent("i", "getsGreenLight()", "Rule " + getName() + " has not flipped since its last execution.", 4);
Miscellaneous.logEvent("i", "getsGreenLight()", "Rule \"" + getName() + "\" has not flipped since its last execution.", 4);
}
else
Miscellaneous.logEvent("i", "getsGreenLight()", "Rule " + getName() + " does not apply.", 4);
Miscellaneous.logEvent("i", "getsGreenLight()", "Rule \"" + getName() + "\" does not apply.", 4);
return false;
}
public boolean applies(Context context)
{
if(AutomationService.getInstance() == null)
{
Miscellaneous.logEvent("i", "RuleCheck", "Automation service not running. Rule " + getName() + " cannot apply.", 3);
Miscellaneous.logEvent("i", "RuleCheck", "Automation service not running. Rule \"" + getName() + "\" cannot apply.", 3);
return false;
}
@ -392,7 +409,7 @@ public class Rule implements Comparable<Rule>
return false;
}
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), String.format("Rule %1$s generally applies currently. Checking if it's really due, yet will be done separately.", this.getName()), 3);
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), String.format("Rule \"%1$s\" generally applies currently. Checking if it's really due, yet will be done separately.", this.getName()), 3);
return true;
}
@ -498,7 +515,7 @@ public class Rule implements Comparable<Rule>
{
boolean isActuallyToggleable = isActuallyToggable();
boolean notLastActive = getLastActivatedRule() == null || !getLastActivatedRule().equals(Rule.this);
// boolean notLastActive = getLastActivatedRule() == null || !getLastActivatedRule().equals(Rule.this);
boolean doToggle = ruleToggle && isActuallyToggleable;
String message;
@ -512,6 +529,29 @@ public class Rule implements Comparable<Rule>
if(Settings.startNewThreadForRuleActivation)
publishProgress(message);
/*
Make a note of Rule/CalendarEvent executed combinations
*/
if(Rule.this.hasTriggerOfType(Trigger.Trigger_Enum.calendarEvent))
{
for(CalendarReceiver.CalendarEvent event : CalendarReceiver.getApplyingCalendarEvents(Rule.this))
{
if(!CalendarReceiver.hasEventBeenUsedInRule(Rule.this, event))
{
/*
Record only the first calendar event that matched because the rule may
be executed once for every matching event.
*/
Miscellaneous.logEvent("i", "Rule", "Executing this rule run for calender event: " + event, 5);
CalendarReceiver.addUsedPair(new CalendarReceiver.RuleEventPair(Rule.this, event));
break;
}
}
}
/*
Run actions one after another
*/
for(int i = 0; i< Rule.this.getActionSet().size(); i++)
{
try
@ -771,4 +811,71 @@ public class Rule implements Comparable<Rule>
return null;
}
@Override
public boolean equals(@Nullable Object obj)
{
return this.getName().equals(((Rule)obj).getName());
}
public boolean hasTriggerOfType(Trigger.Trigger_Enum queryType)
{
for(Trigger t : getTriggerSet())
{
if(t.getTriggerType().equals(queryType))
return true;
}
return false;
}
public boolean hasActionOfType(Action.Action_Enum queryType)
{
for(Action a : getActionSet())
{
if(a.getAction().equals(queryType))
return true;
}
return false;
}
public int getAmountOfTriggersForType(Trigger.Trigger_Enum type)
{
int amount = 0;
for(Trigger t : getTriggerSet())
{
if(t.getTriggerType().equals(type))
amount++;
}
return amount;
}
public int getAmountOfActionsForType(Action.Action_Enum type)
{
int amount = 0;
for(Action a : getActionSet())
{
if(a.getAction().equals(type))
amount++;
}
return amount;
}
public static int getAmountOfActivatedRules()
{
int amount = 0;
for(Rule r : Rule.getRuleCollection())
{
if(r.isRuleActive())
amount++;
}
return amount;
}
}

View File

@ -1,4 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>

View File

@ -7,10 +7,11 @@ import android.util.Log;
import android.widget.Toast;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.methods.HttpGet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
public class Action
@ -19,7 +20,10 @@ public class Action
public static final String actionParameter2Split = "ap2split";
public static final String intentPairSeparator = "intPairSplit";
public static final String actionParameters2SeparatorInner = "a2splitInner";
public static final String actionParameters2SeparatorOuter = "a2splitOuter";
public static final String vibrateSeparator = ",";
public static final String httpErrorDefaultText = "HTTP_ERROR";
public enum Action_Enum
{
@ -56,6 +60,8 @@ public class Action
startPhoneCall,
stopPhoneCall,
copyToClipboard,
takeScreenshot,
setLocationService,
sendTextMessage;
public String getFullName(Context context)
@ -140,6 +146,10 @@ public class Action
return context.getResources().getString(R.string.endPhoneCall);
case copyToClipboard:
return context.getResources().getString(R.string.copyTextToClipboard);
case takeScreenshot:
return context.getResources().getString(R.string.takeScreenshot);
case setLocationService:
return context.getResources().getString(R.string.setLocationServiceCapital);
default:
return "Unknown";
}
@ -307,22 +317,61 @@ public class Action
break;
case copyToClipboard:
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.copyTextToClipboard));
break;
case takeScreenshot:
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.takeScreenshot));
break;
case setLocationService:
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.setLocationService) + ": " );
switch(Integer.parseInt(getParameter2()))
{
case android.provider.Settings.Secure.LOCATION_MODE_OFF:
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.off));
break;
case android.provider.Settings.Secure.LOCATION_MODE_SENSORS_ONLY:
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.LOCATION_MODE_SENSOR_ONLY));
break;
case android.provider.Settings.Secure.LOCATION_MODE_BATTERY_SAVING:
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.LOCATION_MODE_BATTERY_SAVING));
break;
case android.provider.Settings.Secure.LOCATION_MODE_HIGH_ACCURACY:
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.LOCATION_MODE_HIGH_ACCURACY));
break;
}
break;
default:
returnString.append(action.toString());
}
if (this.getAction().equals(Action_Enum.triggerUrl))
{
String[] components = parameter2.split(";");
String[] components;
if(parameter2.contains(Action.actionParameter2Split))
components = parameter2.split(Action.actionParameter2Split);
else
components = parameter2.split(";");
if (components.length >= 3)
{
returnString.append(" (");
if(components.length >= 4)
returnString.append(components[3]);
else
returnString.append(ActivityManageActionTriggerUrl.methodGet);
returnString.append(")");
returnString.append(": " + components[2]);
if (parameter1)
returnString.append(" " + Miscellaneous.getAnyContext().getResources().getString(R.string.usingAuthentication) + ".");
}
else
{
returnString.append(" (");
returnString.append(ActivityManageActionTriggerUrl.methodGet);;
returnString.append(")");
returnString.append(": " + components[0]);
}
}
else if (this.getAction().equals(Action_Enum.startOtherActivity))
{
@ -414,7 +463,7 @@ public class Action
{
returnString.append(": " + parameter2.replace(Action.actionParameter2Split, "; ").replace(Action.intentPairSeparator, "/"));
}
else if(this.getAction().equals(Action_Enum.setVariable) || this.getAction().equals(Action_Enum.copyToClipboard))
else if(this.getAction().equals(Action_Enum.setVariable) || this.getAction().equals(Action_Enum.copyToClipboard) || this.getAction().equals(Action_Enum.setLocationService))
; // it's completed further above already
else if (parameter2 != null && parameter2.length() > 0)
returnString.append(": " + parameter2.replace(Action.actionParameter2Split, "; "));
@ -632,6 +681,12 @@ public class Action
case copyToClipboard:
Actions.copyToClipboard(context, Miscellaneous.replaceVariablesInText(this.getParameter2(), context));
break;
case takeScreenshot:
Actions.takeScreenshot();
break;
case setLocationService:
Actions.setLocationService(Integer.parseInt(this.getParameter2()), AutomationService.getInstance());
break;
default:
Miscellaneous.logEvent("w", "Action", context.getResources().getString(R.string.unknownActionSpecified), 3);
break;
@ -645,18 +700,33 @@ public class Action
}
private void triggerUrl(Context context)
{
{
//TODO: Check if data needs to be escaped
String username = null;
String password = null;
String method = ActivityManageActionTriggerUrl.methodGet;
String url;
String params = null;
String[] components = getParameter2().split(";");
String[] components;
if(getParameter2().contains(Action.actionParameter2Split))
components = getParameter2().split(Action.actionParameter2Split, -1);
else
components = getParameter2().split(";", -1);
if(components.length >= 3)
{
username = components[0];
password = components[1];
url = components[2];
if(components.length >= 4)
method = components[3];
if(components.length >= 5)
{
params = components[4];
}
}
else // compatibility for very old versions which haven't upgraded, yet.
url = components[0];
@ -664,15 +734,21 @@ public class Action
try
{
url = Miscellaneous.replaceVariablesInText(url, context);
if(!StringUtils.isEmpty(params))
params = Miscellaneous.replaceVariablesInText(params, context);
Actions myAction = new Actions();
Miscellaneous.logEvent("i", "HTTP", "Attempting download of " + url, 4); //getResources().getString("attemptingDownloadOf");
/*
Theoretically credentials could be saved, but authentication has been turned off afterwards.
The following if clause is there to force username and password to be null.
*/
if(this.getParameter1()) // use authentication
new DownloadTask().execute(url, username, password);
new DownloadTask().execute(url, username, password, method, params);
else
new DownloadTask().execute(url, null, null);
new DownloadTask().execute(url, null, null, method, params);
}
catch(Exception e)
{
@ -687,32 +763,49 @@ public class Action
{
Thread.setDefaultUncaughtExceptionHandler(Miscellaneous.uncaughtExceptionHandler);
int attempts=1;
int attempts = 1;
String urlString=parameters[0];
String urlUsername = null;
String urlPassword = null;
String method = ActivityManageActionTriggerUrl.methodGet;
Map<String,String> httpParams = new HashMap<>();
if(parameters.length >= 3)
{
urlUsername=parameters[1];
urlPassword=parameters[2];
urlUsername = parameters[1];
urlPassword = parameters[2];
if(parameters.length >= 4)
method = parameters[3];
if(parameters.length >= 5 && parameters[4] != null)
{
// has params
String[] paramPairs = parameters[4].split(Action.actionParameters2SeparatorOuter);
for(String pair : paramPairs)
{
String[] pieces = pair.split(Action.actionParameters2SeparatorInner);
httpParams.put(pieces[0], pieces[1]);
}
}
}
String response = "httpError";
HttpGet post;
if(Settings.httpAttempts < 1)
String response = httpErrorDefaultText;
if(Settings.httpAttempts < 1)
Miscellaneous.logEvent("w", "HTTP Request", Miscellaneous.getAnyContext().getResources().getString(R.string.cantDownloadTooFewRequestsInSettings), 3);
while(attempts <= Settings.httpAttempts && response.equals("httpError"))
while(attempts <= Settings.httpAttempts && response.equals(httpErrorDefaultText))
{
Miscellaneous.logEvent("i", "HTTP Request", "Attempt " + String.valueOf(attempts++) + " of " + String.valueOf(Settings.httpAttempts), 3);
// Either thorough checking or no encryption
if(!Settings.httpAcceptAllCertificates || !urlString.toLowerCase(Locale.getDefault()).contains("https"))
response = Miscellaneous.downloadURL(urlString, urlUsername, urlPassword);
response = Miscellaneous.downloadURL(urlString, urlUsername, urlPassword, method, httpParams);
else
response = Miscellaneous.downloadURLwithoutCertificateChecking(urlString, urlUsername, urlPassword);
response = Miscellaneous.downloadUrlWithoutCertificateChecking(urlString, urlUsername, urlPassword, method, httpParams);
try
{

View File

@ -1,6 +1,7 @@
package com.jens.automation2;
import android.Manifest;
import android.accessibilityservice.AccessibilityService;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.NotificationManager;
@ -225,7 +226,16 @@ public class Actions
Map<String,String> map = AutomationService.getInstance().getVariableMap();
if(parts.length > 1)
map.put(parts[0], parts[1]);
{
try
{
map.put(parts[0], Miscellaneous.replaceVariablesInText(parts[1], Miscellaneous.getAnyContext()));
}
catch (Exception e)
{
map.put(parts[0], parts[1]);
}
}
else
map.remove(parts[0]);
}
@ -725,7 +735,6 @@ public class Actions
if (method == null)
throw new NoSuchMethodException();
/*
* For some reason this doesn't work, throws NoSuchMethodExpection even if the method is present.
*/
@ -985,6 +994,7 @@ public class Actions
public void useDownloadedWebpage(String result)
{
// Toast.makeText(context, "Result: " + result, Toast.LENGTH_LONG).show();
Actions.setVariable("last_triggerurl_result" + Action.actionParameter2Split + result);
}
public static HttpClient getInsecureSslClient(HttpClient client)
@ -1043,7 +1053,12 @@ public class Actions
{
Miscellaneous.logEvent("i", "StartOtherActivity", "Starting other Activity...", 4);
String params[] = param.split(";");
String params[];
if(param.contains(Action.actionParameter2Split))
params = param.split(Action.actionParameter2Split);
else
params = param.split(";");
try
{
@ -1977,7 +1992,6 @@ public class Actions
boolean suAvailable = false;
String suVersion = null;
String suVersionInternal = null;
// List<String> suResult = null;
int suResult;
boolean success = false;
@ -1991,12 +2005,15 @@ public class Actions
suVersionInternal = Shell.SU.version(true);
Miscellaneous.logEvent("i", "executeCommandViaSu()", "suVersion: " + suVersion + ", suVersionInternal: " + suVersionInternal, 5);
Miscellaneous.logEvent("i", "executeCommandViaSu()", "calling method: " + Miscellaneous.getCallingMethodName(), 5);
// suResult = Shell.SU.run(commands);
suResult = Shell.Pool.SU.run(commands);
// if (suResult != null)
// success = true;
if(Miscellaneous.getCallingMethodName().equals("runExecutable"))
{
Actions.setVariable("last_run_executable_exit_code" + Action.actionParameter2Split + String.valueOf(suResult));
// Actions.setVariable("last_run_executable_output" + Action.actionParameter2Split + (String) result[1]);
}
Miscellaneous.logEvent("i", "executeCommandViaSu()", "RC=" + String.valueOf(suResult), 3);
@ -2060,7 +2077,10 @@ public class Actions
else
result = runExternalApplication(path, 0, workingDir, null);
boolean execResult = (boolean) result[0];
boolean execResult = ((int) result[0] == 0);
Actions.setVariable("last_run_executable_exit_code" + Action.actionParameter2Split + String.valueOf((int) result[0]));
Actions.setVariable("last_run_executable_output" + Action.actionParameter2Split + (String) result[1]);
return execResult;
}
@ -2108,19 +2128,6 @@ public class Actions
stderr = process.getErrorStream ();
stdout = process.getInputStream ();
// "write" the parms into stdin
/*line = "param1" + "\n";
stdin.write(line.getBytes() );
stdin.flush();
line = "param2" + "\n";
stdin.write(line.getBytes() );
stdin.flush();
line = "param3" + "\n";
stdin.write(line.getBytes() );
stdin.flush();*/
stdin.close();
// clean up if any output in stdout
@ -2185,10 +2192,6 @@ public class Actions
Miscellaneous.logEvent("i", "Running executable", "Error running external application.", 1);
// if(slotMap != null)
// for(String key : slotMap.keySet())
// System.clearProperty(key);
return null;
}
@ -2281,7 +2284,18 @@ public class Actions
public static void startPhoneCall(Context context, String phoneNumber)
{
Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + Uri.encode(phoneNumber)));
Intent intent;
/*
Bug in Android 14 makes it necessary to add double quotes around MMI code.
More precisely it's required for codes containing the # character.
*/
if(Build.VERSION.SDK_INT >= 34)
intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + Uri.encode("\"" + phoneNumber + "\"")));
else
intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + Uri.encode(phoneNumber)));
// intent.setClassName("com.android.phone","com.android.phone.OutgoingCallBroadcaster");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_FROM_BACKGROUND);
@ -2334,4 +2348,26 @@ public class Actions
clipboard.setPrimaryClip(clip);
}
}
public static void takeScreenshot()
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
{
MyAccessibilityService.getInstance().performGlobalAction(AccessibilityService.GLOBAL_ACTION_TAKE_SCREENSHOT);
}
}
public static void setLocationService(int desiredState, Context context)
{
// if(desiredState)
// {
// android.provider.Settings.Secure.putString(context.getContentResolver(), android.provider.Settings.Secure.LOCATION_MODE, new Integer(android.provider.Settings.Secure.LOCATION_MODE_HIGH_ACCURACY).toString());
// }
// else
// {
// android.provider.Settings.Secure.putString(context.getContentResolver(), android.provider.Settings.Secure.LOCATION_MODE, new Integer(android.provider.Settings.Secure.LOCATION_MODE_OFF).toString());
// }
android.provider.Settings.Secure.putString(context.getContentResolver(), android.provider.Settings.Secure.LOCATION_MODE, String.valueOf(desiredState));
}
}

View File

@ -526,15 +526,23 @@ public class ActivityMainScreen extends ActivityGeneric
{
if (Rule.getRuleCollection().size() > 0)
{
if(Rule.getAmountOfActivatedRules() == 0)
{
Toast.makeText(context, context.getResources().getString(R.string.serviceWontStartNoActivatedRules), Toast.LENGTH_LONG).show();
activityMainScreenInstance.toggleService.setChecked(false);
return;
}
if (!AutomationService.isMyServiceRunning(context))
{
// if(myServiceIntent == null) //do we need that line?????
myServiceIntent = new Intent(context, AutomationService.class);
myServiceIntent.putExtra("startAtBoot", startAtBoot);
context.startService(myServiceIntent);
} else
}
else
Miscellaneous.logEvent("w", "Service", context.getResources().getString(R.string.logServiceAlreadyRunning), 3);
} else
}
else
{
Toast.makeText(context, context.getResources().getString(R.string.serviceWontStart), Toast.LENGTH_LONG).show();
activityMainScreenInstance.toggleService.setChecked(false);

View File

@ -0,0 +1,75 @@
package com.jens.automation2;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.provider.Settings;
import android.view.View;
import android.widget.Button;
import android.widget.RadioButton;
import androidx.annotation.Nullable;
public class ActivityManageActionLocationService extends Activity
{
RadioButton rbActionLocationServiceOff, rbActionLocationServiceSensorsOnly, rbActionLocationServiceBatterySaving, rbActionLocationServiceHighAccuracy;
Button bActionSetLocationServiceSave;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
setContentView(R.layout.activity_manage_action_location_service);
rbActionLocationServiceOff = (RadioButton) findViewById(R.id.rbActionLocationServiceOff);
rbActionLocationServiceSensorsOnly = (RadioButton)findViewById(R.id.rbActionLocationServiceSensorsOnly);
rbActionLocationServiceBatterySaving = (RadioButton)findViewById(R.id.rbActionLocationServiceBatterySaving);
rbActionLocationServiceHighAccuracy = (RadioButton)findViewById(R.id.rbActionLocationServiceHighAccuracy);
bActionSetLocationServiceSave = (Button) findViewById(R.id.bActionSetLocationServiceSave);
Intent input = getIntent();
if(input.hasExtra(ActivityManageRule.intentNameActionParameter2))
{
String[] params = input.getStringExtra(ActivityManageRule.intentNameActionParameter2).split(Action.actionParameter2Split);
int desiredState = Integer.parseInt(params[0]);
switch(desiredState)
{
case Settings.Secure.LOCATION_MODE_OFF:
rbActionLocationServiceOff.setChecked(true);
break;
case Settings.Secure.LOCATION_MODE_SENSORS_ONLY:
rbActionLocationServiceSensorsOnly.setChecked(true);
break;
case Settings.Secure.LOCATION_MODE_BATTERY_SAVING:
rbActionLocationServiceBatterySaving.setChecked(true);
break;
case Settings.Secure.LOCATION_MODE_HIGH_ACCURACY:
rbActionLocationServiceHighAccuracy.setChecked(true);
break;
}
}
bActionSetLocationServiceSave.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View view)
{
Intent response = new Intent();
if(rbActionLocationServiceOff.isChecked())
response.putExtra(ActivityManageRule.intentNameActionParameter2, String.valueOf(Settings.Secure.LOCATION_MODE_OFF));
else if(rbActionLocationServiceSensorsOnly.isChecked())
response.putExtra(ActivityManageRule.intentNameActionParameter2, String.valueOf(Settings.Secure.LOCATION_MODE_SENSORS_ONLY));
else if(rbActionLocationServiceBatterySaving.isChecked())
response.putExtra(ActivityManageRule.intentNameActionParameter2, String.valueOf(Settings.Secure.LOCATION_MODE_BATTERY_SAVING));
else
response.putExtra(ActivityManageRule.intentNameActionParameter2, String.valueOf(Settings.Secure.LOCATION_MODE_HIGH_ACCURACY));
setResult(RESULT_OK, response);
finish();
}
});
}
}

View File

@ -236,8 +236,6 @@ public class ActivityManageActionSendBroadcast extends Activity
@Override
public void onNothingSelected(AdapterView<?> arg0)
{
// TODO Auto-generated method stub
}
});
}

View File

@ -1,6 +1,6 @@
package com.jens.automation2;
import static com.jens.automation2.ActivityManageActionTriggerUrl.edit;
//import static com.jens.automation2.ActivityManageActionTriggerUrl.edit;
import android.app.Activity;
import android.content.Intent;

View File

@ -58,10 +58,10 @@ public class ActivityManageActionStartActivity extends Activity
RadioButton rbStartAppSelectByActivity, rbStartAppSelectByAction, rbStartAppByActivity, rbStartAppByBroadcast, rbStartAppByService, rbStartAppByForegroundService;
final String urlShowExamples = "https://server47.de/automation/examples_startProgram.html";
final static String startByActivityString = "0";
final static String startByBroadcastString = "1";
final static String startByServiceString = "2";
final static String startByForegroundServiceString = "3";
public final static String startByActivityString = "0";
public final static String startByBroadcastString = "1";
public final static String startByServiceString = "2";
public final static String startByForegroundServiceString = "3";
final static int requestCodeForRequestQueryAllPackagesPermission = 4711;
@ -234,29 +234,28 @@ public class ActivityManageActionStartActivity extends Activity
String parameter2 = "";
if (rbStartAppSelectByActivity.isChecked())
parameter2 += etPackageName.getText().toString() + ";" + etActivityOrActionPath.getText().toString();
parameter2 += etPackageName.getText().toString() + Action.actionParameter2Split + etActivityOrActionPath.getText().toString();
else
{
if (etPackageName.getText().toString() != null && etPackageName.getText().toString().length() > 0)
parameter2 += etPackageName.getText().toString() + ";" + etActivityOrActionPath.getText().toString();
parameter2 += etPackageName.getText().toString() + Action.actionParameter2Split + etActivityOrActionPath.getText().toString();
else
parameter2 += Actions.dummyPackageString + ";" + etActivityOrActionPath.getText().toString();
parameter2 += Actions.dummyPackageString + Action.actionParameter2Split + etActivityOrActionPath.getText().toString();
// if(etClassName.getText().toString().length() > 0)
parameter2 += ";" + etClassName.getText().toString();
parameter2 += Action.actionParameter2Split + etClassName.getText().toString();
}
if (rbStartAppByActivity.isChecked())
parameter2 += ";" + startByActivityString;
parameter2 += Action.actionParameter2Split + startByActivityString;
else if(rbStartAppByService.isChecked())
parameter2 += ";" + startByServiceString;
parameter2 += Action.actionParameter2Split + startByServiceString;
else if(rbStartAppByForegroundService.isChecked())
parameter2 += ";" + startByForegroundServiceString;
parameter2 += Action.actionParameter2Split + startByForegroundServiceString;
else
parameter2 += ";" + startByBroadcastString;
parameter2 += Action.actionParameter2Split + startByBroadcastString;
for (String s : intentPairList)
parameter2 += ";" + s;
parameter2 += Action.actionParameter2Split + s;
returnData.putExtra(ActivityManageRule.intentNameActionParameter2, parameter2);
@ -292,8 +291,6 @@ public class ActivityManageActionStartActivity extends Activity
@Override
public void onNothingSelected(AdapterView<?> arg0)
{
// TODO Auto-generated method stub
}
});
@ -628,7 +625,13 @@ public class ActivityManageActionStartActivity extends Activity
rbStartAppSelectByActivity.setChecked(!selectionByAction);
rbStartAppSelectByAction.setChecked(selectionByAction);
String[] params = input.getStringExtra(ActivityManageRule.intentNameActionParameter2).split(";");
String[] params;
String partsString = input.getStringExtra(ActivityManageRule.intentNameActionParameter2);
if(partsString.contains(Action.actionParameter2Split))
params = partsString.split(Action.actionParameter2Split);
else
params = partsString.split(";");
if(Miscellaneous.isNumeric(params[2])) // old configuration file
{

View File

@ -1,6 +1,10 @@
package com.jens.automation2;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
@ -13,27 +17,37 @@ import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.RadioButton;
import android.widget.TableLayout;
import android.widget.Toast;
import androidx.annotation.NonNull;
import com.jens.automation2.Action.Action_Enum;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.Map;
public class ActivityManageActionTriggerUrl extends Activity
{
Button bSaveTriggerUrl;
EditText etTriggerUrl, etTriggerUrlUsername, etTriggerUrlPassword;
Button bSaveTriggerUrl, bAddHttpParam;
EditText etTriggerUrl, etTriggerUrlUsername, etTriggerUrlPassword, etParameterName, etParameterValue;
ListView lvTriggerUrlPostParameters;
CheckBox chkTriggerUrlUseAuthentication;
RadioButton rbTriggerUrlMethodGet, rbTriggerUrlMethodPost;
TableLayout tlTriggerUrlAuthentication;
ArrayAdapter<String> httpParametersAdapter;
private ArrayList<String> httpParamsList = new ArrayList<>();
ArrayAdapter<Map<String,String>> lvTriggerUrlPostParametersAdapter;
public static final String methodGet = "GET";
public static final String methodPost = "POST";
// private String existingUrl = "";
public static boolean edit = false;
public static Action resultingAction = null;
// public static boolean edit = false;
// public static Action resultingAction = null;
@Override
protected void onCreate(Bundle savedInstanceState)
@ -49,6 +63,32 @@ public class ActivityManageActionTriggerUrl extends Activity
lvTriggerUrlPostParameters = (ListView)findViewById(R.id.lvTriggerUrlPostParameters);
tlTriggerUrlAuthentication = (TableLayout)findViewById(R.id.tlTriggerUrlAuthentication);
bSaveTriggerUrl = (Button)findViewById(R.id.bSaveSpeakText);
rbTriggerUrlMethodGet = (RadioButton) findViewById(R.id.rbTriggerUrlMethodGet);
rbTriggerUrlMethodPost = (RadioButton) findViewById(R.id.rbTriggerUrlMethodPost);
etTriggerUrl = (EditText) findViewById(R.id.etTriggerUrl);
etParameterName = (EditText) findViewById(R.id.etParameterName);
etParameterValue = (EditText)findViewById(R.id.etParameterValue);
bAddHttpParam = (Button)findViewById(R.id.bAddHttpParam);
etParameterName.setEnabled(false);
etParameterValue.setEnabled(false);
bAddHttpParam.setEnabled(false);
rbTriggerUrlMethodPost.setOnCheckedChangeListener(new OnCheckedChangeListener()
{
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked)
{
etParameterName.setEnabled(checked);
etParameterValue.setEnabled(checked);
bAddHttpParam.setEnabled(checked);
if(checked)
lvTriggerUrlPostParameters.setVisibility(View.VISIBLE);
}
});
httpParametersAdapter = new ArrayAdapter<String>(this, R.layout.text_view_for_poi_listview_mediumtextsize, httpParamsList);
bSaveTriggerUrl.setOnClickListener(new OnClickListener()
{
@Override
@ -56,44 +96,64 @@ public class ActivityManageActionTriggerUrl extends Activity
{
if(etTriggerUrl.getText().toString().length() > 0)
{
if(resultingAction == null)
{
resultingAction = new Action();
resultingAction.setAction(Action_Enum.triggerUrl);
resultingAction.setParameter1(chkTriggerUrlUseAuthentication.isChecked());
String username = etTriggerUrlUsername.getText().toString();
String password = etTriggerUrlPassword.getText().toString();
if(username == null)
username = "";
if(password == null)
password = "";
ActivityManageActionTriggerUrl.resultingAction.setParameter2(
username + ";" +
password + ";" +
etTriggerUrl.getText().toString().trim()
);
}
backToRuleManager();
Intent returnIntent = new Intent();
returnIntent.putExtra(ActivityManageRule.intentNameActionParameter1, chkTriggerUrlUseAuthentication.isChecked());
String username = etTriggerUrlUsername.getText().toString();
String password = etTriggerUrlPassword.getText().toString();
if(username == null)
username = "";
if(password == null)
password = "";
String method = methodGet;
if(rbTriggerUrlMethodPost.isChecked())
method = methodPost;
String httpParams = "";
for (String s : httpParamsList)
httpParams += Action.actionParameters2SeparatorOuter + s;
if(httpParams.length() > 0)
httpParams = httpParams.substring(Action.actionParameters2SeparatorOuter.length());
returnIntent.putExtra(ActivityManageRule.intentNameActionParameter2,
username + Action.actionParameter2Split +
password + Action.actionParameter2Split +
etTriggerUrl.getText().toString().trim() + Action.actionParameter2Split +
method + Action.actionParameter2Split +
httpParams
);
setResult(RESULT_OK, returnIntent);
finish();
}
else
Toast.makeText(getBaseContext(), getResources().getString(R.string.urlTooShort), Toast.LENGTH_LONG).show();
}
});
chkTriggerUrlUseAuthentication.setOnCheckedChangeListener(new OnCheckedChangeListener()
{
{
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
{
if(isChecked)
{
tlTriggerUrlAuthentication.setVisibility(View.VISIBLE);
rbTriggerUrlMethodGet.setChecked(false);
rbTriggerUrlMethodPost.setChecked(true);
rbTriggerUrlMethodGet.setEnabled(false);
rbTriggerUrlMethodPost.setEnabled(false);
}
else
{
tlTriggerUrlAuthentication.setVisibility(View.GONE);
rbTriggerUrlMethodGet.setEnabled(true);
rbTriggerUrlMethodPost.setEnabled(true);
}
etTriggerUrlUsername.setEnabled(isChecked);
etTriggerUrlPassword.setEnabled(isChecked);
@ -110,52 +170,86 @@ public class ActivityManageActionTriggerUrl extends Activity
});
updateListView();
ActivityManageActionTriggerUrl.edit = getIntent().getBooleanExtra("edit", false);
if(edit)
if(getIntent().hasExtra(ActivityManageRule.intentNameActionParameter2))
{
// username,password,URL
String[] components = ActivityManageActionTriggerUrl.resultingAction.getParameter2().split(";");
// username,password,URL,etc.
String[] components;
if(getIntent().getStringExtra(ActivityManageRule.intentNameActionParameter2).contains(Action.actionParameter2Split))
components = getIntent().getStringExtra(ActivityManageRule.intentNameActionParameter2).split(Action.actionParameter2Split, -1);
else
components = getIntent().getStringExtra(ActivityManageRule.intentNameActionParameter2).split(";", -1);
if(components.length >= 3)
{
etTriggerUrl.setText(components[2]);
chkTriggerUrlUseAuthentication.setChecked(ActivityManageActionTriggerUrl.resultingAction.getParameter1());
etTriggerUrl.setText(components[2]);
chkTriggerUrlUseAuthentication.setChecked(getIntent().getBooleanExtra(ActivityManageRule.intentNameActionParameter1, false));
etTriggerUrlUsername.setText(components[0]);
etTriggerUrlPassword.setText(components[1]);
if(components.length >= 4)
{
switch(components[3])
{
case methodPost:
rbTriggerUrlMethodPost.setChecked(true);
break;
case methodGet:
default:
rbTriggerUrlMethodGet.setChecked(true);
break;
}
}
if(components.length >= 5)
{
if(!StringUtils.isEmpty(components[4]) && components[4].contains(Action.actionParameters2SeparatorInner))
{
String httpParams[] = components[4].split(Action.actionParameters2SeparatorOuter);
for (String paramPair : httpParams)
httpParamsList.add(paramPair);
updateHttpParamsList();
}
}
}
else
etTriggerUrl.setText(components[0]);
}
}
private void backToRuleManager()
{
if(edit && resultingAction != null)
bAddHttpParam.setOnClickListener(new OnClickListener()
{
String username = etTriggerUrlUsername.getText().toString();
String password = etTriggerUrlPassword.getText().toString();
if(username == null)
username = "";
if(password == null)
password = "";
ActivityManageActionTriggerUrl.resultingAction.setParameter1(chkTriggerUrlUseAuthentication.isChecked());
ActivityManageActionTriggerUrl.resultingAction.setParameter2(
username + ";" +
password + ";" +
etTriggerUrl.getText().toString()
);
}
setResult(RESULT_OK);
this.finish();
@Override
public void onClick(View view)
{
if(StringUtils.isEmpty(etParameterName.getText()) || StringUtils.isEmpty(etParameterValue.getText()))
{
Toast.makeText(ActivityManageActionTriggerUrl.this, getResources().getString(R.string.enterValidDataIntoParametersFields), Toast.LENGTH_SHORT).show();
return;
}
httpParamsList.add(etParameterName.getText() + Action.actionParameters2SeparatorInner + etParameterValue.getText());
updateHttpParamsList();
etParameterName.setText("");
etParameterValue.setText("");
if(lvTriggerUrlPostParameters.getVisibility() != View.VISIBLE)
lvTriggerUrlPostParameters.setVisibility(View.VISIBLE);
}
});
lvTriggerUrlPostParameters.setOnItemLongClickListener(new OnItemLongClickListener()
{
@Override
public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int arg2, long arg3)
{
getHttpParamsDialog(arg2).show();
return false;
}
});
}
private void updateListView()
{
Miscellaneous.logEvent("i", "ListView", "Attempting to update lvTriggerUrlPostParameters", 4);
@ -163,10 +257,36 @@ public class ActivityManageActionTriggerUrl extends Activity
{
if(lvTriggerUrlPostParameters.getAdapter() == null)
lvTriggerUrlPostParameters.setAdapter(lvTriggerUrlPostParametersAdapter);
lvTriggerUrlPostParametersAdapter.notifyDataSetChanged();
}
catch(NullPointerException e)
{}
}
private void updateHttpParamsList()
{
if(lvTriggerUrlPostParameters.getAdapter() == null)
lvTriggerUrlPostParameters.setAdapter(httpParametersAdapter);
httpParametersAdapter.notifyDataSetChanged();
}
private AlertDialog getHttpParamsDialog(final int itemPosition)
{
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(ActivityManageActionTriggerUrl.this);
alertDialogBuilder.setTitle(getResources().getString(R.string.whatToDoWithIntentPair));
alertDialogBuilder.setItems(new String[]{getResources().getString(R.string.delete)}, new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
// Only 1 choice at the moment, no need to check
ActivityManageActionTriggerUrl.this.httpParamsList.remove(itemPosition);
updateHttpParamsList();
}
});
AlertDialog alertDialog = alertDialogBuilder.create();
return alertDialog;
}
}

View File

@ -411,22 +411,16 @@ public class ActivityManagePoi extends Activity
@Override
public void onProviderDisabled(String provider)
{
// TODO Auto-generated method stub
}
@Override
public void onProviderEnabled(String provider)
{
// TODO Auto-generated method stub
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras)
{
// TODO Auto-generated method stub
}
}
@ -454,22 +448,16 @@ public class ActivityManagePoi extends Activity
@Override
public void onProviderDisabled(String provider)
{
// TODO Auto-generated method stub
}
@Override
public void onProviderEnabled(String provider)
{
// TODO Auto-generated method stub
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras)
{
// TODO Auto-generated method stub
}
}

View File

@ -141,6 +141,12 @@ public class ActivityManageRule extends Activity
final static int requestCodeTriggerCheckVariableEdit = 828;
final static int requestCodeActionCopyTextToClipboardAdd = 829;
final static int requestCodeActionCopyTextToClipboardEdit = 830;
final static int requestCodeActionSetLocationServiceAdd = 831;
final static int requestCodeActionSetLocationServiceEdit = 832;
final static int requestCodeTriggerCalendarEventAdd = 833;
final static int requestCodeTriggerCalendarEventEdit = 834;
final static int requestCodeTriggerChargingAdd = 835;
final static int requestCodeTriggerChargingEdit = 836;
public static ActivityManageRule getInstance()
{
@ -345,6 +351,18 @@ public class ActivityManageRule extends Activity
variableStateEditor.putExtra(intentNameTriggerParameter2, selectedTrigger.getTriggerParameter2());
startActivityForResult(variableStateEditor, requestCodeTriggerCheckVariableEdit);
break;
case calendarEvent:
Intent calendarStateEditor = new Intent(ActivityManageRule.this, ActivityManageTriggerCalendar.class);
calendarStateEditor.putExtra(intentNameTriggerParameter1, selectedTrigger.getTriggerParameter());
calendarStateEditor.putExtra(intentNameTriggerParameter2, selectedTrigger.getTriggerParameter2());
startActivityForResult(calendarStateEditor, requestCodeTriggerCalendarEventEdit);
break;
case charging:
Intent chargingStateEditor = new Intent(ActivityManageRule.this, ActivityManageTriggerCharging.class);
chargingStateEditor.putExtra(intentNameTriggerParameter1, selectedTrigger.getTriggerParameter());
chargingStateEditor.putExtra(intentNameTriggerParameter2, selectedTrigger.getTriggerParameter2());
startActivityForResult(chargingStateEditor, requestCodeTriggerChargingEdit);
break;
default:
break;
}
@ -386,9 +404,8 @@ public class ActivityManageRule extends Activity
break;
case triggerUrl:
Intent activityEditTriggerUrlIntent = new Intent(ActivityManageRule.this, ActivityManageActionTriggerUrl.class);
ActivityManageActionTriggerUrl.resultingAction = a;
ActivityManageActionTriggerUrl.resultingAction.setParentRule(ruleToEdit);
activityEditTriggerUrlIntent.putExtra("edit", true);
activityEditTriggerUrlIntent.putExtra(intentNameActionParameter1, a.getParameter1());
activityEditTriggerUrlIntent.putExtra(intentNameActionParameter2, a.getParameter2());
startActivityForResult(activityEditTriggerUrlIntent, requestCodeActionTriggerUrlEdit);
break;
case speakText:
@ -478,6 +495,12 @@ public class ActivityManageRule extends Activity
actionCopyToClipboardIntent.putExtra(intentNameActionParameter2, a.getParameter2());
startActivityForResult(actionCopyToClipboardIntent, requestCodeActionCopyTextToClipboardEdit);
break;
case setLocationService:
Intent actionSetLocationServiceIntent = new Intent(context, ActivityManageActionLocationService.class);
// actionSetLocationServiceIntent.putExtra(intentNameActionParameter1, a.getParameter1());
actionSetLocationServiceIntent.putExtra(intentNameActionParameter2, a.getParameter2());
startActivityForResult(actionSetLocationServiceIntent, requestCodeActionSetLocationServiceEdit);
break;
default:
Miscellaneous.logEvent("w", "Edit action", "Editing of action type " + a.getAction().toString() + " not implemented, yet.", 4);
break;
@ -628,6 +651,10 @@ public class ActivityManageRule extends Activity
items.add(new Item(typesLong[i].toString(), R.drawable.router));
else if(types[i].toString().equals(Trigger_Enum.subSystemState.toString()))
items.add(new Item(typesLong[i].toString(), R.drawable.subsystemstate));
else if(types[i].toString().equals(Trigger_Enum.checkVariable.toString()))
items.add(new Item(typesLong[i].toString(), R.drawable.variable));
else if(types[i].toString().equals(Trigger_Enum.calendarEvent.toString()))
items.add(new Item(typesLong[i].toString(), R.drawable.calendar));
else
items.add(new Item(typesLong[i].toString(), R.drawable.placeholder));
}
@ -636,15 +663,15 @@ public class ActivityManageRule extends Activity
{
public View getView(int position, View convertView, ViewGroup parent)
{
//User super class to create the View
// User super class to create the View
View v = super.getView(position, convertView, parent);
TextView tv = (TextView)v.findViewById(android.R.id.text1);
//Put the image on the TextView
// Put the image on the TextView
tv.setCompoundDrawablesWithIntrinsicBounds(items.get(position).icon, 0, 0, 0);
//Add margin between image and text (support various screen densities)
// Add margin between image and text (support various screen densities)
int dp5 = (int) (5 * getResources().getDisplayMetrics().density + 0.5f);
tv.setCompoundDrawablePadding(dp5);
@ -688,7 +715,14 @@ public class ActivityManageRule extends Activity
startActivityForResult(timeFrameEditor, requestCodeTriggerTimeframeAdd);
return;
}
else if(triggerType == Trigger_Enum.charging || triggerType == Trigger_Enum.musicPlaying)
else if(triggerType == Trigger_Enum.charging)
{
newTrigger.setTriggerType(Trigger_Enum.charging);
Intent triggerChargingIntent = new Intent(myContext, ActivityManageTriggerCharging.class);
startActivityForResult(triggerChargingIntent, requestCodeTriggerChargingAdd);
return;
}
else if(triggerType == Trigger_Enum.musicPlaying)
booleanChoices = new String[]{getResources().getString(R.string.started), getResources().getString(R.string.stopped)};
else if(triggerType == Trigger_Enum.usb_host_connection)
booleanChoices = new String[]{getResources().getString(R.string.connected), getResources().getString(R.string.disconnected)};
@ -853,6 +887,13 @@ public class ActivityManageRule extends Activity
startActivityForResult(variableTriggerEditor, requestCodeTriggerCheckVariableAdd);
return;
}
else if(triggerType == Trigger_Enum.calendarEvent)
{
newTrigger.setTriggerType(Trigger_Enum.calendarEvent);
Intent calendarTriggerEditor = new Intent(myContext, ActivityManageTriggerCalendar.class);
startActivityForResult(calendarTriggerEditor, requestCodeTriggerCalendarEventAdd);
return;
}
else
getTriggerParameterDialog(context, booleanChoices).show();
@ -1355,9 +1396,11 @@ public class ActivityManageRule extends Activity
{
if(resultCode == RESULT_OK)
{
//add TriggerUrl
ActivityManageActionTriggerUrl.resultingAction.setParentRule(ruleToEdit);
ruleToEdit.getActionSet().add(ActivityManageActionTriggerUrl.resultingAction);
newAction.setParentRule(ruleToEdit);
newAction.setAction(Action_Enum.triggerUrl);
newAction.setParameter1(data.getBooleanExtra(intentNameActionParameter1, true));
newAction.setParameter2(data.getStringExtra(intentNameActionParameter2));
ruleToEdit.getActionSet().add(newAction);
this.refreshActionList();
}
}
@ -1365,7 +1408,14 @@ public class ActivityManageRule extends Activity
{
if(resultCode == RESULT_OK)
{
//edit TriggerUrl
ruleToEdit.getActionSet().get(editIndex).setParentRule(ruleToEdit);
if(data.hasExtra(intentNameActionParameter1))
ruleToEdit.getActionSet().get(editIndex).setParameter1(data.getBooleanExtra(intentNameActionParameter1, true));
if(data.hasExtra(intentNameActionParameter2))
ruleToEdit.getActionSet().get(editIndex).setParameter2(data.getStringExtra(intentNameActionParameter2));
this.refreshActionList();
}
}
@ -1422,6 +1472,30 @@ public class ActivityManageRule extends Activity
this.refreshTriggerList();
}
}
else if(requestCode == requestCodeTriggerChargingAdd)
{
if(resultCode == RESULT_OK)
{
newTrigger.setTriggerParameter(data.getBooleanExtra(ActivityManageRule.intentNameTriggerParameter1, false));
newTrigger.setTriggerParameter2(data.getStringExtra(ActivityManageRule.intentNameTriggerParameter2));
newTrigger.setParentRule(ruleToEdit);
ruleToEdit.getTriggerSet().add(newTrigger);
this.refreshTriggerList();
}
}
else if(requestCode == requestCodeTriggerChargingEdit)
{
if(resultCode == RESULT_OK)
{
Trigger responseTimeFrame = new Trigger();
responseTimeFrame.setTriggerType(Trigger_Enum.charging);
responseTimeFrame.setTriggerParameter(data.getBooleanExtra(intentNameTriggerParameter1, true));
responseTimeFrame.setTriggerParameter2(data.getStringExtra(intentNameTriggerParameter2));
responseTimeFrame.setParentRule(ruleToEdit);
ruleToEdit.getTriggerSet().set(editIndex, responseTimeFrame);
this.refreshTriggerList();
}
}
else if(requestCode == requestCodeActionStartActivityAdd)
{
// manage start of other activity
@ -1986,6 +2060,17 @@ public class ActivityManageRule extends Activity
this.refreshTriggerList();
}
}
else if(requestCode == requestCodeTriggerCalendarEventAdd)
{
if(resultCode == RESULT_OK)
{
newTrigger.setTriggerParameter(data.getBooleanExtra(intentNameTriggerParameter1, true));
newTrigger.setTriggerParameter2(data.getStringExtra(intentNameTriggerParameter2));
newTrigger.setParentRule(ruleToEdit);
ruleToEdit.getTriggerSet().add(newTrigger);
this.refreshTriggerList();
}
}
else if(requestCode == requestCodeTriggerTetheringEdit)
{
if(resultCode == RESULT_OK)
@ -2025,6 +2110,19 @@ public class ActivityManageRule extends Activity
this.refreshTriggerList();
}
}
else if(requestCode == requestCodeTriggerCalendarEventEdit)
{
if(resultCode == RESULT_OK)
{
Trigger editedTrigger = new Trigger();
editedTrigger.setTriggerType(Trigger_Enum.calendarEvent);
editedTrigger.setTriggerParameter(data.getBooleanExtra(intentNameTriggerParameter1, true));
editedTrigger.setTriggerParameter2(data.getStringExtra(intentNameTriggerParameter2));
editedTrigger.setParentRule(ruleToEdit);
ruleToEdit.getTriggerSet().set(editIndex, editedTrigger);
this.refreshTriggerList();
}
}
else if(requestCode == requestCodeActionCopyTextToClipboardAdd)
{
if(resultCode == RESULT_OK)
@ -2047,6 +2145,32 @@ public class ActivityManageRule extends Activity
ruleToEdit.getActionSet().get(editIndex).setParameter2(data.getStringExtra(intentNameActionParameter2));
}
this.refreshActionList();
}
}
else if(requestCode == requestCodeActionSetLocationServiceAdd)
{
if(resultCode == RESULT_OK)
{
newAction.setParentRule(ruleToEdit);
// newAction.setParameter1(data.getBooleanExtra(intentNameActionParameter1, false));
newAction.setParameter2(data.getStringExtra(intentNameActionParameter2));
ruleToEdit.getActionSet().add(newAction);
this.refreshActionList();
}
}
else if(requestCode == requestCodeActionSetLocationServiceEdit)
{
if(resultCode == RESULT_OK)
{
ruleToEdit.getActionSet().get(editIndex).setParentRule(ruleToEdit);
// ruleToEdit.getActionSet().get(editIndex).setParameter1(data.getBooleanExtra(intentNameActionParameter1, false));
if(data.hasExtra(intentNameActionParameter2))
{
ruleToEdit.getActionSet().get(editIndex).setParameter2(data.getStringExtra(intentNameActionParameter2));
}
this.refreshActionList();
}
}
@ -2126,6 +2250,12 @@ public class ActivityManageRule extends Activity
}
else if(types[i].toString().equals(Action_Enum.copyToClipboard.toString()))
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()))
items.add(new Item(typesLong[i].toString(), R.drawable.variable));
else if(types[i].toString().equals(Action_Enum.setLocationService.toString()))
items.add(new Item(typesLong[i].toString(), R.drawable.compass_small));
else
items.add(new Item(typesLong[i].toString(), R.drawable.placeholder));
}
@ -2162,7 +2292,7 @@ public class ActivityManageRule extends Activity
{
//launch other activity to enter a url and parameters;
newAction.setAction(Action_Enum.triggerUrl);
ActivityManageActionTriggerUrl.resultingAction = null;
// ActivityManageActionTriggerUrl.resultingAction = null;
Intent editTriggerIntent = new Intent(context, ActivityManageActionTriggerUrl.class);
startActivityForResult(editTriggerIntent, requestCodeActionTriggerUrlAdd);
}
@ -2352,6 +2482,18 @@ public class ActivityManageRule extends Activity
Intent intent = new Intent(ActivityManageRule.this, ActivityManageActionCopyToClipboard.class);
startActivityForResult(intent, requestCodeActionCopyTextToClipboardAdd);
}
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.takeScreenshot.toString()))
{
newAction.setAction(Action_Enum.takeScreenshot);
ruleToEdit.getActionSet().add(newAction);
refreshActionList();
}
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.setLocationService.toString()))
{
newAction.setAction(Action_Enum.setLocationService);
Intent intent = new Intent(ActivityManageRule.this, ActivityManageActionLocationService.class);
startActivityForResult(intent, requestCodeActionSetLocationServiceAdd);
}
}
});

View File

@ -0,0 +1,404 @@
package com.jens.automation2;
import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.provider.CalendarContract;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.jens.automation2.receivers.CalendarReceiver;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.List;
public class ActivityManageTriggerCalendar extends Activity
{
CheckBox chkCalendarEventActive, chkCalendarAvailabilityBusy, chkCalendarAvailabilityFree, chkCalendarAvailabilityTentative, chkCalendarAvailabilityOutOfOffice, chkCalendarAvailabilityWorkingElsewhere, chkCalendarAllDayEvent, chkCalendarEvaluateAllDayEvent, chkCalendarEvaluateReoccurring, chkCalendarReoccurring;
Spinner spinnerCalendarTitleDirection, spinnerCalendarLocationDirection, spinnerCalendarDescriptionDirection;
EditText etCalendarTitle, etCalendarLocation, etCalendarDescription;
LinearLayout llCalendarSelection;
Button bSaveTriggerCalendar;
List<CheckBox> checkboxesCalendars = new ArrayList<>();
final static String separator = ",";
TextView tvMissingCalendarHint;
private static String[] directions;
ArrayAdapter<String> directionSpinnerAdapter;
public static int requestCodePermissionReadCalendar = 815;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
setContentView(R.layout.activity_manage_trigger_calendar);
chkCalendarEventActive = (CheckBox) findViewById(R.id.chkCalendarEventActive);
spinnerCalendarTitleDirection = (Spinner)findViewById(R.id.spinnerCalendarTitleDirection);
spinnerCalendarLocationDirection = (Spinner)findViewById(R.id.spinnerCalendarLocationDirection);
spinnerCalendarDescriptionDirection = (Spinner)findViewById(R.id.spinnerCalendarDescriptionDirection);
chkCalendarAllDayEvent = (CheckBox)findViewById(R.id.chkCalendarAllDayEvent);
chkCalendarAvailabilityBusy = (CheckBox)findViewById(R.id.chkCalendarAvailabilityBusy);
chkCalendarAvailabilityFree = (CheckBox)findViewById(R.id.chkCalendarAvailabilityFree);
chkCalendarAvailabilityTentative = (CheckBox)findViewById(R.id.chkCalendarAvailabilityTentative);
chkCalendarAvailabilityOutOfOffice = (CheckBox)findViewById(R.id.chkCalendarAvailabilityOutOfOffice);
chkCalendarAvailabilityWorkingElsewhere = (CheckBox)findViewById(R.id.chkCalendarAvailabilityWorkingElsewhere);
chkCalendarEvaluateAllDayEvent = (CheckBox)findViewById(R.id.chkCalendarEvaluateAllDayEvent);
chkCalendarEvaluateReoccurring = (CheckBox)findViewById(R.id.chkCalendarEvaluateReoccurring);
chkCalendarReoccurring = (CheckBox)findViewById(R.id.chkCalendarReoccurring);
tvMissingCalendarHint = (TextView) findViewById(R.id.tvMissingCalendarHint);
llCalendarSelection = (LinearLayout)findViewById(R.id.llCalendarSelection);
etCalendarTitle = (EditText)findViewById(R.id.etCalendarTitle);
etCalendarLocation = (EditText)findViewById(R.id.etCalendarLocation);
etCalendarDescription = (EditText)findViewById(R.id.etCalendarDescription);
bSaveTriggerCalendar = (Button)findViewById(R.id.bSaveTriggerCalendar);
directions = new String[] {
getResources().getString(R.string.directionStringEquals),
getResources().getString(R.string.directionStringContains),
getResources().getString(R.string.directionStringDoesNotContain),
getResources().getString(R.string.directionStringStartsWith),
getResources().getString(R.string.directionStringEndsWith),
getResources().getString(R.string.directionStringNotEquals)
};
directionSpinnerAdapter = new ArrayAdapter<>(this, R.layout.text_view_for_poi_listview_mediumtextsize, ActivityManageTriggerCalendar.directions);
spinnerCalendarTitleDirection.setAdapter(directionSpinnerAdapter);
spinnerCalendarLocationDirection.setAdapter(directionSpinnerAdapter);
spinnerCalendarDescriptionDirection.setAdapter(directionSpinnerAdapter);
directionSpinnerAdapter.notifyDataSetChanged();
chkCalendarEvaluateAllDayEvent.setChecked(false);
chkCalendarAllDayEvent.setEnabled(false);
chkCalendarEvaluateAllDayEvent.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener()
{
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked)
{
chkCalendarAllDayEvent.setEnabled(checked);
}
});
chkCalendarEvaluateReoccurring.setChecked(false);
chkCalendarReoccurring.setEnabled(false);
chkCalendarEvaluateReoccurring.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener()
{
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked)
{
chkCalendarReoccurring.setEnabled(checked);
}
});
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
{
if(ActivityPermissions.havePermission(Manifest.permission.READ_CALENDAR, ActivityManageTriggerCalendar.this) || ActivityPermissions.havePermission(Manifest.permission.WRITE_CALENDAR, ActivityManageTriggerCalendar.this))
populateCalenderCheckboxes();
else
{
AlertDialog.Builder builder = new AlertDialog.Builder(ActivityManageTriggerCalendar.this);
builder.setTitle(getResources().getString(R.string.info));
builder.setMessage(getResources().getString(R.string.permissionCalendarRequired));
builder.setNegativeButton(getResources().getString(R.string.cancel), new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialogInterface, int i)
{
ActivityManageTriggerCalendar.this.finish();
}
});
builder.setPositiveButton(getResources().getString(R.string.ok), new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialogInterface, int i)
{
requestPermissions(new String[]{ Manifest.permission.READ_CALENDAR } , requestCodePermissionReadCalendar);
}
});
builder.show();
}
}
else
populateCalenderCheckboxes();
chkCalendarEventActive.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener()
{
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked)
{
if(checked)
chkCalendarEventActive.setText(R.string.eventIsCurrentlyHappening);
else
chkCalendarEventActive.setText(R.string.eventIsCurrentlyNotHappening);
}
});
chkCalendarAllDayEvent.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener()
{
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked)
{
if(checked)
chkCalendarAllDayEvent.setText(getResources().getString(R.string.allDayEventTrue));
else
chkCalendarAllDayEvent.setText(getResources().getString(R.string.allDayEventFalse));
}
});
chkCalendarReoccurring.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener()
{
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked)
{
if(checked)
chkCalendarReoccurring.setText(R.string.reoccurringTrue);
else
chkCalendarReoccurring.setText(R.string.reoccurringFalse);
}
});
bSaveTriggerCalendar.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View view)
{
String titleDir = Trigger.getMatchCode(spinnerCalendarTitleDirection.getSelectedItem().toString());
String title = etCalendarTitle.getText().toString();
String descriptionDir = Trigger.getMatchCode(spinnerCalendarDescriptionDirection.getSelectedItem().toString());
String description = etCalendarDescription.getText().toString();
String locationDir = Trigger.getMatchCode(spinnerCalendarLocationDirection.getSelectedItem().toString());
String location = etCalendarLocation.getText().toString();
List<String> availabilityList = new ArrayList<>();
if(chkCalendarAvailabilityBusy.isChecked())
availabilityList.add(String.valueOf(CalendarContract.Events.AVAILABILITY_BUSY));
if(chkCalendarAvailabilityFree.isChecked())
availabilityList.add(String.valueOf(CalendarContract.Events.AVAILABILITY_FREE));
if(chkCalendarAvailabilityTentative.isChecked())
availabilityList.add(String.valueOf(CalendarContract.Events.AVAILABILITY_TENTATIVE));
if(chkCalendarAvailabilityOutOfOffice.isChecked())
availabilityList.add(String.valueOf(CalendarReceiver.AVAILABILITY_OUT_OF_OFFICE));
if(chkCalendarAvailabilityWorkingElsewhere.isChecked())
availabilityList.add(String.valueOf(CalendarReceiver.AVAILABILITY_WORKING_ELSEWHERE));
List<CalendarReceiver.AndroidCalendar> selectedCalendarsList = new ArrayList<>();
for(CheckBox calCheckbox : checkboxesCalendars)
{
if(calCheckbox.isChecked())
selectedCalendarsList.add((CalendarReceiver.AndroidCalendar) calCheckbox.getTag());
}
List<String> selectedCalendarsIdArray = new ArrayList<>();
for(CalendarReceiver.AndroidCalendar cal : selectedCalendarsList)
selectedCalendarsIdArray.add(String.valueOf(cal.calendarId));
String returnString =
titleDir + Trigger.triggerParameter2Split + title + Trigger.triggerParameter2Split +
descriptionDir + Trigger.triggerParameter2Split + description + Trigger.triggerParameter2Split +
locationDir + Trigger.triggerParameter2Split + location + Trigger.triggerParameter2Split +
String.valueOf(chkCalendarEvaluateAllDayEvent.isChecked()) + Trigger.triggerParameter2Split +
String.valueOf(chkCalendarAllDayEvent.isChecked()) + Trigger.triggerParameter2Split +
String.valueOf(chkCalendarEvaluateReoccurring.isChecked()) + Trigger.triggerParameter2Split +
String.valueOf(chkCalendarReoccurring.isChecked()) + Trigger.triggerParameter2Split +
Miscellaneous.explode(separator, availabilityList.toArray(new String[availabilityList.size()])) + Trigger.triggerParameter2Split +
Miscellaneous.explode(separator, selectedCalendarsIdArray.toArray(new String[selectedCalendarsIdArray.size()]));
Intent data = new Intent();
data.putExtra(ActivityManageRule.intentNameTriggerParameter1, chkCalendarEventActive.isChecked());
data.putExtra(ActivityManageRule.intentNameTriggerParameter2, returnString);
ActivityManageTriggerCalendar.this.setResult(RESULT_OK, data);
finish();
}
});
Intent inputIntent = getIntent();
if(inputIntent.hasExtra(ActivityManageRule.intentNameTriggerParameter1))
loadValuesIntoGui(inputIntent);
}
private void populateCalenderCheckboxes()
{
List<CalendarReceiver.AndroidCalendar> calList = CalendarReceiver.readCalendars(ActivityManageTriggerCalendar.this);
if(calList != null)
{
if(calList.size() > 0)
{
for (CalendarReceiver.AndroidCalendar cal : calList)
{
CheckBox oneCalCheckbox = new CheckBox(ActivityManageTriggerCalendar.this);
oneCalCheckbox.setText(cal.toString());
oneCalCheckbox.setTag(cal);
llCalendarSelection.addView(oneCalCheckbox);
checkboxesCalendars.add(oneCalCheckbox);
}
}
else
Miscellaneous.messageBox(getResources().getString(R.string.warning), getResources().getString(R.string.noCalendarsOnYourDevice), ActivityManageTriggerCalendar.this).show();
}
else
Miscellaneous.messageBox(getResources().getString(R.string.warning), getResources().getString(R.string.errorReadingCalendars), ActivityManageTriggerCalendar.this).show();
}
void loadValuesIntoGui(Intent data)
{
try
{
if (data.hasExtra(ActivityManageRule.intentNameTriggerParameter1))
chkCalendarEventActive.setChecked(data.getBooleanExtra(ActivityManageRule.intentNameTriggerParameter1, true));
if (data.hasExtra(ActivityManageRule.intentNameTriggerParameter2))
{
String input[] = data.getStringExtra(ActivityManageRule.intentNameTriggerParameter2).split(Trigger.triggerParameter2Split, -1);
/*
0 = titleDir
1 = title
2 = descriptionDir
3 = description
4 = locationDir
5 = location
6 = evaluate all day event
7 = all day event
8 = evaluate reoccurring
9 = reoccurring
10 = availability list
11 = calendars list
*/
for (int i = 0; i < directions.length; i++)
{
if (Trigger.getMatchCode(directions[i]).equalsIgnoreCase(input[0]))
spinnerCalendarTitleDirection.setSelection(i);
if (Trigger.getMatchCode(directions[i]).equalsIgnoreCase(input[2]))
spinnerCalendarDescriptionDirection.setSelection(i);
if (Trigger.getMatchCode(directions[i]).equalsIgnoreCase(input[4]))
spinnerCalendarLocationDirection.setSelection(i);
}
etCalendarTitle.setText(input[1]);
etCalendarDescription.setText(input[3]);
etCalendarLocation.setText(input[5]);
chkCalendarEvaluateAllDayEvent.setChecked(Boolean.parseBoolean(input[6]));
chkCalendarAllDayEvent.setChecked(Boolean.parseBoolean(input[7]));
chkCalendarEvaluateReoccurring.setChecked(Boolean.parseBoolean(input[8]));
chkCalendarReoccurring.setChecked(Boolean.parseBoolean(input[9]));
String[] availabilities = null;
if (!StringUtils.isEmpty(input[10]))
availabilities = input[10].split(separator);
if (availabilities != null)
{
for (String avail : availabilities)
{
if (Integer.parseInt(avail) == CalendarContract.Events.AVAILABILITY_BUSY)
chkCalendarAvailabilityBusy.setChecked(true);
else if (Integer.parseInt(avail) == CalendarContract.Events.AVAILABILITY_FREE)
chkCalendarAvailabilityFree.setChecked(true);
else if (Integer.parseInt(avail) == CalendarContract.Events.AVAILABILITY_TENTATIVE)
chkCalendarAvailabilityTentative.setChecked(true);
else if (Integer.parseInt(avail) == CalendarReceiver.AVAILABILITY_OUT_OF_OFFICE)
chkCalendarAvailabilityOutOfOffice.setChecked(true);
else if (Integer.parseInt(avail) == CalendarReceiver.AVAILABILITY_WORKING_ELSEWHERE)
chkCalendarAvailabilityWorkingElsewhere.setChecked(true);
}
}
String[] calendars = null;
if (!StringUtils.isEmpty(input[11]))
calendars = input[11].split(separator);
if (calendars != null)
{
List<String> usedCalendarIDs = new ArrayList<>();
List<String> unusedCalendarIDs = new ArrayList<>();
for (CheckBox checkbox : checkboxesCalendars)
{
int id = ((CalendarReceiver.AndroidCalendar) checkbox.getTag()).calendarId;
for (String calId : calendars)
{
if (calId.equals(String.valueOf(id)))
{
usedCalendarIDs.add(String.valueOf(id));
checkbox.setChecked(true);
break;
}
}
}
for (String calId : calendars)
{
if (!Miscellaneous.arraySearch((ArrayList<String>) usedCalendarIDs, calId, false, true))
unusedCalendarIDs.add(calId);
}
if (unusedCalendarIDs.size() > 0)
{
/*
A calendar has been configured that has been deleted since. We cannot resolve it.
It will be removed with the next save, but we should inform this user
of these circumstances.
*/
tvMissingCalendarHint.setText(String.format(getResources().getString(R.string.calendarsMissingHint), Miscellaneous.explode(", ", (ArrayList<String>) unusedCalendarIDs)));
}
}
}
}
catch (Exception e)
{
Miscellaneous.logEvent("e", "ActivityManagerTriggerCalender", "Error loading values into GUI: " + Log.getStackTraceString(e), 1);
Toast.makeText(ActivityManageTriggerCalendar.this, getResources().getString(R.string.errorLoadingValues), Toast.LENGTH_SHORT).show();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
{
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if(requestCode == requestCodePermissionReadCalendar)
{
if(
permissions[0].equals(Manifest.permission.READ_CALENDAR)
||
permissions[0].equals(Manifest.permission.WRITE_CALENDAR)
)
{
if(grantResults[0] == PackageManager.PERMISSION_GRANTED)
populateCalenderCheckboxes();
else
finish();
}
}
}
}

View File

@ -0,0 +1,87 @@
package com.jens.automation2;
import android.app.Activity;
import android.content.Intent;
import android.os.BatteryManager;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.RadioButton;
import androidx.annotation.Nullable;
import com.jens.automation2.ActivityManageRule;
import com.jens.automation2.Miscellaneous;
import com.jens.automation2.R;
import com.jens.automation2.Trigger;
import org.apache.commons.lang3.StringUtils;
public class ActivityManageTriggerCharging extends Activity
{
RadioButton rbChargingOn, rbChargingOff, rbChargingTypeAny, rbChargingTypeAc, rbChargingTypeUsb, rbChargingTypeWireless;
Button bTriggerChargingSave;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
setContentView(R.layout.activity_manage_trigger_charging);
rbChargingOn = (RadioButton) findViewById(R.id.rbChargingOn);
rbChargingOff = (RadioButton) findViewById(R.id.rbChargingOff);
rbChargingTypeAny = (RadioButton) findViewById(R.id.rbChargingTypeAny);
rbChargingTypeAc = (RadioButton) findViewById(R.id.rbChargingTypeAc);
rbChargingTypeUsb = (RadioButton) findViewById(R.id.rbChargingTypeUsb);
rbChargingTypeWireless = (RadioButton) findViewById(R.id.rbChargingTypeWireless);
bTriggerChargingSave = (Button) findViewById(R.id.bTriggerChargingSave);
Intent input = getIntent();
if(input.hasExtra(ActivityManageRule.intentNameTriggerParameter1))
{
rbChargingOn.setChecked(input.getBooleanExtra(ActivityManageRule.intentNameTriggerParameter1, true));
rbChargingOff.setChecked(!input.getBooleanExtra(ActivityManageRule.intentNameTriggerParameter1, false));
if(input.hasExtra(ActivityManageRule.intentNameTriggerParameter2))
{
String[] params2 = input.getStringExtra(ActivityManageRule.intentNameTriggerParameter2).split(Trigger.triggerParameter2Split);
int chargingType = Integer.parseInt(params2[0]);
rbChargingTypeAny.setChecked(chargingType == 0);
rbChargingTypeAc.setChecked(chargingType == BatteryManager.BATTERY_PLUGGED_AC);
rbChargingTypeUsb.setChecked(chargingType == BatteryManager.BATTERY_PLUGGED_USB);
rbChargingTypeWireless.setChecked(chargingType == BatteryManager.BATTERY_PLUGGED_WIRELESS);
}
}
bTriggerChargingSave.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View view)
{
Intent response = new Intent();
response.putExtra(ActivityManageRule.intentNameTriggerParameter1, rbChargingOn.isChecked());
String param2 = "";
if(rbChargingTypeAny.isChecked())
param2 = "0";
else if(rbChargingTypeAc.isChecked())
param2 = String.valueOf(BatteryManager.BATTERY_PLUGGED_AC);
else if(rbChargingTypeUsb.isChecked())
param2 = String.valueOf(BatteryManager.BATTERY_PLUGGED_USB);
else if(rbChargingTypeWireless.isChecked())
param2 = String.valueOf(BatteryManager.BATTERY_PLUGGED_WIRELESS);
response.putExtra(ActivityManageRule.intentNameTriggerParameter2, param2);
setResult(RESULT_OK, response);
finish();
}
});
}
}

View File

@ -18,6 +18,8 @@ import android.os.Bundle;
import android.os.PowerManager;
import android.provider.Settings;
import android.text.Html;
import android.text.TextUtils;
import android.text.util.Linkify;
import android.util.Log;
import android.view.View;
import android.widget.Button;
@ -51,12 +53,14 @@ public class ActivityPermissions extends Activity
private static final int requestCodeForPermissionsBatteryOptimization = 12048;
private static final int requestCodeForPermissionNotificationAccessAndroid13 = 12049;
private static final int requestCodeForPermissionsManageOverlay = 12050;
private static final int requestCodeForPermissionsAccessibility = 12051;
private static final int requestCodeForPermissionsScheduleExactAlarms = 12052;
protected String[] specificPermissionsToRequest = null;
public static String intentExtraName = "permissionsToBeRequested";
Button bCancelPermissions, bRequestPermissions;
TextView tvPermissionsExplanation, tvPermissionsExplanationSystemSettings, tvPermissionsExplanationLong;
TextView tvPermissionsExplanation, tvPermissionsExplanationSystemSettings, tvPermissionsExplanationLong, tvRestrictionPermissionsNotice;
static ActivityPermissions instance = null;
public final static String permissionNameWireguard = "com.wireguard.android.permission.CONTROL_TUNNELS";
@ -87,6 +91,7 @@ public class ActivityPermissions extends Activity
tvPermissionsExplanation = (TextView)findViewById(R.id.tvPermissionsExplanation);
tvPermissionsExplanationSystemSettings = (TextView)findViewById(R.id.tvPermissionsExplanationSystemSettings);
tvPermissionsExplanationLong = (TextView)findViewById(R.id.tvPermissionsExplanationLong);
tvRestrictionPermissionsNotice = (TextView)findViewById(R.id.tvRestrictionPermissionsNotice);
bCancelPermissions.setOnClickListener(new View.OnClickListener()
{
@ -161,7 +166,7 @@ public class ActivityPermissions extends Activity
/*
Filter location permission and only name it once
*/
if(s.equals(Manifest.permission.ACCESS_COARSE_LOCATION) | s.equals(Manifest.permission.ACCESS_FINE_LOCATION))
if(s.equals(Manifest.permission.ACCESS_COARSE_LOCATION) || s.equals(Manifest.permission.ACCESS_FINE_LOCATION))
{
if(!locationPermissionExplained)
{
@ -305,6 +310,10 @@ public class ActivityPermissions extends Activity
{
return android.provider.Settings.canDrawOverlays(Miscellaneous.getAnyContext());
}
else if(s.equals(Manifest.permission.BIND_ACCESSIBILITY_SERVICE))
{
return haveAccessibilityAccess(Miscellaneous.getAnyContext());
}
else
{
int res = context.checkCallingOrSelfPermission(s);
@ -323,11 +332,59 @@ public class ActivityPermissions extends Activity
return active;
}
public static boolean haveAccessibilityAccess(Context mContext)
{
int accessibilityEnabled = 0;
final String service = mContext.getPackageName() + "/" + BuildConfig.APPLICATION_ID + ".MyAccessibilityService";
boolean accessibilityFound = false;
try
{
accessibilityEnabled = Settings.Secure.getInt(mContext.getApplicationContext().getContentResolver(), Settings.Secure.ACCESSIBILITY_ENABLED);
// Log.v(TAG, "accessibilityEnabled = " + accessibilityEnabled);
}
catch (Settings.SettingNotFoundException e)
{
// Log.e(TAG, "Error finding setting, default accessibility to not found: " + e.getMessage());
}
TextUtils.SimpleStringSplitter mStringColonSplitter = new TextUtils.SimpleStringSplitter(':');
if (accessibilityEnabled == 1)
{
String settingValue = Settings.Secure.getString(mContext.getApplicationContext().getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
if (settingValue != null)
{
TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
splitter.setString(settingValue);
while (splitter.hasNext())
{
String accessibilityService = splitter.next();
if (accessibilityService.equalsIgnoreCase(service))
{
return true;
}
}
}
}
return accessibilityFound;
}
public static void requestOverlay()
{
Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
ActivityPermissions.getInstance().startActivityForResult(intent, requestCodeForPermissionsManageOverlay);
}
public static void requestBindAccessibilityService()
{
Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ActivityPermissions.getInstance().startActivityForResult(intent, requestCodeForPermissionsAccessibility);
}
public static void requestDeviceAdmin()
{
if(!haveDeviceAdmin())
@ -370,10 +427,19 @@ public class ActivityPermissions extends Activity
if(!havePermission(Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, workingContext))
addToArrayListUnique(Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, requiredPermissions);
for(Profile p : Profile.getProfileCollection())
if(Build.VERSION.SDK_INT >= 33 && BuildConfig.FLAVOR.equals(AutomationService.flavor_name_googleplay))
{
if(p.changeIncomingCallsRingtone || p.changeNotificationRingtone)
addToArrayListUnique(Manifest.permission.READ_EXTERNAL_STORAGE, requiredPermissions);
if (!havePermission(android.Manifest.permission.POST_NOTIFICATIONS, workingContext))
addToArrayListUnique(android.Manifest.permission.POST_NOTIFICATIONS, requiredPermissions);
}
if(!havePermission(Manifest.permission.READ_EXTERNAL_STORAGE, workingContext))
{
for (Profile p : Profile.getProfileCollection())
{
if (p.changeIncomingCallsRingtone || p.changeNotificationRingtone)
addToArrayListUnique(Manifest.permission.READ_EXTERNAL_STORAGE, requiredPermissions);
}
}
if (!onlyGeneral)
@ -407,27 +473,6 @@ public class ActivityPermissions extends Activity
}
}
}
/*
Not all permissions need to be asked for.
*/
/*if(shouldShowRequestPermissionRationale("android.permission.RECORD_AUDIO"))
Toast.makeText(ActivityMainScreen.this, "shouldShowRequestPermissionRationale", Toast.LENGTH_LONG).show();
else
Toast.makeText(ActivityMainScreen.this, "not shouldShowRequestPermissionRationale", Toast.LENGTH_LONG).show();*/
// addToArrayListUnique("Manifest.permission.RECORD_AUDIO", requiredPermissions);
/*int hasPermission = checkSelfPermission(Manifest.permission.RECORD_AUDIO);
if (hasPermission == PackageManager.PERMISSION_DENIED)
{
Toast.makeText(ActivityMainScreen.this, "Don't have record_audio. Requesting...", Toast.LENGTH_LONG).show();
// requestPermissions(new String[]{"Manifest.permission.CAMERA"}, requestCodeForPermissions);
ActivityCompat.requestPermissions(ActivityMainScreen.this, new String[]{"Manifest.permission.CAMERA"}, requestCodeForPermissions);
}
else
Toast.makeText(ActivityMainScreen.this, "Have record_audio.", Toast.LENGTH_LONG).show();*/
}
return requiredPermissions.toArray(new String[requiredPermissions.size()]);
@ -520,6 +565,8 @@ public class ActivityPermissions extends Activity
addToArrayListUnique(Manifest.permission.INTERNET, requiredPermissions);
break;
case timeFrame:
if(Build.VERSION.SDK_INT >= 31 && Miscellaneous.getTargetSDK(Miscellaneous.getAnyContext()) >= 31)
addToArrayListUnique(Manifest.permission.SCHEDULE_EXACT_ALARM, requiredPermissions);
break;
case usb_host_connection:
addToArrayListUnique(Manifest.permission.READ_PHONE_STATE, requiredPermissions);
@ -542,6 +589,11 @@ public class ActivityPermissions extends Activity
case notification:
addToArrayListUnique(Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE, requiredPermissions);
break;
case calendarEvent:
addToArrayListUnique(Manifest.permission.READ_CALENDAR, requiredPermissions);
if(Build.VERSION.SDK_INT >= 31 && Miscellaneous.getTargetSDK(Miscellaneous.getAnyContext()) >= 31)
addToArrayListUnique(Manifest.permission.SCHEDULE_EXACT_ALARM, requiredPermissions);
break;
default:
break;
}
@ -650,7 +702,18 @@ public class ActivityPermissions extends Activity
// )
// addToArrayListUnique("net.kollnig.missioncontrol.permission.ADMIN", requiredPermissions);
if(Build.VERSION.SDK_INT >= 29)
addToArrayListUnique(Manifest.permission.SYSTEM_ALERT_WINDOW, requiredPermissions);
{
String parts[];
if(action.getParameter2().contains(Action.actionParameter2Split))
parts = action.getParameter2().split(Action.actionParameter2Split);
else
parts = action.getParameter2().split(";");
// Permission only required for starts of activity, not broadcasts or services
if(parts[2].equals(ActivityManageActionStartActivity.startByActivityString))
addToArrayListUnique(Manifest.permission.SYSTEM_ALERT_WINDOW, requiredPermissions);
}
break;
case triggerUrl:
addToArrayListUnique(Manifest.permission.INTERNET, requiredPermissions);
@ -711,6 +774,12 @@ public class ActivityPermissions extends Activity
case stopPhoneCall:
addToArrayListUnique(Manifest.permission.ANSWER_PHONE_CALLS, requiredPermissions);
break;
case takeScreenshot:
addToArrayListUnique(Manifest.permission.BIND_ACCESSIBILITY_SERVICE, requiredPermissions);
break;
case setLocationService:
addToArrayListUnique(Manifest.permission.WRITE_SECURE_SETTINGS, requiredPermissions);
break;
default:
break;
}
@ -773,6 +842,12 @@ public class ActivityPermissions extends Activity
case Manifest.permission.WRITE_EXTERNAL_STORAGE:
usingElements.add(getResources().getString(R.string.storeSettings));
break;
case Manifest.permission.SCHEDULE_EXACT_ALARM:
for(String ruleName : getRulesUsing(Trigger.Trigger_Enum.timeFrame))
usingElements.add(String.format(getResources().getString(R.string.ruleXrequiresThis), ruleName));
for(String ruleName : getRulesUsing(Trigger.Trigger_Enum.calendarEvent))
usingElements.add(String.format(getResources().getString(R.string.ruleXrequiresThis), ruleName));
break;
case Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE:
for(String ruleName : getRulesUsing(Trigger.Trigger_Enum.notification))
usingElements.add(String.format(getResources().getString(R.string.ruleXrequiresThis), ruleName));
@ -960,6 +1035,18 @@ public class ActivityPermissions extends Activity
case Manifest.permission.QUERY_ALL_PACKAGES:
usingElements.add(getResources().getString(R.string.queryAllPackages));
break;
case Manifest.permission.BIND_ACCESSIBILITY_SERVICE:
for(String ruleName : getRulesUsing(Action.Action_Enum.takeScreenshot))
usingElements.add(String.format(getResources().getString(R.string.ruleXrequiresThis), ruleName));
break;
case Manifest.permission.WRITE_SECURE_SETTINGS:
for(String ruleName : getRulesUsing(Action.Action_Enum.setLocationService))
usingElements.add(String.format(getResources().getString(R.string.ruleXrequiresThis), ruleName));
break;
case Manifest.permission.READ_CALENDAR:
for(String ruleName : getRulesUsing(Trigger.Trigger_Enum.calendarEvent))
usingElements.add(String.format(getResources().getString(R.string.ruleXrequiresThis), ruleName));
break;
}
return usingElements;
@ -968,6 +1055,15 @@ public class ActivityPermissions extends Activity
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
/*
All of the following permissions need to be "manually" activated by the user in some
buried system menu.
In my opinion by mistake the function will be called when the user has just landed
on one of those screens, not when he exits it again. To compensate for that onResume()
is overridden. This enables the permission screen to automatically close after all
required permissions have been granted.
*/
super.onActivityResult(requestCode, resultCode, data);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
@ -1015,6 +1111,14 @@ public class ActivityPermissions extends Activity
if (requestCode == requestCodeForPermissionsManageOverlay)
if(havePermission(Manifest.permission.SYSTEM_ALERT_WINDOW, ActivityPermissions.this))
requestPermissions(cachedPermissionsToRequest, true);
if (requestCode == requestCodeForPermissionsAccessibility)
if(havePermission(Manifest.permission.BIND_ACCESSIBILITY_SERVICE, ActivityPermissions.this))
requestPermissions(cachedPermissionsToRequest, true);
if (requestCode == requestCodeForPermissionsScheduleExactAlarms)
if(havePermission(Manifest.permission.SCHEDULE_EXACT_ALARM, ActivityPermissions.this))
requestPermissions(cachedPermissionsToRequest, true);
}
}
@ -1074,10 +1178,14 @@ public class ActivityPermissions extends Activity
}
else if (s.equalsIgnoreCase(Manifest.permission.ACCESS_NOTIFICATION_POLICY))
{
if(BuildConfig.FLAVOR.equals(AutomationService.flavor_name_apk))
Miscellaneous.messageBox(getResources().getString(R.string.info), getResources().getString(R.string.noticeRestrictedPermissions), ActivityPermissions.this).show();
requiredPermissions.remove(s);
cachedPermissionsToRequest = requiredPermissions;
Intent intent = new Intent(android.provider.Settings.ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS);
startActivityForResult(intent, requestCodeForPermissionsNotificationPolicy);
return;
}
else if (s.equalsIgnoreCase(Manifest.permission.SYSTEM_ALERT_WINDOW))
@ -1096,6 +1204,22 @@ public class ActivityPermissions extends Activity
diag.show();
return;
}
else if (s.equalsIgnoreCase(Manifest.permission.BIND_ACCESSIBILITY_SERVICE))
{
AlertDialog diag = Miscellaneous.messageBox(getResources().getString(R.string.info), getResources().getString(R.string.accessibilityApiPermissionHint), ActivityPermissions.this);
diag.setOnDismissListener(new DialogInterface.OnDismissListener()
{
@Override
public void onDismiss(DialogInterface dialogInterface)
{
requiredPermissions.remove(s);
cachedPermissionsToRequest = requiredPermissions;
requestBindAccessibilityService();
}
});
diag.show();
return;
}
else if (s.equalsIgnoreCase(Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE))
{
if(Build.VERSION.SDK_INT >= 33)
@ -1122,6 +1246,22 @@ public class ActivityPermissions extends Activity
return;
}
else if (s.equalsIgnoreCase(Manifest.permission.SCHEDULE_EXACT_ALARM))
{
AlertDialog diag = Miscellaneous.messageBox(getResources().getString(R.string.info), getResources().getString(R.string.alarmsPermissionHint), ActivityPermissions.this);
diag.setOnDismissListener(new DialogInterface.OnDismissListener()
{
@Override
public void onDismiss(DialogInterface dialogInterface)
{
requiredPermissions.remove(s);
cachedPermissionsToRequest = requiredPermissions;
requestScheduleExactAlarms();
}
});
diag.show();
return;
}
else if(s.equals(Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS))
{
requiredPermissions.remove(s);
@ -1151,6 +1291,13 @@ public class ActivityPermissions extends Activity
return;
}
else if(s.equalsIgnoreCase(Manifest.permission.WRITE_SECURE_SETTINGS))
{
AlertDialog diaglog = Miscellaneous.messageBox(getResources().getString(R.string.info), getResources().getString(R.string.writeSecureSettingsNotice), ActivityPermissions.this);
diaglog.show();
Linkify.addLinks((TextView) diaglog.findViewById(android.R.id.message), Linkify.ALL);
// return;
}
}
}
@ -1200,6 +1347,14 @@ public class ActivityPermissions extends Activity
startActivityForResult(intent, requestCodeForPermissionsNotifications);
}
void requestScheduleExactAlarms()
{
Intent intent = new Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM);
startActivityForResult(intent, requestCodeForPermissionsScheduleExactAlarms);
}
protected void applyChanges()
{
AutomationService service = AutomationService.getInstance();
@ -1578,4 +1733,47 @@ public class ActivityPermissions extends Activity
return false;
}
}
@Override
protected void onResume()
{
super.onResume();
if(Build.VERSION.SDK_INT >= 33 && BuildConfig.FLAVOR.equals(AutomationService.flavor_name_apk))
{
for (String p : getRequiredPermissions(false))
{
if (p.equals(Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE) || p.equals(Manifest.permission.BIND_ACCESSIBILITY_SERVICE))
{
tvRestrictionPermissionsNotice.setText(getResources().getString(R.string.noticeRestrictedPermissions));
/*
Opening the app's settings directly does not work because the
mentioned 3 dots are only displayed when you went there the hard way.
*/
/*
tvRestrictionPermissionsNotice.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View view)
{
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.parse("package:" + getPackageName()));
startActivity(intent);
}
})*/;
break;
}
}
}
for(String p : getRequiredPermissions(false))
{
if(!havePermission(p, this))
return;
}
// have all
setHaveAllPermissions();
}
}

View File

@ -49,20 +49,15 @@ public class ActivityVolumeTest extends Activity
@Override
public void onStopTrackingTouch(SeekBar seekBar)
{
// TODO Auto-generated method stub
}
@Override
public void onStartTrackingTouch(SeekBar seekBar)
{
// TODO Auto-generated method stub
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser)
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
{
etReferenceValue.setText(String.valueOf(sbReferenceValue.getProgress()));
}

View File

@ -22,7 +22,7 @@ public class AsyncTasks
try
{
String result = Miscellaneous.downloadURL("https://server47.de/automation/?action=getLatestVersionCode", null, null).trim();
String result = Miscellaneous.downloadURL("https://server47.de/automation/?action=getLatestVersionCode", null, null, ActivityManageActionTriggerUrl.methodGet, null).trim();
int latestVersion = Integer.parseInt(result);
// At this point the update check itself has already been successful.

View File

@ -28,6 +28,7 @@ import androidx.core.app.NotificationManagerCompat;
import com.jens.automation2.Trigger.Trigger_Enum;
import com.jens.automation2.location.LocationProvider;
import com.jens.automation2.receivers.CalendarReceiver;
import com.jens.automation2.receivers.DateTimeListener;
import com.jens.automation2.receivers.PackageReplacedReceiver;
import com.jens.automation2.receivers.PhoneStatusListener;
@ -127,7 +128,18 @@ public class AutomationService extends Service implements OnInitListener
// Store a reference to myself. Other classes often need a context or something, this can provide that.
centralInstance = this;
Miscellaneous.setDisplayLanguage(AutomationService.this);
/*
This has been reported to throw a NullPointerException under
rare circumstances. The root cause remains unknown.
*/
try
{
Miscellaneous.setDisplayLanguage(AutomationService.this);
}
catch(NullPointerException e)
{
Miscellaneous.logEvent("e", "setDisplayLanguage()", Log.getStackTraceString(e), 3);
}
}
public boolean checkStartupRequirements(Context context, boolean startAtBoot)
@ -223,7 +235,10 @@ public class AutomationService extends Service implements OnInitListener
startUpRoutine();
Intent myIntent = new Intent(this, ActivityMainTabLayout.class);
myPendingIntent = PendingIntent.getActivity(this, 0, myIntent, 0);
if(getApplicationContext().getApplicationInfo().targetSdkVersion >= 31)
myPendingIntent = PendingIntent.getActivity(this, 0, myIntent, PendingIntent.FLAG_MUTABLE);
else
myPendingIntent = PendingIntent.getActivity(this, 0, myIntent, 0);
notificationBuilder = createServiceNotificationBuilder();
updateNotification();
@ -306,6 +321,7 @@ public class AutomationService extends Service implements OnInitListener
ReceiverCoordinator.applySettingsAndRules();
DateTimeListener.reloadAlarms();
CalendarReceiver.armOrRearmTimer();
}
@Override
@ -676,8 +692,6 @@ public class AutomationService extends Service implements OnInitListener
@Override
public void onInit(int status)
{
// TODO Auto-generated method stub
}
/**

View File

@ -37,16 +37,22 @@ import android.util.Log;
import android.widget.Toast;
import com.jens.automation2.location.LocationProvider;
import com.jens.automation2.receivers.CalendarReceiver;
import com.jens.automation2.receivers.NotificationListener;
import com.jens.automation2.receivers.PhoneStatusListener;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
@ -69,6 +75,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.lang.Thread.UncaughtExceptionHandler;
@ -94,6 +101,7 @@ import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Scanner;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
@ -113,6 +121,8 @@ import androidx.annotation.RequiresApi;
import androidx.core.app.NotificationCompat;
import androidx.documentfile.provider.DocumentFile;
import eu.chainfire.libsuperuser.Shell;
public class Miscellaneous extends Service
{
protected static String writeableFolderStringCache = null;
@ -120,7 +130,7 @@ public class Miscellaneous extends Service
public static final String lineSeparator = System.getProperty("line.separator");
public static String downloadURL(String url, String username, String password)
public static String downloadURL(String url, String username, String password, String method, Map<String, String> httpParams)
{
HttpClient httpclient = new DefaultHttpClient();
StringBuilder responseBody = new StringBuilder();
@ -148,7 +158,27 @@ public class Miscellaneous extends Service
connection.setDoOutput(true);
connection.setRequestProperty ("Authorization", "Basic " + encodedCredentials);
}
else if(method.equals(ActivityManageActionTriggerUrl.methodPost))
connection.setRequestMethod("POST");
if(httpParams.size() > 0)
{
connection.setRequestMethod("POST");
connection.setDoInput(true);
connection.setDoOutput(true);
List<NameValuePair> paramPairs = new ArrayList<NameValuePair>();
for(String key : httpParams.keySet())
paramPairs.add(new BasicNameValuePair(key, httpParams.get(key)));
OutputStream os = connection.getOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
writer.write(getQuery(paramPairs));
writer.flush();
writer.close();
}
InputStream content = (InputStream)connection.getInputStream();
BufferedReader in = new BufferedReader (new InputStreamReader (content));
String line;
@ -173,34 +203,67 @@ public class Miscellaneous extends Service
return responseBody.toString();
}
}
public static String downloadURLwithoutCertificateChecking(String url, String username, String password)
{
// HttpClient httpclient = new DefaultHttpClient();
// StringBuilder responseBody = new StringBuilder();
boolean errorFound = false;
try
private static String getQuery(List<NameValuePair> params) throws UnsupportedEncodingException
{
StringBuilder result = new StringBuilder();
boolean first = true;
for (NameValuePair pair : params)
{
if (first)
first = false;
else
result.append("&");
result.append(URLEncoder.encode(pair.getName(), "UTF-8"));
result.append("=");
result.append(URLEncoder.encode(pair.getValue(), "UTF-8"));
}
return result.toString();
}
public static String downloadUrlWithoutCertificateChecking(String url, String username, String password, String method, Map<String, String> httpParams)
{
try
{
HttpParams params = new BasicHttpParams();
params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false);
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpClient httpclient = new DefaultHttpClient(params);
httpclient = Actions.getInsecureSslClient(httpclient);
HttpPost httppost = new HttpPost(url);
HttpRequestBase httpRequest;
if(
method.equals(ActivityManageActionTriggerUrl.methodPost)
||
(username != null && password != null)
||
httpParams.size() > 0
)
httpRequest = new HttpPost(url);
else
httpRequest = new HttpGet(url);
// Add http simple authentication if specified
if(username != null && password != null)
{
String encodedCredentials = Base64.encodeToString(new String(username + ":" + password).getBytes(), Base64.DEFAULT);
// List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(1);
httppost.addHeader("Authorization", "Basic " + encodedCredentials);
// nameValuePairs.add(new BasicNameValuePair("Authorization", "Basic " + encodedCredentials));
// httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs, "UTF-8"));
httpRequest.addHeader("Authorization", "Basic " + encodedCredentials);
}
if(httpParams.size() > 0)
{
List<NameValuePair> paramPairs = new ArrayList<NameValuePair>();
for(String key : httpParams.keySet())
paramPairs.add(new BasicNameValuePair(key, httpParams.get(key)));
((HttpPost)httpRequest).setEntity(new UrlEncodedFormEntity(paramPairs, "UTF-8"));
}
HttpResponse response = httpclient.execute(httppost);
HttpResponse response = httpclient.execute(httpRequest);
HttpEntity entity = response.getEntity();
if (entity != null)
{
@ -211,8 +274,7 @@ public class Miscellaneous extends Service
catch(Exception e)
{
Miscellaneous.logEvent("e", "HTTP error", Log.getStackTraceString(e), 3);
errorFound = true;
return "httpError";
return "httpError";
}
// finally
// {
@ -237,25 +299,9 @@ public class Miscellaneous extends Service
@Override
public IBinder onBind(Intent arg0)
{
// TODO Auto-generated method stub
return null;
}
// public static void logEvent(String type, String header, String description)
// {
// if(type.equals("e"))
// Log.e(header, description);
//
// if(type.equals("w"))
// Log.w(header, description);
//
// if(type.equals("i"))
// Log.i(header, description);
//
// if(Settings.writeLogFile)
// writeToLogFile(type, header, description);
// }
public static void logEvent(String type, String header, String description, int logLevel)
{
try
@ -292,7 +338,6 @@ public class Miscellaneous extends Service
{
logCleanerRunning = true;
long maxSizeInBytes = (long)Settings.logFileMaxSize * 1024 * 1024;
if(logFile.exists() && logFile.length() > (maxSizeInBytes))
@ -746,6 +791,78 @@ public class Miscellaneous extends Service
}
}
if(source.contains("[last_trigger_url_result]"))
{
try
{
source = source.replace("[last_trigger_url_result]", AutomationService.getInstance().getVariableMap().get("last_trigger_url_result"));
}
catch (Exception e)
{
Miscellaneous.logEvent("w", "Variable replacement", "Error replacing variable last_trigger_url_result.", 3);
}
}
if(source.contains("[last_run_executable_exit_code]"))
{
try
{
source = source.replace("[last_run_executable_exit_code]", AutomationService.getInstance().getVariableMap().get("last_run_executable_exit_code"));
}
catch (Exception e)
{
Miscellaneous.logEvent("w", "Variable replacement", "Error replacing variable last_run_executable_exit_code.", 3);
}
}
if(source.contains("[last_run_executable_output]"))
{
try
{
source = source.replace("[last_run_executable_output]", AutomationService.getInstance().getVariableMap().get("last_run_executable_output"));
}
catch (Exception e)
{
Miscellaneous.logEvent("w", "Variable replacement", "Error replacing variable last_run_executable_output.", 3);
}
}
if(source.contains("[last_calendar_title]"))
{
try
{
source = source.replace("[last_calendar_title]", CalendarReceiver.getLastTriggeringEvent().title);
}
catch (Exception e)
{
Miscellaneous.logEvent("w", "Variable replacement", "Error replacing variable last_calendar_title.", 3);
}
}
if(source.contains("[last_calendar_description]"))
{
try
{
source = source.replace("[last_calendar_description]", CalendarReceiver.getLastTriggeringEvent().description);
}
catch (Exception e)
{
Miscellaneous.logEvent("w", "Variable replacement", "Error replacing variable last_calendar_description.", 3);
}
}
if(source.contains("[last_calendar_location]"))
{
try
{
source = source.replace("[last_calendar_location]", CalendarReceiver.getLastTriggeringEvent().location);
}
catch (Exception e)
{
Miscellaneous.logEvent("w", "Variable replacement", "Error replacing variable last_calendar_location.", 3);
}
}
while(source.contains("[variable-"))
{
int pos1 = source.indexOf("[variable-");
@ -792,7 +909,7 @@ public class Miscellaneous extends Service
alertDialog.setTitle(title);
alertDialog.setMessage(message);
alertDialog.setPositiveButton("Ok", new DialogInterface.OnClickListener()
alertDialog.setPositiveButton(context.getResources().getString(R.string.ok), new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int whichButton)
{
@ -828,36 +945,40 @@ public class Miscellaneous extends Service
*/
public static boolean isPhoneRooted()
{
// if(true)
// return true;
// get from build info
String buildTags = Build.TAGS;
if (buildTags != null && buildTags.contains("test-keys"))
{
return true;
}
// check if /system/app/Superuser.apk is present
try
{
File file = new File("/system/app/Superuser.apk");
if (file.exists())
return Shell.SU.available();
}
catch(Exception e)
{
// get from build info
String buildTags = Build.TAGS;
if (buildTags != null && buildTags.contains("test-keys"))
{
return true;
}
}
catch (Exception e1)
{
// ignore
}
// try executing commands
return canExecuteCommand("/system/xbin/which su")
||
canExecuteCommand("/system/bin/which su")
||
canExecuteCommand("which su");
// check if /system/app/Superuser.apk is present
try
{
File file = new File("/system/app/Superuser.apk");
if (file.exists())
{
return true;
}
}
catch (Exception e1)
{
// ignore
}
// try executing commands
return canExecuteCommand("/system/xbin/which su")
||
canExecuteCommand("/system/bin/which su")
||
canExecuteCommand("which su");
}
}
// executes a command on the system
@ -905,51 +1026,45 @@ public class Miscellaneous extends Service
private static void disableSSLCertificateChecking()
{
try
{
SSLSocketFactory ssf = null;
try
{
SSLContext ctx = SSLContext.getInstance("TLS");
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
ssf = new MySSLSocketFactoryInsecure(trustStore);
ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
ctx.init(null, null, null);
{
SSLSocketFactory ssf = null;
try
{
SSLContext ctx = SSLContext.getInstance("TLS");
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
ssf = new MySSLSocketFactoryInsecure(trustStore);
ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
ctx.init(null, null, null);
// return new DefaultHttpClient(ccm, client.getParams());
}
catch (Exception ex)
{
ex.printStackTrace();
}
catch (Exception ex)
{
ex.printStackTrace();
// return null;
}
// Install the all-trusting trust manager
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, getInsecureTrustManager(), new java.security.SecureRandom());
}
// Install the all-trusting trust manager
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, getInsecureTrustManager(), new java.security.SecureRandom());
// HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
// HttpsURLConnection.setDefaultSSLSocketFactory(ssf);
// Install the all-trusting host verifier
HttpsURLConnection.setDefaultHostnameVerifier(getInsecureHostnameVerifier());
HttpsURLConnection.setDefaultHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
}
catch (KeyManagementException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (NoSuchAlgorithmException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
finally
{
}
// Install the all-trusting host verifier
HttpsURLConnection.setDefaultHostnameVerifier(getInsecureHostnameVerifier());
HttpsURLConnection.setDefaultHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
}
catch (KeyManagementException e)
{
Miscellaneous.logEvent("e", "SSL", Log.getStackTraceString(e), 4);
}
catch (NoSuchAlgorithmException e)
{
Miscellaneous.logEvent("e", "SSL", Log.getStackTraceString(e), 4);
}
}
public static TrustManager[] getInsecureTrustManager()
@ -2066,4 +2181,10 @@ public class Miscellaneous extends Service
return output;
}
public static String getCallingMethodName()
{
StackTraceElement callingFrame = Thread.currentThread().getStackTrace()[4];
return callingFrame.getMethodName();
}
}

View File

@ -0,0 +1,51 @@
package com.jens.automation2;
import android.accessibilityservice.AccessibilityService;
import android.os.Build;
import android.util.Log;
import android.view.Display;
import android.view.accessibility.AccessibilityEvent;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
public class MyAccessibilityService extends AccessibilityService
{
static MyAccessibilityService instance;
public static MyAccessibilityService getInstance()
{
if(instance == null)
{
instance = new MyAccessibilityService();
}
return instance;
}
@Override
public void onAccessibilityEvent(AccessibilityEvent accessibilityEvent)
{
}
@Override
public void onInterrupt()
{
}
@Override
public void onCreate()
{
super.onCreate();
instance = this;
}
@Override
protected void onServiceConnected()
{
super.onServiceConnected();
Miscellaneous.logEvent("i", "Accessibility service", "Service started.", 4);
}
}

View File

@ -79,7 +79,7 @@ public class News
if (!(new File(filePath)).exists() || Settings.lastNewsPolltime == Settings.default_lastNewsPolltime || now.getTimeInMillis() >= Settings.lastNewsPolltime + (long)(Settings.newsDisplayForXDays * 24 * 60 * 60 * 1000))
{
String newsUrl = "https://server47.de/automation/appNews.php";
newsContent = Miscellaneous.downloadURL(newsUrl, null, null);
newsContent = Miscellaneous.downloadURL(newsUrl, null, null, ActivityManageActionTriggerUrl.methodGet, null);
// Cache content to local storage
if(Miscellaneous.writeStringToFile(filePath, newsContent))

View File

@ -694,22 +694,16 @@ public class PointOfInterest implements Comparable<PointOfInterest>
@Override
public void onProviderDisabled(String provider)
{
// TODO Auto-generated method stub
}
@Override
public void onProviderEnabled(String provider)
{
// TODO Auto-generated method stub
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras)
{
// TODO Auto-generated method stub
}
}

View File

@ -6,6 +6,7 @@ import android.util.Log;
import com.jens.automation2.location.CellLocationChangedReceiver;
import com.jens.automation2.location.WifiBroadcastReceiver;
import com.jens.automation2.receivers.BroadcastListener;
import com.jens.automation2.receivers.CalendarReceiver;
import com.jens.automation2.receivers.DateTimeListener;
import com.jens.automation2.receivers.AutomationListenerInterface;
import com.jens.automation2.receivers.BatteryReceiver;
@ -145,7 +146,8 @@ public class ReceiverCoordinator
}
// startPhoneStateListener
PhoneStatusListener.startPhoneStatusListener(AutomationService.getInstance()); // also used to mute anouncements during calls
if(!BuildConfig.FLAVOR.equals(AutomationService.flavor_name_googleplay))
PhoneStatusListener.startPhoneStatusListener(AutomationService.getInstance()); // also used to mute anouncements during calls
// startConnectivityReceiver
ConnectivityReceiver.startConnectivityReceiver(AutomationService.getInstance());
@ -209,6 +211,9 @@ public class ReceiverCoordinator
if(Rule.isAnyRuleUsing(Trigger.Trigger_Enum.screenState))
ScreenStateReceiver.startScreenStateReceiver(AutomationService.getInstance());
if(Rule.isAnyRuleUsing(Trigger.Trigger_Enum.calendarEvent))
CalendarReceiver.startCalendarReceiver(AutomationService.getInstance());
}
public static void stopAllReceivers()
@ -242,6 +247,7 @@ public class ReceiverCoordinator
BluetoothReceiver.stopBluetoothReceiver();
HeadphoneJackListener.getInstance().stopListener(AutomationService.getInstance());
DeviceOrientationListener.getInstance().stopListener(AutomationService.getInstance());
CalendarReceiver.getInstance().stopListener(AutomationService.getInstance());
}
catch(Exception e)
{
@ -463,6 +469,19 @@ public class ReceiverCoordinator
}
}
if(Rule.isAnyRuleUsing(Trigger.Trigger_Enum.calendarEvent))
{
if(!CalendarReceiver.getInstance().isListenerRunning())
CalendarReceiver.getInstance().startListener(AutomationService.getInstance());
else
CalendarReceiver.armOrRearmTimer();
}
else
{
if(CalendarReceiver.getInstance().isListenerRunning())
CalendarReceiver.getInstance().stopListener(AutomationService.getInstance());
}
AutomationService.updateNotification();
}
}

View File

@ -149,56 +149,45 @@ public class Settings implements SharedPreferences
@Override
public Editor edit()
{
// TODO Auto-generated method stub
return null;
}
@Override
public Map<String, ?> getAll()
{
// TODO Auto-generated method stub
return null;
}
@Override
public boolean getBoolean(String arg0, boolean arg1)
{
// TODO Auto-generated method stub
return false;
}
@Override
public float getFloat(String arg0, float arg1)
{
// TODO Auto-generated method stub
return 0;
}
@Override
public int getInt(String arg0, int arg1)
{
// TODO Auto-generated method stub
return 0;
}
@Override
public long getLong(String arg0, long arg1)
{
// TODO Auto-generated method stub
return 0;
}
@Override
public String getString(String arg0, String arg1)
{
// TODO Auto-generated method stub
return null;
}
@Override
public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener arg0)
{
// TODO Auto-generated method stub
}
@Override
public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener arg0)
{
// TODO Auto-generated method stub
}
public static void readFromPersistentStorage(Context context)
@ -619,7 +608,6 @@ public class Settings implements SharedPreferences
@Override
public Set<String> getStringSet(String arg0, Set<String> arg1)
{
// TODO Auto-generated method stub
return null;
}
}

View File

@ -2,6 +2,7 @@ package com.jens.automation2;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.os.BatteryManager;
import android.os.Build;
import android.service.notification.StatusBarNotification;
import android.telephony.TelephonyManager;
@ -14,6 +15,7 @@ import com.jens.automation2.location.WifiBroadcastReceiver;
import com.jens.automation2.receivers.BatteryReceiver;
import com.jens.automation2.receivers.BluetoothReceiver;
import com.jens.automation2.receivers.BroadcastListener;
import com.jens.automation2.receivers.CalendarReceiver;
import com.jens.automation2.receivers.ConnectivityReceiver;
import com.jens.automation2.receivers.DeviceOrientationListener;
import com.jens.automation2.receivers.HeadphoneJackListener;
@ -31,6 +33,7 @@ import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
public class Trigger
@ -63,6 +66,7 @@ public class Trigger
tethering,
subSystemState,
checkVariable,
calendarEvent,
phoneCall; //phoneCall always needs to be at the very end because of Google's shitty so called privacy
public String getFullName(Context context)
@ -123,6 +127,8 @@ public class Trigger
return context.getResources().getString(R.string.subSystemState);
case checkVariable:
return context.getResources().getString(R.string.checkVariable);
case calendarEvent:
return context.getResources().getString(R.string.calendarEventCapital);
default:
return "Unknown";
}
@ -247,11 +253,14 @@ public class Trigger
case subSystemState:
if(!checkSubSystemState())
result = false;
break;
case checkVariable:
if(!checkVariable())
result = false;
break;
case calendarEvent:
if(!checkCalendarEvent(false))
result = false;
break;
default:
break;
}
@ -358,6 +367,14 @@ public class Trigger
else
Miscellaneous.logEvent("i", "NotificationCheck", "A required text for a notification trigger was not specified.", 5);
/*
We can only get here through the startup routine of the main service.
Because the notification did not come in at runtime, but was there
before we started, w need to take a record of it.
*/
if(NotificationListener.getLastNotification() == null)
NotificationListener.setLastNotification(sn);
foundMatch = true;
break;
}
@ -609,6 +626,141 @@ public class Trigger
return false;
}
public boolean checkCalendarEvent(boolean ignoreActive)
{
try
{
List<CalendarReceiver.CalendarEvent> calendarEvents = CalendarReceiver.readCalendarEvents(AutomationService.getInstance(), true,false);
for(CalendarReceiver.CalendarEvent event : calendarEvents)
{
if(!checkCalendarEvent(event, ignoreActive))
continue;
return true;
}
// At this point none of the calendar items match this trigger
/*
If trigger demands no calendar event and there is absolutely no future event,
further criteria don't matter if there are no events to check.
*/
if(calendarEvents.size() == 0 && getTriggerParameter() == false)
return true;
}
catch(Exception e)
{
Miscellaneous.logEvent("e", "checkCalendarEvent()", Log.getStackTraceString(e), 1);
}
return false;
}
public boolean checkCalendarEvent(CalendarReceiver.CalendarEvent event, boolean ignoreActive)
{
String[] conditions = this.getTriggerParameter2().split(Trigger.triggerParameter2Split);
List<CalendarReceiver.CalendarEvent> calendarEvents = CalendarReceiver.readCalendarEvents(AutomationService.getInstance(), true,false);
/*
0 = titleDir
1 = title
2 = descriptionDir
3 = description
4 = locationDir
5 = location
6 = evaluate all day event
7 = all day event
8 = evaluate reoccurring
9 = reoccurring
10 = availability list
11 = calendars list
*/
boolean isActive = getTriggerParameter();
if (!ignoreActive && isActive != event.isCurrentlyActive())
{
Miscellaneous.logEvent("i", "CalendarCheck", "Event " + event.title + " has to be currently active: " + String.valueOf(triggerParameter) + ", but is required otherwise.", 5);
return false;
}
if (!StringUtils.isEmpty(conditions[1]))
{
if (!Miscellaneous.compare(conditions[0], conditions[1], event.title))
{
Miscellaneous.logEvent("i", "CalendarCheck", "Title of event " + event.title + " does not match.", 5);
return false;
}
}
if (!StringUtils.isEmpty(conditions[3]))
{
if (!Miscellaneous.compare(conditions[2], conditions[3], event.description))
{
Miscellaneous.logEvent("i", "CalendarCheck", "Description " + event.title + " does not match.", 5);
return false;
}
}
if (!StringUtils.isEmpty(conditions[5]))
{
if (!Miscellaneous.compare(conditions[4], conditions[5], event.location))
{
Miscellaneous.logEvent("i", "CalendarCheck", "Location " + event.title + " does not match.", 5);
return false;
}
}
if (Boolean.parseBoolean(conditions[6]))
{
if (Boolean.parseBoolean(conditions[7]) != event.allDay)
{
Miscellaneous.logEvent("i", "CalendarCheck", "All day setting " + event.title + " does not match.", 5);
return false;
}
}
if (Boolean.parseBoolean(conditions[8]))
{
if (Boolean.parseBoolean(conditions[9]) != event.reoccurring)
{
Miscellaneous.logEvent("i", "CalendarCheck", "Reoccurring setting " + event.title + " does not match.", 5);
return false;
}
}
if (!StringUtils.isEmpty(conditions[10]))
{
String[] availabilities = conditions[10].split(ActivityManageTriggerCalendar.separator);
if (availabilities.length > 0)
{
if (!Miscellaneous.arraySearch(availabilities, event.availability, false, true))
{
Miscellaneous.logEvent("i", "CalendarCheck", "Availability of event " + event.title + " does not match.", 5);
return false;
}
}
}
if (!StringUtils.isEmpty(conditions[11]))
{
String[] calendars = conditions[11].split(ActivityManageTriggerCalendar.separator);
if (calendars.length > 0)
{
if (!Miscellaneous.arraySearch(calendars, String.valueOf(event.calendarId), false, true))
{
Miscellaneous.logEvent("i", "CalendarCheck", "Calendar of event " + event.title + " does not match.", 5);
return false;
}
}
}
// No contradictions found
Miscellaneous.logEvent("i", "CalendarCheck", "Event " + event + " matches.", 4);
return true;
}
boolean checkBluetooth()
{
Miscellaneous.logEvent("i", Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), String.format("Checking for bluetooth...", this.getParentRule().getName()), 4);
@ -948,13 +1100,13 @@ public class Trigger
{
if(!this.getTriggerParameter())
{
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 entering POI: " + this.getPointOfInterest().getName() + ", not leaving it.", getParentRule().getName()), 4);
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 entering POI: " + this.getPointOfInterest().getName() + ", not leaving it.", getParentRule().getName()), 4);
return false;
}
}
else
{
Miscellaneous.logEvent("i", String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), this.getParentRule().getName()), String.format("Rule %1$s doesn't apply. This is " + activePoi.getName() + ", not " + this.getPointOfInterest().getName() + ".", getParentRule().getName()), 4);
Miscellaneous.logEvent("i", String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), this.getParentRule().getName()), String.format("Rule \"%1$s\" doesn't apply. This is " + activePoi.getName() + ", not " + this.getPointOfInterest().getName() + ".", getParentRule().getName()), 4);
return false;
}
}
@ -980,7 +1132,7 @@ public class Trigger
}
else
{
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;
}
// }
@ -989,7 +1141,7 @@ public class Trigger
{
if(!this.getTriggerParameter())
{
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 at no POI. Rule specifies to be at anyone.", getParentRule().getName()), 5);
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 at no POI. Rule specifies to be at anyone.", getParentRule().getName()), 5);
return false;
}
}
@ -1020,22 +1172,34 @@ public class Trigger
boolean checkCharging()
{
if(BatteryReceiver.isDeviceCharging(Miscellaneous.getAnyContext()) == 0)
if(BatteryReceiver.isDeviceCharging(Miscellaneous.getAnyContext()) == 0) // unknown state
{
return false; // unknown charging state, can't activate rule under these conditions
}
else if(BatteryReceiver.isDeviceCharging(Miscellaneous.getAnyContext()) == 1)
else if(BatteryReceiver.isDeviceCharging(Miscellaneous.getAnyContext()) == 1) // we are discharging
{
if(this.getTriggerParameter()) //rule says when charging, but we're currently discharging
return false;
if(!this.getTriggerParameter()) // rule says when charging, but we're currently discharging
return true;
}
else if(BatteryReceiver.isDeviceCharging(Miscellaneous.getAnyContext()) == 2)
else if(BatteryReceiver.isDeviceCharging(Miscellaneous.getAnyContext()) == 2) // we are charging
{
if(!this.getTriggerParameter()) //rule says when discharging, but we're currently charging
return false;
if(this.getTriggerParameter()) // rule says when discharging, but we're currently charging
{
// check charging type
if(StringUtils.isEmpty(getTriggerParameter2()))
return true;
else
{
int desiredType;
String[] typeParams = getTriggerParameter2().split(triggerParameter2Split, -1);
desiredType = Integer.parseInt(typeParams[0]);
if(desiredType == BatteryReceiver.getCurrentChargingType())
return true;
}
}
}
return true;
return false;
}
boolean checkTetheringActive()
@ -1474,6 +1638,20 @@ public class Trigger
else
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.stopping) + " ");
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.triggerCharging));
returnString.append(" (");
if(!StringUtils.isEmpty(getTriggerParameter2()))
{
String[] pieces = getTriggerParameter2().split(triggerParameter2Split, -1);
if(pieces[0].equals("0"))
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.any));
else if(pieces[0].equals(String.valueOf(BatteryManager.BATTERY_PLUGGED_AC)))
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.charging_AC));
else if(pieces[0].equals(String.valueOf(BatteryManager.BATTERY_PLUGGED_USB)))
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.usb));
else if(pieces[0].equals(String.valueOf(BatteryManager.BATTERY_PLUGGED_WIRELESS)))
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.charging_wireless));
}
returnString.append(")");
break;
case batteryLevel:
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.batteryLevel));
@ -1813,6 +1991,55 @@ public class Trigger
else
returnString.append(String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.variableCheckStringDeleted), triggerParameter2));
break;
case calendarEvent:
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.calendarEvent));
returnString.append(" (");
if(triggerParameter)
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.eventIsCurrentlyHappening));
else
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.eventIsCurrentlyNotHappening));
returnString.append( ", ");
String[] conditions = triggerParameter2.split(triggerParameter2Split, -1);
if (!StringUtils.isEmpty(conditions[1]))
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.title) + " " + conditions[0] + " " + conditions[1] + ", ");
if (!StringUtils.isEmpty(conditions[3]))
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.location) + " " + conditions[2] + " " + conditions[3] + ", ");
if (!StringUtils.isEmpty(conditions[5]))
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.calendarDescription) + " " + conditions[4] + " " + conditions[5] + ", ");
if(Boolean.parseBoolean(conditions[6]))
{
if (Boolean.parseBoolean(conditions[7]))
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.allDayEventTrue) + ", ");
else
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.allDayEventFalse) + ", ");
}
if(Boolean.parseBoolean(conditions[8]))
{
if (Boolean.parseBoolean(conditions[9]))
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.reoccurringTrue) + ", ");
else
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.reoccurringFalse) + ", ");
}
if (!StringUtils.isEmpty(conditions[10]))
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.availabilities) + " " + conditions[10] + ", ");
if (!StringUtils.isEmpty(conditions[11]))
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.calendars) + " " + conditions[11]);
if (returnString.toString().endsWith(", "))
returnString.delete(returnString.length() - 2, returnString.length());
returnString.append(")");
break;
default:
returnString.append("error");
break;

View File

@ -217,7 +217,7 @@ public class XmlFileInterface
}
serializer.endTag(null, "ProfileCollection");
serializer.startTag(null, "RuleCollection");
for(int i=0; i<Rule.getRuleCollection().size(); i++)
{
@ -1286,20 +1286,24 @@ public class XmlFileInterface
else
newTag = tag.replace("/", Action.intentPairSeparator);
String[] newTagPieces = newTag.split(";");
String[] newTagPieces = new String[0];
if(newTag.contains(Action.actionParameter2Split))
newTagPieces = newTag.split(Action.actionParameter2Split);
else
newTag.split(";");
if(newTagPieces.length < 2 || (!newTagPieces[0].contains(Actions.dummyPackageString) && newTagPieces[1].contains(Action.intentPairSeparator)))
{
newTag = Actions.dummyPackageString + ";" + newTag;
newTagPieces = newTag.split(";");
newTag = Actions.dummyPackageString + Action.actionParameter2Split + newTag;
newTagPieces = newTag.split(Action.actionParameter2Split);
}
if(newTagPieces.length < 3)
newTag += ";" + ActivityManageActionStartActivity.startByActivityString;
newTag += Action.actionParameter2Split + ActivityManageActionStartActivity.startByActivityString;
else if(newTagPieces.length >= 3)
{
if(newTagPieces[2].contains(Action.intentPairSeparator))
newTag = newTagPieces[0] + ";" + newTagPieces[1] + ";" + ActivityManageActionStartActivity.startByActivityString + ";" + newTagPieces[2];
newTag = newTagPieces[0] + Action.actionParameter2Split + newTagPieces[1] + Action.actionParameter2Split + ActivityManageActionStartActivity.startByActivityString + Action.actionParameter2Split + newTagPieces[2];
}
newAction.setParameter2(newTag);

View File

@ -272,29 +272,23 @@ public class CellLocationChangedReceiver extends PhoneStateListener
locationListenerArmed = false;
Miscellaneous.logEvent("i", "LocationListener", "Disarmed location listener, accuracy reached", 4);
}
// Miscellaneous.logEvent("i", "LocationListener", "Giving update to POI class");
// PointOfInterest.positionUpdate(up2DateLocation, parentLocationProvider.parentService);
}
@Override
public void onProviderDisabled(String provider)
{
// TODO Auto-generated method stub
}
@Override
public void onProviderEnabled(String provider)
{
// TODO Auto-generated method stub
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras)
{
// TODO Auto-generated method stub
}
}

View File

@ -11,6 +11,7 @@ import android.util.Log;
import com.jens.automation2.ActivityMainScreen;
import com.jens.automation2.AutomationService;
import com.jens.automation2.BuildConfig;
import com.jens.automation2.Miscellaneous;
import com.jens.automation2.PointOfInterest;
import com.jens.automation2.R;
@ -232,6 +233,7 @@ public class LocationProvider
public void startLocationService()
{
// startPhoneStateListener
if(!BuildConfig.FLAVOR.equals(AutomationService.flavor_name_googleplay))
PhoneStatusListener.startPhoneStatusListener(parentService); // also used to mute anouncements during calls
// startConnectivityReceiver

View File

@ -1,6 +1,5 @@
package com.jens.automation2.location;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@ -18,6 +17,8 @@ import com.jens.automation2.Rule;
import com.jens.automation2.Settings;
import com.jens.automation2.Trigger;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
public class WifiBroadcastReceiver extends BroadcastReceiver
@ -30,7 +31,7 @@ public class WifiBroadcastReceiver extends BroadcastReceiver
protected static boolean mayCellLocationChangedReceiverBeActivatedFromWifiPointOfView = true;
protected static WifiBroadcastReceiver wifiBrInstance;
protected static IntentFilter wifiListenerIntentFilter;
protected static boolean wifiListenerActive=false;
protected static boolean wifiListenerActive = false;
final static String unknownSsidName = "<unknown ssid>";
@ -46,13 +47,16 @@ public class WifiBroadcastReceiver extends BroadcastReceiver
public static void setLastWifiSsid(String newWifiSsid)
{
// Remove double quotes that sometimes come
if(newWifiSsid.startsWith("\"") && newWifiSsid.endsWith("\""))
newWifiSsid = newWifiSsid.substring(1, newWifiSsid.length()-1);
// If it's a real name, not an empty string, it's stored as the last ssid
if(newWifiSsid.length() > 0)
{
if(newWifiSsid.equals(unknownSsidName))
WifiBroadcastReceiver.lastWifiSsidReal = lastWifiSsid;
if(!newWifiSsid.equals(unknownSsidName))
WifiBroadcastReceiver.lastWifiSsidReal = lastWifiSsid;
WifiBroadcastReceiver.lastWifiSsid = newWifiSsid;
}
}
@ -72,24 +76,20 @@ public class WifiBroadcastReceiver extends BroadcastReceiver
{
try
{
// int state = -1;
if(!StringUtils.isEmpty(intent.getAction()))
Miscellaneous.logEvent("i", "WifiReceiver", "Received signal with action \""+ intent.getAction() + "\".", 4);
else
Miscellaneous.logEvent("i", "WifiReceiver", "Received signal with empty action.", 4);
NetworkInfo myWifi = null;
if(intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) // fired upon disconnection
{
// state = intent.getIntExtra(WifiManager.NETWORK_STATE_CHANGED_ACTION, -1);
// Miscellaneous.logEvent("i", "WifiReceiver", "NETWORK_STATE_CHANGED_ACTION: " + String.valueOf(state));
myWifi = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
}
WifiManager myWifiManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
// ConnectivityManager connManager = (ConnectivityManager)context.getSystemService(context.CONNECTIVITY_SERVICE);
// myWifi = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
// myWifi = state
// WifiInfo wifiInfo = myWifiManager.getConnectionInfo();
// SupplicantState supState = wifiInfo.getSupplicantState();
if(intent.getAction().equals(WifiManager.RSSI_CHANGED_ACTION)) // fired upon connection
{
String ssid = myWifiManager.getConnectionInfo().getSSID();
@ -105,8 +105,8 @@ public class WifiBroadcastReceiver extends BroadcastReceiver
CellLocationChangedReceiver.stopCellLocationChangedReceiver();
/*
TODO: Every time the screen is turned on, we receiver a "wifi has been connected"-event.
This is technically wrong and not really any changed to when the screen was off. It has
TODO: Every time the screen is turned on, we receive a "wifi has been connected"-event.
This is technically wrong and not really any change to when the screen was off. It has
to be filtered.
*/
}
@ -132,12 +132,12 @@ public class WifiBroadcastReceiver extends BroadcastReceiver
}
else if(!myWifi.isConnectedOrConnecting()) // really disconnected? because sometimes also fires on connect
{
if(wasConnected) // wir könnten einfach noch nicht daheim sein
if(wasConnected) // we could simply not be home yet
{
try
{
wasConnected = false;
Miscellaneous.logEvent("i", "WifiReceiver", String.format(context.getResources().getString(R.string.disconnectedFromWifi), getLastWifiSsid()) + " Switching to CellLocationChangedReceiver.", 3);
Miscellaneous.logEvent("i", "WifiReceiver", "Disconnected from wifi \"" + getLastWifiSsid() + "\". Switching to CellLocationChangedReceiver.", 3);
mayCellLocationChangedReceiverBeActivatedFromWifiPointOfView = true;
CellLocationChangedReceiver.startCellLocationChangedReceiver();
lastConnectedState = false;
@ -226,17 +226,16 @@ public class WifiBroadcastReceiver extends BroadcastReceiver
{
try
{
if(wifiListenerActive)
if (wifiListenerActive)
{
Miscellaneous.logEvent("i", "Wifi Listener", "Stopping wifiListener", 4);
wifiListenerActive = false;
parentLocationProvider.getParentService().unregisterReceiver(wifiBrInstance);
}
}
catch(Exception ex)
catch (Exception ex)
{
Miscellaneous.logEvent("e", "Wifi Listener", "Error stopping wifiListener: " + Log.getStackTraceString(ex), 3);
}
}
}

View File

@ -7,7 +7,6 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.util.Log;
import android.widget.Toast;
import com.jens.automation2.ActivityPermissions;
import com.jens.automation2.AutomationService;
@ -25,6 +24,9 @@ public class BatteryReceiver extends BroadcastReceiver implements AutomationList
static boolean batteryReceiverActive = false;
static IntentFilter batteryIntentFilter = null;
static Intent batteryStatus = null;
private static int currentChargingState = 0; //0=unknown, 1=no, 2=yes
private static int currentChargingType = 0; //AC, wireless, USB
static BroadcastReceiver batteryInfoReceiverInstance = null;
public static void startBatteryReceiver(final AutomationService automationServiceRef)
@ -41,8 +43,6 @@ public class BatteryReceiver extends BroadcastReceiver implements AutomationList
batteryIntentFilter = new IntentFilter();
batteryIntentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
batteryIntentFilter.addAction(Intent.ACTION_BATTERY_LOW);
// batteryIntentFilter.addAction(Intent.ACTION_POWER_CONNECTED);
// batteryIntentFilter.addAction(Intent.ACTION_POWER_DISCONNECTED);
}
batteryStatus = automationServiceRef.registerReceiver(batteryInfoReceiverInstance, batteryIntentFilter);
@ -79,8 +79,6 @@ public class BatteryReceiver extends BroadcastReceiver implements AutomationList
return batteryLevel;
}
private static int currentChargingState = 0; //0=unknown, 1=no, 2=yes
public static int getCurrentChargingState()
{
return currentChargingState;
@ -123,7 +121,12 @@ public class BatteryReceiver extends BroadcastReceiver implements AutomationList
case BatteryManager.BATTERY_PLUGGED_AC:
// Toast.makeText(context, "Regular charging", Toast.LENGTH_LONG).show();
Miscellaneous.logEvent("i", "BatteryReceiver", "Regular charging.", 5);
this.actionCharging(context);
this.actionCharging(context, statusPlugged);
break;
case BatteryManager.BATTERY_PLUGGED_WIRELESS:
// Toast.makeText(context, "Regular charging", Toast.LENGTH_LONG).show();
Miscellaneous.logEvent("i", "BatteryReceiver", "Wireless charging.", 5);
this.actionCharging(context, statusPlugged);
break;
case BatteryManager.BATTERY_PLUGGED_USB:
this.actionUsbConnected(context);
@ -134,8 +137,8 @@ public class BatteryReceiver extends BroadcastReceiver implements AutomationList
{
case BatteryManager.BATTERY_STATUS_CHARGING:
case BatteryManager.BATTERY_STATUS_FULL:
Miscellaneous.logEvent("i", "BatteryReceiver", "Device has been fully charged.", 5);
this.actionCharging(context);
// Miscellaneous.logEvent("i", "BatteryReceiver", "Device has been fully charged.", 5);
this.actionCharging(context, statusPlugged);
break;
case BatteryManager.BATTERY_STATUS_DISCHARGING:
case BatteryManager.BATTERY_STATUS_NOT_CHARGING:
@ -155,28 +158,33 @@ public class BatteryReceiver extends BroadcastReceiver implements AutomationList
switch(currentChargingState)
{
case 0:
Miscellaneous.logEvent("w", "ChargingInfo", "Status of device charging was requested. Information isn't available, yet.", 4);
Miscellaneous.logEvent("w", "ChargingInfo", "Information isn't available, yet.", 4);
break;
case 1:
Miscellaneous.logEvent("i", "ChargingInfo", "Status of device charging was requested. Device is discharging.", 3);
Miscellaneous.logEvent("i", "ChargingInfo", "Device is discharging.", 3);
break;
case BatteryManager.BATTERY_STATUS_CHARGING:
Miscellaneous.logEvent("i", "ChargingInfo", "Status of device charging was requested. Device is charging.", 3);
Miscellaneous.logEvent("i", "ChargingInfo", "Device is charging.", 3);
break;
}
return currentChargingState;
}
private void actionCharging(Context context)
public static int getCurrentChargingType()
{
return currentChargingType;
}
private void actionCharging(Context context, int statusPlugged)
{
if(currentChargingState != BatteryManager.BATTERY_STATUS_CHARGING) // Avoid flooding the log. This event will occur on a regular basis even though charging state wasn't changed.
{
Miscellaneous.logEvent("i", "BatteryReceiver", "Battery is charging or full.", 3);
currentChargingState = BatteryManager.BATTERY_STATUS_CHARGING;
//activate rule(s)
currentChargingType = statusPlugged;
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidates(Trigger_Enum.charging);
// ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByCharging(true);
for(int i=0; i<ruleCandidates.size(); i++)
{
if(ruleCandidates.get(i).getsGreenLight(context))
@ -229,14 +237,13 @@ public class BatteryReceiver extends BroadcastReceiver implements AutomationList
// Toast.makeText(context, "Connected to computer.", Toast.LENGTH_LONG).show();
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidates(Trigger_Enum.usb_host_connection);
// ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByUsbHost(true);
for(Rule oneRule : ruleCandidates)
{
if(oneRule.getsGreenLight(context))
oneRule.activate(automationServiceRef, false);
}
this.actionCharging(context);
this.actionCharging(context, BatteryManager.BATTERY_PLUGGED_USB);
}
}

View File

@ -52,9 +52,13 @@ public class BroadcastListener extends android.content.BroadcastReceiver impleme
{
broadcastsCollection.add(new EventOccurrence(Calendar.getInstance(), intent.getAction()));
for(String key : intent.getExtras().keySet())
Miscellaneous.logEvent("i", "Broadcast received", "Broadcast " + intent.getAction() + " received.", 4);
if(intent.getExtras() != null && intent.getExtras().size() > 0)
{
Miscellaneous.logEvent("i", "Broadcast extra", "Broadcast " + intent.getAction() + " has extra " + key + " and type " + intent.getExtras().get(key).getClass().getName(), 4);
for (String key : intent.getExtras().keySet())
{
Miscellaneous.logEvent("i", "Broadcast extra", "Broadcast " + intent.getAction() + " has extra " + key + " and type " + intent.getExtras().get(key).getClass().getName(), 4);
}
}
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidates(Trigger.Trigger_Enum.broadcastReceived);

View File

@ -0,0 +1,659 @@
package com.jens.automation2.receivers;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.provider.CalendarContract;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.jens.automation2.AutomationService;
import com.jens.automation2.Miscellaneous;
import com.jens.automation2.Rule;
import com.jens.automation2.Trigger;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
public class CalendarReceiver extends BroadcastReceiver implements AutomationListenerInterface
{
static CalendarReceiver calendarReceiverInstance = null;
static boolean calendarReceiverActive = false;
static IntentFilter calendarIntentFilter = null;
private static Intent calendarIntent = null;
public static final int AVAILABILITY_OUT_OF_OFFICE = 4;
public static final int AVAILABILITY_WORKING_ELSEWHERE = 5;
public static final String calendarAlarmAction = "ALARM_FOR_CALENDAR";
static List<AndroidCalendar> calendarsCache = null;
static List<CalendarEvent> calendarEventsCache = null;
static List<CalendarEvent> calendarEventsReoccurringCache = null;
// To determine for which events which rules have been executed
static List<RuleEventPair> calendarEventsUsed = new ArrayList<>();
static Timer timer = null;
static TimerTask timerTask = null;
static Calendar nextWakeup = null;
static AlarmManager alarmManager = null;
static boolean wakeupNeedsToBeScheduledOrRescheduled = false;
public static CalendarEvent getLastTriggeringEvent()
{
if(calendarEventsUsed.size() > 0)
{
return calendarEventsUsed.get(calendarEventsUsed.size() -1).event;
}
return null;
}
public static class RuleEventPair
{
Rule rule;
CalendarEvent event;
public RuleEventPair(Rule rule, CalendarEvent event)
{
this.rule = rule;
this.event = event;
}
}
public static void addUsedPair(RuleEventPair pair)
{
// Add pair only if it's not in the list already.
for(RuleEventPair usedPair : calendarEventsUsed)
{
if(usedPair.rule.equals(pair.rule) && usedPair.event.equals(pair.event))
return;
}
calendarEventsUsed.add(pair);
}
public static CalendarReceiver getInstance()
{
if(calendarReceiverInstance == null)
calendarReceiverInstance = new CalendarReceiver();
return calendarReceiverInstance;
}
@Override
public void onReceive(Context context, Intent intent)
{
Miscellaneous.logEvent("i", "CalendarReceiver", "Received " + intent.getAction(), 4);
if(intent.getAction().equalsIgnoreCase(Intent.ACTION_PROVIDER_CHANGED))
{
Miscellaneous.logEvent("i", "CalendarReceiver", "Clearing calendar caches.", 4);
clearCaches();
routineAtAlarm();
}
else if(intent.getAction().equalsIgnoreCase(calendarAlarmAction))
{
routineAtAlarm();
}
}
static void checkForRules(Context context)
{
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidates(Trigger.Trigger_Enum.calendarEvent);
for (int i = 0; i < ruleCandidates.size(); i++)
{
if (ruleCandidates.get(i).getsGreenLight(context))
ruleCandidates.get(i).activate(AutomationService.getInstance(), false);
}
}
@Override
public void startListener(AutomationService automationServiceRef)
{
startCalendarReceiver(automationServiceRef);
}
static void clearCaches()
{
calendarsCache = null;
calendarEventsCache = null;
calendarEventsReoccurringCache = null;
}
@Override
public void stopListener(AutomationService automationService)
{
if(calendarReceiverActive)
{
if(calendarReceiverInstance != null)
{
AutomationService.getInstance().unregisterReceiver(calendarReceiverInstance);
calendarReceiverInstance = null;
}
clearCaches();
calendarEventsUsed.clear();
calendarReceiverActive = false;
}
}
@Override
public boolean isListenerRunning()
{
return calendarReceiverActive;
}
@Override
public Trigger.Trigger_Enum[] getMonitoredTrigger()
{
return new Trigger.Trigger_Enum[]{Trigger.Trigger_Enum.calendarEvent};
}
public static class AndroidCalendar
{
public int calendarId;
public String displayName;
public String accountString;
@NonNull
@Override
public String toString()
{
return displayName + " (" + accountString + ")";
}
}
public static class CalendarEvent
{
public AndroidCalendar calendar;
public int calendarId;
public String eventId;
public String title;
public String description;
public String location;
public String availability;
public Calendar start, end;
public boolean allDay, reoccurring;
public boolean isCurrentlyActive()
{
Calendar now = Calendar.getInstance();
return now.getTimeInMillis() >= start.getTimeInMillis() && now.getTimeInMillis() < end.getTimeInMillis();
}
@NonNull
@Override
public String toString()
{
return "Title: " + title + ", location: " + location + ", description: " + description + ", start: " + Miscellaneous.formatDate(start.getTime()) + ", end: " + Miscellaneous.formatDate(end.getTime()) + ", is currently active: " + String.valueOf(isCurrentlyActive()) + ", all day: " + String.valueOf(allDay) + ", availability: " + availability;
}
@Override
public boolean equals(@Nullable Object obj)
{
try
{
CalendarEvent compareEvent = (CalendarEvent) obj;
return calendarId == compareEvent.calendarId
&&
eventId.equals(compareEvent.eventId)
&&
title.equals(compareEvent.title)
&&
description.equals(compareEvent.description)
&&
location.equals(compareEvent.location)
&&
availability.equals(compareEvent.availability)
&&
start.getTimeInMillis() == compareEvent.start.getTimeInMillis()
&&
end.getTimeInMillis() == compareEvent.end.getTimeInMillis()
&&
allDay == compareEvent.allDay;
}
catch (Exception e)
{
Miscellaneous.logEvent("e", "CalendarReceiver compare()", Log.getStackTraceString(e), 5);
return false;
}
}
}
public static List<AndroidCalendar> readCalendars(Context context)
{
if(calendarsCache == null)
{
calendarsCache = new ArrayList<>();
Cursor cursor;
cursor = context.getContentResolver().query(
Uri.parse("content://com.android.calendar/calendars"),
new String[]{ CalendarContract.Calendars._ID, CalendarContract.Calendars.CALENDAR_DISPLAY_NAME, CalendarContract.Calendars.OWNER_ACCOUNT, },
null, null, null);
cursor.moveToFirst();
// fetching calendars name
String CNames[] = new String[cursor.getCount()];
for (int i = 0; i < CNames.length; i++)
{
try
{
AndroidCalendar calendar = new AndroidCalendar();
calendar.calendarId = Integer.parseInt(cursor.getString(0));
calendar.displayName = cursor.getString(1);
calendar.accountString = cursor.getString(2);
calendarsCache.add(calendar);
}
catch (Exception e)
{
}
cursor.moveToNext();
}
if (cursor != null)
cursor.close();
}
return calendarsCache;
}
public static List<CalendarEvent> readCalendarEvents(Context context, boolean includeReoccurring, boolean includePastEvents)
{
if(calendarEventsCache == null)
{
calendarEventsCache = new ArrayList<>();
Cursor cursor;
cursor = context.getContentResolver().query(
Uri.parse("content://com.android.calendar/events"),
new String[] {
CalendarContract.Events.CALENDAR_ID,
CalendarContract.Events._ID,
CalendarContract.Events.TITLE,
CalendarContract.Events.DESCRIPTION,
CalendarContract.Events.ALL_DAY,
CalendarContract.Events.DTSTART,
CalendarContract.Events.DTEND,
CalendarContract.Events.EVENT_LOCATION,
CalendarContract.Events.AVAILABILITY
},
null, null, null);
cursor.moveToFirst();
// fetching calendars name
String CNames[] = new String[cursor.getCount()];
Calendar now = Calendar.getInstance();
for (int i = 0; i < CNames.length; i++)
{
try
{
CalendarEvent event = new CalendarEvent();
event.calendarId = Integer.parseInt(cursor.getString(0));
for(AndroidCalendar cal : readCalendars(context))
{
if(cal.calendarId == event.calendarId)
{
event.calendar = cal;
break;
}
}
event.eventId = cursor.getString(1);
event.title = cursor.getString(2);
event.description = cursor.getString(3);
event.allDay = cursor.getString(4).equals("1");
event.start = Miscellaneous.calendarFromLong(Long.parseLong(cursor.getString(5)));
event.end = Miscellaneous.calendarFromLong(Long.parseLong(cursor.getString(6)));
event.location = cursor.getString(7);
event.availability = cursor.getString(8);
event.reoccurring = false;
if(includePastEvents || event.end.getTimeInMillis() > now.getTimeInMillis())
calendarEventsCache.add(event);
}
catch (Exception e)
{}
cursor.moveToNext();
}
if(cursor != null)
cursor.close();
}
if(includeReoccurring && calendarEventsReoccurringCache == null)
{
calendarEventsReoccurringCache = new ArrayList<>();
Cursor cursor;
Calendar queryStart, queryEnd;
if(includePastEvents)
queryStart = Miscellaneous.calendarFromLong(0);
else
queryStart = Calendar.getInstance();
queryEnd = Calendar.getInstance();
queryEnd.add(Calendar.YEAR, 1);
cursor = context.getContentResolver().query(
Uri.parse("content://com.android.calendar/instances/when/" + queryStart.getTimeInMillis() + "/" + queryEnd.getTimeInMillis()),
new String[] {
CalendarContract.Instances.CALENDAR_ID,
CalendarContract.Instances._ID,
CalendarContract.Instances.TITLE,
CalendarContract.Instances.DESCRIPTION,
CalendarContract.Instances.ALL_DAY,
CalendarContract.Instances.BEGIN,
CalendarContract.Instances.END,
CalendarContract.Instances.EVENT_LOCATION,
CalendarContract.Instances.AVAILABILITY
},
null, null, null);
cursor.moveToFirst();
String CNames[] = new String[cursor.getCount()];
Calendar now = Calendar.getInstance();
for (int i = 0; i < CNames.length; i++)
{
try
{
CalendarEvent event = new CalendarEvent();
event.calendarId = Integer.parseInt(cursor.getString(0));
for(AndroidCalendar cal : readCalendars(context))
{
if(cal.calendarId == event.calendarId)
{
event.calendar = cal;
break;
}
}
event.eventId = cursor.getString(1);
event.title = cursor.getString(2);
event.description = cursor.getString(3);
event.allDay = cursor.getString(4).equals("1");
event.start = Miscellaneous.calendarFromLong(Long.parseLong(cursor.getString(5)));
event.end = Miscellaneous.calendarFromLong(Long.parseLong(cursor.getString(6)));
event.location = cursor.getString(7);
event.availability = cursor.getString(8);
event.reoccurring = true;
if(includePastEvents || event.end.getTimeInMillis() > now.getTimeInMillis())
{
// For the moment keeping separate records to some extent
calendarEventsReoccurringCache.add(event);
calendarEventsCache.add(event);
}
}
catch (Exception e)
{}
cursor.moveToNext();
}
if(cursor != null)
cursor.close();
}
return calendarEventsCache;
}
protected static void routineAtAlarm()
{
checkForRules(Miscellaneous.getAnyContext());
// Set next timer
calculateNextWakeup();
armOrRearmTimer();
}
public static void armOrRearmTimer()
{
PendingIntent pi = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
{
if (alarmManager == null)
{
alarmManager = (AlarmManager) Miscellaneous.getAnyContext().getSystemService(Context.ALARM_SERVICE);
}
if(pi == null)
{
Intent intent = new Intent(Miscellaneous.getAnyContext(), CalendarReceiver.class);
intent.setAction(calendarAlarmAction);
pi = PendingIntent.getBroadcast(AutomationService.getInstance(), 0, intent, 0);
}
}
else
{
timerTask = new TimerTask()
{
@Override
public void run()
{
routineAtAlarm();
}
};
if(timer != null)
{
timer.cancel();
timer.purge();
}
timer = new Timer();
}
if(nextWakeup == null)
{
readCalendarEvents(Miscellaneous.getAnyContext(), true,false);
calculateNextWakeup();
}
// If it's now filled, go on
if(nextWakeup != null && wakeupNeedsToBeScheduledOrRescheduled)
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
{
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && alarmManager.canScheduleExactAlarms()))
{
try
{
alarmManager.cancel(pi);
}
catch (Exception e)
{
}
Miscellaneous.logEvent("i", "armOrRearmTimer()", "Scheduling wakeup for calendar at " + Miscellaneous.formatDate(nextWakeup.getTime()), 4);
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, nextWakeup.getTimeInMillis(), pi);
wakeupNeedsToBeScheduledOrRescheduled = false;
}
}
else
timer.schedule(timerTask, nextWakeup.getTimeInMillis());
}
}
private static void calculateNextWakeup()
{
Calendar now = Calendar.getInstance();
List<CalendarEvent> events = readCalendarEvents(Miscellaneous.getAnyContext(), true, false);
if (events.size() == 0)
{
Miscellaneous.logEvent("i", "calculateNextWakeup()", "No future events, nothing to schedule.", 4);
}
else
{
List<Rule> ruleCandidates = Rule.findRuleCandidates(Trigger.Trigger_Enum.calendarEvent);
List<Long> wakeUpCandidatesList = new ArrayList<>();
for (CalendarEvent event : events)
{
for (Rule r : ruleCandidates)
{
for (Trigger t : r.getTriggerSet())
{
if (t.getTriggerType().equals(Trigger.Trigger_Enum.calendarEvent) && t.checkCalendarEvent(event, true))
{
/*
Device needs to wakeup at start AND end of events, no matter what is specified in triggers.
This is because we also need to know when a trigger doesn't apply anymore to make it
count for hasStateNotAppliedSinceLastRuleExecution().
Otherwise the same rule would not get executed again even after calendar events have come and gone.
*/
if(event.start.getTimeInMillis() > now.getTimeInMillis())
wakeUpCandidatesList.add(event.start.getTimeInMillis());
if(event.end.getTimeInMillis() > now.getTimeInMillis())
wakeUpCandidatesList.add(event.end.getTimeInMillis());
}
}
}
}
Collections.sort(wakeUpCandidatesList);
if(wakeUpCandidatesList.size() == 0)
Miscellaneous.logEvent("i", "calculateNextWakeupForCalendar()", "Not scheduling any calendar related wakeup as there are no future events that might match a configured trigger.", 4);
else
{
if (nextWakeup == null || nextWakeup.getTimeInMillis() != wakeUpCandidatesList.get(0))
{
Calendar newAlarm = Miscellaneous.calendarFromLong(wakeUpCandidatesList.get(0));
if (nextWakeup == null)
Miscellaneous.logEvent("i", "calculateNextWakeupForCalendar()", "Chose " + Miscellaneous.formatDate(newAlarm.getTime()) + " as next wakeup for calendar triggers. Old was null.", 4);
else
Miscellaneous.logEvent("i", "calculateNextWakeupForCalendar()", "Chose " + Miscellaneous.formatDate(newAlarm.getTime()) + " as next wakeup for calendar triggers. Old was " + Miscellaneous.formatDate(nextWakeup.getTime()), 4);
nextWakeup = newAlarm;
if (!wakeupNeedsToBeScheduledOrRescheduled)
wakeupNeedsToBeScheduledOrRescheduled = true;
}
else
Miscellaneous.logEvent("i", "calculateNextWakeupForCalendar()", "Alarm " + Miscellaneous.formatDate(nextWakeup.getTime()) + " has been selected as next wakeup, but not rescheduling since this was not a change.", 4);
}
}
}
public static void startCalendarReceiver(final AutomationService automationServiceRef)
{
if (!calendarReceiverActive)
{
if (calendarReceiverInstance == null)
calendarReceiverInstance = new CalendarReceiver();
if (calendarIntentFilter == null)
{
calendarIntentFilter = new IntentFilter();
calendarIntentFilter.addAction(Intent.ACTION_PROVIDER_CHANGED);
calendarIntentFilter.addDataScheme("content");
calendarIntentFilter.addDataAuthority("com.android.calendar", null);
}
calendarIntent = automationServiceRef.registerReceiver(calendarReceiverInstance, calendarIntentFilter);
calendarReceiverActive = true;
armOrRearmTimer();
}
}
public static boolean mayRuleStillBeActivatedForPendingCalendarEvents(Rule rule)
{
for(RuleEventPair pair : calendarEventsUsed)
Miscellaneous.logEvent("i", "mayRuleStillBeActivatedForPendingCalendarEvents()", "Existing pair of " + pair.rule.getName() + " and " + pair.event, 5);
for(CalendarEvent event : readCalendarEvents(Miscellaneous.getAnyContext(), true,false))
{
for(Trigger t : rule.getTriggerSet())
{
if(t.getTriggerType().equals(Trigger.Trigger_Enum.calendarEvent) && t.checkCalendarEvent(event, false))
{
if (!hasEventBeenUsedInRule(rule, event))
{
/*
If there are multiple parallel calendar events and a rule has multiple
triggers of type calendar event, we don't want the rule to fire only once.
*/
if(rule.getAmountOfTriggersForType(Trigger.Trigger_Enum.calendarEvent) == 1)
{
Miscellaneous.logEvent("i", "mayRuleStillBeActivatedForPendingCalendarEvents()", "Rule " + rule.getName() + " has not been used in conjunction with event " + event, 4);
return true;
}
}
}
}
}
return false;
}
public static boolean hasEventBeenUsedInRule(Rule rule, CalendarEvent event)
{
for (RuleEventPair executedPair : calendarEventsUsed)
{
if (executedPair.rule.equals(rule) && executedPair.event.equals(event))
return true;
}
return false;
}
public static List<CalendarReceiver.CalendarEvent> getApplyingCalendarEvents(Rule rule)
{
List<CalendarReceiver.CalendarEvent> returnList = new ArrayList<>();
try
{
List<CalendarReceiver.CalendarEvent> calendarEvents = CalendarReceiver.readCalendarEvents(AutomationService.getInstance(), true,false);
for(Trigger t : rule.getTriggerSet())
{
if(t.getTriggerType().equals(Trigger.Trigger_Enum.calendarEvent))
{
for (CalendarReceiver.CalendarEvent event : calendarEvents)
{
if (t.checkCalendarEvent(event, false))
returnList.add(event);
}
}
}
}
catch(Exception e)
{
Miscellaneous.logEvent("e", "getApplyingCalendarEvents()", Log.getStackTraceString(e), 1);
}
return returnList;
}
}

View File

@ -11,6 +11,7 @@ import android.util.Log;
import androidx.annotation.RequiresApi;
import com.jens.automation2.AutomationService;
import com.jens.automation2.BuildConfig;
import com.jens.automation2.Miscellaneous;
import com.jens.automation2.Rule;
import com.jens.automation2.TimeFrame;
@ -22,13 +23,14 @@ import java.sql.Time;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
public class DateTimeListener extends BroadcastReceiver implements AutomationListenerInterface
{
private static AutomationService automationServiceRef;
private static AlarmManager centralAlarmManagerInstance;
private static boolean alarmListenerActive=false;
private static boolean alarmListenerActive = false;
private static ArrayList<ScheduleElement> alarmCandidates = new ArrayList<>();
private static ArrayList<Integer> requestCodeList = new ArrayList<Integer>();
static PendingIntent alarmPendingIntent = null;
@ -200,7 +202,7 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis
{
Calendar calSchedule = getNextRepeatedExecutionAfter(oneTrigger, calNow);
alarmCandidates.add(new ScheduleElement(calSchedule, "Rule " + oneRule.getName() + ", trigger " + oneTrigger.toString()));
alarmCandidates.add(new ScheduleElement(calSchedule, "Rule " + oneRule.getName() + ", repetition in trigger " + oneTrigger.toString()));
}
}
}
@ -218,38 +220,28 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis
private static void scheduleNextAlarm()
{
Long currentTime = System.currentTimeMillis();
ScheduleElement scheduleCandidate = null;
if(alarmCandidates.size() == 0)
{
Miscellaneous.logEvent("i", "AlarmManager", "No alarms to be scheduled.", 3);
return;
}
else if(alarmCandidates.size() == 1)
else
{
// only one alarm, schedule that
scheduleCandidate = alarmCandidates.get(0);
}
else if(alarmCandidates.size() > 1)
{
scheduleCandidate = alarmCandidates.get(0);
for(ScheduleElement alarmCandidate : alarmCandidates)
{
if(Math.abs(currentTime - alarmCandidate.time.getTimeInMillis()) < Math.abs(currentTime - scheduleCandidate.time.getTimeInMillis()))
scheduleCandidate = alarmCandidate;
}
}
Intent alarmIntent = new Intent(automationServiceRef, DateTimeListener.class);
alarmPendingIntent = PendingIntent.getBroadcast(automationServiceRef, 0, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
centralAlarmManagerInstance.set(AlarmManager.RTC_WAKEUP, scheduleCandidate.time.getTimeInMillis(), alarmPendingIntent);
Collections.sort(alarmCandidates);
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);
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);
}
}
public static void clearAlarms()
@ -260,7 +252,7 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis
Intent alarmIntent = new Intent(automationServiceRef, DateTimeListener.class);
if(alarmPendingIntent == null)
alarmPendingIntent = PendingIntent.getBroadcast(automationServiceRef, requestCode, alarmIntent, 0);
// Miscellaneous.logEvent("i", "AlarmManager", "Clearing alarm with request code: " + String.valueOf(requestCode));
centralAlarmManagerInstance.cancel(alarmPendingIntent);
}
requestCodeList.clear();
@ -273,17 +265,9 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis
Miscellaneous.logEvent("i", "AlarmListener", "Starting alarm listener.", 4);
DateTimeListener.automationServiceRef = givenAutomationServiceRef;
centralAlarmManagerInstance = (AlarmManager)automationServiceRef.getSystemService(automationServiceRef.ALARM_SERVICE);
// alarmIntent = new Intent(automationServiceRef, AlarmListener.class);
// alarmPendingIntent = PendingIntent.getBroadcast(automationServiceRef, 0, alarmIntent, 0);
alarmListenerActive = true;
Miscellaneous.logEvent("i", "AlarmListener", "Alarm listener started.", 4);
DateTimeListener.setAlarms();
// // get a Calendar object with current time
// Calendar cal = Calendar.getInstance();
// // add 5 minutes to the calendar object
// cal.add(Calendar.SECOND, 10);
// centralAlarmManagerInstance.setInexactRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 5000, alarmPendingIntent);
}
else
Miscellaneous.logEvent("i", "AlarmListener", "Request to start AlarmListener. But it's already active.", 5);
@ -295,7 +279,6 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis
{
Miscellaneous.logEvent("i", "AlarmListener", "Stopping alarm listener.", 4);
clearAlarms();
centralAlarmManagerInstance.cancel(alarmPendingIntent);
alarmListenerActive = false;
}
else
@ -392,11 +375,6 @@ public class DateTimeListener extends BroadcastReceiver implements AutomationLis
Calendar calSchedule = Calendar.getInstance();
calSchedule.setTimeInMillis(nextScheduleTimestamp * 1000);
/*
* Das war mal aktiviert. Allerdings: Die ganze Funktion liefert zurück, wenn die Regel NOCH nicht
* zutrifft, aber wir z.B. gleich den zeitlichen Bereich betreten.
*/
return calSchedule;
}
else

View File

@ -3,13 +3,13 @@ package com.jens.automation2.receivers;
import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.Bundle;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.util.Log;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import com.jens.automation2.AutomationService;
@ -19,6 +19,7 @@ import com.jens.automation2.Trigger;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
// See here for reference: http://gmariotti.blogspot.com/2013/11/notificationlistenerservice-and-kitkat.html
@ -26,8 +27,6 @@ import java.util.Calendar;
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public class NotificationListener extends NotificationListenerService// implements AutomationListenerInterface
{
static Calendar lastResponseToNotification = null;
static boolean listenerRunning = false;
static NotificationListener instance;
static SimpleNotification lastNotification = null;
@ -43,13 +42,30 @@ public class NotificationListener extends NotificationListenerService// implemen
// a bitmap to be used instead of the small icon when showing the notification payload
public static final String EXTRA_LARGE_ICON = "android.largeIcon";
protected static IntentFilter notificationReceiverIntentFilter = null;
public static void setLastNotification(SimpleNotification notification)
{
lastNotification = notification;
}
public static SimpleNotification getLastNotification()
{
return lastNotification;
}
// To determine for which notifications which rules have been executed
static List<RuleNotificationPair> notificationUsed = new ArrayList<>();
public static class RuleNotificationPair
{
Rule rule;
SimpleNotification notification;
public RuleNotificationPair(Rule rule, SimpleNotification sn)
{
this.rule = rule;
this.notification = sn;
}
}
@Override
public void onCreate()
{
@ -84,6 +100,7 @@ public class NotificationListener extends NotificationListenerService// implemen
synchronized boolean checkNotification(boolean created, StatusBarNotification sbn)
{
//TODO: Merge with functino in Trigger class
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT)
{
lastNotification = convertNotificationToSimpleNotification(created, sbn);
@ -215,6 +232,19 @@ public class NotificationListener extends NotificationListenerService// implemen
", text='" + text + '\'' +
'}';
}
@Override
public boolean equals(@Nullable Object obj)
{
return
this.publishTime.getTimeInMillis() == ((SimpleNotification)obj).publishTime.getTimeInMillis()
&&
this.app.equals(((SimpleNotification)obj).app)
&&
this.title.equals(((SimpleNotification)obj).title)
&&
this.text.equals(((SimpleNotification)obj).text);
}
}
@Override
@ -235,7 +265,6 @@ public class NotificationListener extends NotificationListenerService// implemen
cancelNotification(sbn.getPackageName(), sbn.getTag(), sbn.getId());
else
cancelNotification(sbn.getKey());
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -88,21 +88,54 @@
android:textAppearance="?android:attr/textAppearanceLarge" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_margin="10dp" >
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_margin="10dp" >
<TextView
android:id="@+id/tvRuleHelpText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/helpTextRules" />
android:id="@+id/tvRuleHelpText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/helpTextRules" />
</LinearLayout>
<LinearLayout
android:layout_marginTop="10dp"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/barBackgroundColor" >
<TextView
android:id="@+id/tvProfileTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/profiles"
android:layout_marginLeft="10dp"
android:textAppearance="?android:attr/textAppearanceLarge" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_margin="10dp" >
<TextView
android:id="@+id/tvProfileHelpText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/helpTextProfiles" />
</LinearLayout>
<LinearLayout
android:layout_marginTop="10dp"

View File

@ -180,6 +180,7 @@
android:id="@+id/rbNotificationDismissSimple"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="@string/simplyDismissNotification" />
<RadioButton

View File

@ -0,0 +1,100 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_margin="@dimen/default_margin" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_span="2"
android:textSize="25dp"
android:textStyle="bold"
android:layout_marginBottom="@dimen/default_margin"
android:text="@string/actionSetLocationService"/>
<TextView
android:id="@+id/tvWifiExplanation1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/wifiExplanation1" />
<TextView
android:id="@+id/tvWifiExplanation2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/default_margin"
android:text="@string/wifiExplanation2" />
<TableLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/default_margin"
android:stretchColumns="1"
android:shrinkColumns="1" >
<TableRow
android:layout_marginTop="@dimen/default_margin">
<TextView
android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="@dimen/default_margin"
android:text="@string/state" />
<RadioGroup
android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<RadioButton
android:id="@+id/rbActionLocationServiceOff"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="@string/off" />
<RadioButton
android:id="@+id/rbActionLocationServiceSensorsOnly"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="false"
android:text="@string/LOCATION_MODE_SENSOR_ONLY" />
<RadioButton
android:id="@+id/rbActionLocationServiceBatterySaving"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="false"
android:text="@string/LOCATION_MODE_BATTERY_SAVING" />
<RadioButton
android:id="@+id/rbActionLocationServiceHighAccuracy"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="false"
android:text="@string/LOCATION_MODE_HIGH_ACCURACY" />
</RadioGroup>
</TableRow>
</TableLayout>
<Button
android:id="@+id/bActionSetLocationServiceSave"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/default_margin"
android:text="@string/save" />
</LinearLayout>
</ScrollView>

View File

@ -61,6 +61,12 @@
android:layout_marginVertical="@dimen/default_margin"
android:text="@string/setVariableExplanation" />
<TextView
android:id="@+id/tvLegend"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/urlLegend" />
<Button
android:id="@+id/bSaveVariable"
android:layout_marginTop="@dimen/default_margin"

View File

@ -293,7 +293,6 @@
android:layout_height="wrap_content">
<TextView
android:id="@+id/tvCurrentNfcIdValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/parameterName" />
@ -336,6 +335,14 @@
android:layout_marginVertical="@dimen/default_margin"
android:text="@string/intentParametersHint" />
<ListView
android:id="@+id/lvIntentPairs"
android:visibility="gone"
android:layout_marginVertical="@dimen/activity_horizontal_margin"
android:layout_width="match_parent"
android:layout_height="115dp"
android:layout_marginBottom="@dimen/default_margin" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -354,13 +361,6 @@
android:layout_margin="10dp"
android:background="#aa000000" />
<ListView
android:id="@+id/lvIntentPairs"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="115dp"
android:layout_marginBottom="@dimen/default_margin" />
<Button
android:id="@+id/bSaveActionStartOtherActivity"
android:layout_width="wrap_content"

View File

@ -90,12 +90,115 @@
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/method"
android:layout_marginTop="@dimen/fab_margin"
android:textStyle="bold" />
<RadioGroup
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<RadioButton
android:id="@+id/rbTriggerUrlMethodGet"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="@string/methodGet" />
<RadioButton
android:id="@+id/rbTriggerUrlMethodPost"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/default_margin"
android:text="@string/methodPost" />
</RadioGroup>
<TableLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:stretchColumns="1"
android:shrinkColumns="1" >
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_span="2"
android:textSize="25dp"
android:textStyle="bold"
android:layout_marginBottom="@dimen/default_margin"
android:text="@string/addParameters" />
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/parameterName" />
<EditText
android:id="@+id/etParameterName"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/parameterValue" />
<EditText
android:id="@+id/etParameterValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</TableRow>
</TableLayout>
<ImageView
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_margin="10dp"
android:background="#aa000000" />
<ListView
android:id="@+id/lvHttpParams"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="115dp"
android:layout_marginBottom="@dimen/default_margin" />
<Button
android:id="@+id/bAddHttpParam"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/addParameters" />
<ListView
android:id="@+id/lvTriggerUrlPostParameters"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone">
</ListView>
android:layout_height="115dp"
android:visibility="gone" />
<ScrollView
android:layout_width="match_parent"
@ -109,6 +212,12 @@
</ScrollView>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/default_margin"
android:text="@string/triggerUrlVariableHint" />
<Button
android:id="@+id/bSaveSpeakText"
android:layout_marginTop="15dp"

View File

@ -0,0 +1,368 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/default_margin" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/calendarEventCapital"
android:textSize="25dp"
android:layout_marginBottom="@dimen/default_margin" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/calendarTriggerExecutionHints"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/selectingNoneItemForAllToMatch"/>
<TableLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:shrinkColumns="1"
android:stretchColumns="1">
<TableRow
android:layout_marginBottom="@dimen/activity_vertical_margin">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/direction"/>
<CheckBox
android:id="@+id/chkCalendarEventActive"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/eventIsCurrentlyHappening"
android:checked="true"/>
</TableRow>
<ImageView
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_margin="10dp"
android:layout_marginVertical="@dimen/default_margin"
android:background="#aa000000" />
<TextView
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textStyle="bold"
android:text="@string/comparisonCaseInsensitive"
android:layout_marginBottom="@dimen/default_margin"/>
<TextView
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textStyle="bold"
android:text="@string/regularExpressionsIfEquals"
android:layout_marginBottom="@dimen/default_margin"/>
<TableRow
android:layout_marginBottom="@dimen/activity_vertical_margin">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="@string/title" />
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Spinner
android:id="@+id/spinnerCalendarTitleDirection"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<EditText
android:id="@+id/etCalendarTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10" />
</LinearLayout>
</TableRow>
<ImageView
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_margin="10dp"
android:layout_marginVertical="@dimen/default_margin"
android:background="#aa000000" />
<TableRow
android:layout_marginBottom="@dimen/activity_vertical_margin">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="@string/location" />
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Spinner
android:id="@+id/spinnerCalendarLocationDirection"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<EditText
android:id="@+id/etCalendarLocation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10" />
</LinearLayout>
</TableRow>
<ImageView
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_margin="10dp"
android:layout_marginVertical="@dimen/default_margin"
android:background="#aa000000" />
<TableRow
android:layout_marginBottom="@dimen/activity_vertical_margin">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="@string/calendarDescription" />
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Spinner
android:id="@+id/spinnerCalendarDescriptionDirection"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<EditText
android:id="@+id/etCalendarDescription"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10" />
</LinearLayout>
</TableRow>
<ImageView
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_margin="10dp"
android:layout_marginVertical="@dimen/default_margin"
android:background="#aa000000" />
<CheckBox
android:id="@+id/chkCalendarEvaluateAllDayEvent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/evaluate"
android:checked="false"/>
<TableRow
android:layout_marginBottom="@dimen/activity_vertical_margin">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="@string/allDayEvent" />
<CheckBox
android:id="@+id/chkCalendarAllDayEvent"
android:checked="false"
android:text="@string/allDayEventFalse"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</TableRow>
<ImageView
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_margin="10dp"
android:layout_marginVertical="@dimen/default_margin"
android:background="#aa000000" />
<CheckBox
android:id="@+id/chkCalendarEvaluateReoccurring"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/evaluate"
android:checked="false"/>
<TableRow
android:layout_marginBottom="@dimen/activity_vertical_margin">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="@string/reoccurring" />
<CheckBox
android:id="@+id/chkCalendarReoccurring"
android:checked="false"
android:text="@string/reoccurringFalse"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</TableRow>
<ImageView
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_margin="10dp"
android:layout_marginVertical="@dimen/default_margin"
android:background="#aa000000" />
<TextView
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textStyle="bold"
android:layout_marginBottom="@dimen/default_margin"
android:layout_gravity="center_vertical"
android:text="@string/selectingNoneItemForAllToMatch" />
<TableRow
android:layout_marginBottom="@dimen/activity_vertical_margin">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="@string/availability" />
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<CheckBox
android:id="@+id/chkCalendarAvailabilityBusy"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/calendarStringBusy" />
<CheckBox
android:id="@+id/chkCalendarAvailabilityFree"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/calendarStringFree" />
<CheckBox
android:id="@+id/chkCalendarAvailabilityTentative"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/calendarStringTentative" />
<CheckBox
android:id="@+id/chkCalendarAvailabilityOutOfOffice"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/calendarStringOutOfOffice" />
<CheckBox
android:id="@+id/chkCalendarAvailabilityWorkingElsewhere"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/calendarStringWorkingElsewhere" />
</LinearLayout>
</TableRow>
<TextView
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textStyle="bold"
android:layout_marginBottom="@dimen/default_margin"
android:layout_gravity="center_vertical"
android:text="@string/calendarAvailabilityTypesUnsupported" />
<ImageView
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_margin="10dp"
android:layout_marginVertical="@dimen/default_margin"
android:background="#aa000000" />
<TextView
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textStyle="bold"
android:layout_marginBottom="@dimen/default_margin"
android:layout_gravity="center_vertical"
android:text="@string/selectingNoneItemForAllToMatch" />
<TableRow
android:layout_marginBottom="@dimen/activity_vertical_margin">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="@string/calendars" />
<LinearLayout
android:id="@+id/llCalendarSelection"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</LinearLayout>
<TextView
android:id="@+id/tvMissingCalendarHint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="@dimen/default_margin"
android:layout_gravity="center_vertical"
android:textStyle="bold" />
</TableRow>
</TableLayout>
<Button
android:id="@+id/bSaveTriggerCalendar"
android:layout_marginTop="@dimen/default_margin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/save" />
</LinearLayout>
</ScrollView>

View File

@ -0,0 +1,123 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_margin="@dimen/default_margin" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_span="2"
android:textSize="25dp"
android:textStyle="bold"
android:layout_marginBottom="@dimen/default_margin"
android:text="@string/triggerCharging"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/triggerChargingComment" />
<TableLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/default_margin"
android:stretchColumns="1"
android:shrinkColumns="1" >
<TableRow
android:layout_marginTop="@dimen/default_margin">
<TextView
android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="@dimen/default_margin"
android:text="@string/state" />
<RadioGroup
android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<RadioButton
android:id="@+id/rbChargingOn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="@string/charging" />
<RadioButton
android:id="@+id/rbChargingOff"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/notCharging" />
</RadioGroup>
</TableRow>
<ImageView
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_margin="10dp"
android:background="#aa000000" />
<TableRow>
<TextView
android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="@dimen/default_margin"
android:text="@string/type" />
<RadioGroup>
<RadioButton
android:id="@+id/rbChargingTypeAny"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="@string/any" />
<RadioButton
android:id="@+id/rbChargingTypeAc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/charging_AC" />
<RadioButton
android:id="@+id/rbChargingTypeUsb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/usb" />
<RadioButton
android:id="@+id/rbChargingTypeWireless"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/charging_wireless" />
</RadioGroup>
</TableRow>
</TableLayout>
<Button
android:id="@+id/bTriggerChargingSave"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/default_margin"
android:text="@string/save" />
</LinearLayout>
</ScrollView>

View File

@ -66,6 +66,12 @@
</LinearLayout>
<TextView
android:id="@+id/tvRestrictionPermissionsNotice"
android:textColor="@color/red"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"

View File

@ -65,7 +65,7 @@
<string name="end">Ende</string>
<string name="save">Speichern</string>
<string name="urlToTrigger">URL, die ausgelöst werden soll:</string>
<string name="urlLegend">Variablen:\nSie können die folgenden Variablen verwenden. Vor dem Auslösen werden sie mit dem entsprechenden Wert Ihres Geräts ersetzt. Die Klammern müssen in den Text mit aufgenommen werden.\n\n[uniqueid] - Die Unique ID Ihres Geräts\n[serialnr] - Die Seriennummer Ihres Geräts (&lt; Android 9)\n[latitude] - Ihr gegenwärtiger Breitengrad\n[longitude] - Ihr gegenwärtiger Längengrad\n[phonenr] - Nummer des letzten ein- oder ausgehenden Anrufs\n[d] - Tag des Monats, 2-stellig mit führender Null\n[m] - Monat als Zahl, mit führenden Nullen\n[Y] - Vierstellige Jahreszahl\n[h] - Stunde im 12-Stunden-Format, mit führenden Nullen\n[H] - Stunde im 24-Stunden-Format, mit führenden Nullen\n[i] - Minuten, mit führenden Nullen\n[s] - Sekunden, mit führenden Nullen\n[ms] - milliseconds\n[notificationTitle] - Titel der letzten Benachrichtigung\n[notificationText] - Text der letzten Benachrichtigung\n[variable-VARIABLENAME] - Der Wert Ihrer selbst definitierten Variable</string>
<string name="urlLegend">Variablen:\nSie können die folgenden Variablen verwenden. Vor dem Auslösen werden sie mit dem entsprechenden Wert Ihres Geräts ersetzt. Die Klammern müssen in den Text mit aufgenommen werden.\n\n[uniqueid] - Die Unique ID Ihres Geräts\n[serialnr] - Die Seriennummer Ihres Geräts (&lt; Android 9)\n[latitude] - Ihr gegenwärtiger Breitengrad\n[longitude] - Ihr gegenwärtiger Längengrad\n[phonenr] - Nummer des letzten ein- oder ausgehenden Anrufs\n[d] - Tag des Monats, 2-stellig mit führender Null\n[m] - Monat als Zahl, mit führenden Nullen\n[Y] - Vierstellige Jahreszahl\n[h] - Stunde im 12-Stunden-Format, mit führenden Nullen\n[H] - Stunde im 24-Stunden-Format, mit führenden Nullen\n[i] - Minuten, mit führenden Nullen\n[s] - Sekunden, mit führenden Nullen\n[ms] - milliseconds\n[notificationTitle] - Titel der letzten Benachrichtigung\n[notificationText] - Text der letzten Benachrichtigung\n[last_triggerurl_result] - Das Ergebnis der letzten Ausführung der triggerUrl-Aktion\n[last_run_executable_exit_code] - Der exit code der letzten starte-Programm Aktion\n[last_run_executable_output] - Die Ausgabe der letzten starte-Programm Aktion (nur für nicht-root)\n[last_calendar_title] - Titel des letzten Regel-auslösenden Kalendertermins\n[last_calendar_description] - Beschreibung des letzten Regel-auslösenden Kalendertermins\n[last_calendar_location] - Ort des letzten Regel-auslösenden Kalendertermins\n[variable-VARIABLENAME] - Der Wert Ihrer selbst definitierten Variable</string>
<string name="wifi">WLAN</string>
<string name="activating">Aktiviere</string>
<string name="deactivating">Deaktiviere</string>
@ -120,7 +120,7 @@
<string name="soundSettings">Ton Einstellungen</string>
<string name="showHelp">Hilfe</string>
<string name="rules">Regeln</string>
<string name="helpTextRules">Alle Auslöser sind UND-verknüpft. D.h. die Regel wird nur zutreffen, wenn alle Bedingungen erfüllt sind. Wenn Sie eine ODER-Verknüpfung möchten, müssen Sie eine weitere Regel erstellen.\nDie Begriffe Auslöser und Bedingung werden synonym verwendet. Alle von ihnen sind Bedingungen, aber die letzte, die ihren erforderlichen Wert erfüllt, könnte als Auslöser bezeichnet werden, da sie das letzte Teil des Puzzles ist, um eine Regel auszuführen.</string>
<string name="helpTextRules">Alle Auslöser sind UND-verknüpft. D.h. die Regel wird nur zutreffen, wenn alle Bedingungen erfüllt sind. Wenn Sie eine ODER-Verknüpfung möchten, müssen Sie eine weitere Regel erstellen.\nDie Begriffe Auslöser und Bedingung werden synonym verwendet. Alle von ihnen sind Bedingungen, aber die letzte, die ihren erforderlichen Wert erfüllt, könnte als Auslöser bezeichnet werden, da sie das letzte Teil des Puzzles ist, um eine Regel auszuführen.\nWenn Sie bestimmte Werte aus einer Regel speichern und in einer anderen Regel auswerten möchten, schauen Sie sich mal den Auslöser/Aktion Variable an.</string>
<string name="timeframes">Zeiträume</string>
<string name="helpTextTimeFrame">Wenn Sie eine Regel mit einem Zeitraum erstellen, haben Sie zwei Möglichkeiten. Sie können wählen, ob der Auslöser besagt, daß der Zeitraum entweder verlassen ODER betreten wird. In jedem Fall wird die Regel nur einmal ausgelöst. Wenn eine Regel z.B. besagt \"betrete timeframe xyz\" und das Klingeltonprofil in Vibration ändert, bedeutet das NICHT, daß das Gerät hinterher automatisch wieder zum normalen Klingelprofil zurückschaltet. Wenn das erwünscht ist, muß eine weitere Regel mit einem Folgezeitraum erstellen werden.</string>
<string name="helpTextSound">Auf dem Hauptbildschirm können Sie die Funktion Tonänderunugen sperren benutzen, um vorrübergehend regelbasierte Tonänderungen zu deaktivieren. Z.B. könnten Sie in einer Situation oder an einem Ort sein, wo Klingeltöne normalerweise in Ordnung sind, aber dieses eine Mal würde es stören. Die Funktion wird automatisch wieder deaktiviert nachdem die eingestellte Zeit abgelaufen ist. Klicken Sie den + Knopf, um die angezeigte Zeit zur Frist hinzuzufügen. Sobald es aktiv ist, können Sie es mit dem Schalter rechts wieder abschalten (und so regelbasierte Tonänderungen wieder ermöglichen).</string>
@ -802,4 +802,57 @@
<string name="wifiTriggerDisconnectionHint">Dieser Auslöser ist gültig, wenn Sie gerade die Verbindung zu dem oben angegebenen WLAN getrennt haben ODER während der Dienst noch gestartet wird und wenn Sie mit keinem WLAN verbunden sind. Wenn Sie möchten, dass der Auslöser nur ausgelöst wird, wenn Sie die Verbindung zu einem bestimmten WLAN explizit trennen, fügen Sie einen weiteren Auslöser hinzu: \"Der Dienst wird nicht gestartet\".</string>
<string name="className">Klassenname</string>
<string name="startAppByStartForegroundService">per startForegroundService()</string>
<string name="method">Methode</string>
<string name="takeScreenshot">Screenshot erstellen</string>
<string name="android.permission.BIND_ACCESSIBILITY_SERVICE">An den Barrierefreiheitsdienst anbinden</string>
<string name="bindAccessibilityService">An den Barrierefreiheitsdienst anbinden</string>
<string name="accessibilityApiPermissionHint">Nachdem Sie auf OK geklickt haben, werden Sie zu einem Systemdialog weitergeleitet. Bitte wählen Sie dort Automatisierung aus und erlauben Sie die Barrierefreiheits-API.</string>
<string name="accessibility_service_explanation">Erforderlich für bestimmte Aktionen.</string>
<string name="noticeRestrictedPermissions">Wenn Sie eine der folgenden Berechtigungen nicht erteilen und eine Systemmeldung wie \"Eingeschränkte Berechtigung\" erhalten, müssen Sie zuerst zu den Android-Einstellungen und dann zu den Anwendungen gehen und Automatisierung auswählen. Nun sollten sich 3 Punkte in der oberen rechten Ecke befinden. Klicken Sie auf \"Eingeschränkte Einstellungen zulassen\". Danach sollte die erforderliche Erlaubnis erteilt werden können. Dies sollte nur für die APK-Version der App gelten, nicht für die von F-Droid oder dem Play Store.</string>
<string name="setLocationService">Ortungsdienst festlegen</string>
<string name="setLocationServiceCapital">Ortungsdienst einstellen</string>
<string name="writeSecureSettingsNotice">Leider kann die Erlaubnis WRITE_SECURE_SETTINGS nicht direkt auf Ihrem Android-Gerät erteilt werden. Stattdessen müssen Sie Ihr Gerät an einen Computer anschließen und die Berechtigung über ADB erteilen. Klicken Sie hier, um zu erfahren, wie Sie es gewähren können: https://server47.de/automation/adb_hack.php</string>
<string name="actionSetLocationService">Ortungsdienst</string>
<string name="triggerUrlVariableHint">Das Ergebnis dieser Anfrage wird in der Variablen LAST_TRIGGERURL_RESULT gespeichert, wenn Sie es von einer anderen Regel aus überprüfen möchten. Im Falle von HTTP-Fehlern wie 404 ist der Wert \"HTTP_ERROR\".</string>
<string name="calendarEvent">Kalendertermin</string>
<string name="eventIsCurrentlyHappening">Termin ist derzeit aktiv</string>
<string name="calendarEventCapital">Kalendertermin</string>
<string name="location">Ort</string>
<string name="calendarDescription">Beschreibung/Anmerkungen</string>
<string name="availability">Verfügbarkeit</string>
<string name="eventIsCurrentlyNotHappening">Termin findet derzeit nicht statt/ist beendet</string>
<string name="calendarStringBusy">beschäftigt</string>
<string name="calendarStringFree">frei</string>
<string name="calendarStringTentative">vorbehaltlich</string>
<string name="calendarStringOutOfOffice">nicht im Büro</string>
<string name="calendarStringWorkingElsewhere">Anderswo arbeiten</string>
<string name="selectingNoneItemForAllToMatch">Wenn Sie kein Element auswählen, ist jedes Element in Ordnung.</string>
<string name="calendars">Kalender</string>
<string name="calendarAvailabilityTypesUnsupported">Es kann sein, dass nur die ersten 3 Typen tatsächlich funktionieren, weil die anderen Typen nicht Teil der Standard-Kalenderoberfläche von Android sind.</string>
<string name="anyCalendar">beliebiger Kalender</string>
<string name="availabilities">Verfügbarkeiten</string>
<string name="calendarsMissingHint">In diesem Trigger wurden zuvor Kalender mit der ID %1$s konfiguriert, aber seitdem gelöscht. Beim nächsten Speichern werden diese aus diesem Trigger entfernt. Bis dahin wird dieser Auslöser/diese Bedingung niemals erfüllt sein.</string>
<string name="account">Konto</string>
<string name="allDayEvent">Ganztägige Veranstaltung</string>
<string name="allDayEventTrue">Die Veranstaltung ist eine ganztägige Veranstaltung</string>
<string name="allDayEventFalse">Die Veranstaltung ist keine ganztägige Veranstaltung</string>
<string name="permissionCalendarRequired">Die Berechtigung zum Lesen Ihres Kalenders ist für einen Kalenderauslöser erforderlich. Es ist bereits erforderlich, die Kalenderfelder in diesem Fenster auszufüllen.</string>
<string name="noCalendarsOnYourDevice">Es scheint, als ob auf Ihrem Gerät keine Kalender eingerichtet wurden. Sie können diesen Trigger speichern, aber er wird nie true zurückgeben.</string>
<string name="errorReadingCalendars">Beim Lesen der Kalender auf Ihrem Gerät ist ein Fehler aufgetreten.</string>
<string name="android.permission.SCHEDULE_EXACT_ALARM">Exakte Alarme setzen</string>
<string name="alarmsPermissionHint">Nach dem Klick auf OK öffnet sich ein Fenster. Bitte wählen Sie dort Automatisierung aus und erlauben Sie der App, exakte Alarme zu planen.</string>
<string name="evaluate">Auswerten</string>
<string name="errorLoadingValues">Beim Laden von Werten ist ein Fehler aufgetreten.</string>
<string name="enterValidDataIntoParametersFields">Geben Sie gültige Daten in die Parameterfelder ein.</string>
<string name="reoccurringFalse">Ereignis ist nicht wiederkehrend</string>
<string name="reoccurringTrue">Ereignis ist wiederkehrend</string>
<string name="reoccurring">wiederkehrend</string>
<string name="calendarTriggerExecutionHints">Wenn Ihr Kalender mehrere parallele, überlappende oder direkt aufeinanderfolgende Ereignisse enthält, wird eine Regel so oft ausgeführt, wie es Ereignisse gibt, die den Kriterien der Regel entsprechen. Falls eine Regel mehrere Kalenderauslöser hat und mehrere übereinstimmende Ereignisse parallel vorhanden sind, wird die Regel nur einmal ausgeführt.</string>
<string name="charging_AC">Ladegerät</string>
<string name="charging_wireless">drahtlos</string>
<string name="charging">laden</string>
<string name="notCharging">nicht laden</string>
<string name="triggerChargingComment">Der Typ wird nur ausgewertet, wenn das Gerät aufgeladen wird. Wenn \"Nicht laden\" ausgewählt ist, wird es bei jedem vorherigen Ladetyp ausgelöst. Wenn Sie dies auswerten möchten, sollten Sie die Verwendung der Variablen trigger/action in Betracht ziehen.</string>
<string name="helpTextProfiles">Ein Profil ist eine Sammlung von Einstellungen für Klingeltöne, Lautstärke und andere audiobezogene Einstellungen, die Sie über Regeln oder manuell anwenden können.\\n\\nEs ist auch möglich, das zuletzt aktivierte Profil als Auslöser abzufragen. Im Normalfall wird nur abgefragt, ob das Profil das zuletzt aktivierte war (unabhängig davon, ob in der Zwischenzeit bestimmte Audioeinstellungen geändert wurden). Sie können aber auch die einzelnen Einstellungen vergleichen lassen.</string>
<string name="serviceWontStartNoActivatedRules">Es sind keine aktivierten Regeln definiert. Der Dienst wird nicht gestartet.</string>
</resources>

View File

@ -8,9 +8,9 @@
<string name="languageDutch">Holandés</string>
<string name="languageRussian">Ruso</string>
<string name="languageFrench">Francés</string>
<string name="ruleActivate">Estoy activando regla %1$s</string>
<string name="profileActivate">Estoy activando perfil %1$s</string>
<string name="ruleActivateToggle">Estoy activando regla %1$s en el modo de invertir</string>
<string name="ruleActivate">Activando regla %1$s</string>
<string name="profileActivate">Activando perfil %1$s</string>
<string name="ruleActivateToggle">Activando regla %1$s en el modo de invertir</string>
<string name="addPoi">Crear sitio</string>
<string name="addRule">Crear regla</string>
<string name="poiList">Lista de sitios:</string>
@ -43,7 +43,7 @@
<string name="enterAname">Inserte un nombre.</string>
<string name="username">Nombre de usuario</string>
<string name="ok">Ok</string>
<string name="continueText">continuar</string>
<string name="continueText">Continuar</string>
<string name="rule">Regla</string>
<string name="android.permission.SEND_SMS">Enviar mensajes SMS</string>
<string name="android.permission.READ_CONTACTS">Leer directorio</string>
@ -127,7 +127,7 @@
<string name="actionTurnWifiOn">encender wifi</string>
<string name="actionTurnWifiOff">desactivar wifi</string>
<string name="actionTurnBluetoothOff">desactivar Bluetooth</string>
<string name="actionTriggerUrl">Abrir URL en antecedentes</string>
<string name="actionTriggerUrl">Abrir URL en el fondo</string>
<string name="actionChangeSoundProfile">Cambiar perfil sonido</string>
<string name="actionTurnUsbTetheringOn">encender enrutador USB</string>
<string name="actionTurnUsbTetheringOff">desactivar enrutador USB</string>
@ -197,7 +197,7 @@
<string name="android.permission.RECORD_AUDIO">Grabar audio</string>
<string name="android.permission.PROCESS_OUTGOING_CALLS">Detectar llamadas salientes</string>
<string name="android.permission.READ_PHONE_STATE">Detectar el estado del dispositivo</string>
<string name="android.permission.READ_EXTERNAL_STORAGE">Leer la almacenamiento</string>
<string name="android.permission.READ_EXTERNAL_STORAGE">Leer el almacenamiento</string>
<string name="android.permission.WRITE_EXTERNAL_STORAGE">Escribir en el almacenamiento</string>
<string name="android.permission.WRITE_SETTINGS">Modificar la configuración del dispositivo</string>
<string name="android.permission.BATTERY_STATS">Determinar el estado de la bateria</string>
@ -367,14 +367,14 @@
<string name="networkAccuracy">Red exactitud [m]</string>
<string name="minimumTimeForLocationUpdates">Tiempo mínimo para cambio en milisegundos para actualizar posición</string>
<string name="timeForUpdate">Tiempo para actualizar [milisegundos]</string>
<string name="urlLegend">Variables: Puede usar esas variables. Mientras ejecuta van a sustituir con los valores correspondientes en su dispositivo. Incluya las paréntecis en su texto.\n\n[uniqueid] - el número único de su dispositivo\n[serialnr] - el número de serie de su dispositivo (&lt; Android 9)\n[latitude] - su latitud\n[longitude] - su longitud\n[phonenr] - Ùltimo número de llamada realizada tanto de salida como entrante\n[d] - Dia del mes, 2 digitos con cero al comienzo\n[m] - número del mes, 2 digitos con cero al comienzo\n[Y] - Número del año, 4 digitos\n[h] - Hora, formato 12 horas con cero al comienzo\n[H] - Hora, formato 24 horas con cero al comienzo\n[i] - Minutos con cero al comienzo\n[s] - Segundos con cero al comienzo\n[ms] - milisegundos\n[notificationTitle] - Título de la última notificación\n[notificationText] - Texto de la última notificación\n[variable-VARIABLENAME] - El valor de la variable definida personalizada</string>
<string name="urlLegend">Variables: Puede usar esas variables. Mientras ejecuta van a sustituir con los valores correspondientes en su dispositivo. Incluya las paréntecis en su texto.\n\n[uniqueid] - el número único de su dispositivo\n[serialnr] - el número de serie de su dispositivo (&lt; Android 9)\n[latitude] - su latitud\n[longitude] - su longitud\n[phonenr] - Ùltimo número de llamada realizada tanto de salida como entrante\n[d] - Dia del mes, 2 digitos con cero al comienzo\n[m] - número del mes, 2 digitos con cero al comienzo\n[Y] - Número del año, 4 digitos\n[h] - Hora, formato 12 horas con cero al comienzo\n[H] - Hora, formato 24 horas con cero al comienzo\n[i] - Minutos con cero al comienzo\n[s] - Segundos con cero al comienzo\n[ms] - milisegundos\n[notificationTitle] - Título de la última notificación\n[notificationText] - Texto de la última notificación\n[last_triggerurl_result] - El resultado de la última ejecución de la acción triggerUrl\n[last_run_executable_exit_code] - El código de salida de la última acción ejecutable ejecutada\n[last_run_executable_output] - El resultado de la última acción ejecutable ejecutada (solo para no root)Titel des letzten Regel-auslösenden Kalendertermins\n[last_calendar_title] - Título de la ultima cita en el calendar que ejecutó una regla\n[last_calendar_description] - Descriptión de la ultima cita en el calendar que ejecutó una regla\n[last_calendar_location] - Ubicación de la ultima cita en el calendar que ejecutó una regla\n[variable-VARIABLENAME] - El valor de la variable definida personalizada</string>
<string name="screenRotationAlreadyEnabled">Rotación del monitor todavia esta activado.</string>
<string name="screenRotationAlreadyDisabled">Rotación del monitor todavia esta desactivado.</string>
<string name="needLocationPermForWifiList">Se puede usar la lista de wifis conocidos para determinar los sitios en los cuales estuvo. Por eso el permiso de localización es necesario para cargar la lista de wifis. Si quiere elegir uno de la lista tiene que conceder el permiso. En caso contrario todavia puede introducir un nombre wifi manualmente.</string>
<string name="com.wireguard.android.permission.CONTROL_TUNNELS">Controlar conexiones de la app Wireguard</string>
<string name="shareConfigAndLogFilesWithDev">Adjuntar configuración y procotolo.</string>
<string name="rootExplanation">Necesita permiso root para esta función. Después encienda la función \"ejecutar regla manualmente\" para presentar el permiso superuser dialogo. Es necesario elegir \"siempre permitir root para esta app\". En caso contrario la regla no puede funcionar en segundo plano.</string>
<string name="helpTextRules">Todas las condiciones están \"Y\"-conectadas. La regla solo va a aplicarse cuando todas las condiciones se aplican. Si quiere \"O\", cree otra regla.\nLos términos desencadenante y condición se utilizan como sinónimos. Todas ellas son condiciones, pero la última en cumplir con su valor requerido podría llamarse disparador porque es la pieza final del rompecabezas para hacer que se ejecute una regla.</string>
<string name="helpTextRules">Todas las condiciones están \"Y\"-conectadas. La regla solo va a aplicarse cuando todas las condiciones se aplican. Si quiere \"O\", cree otra regla.\nLos términos desencadenante y condición se utilizan como sinónimos. Todas ellas son condiciones, pero la última en cumplir con su valor requerido podría llamarse disparador porque es la pieza final del rompecabezas para hacer que se ejecute una regla.\nSi desea guardar ciertas variables de una regla y evaluarlas en otra regla, extraiga la variable condición/actión.</string>
<string name="timeBetweenNoiseLevelMeasurementsSummary">Segundos entre dos ensayos de nivel de ruido</string>
<string name="timeBetweenNoiseLevelMeasurementsTitle">Segundos entre dos ensayos de nivel de ruido</string>
<string name="lengthOfNoiseLevelMeasurementsSummary">Duración en segundos para una prueba de nivel de ruido</string>
@ -765,7 +765,7 @@
<string name="startPhoneCall">Llamar al número de teléfono</string>
<string name="android.permission.CALL_PHONE">Llamar al número de teléfono</string>
<string name="makePhoneCallExplanation1">Aquí puede ingresar un número de teléfono al que se llamará sin más indicaciones. Puede usar esto para realizar configuraciones como realizar ajustes en el enrutamiento de llamadas, etc. Por favor, busque los códigos necesarios para esto por su cuenta.</string>
<string name="endPhoneCall">Terminar llamda de teléfono</string>
<string name="endPhoneCall">Terminar llamada de teléfono</string>
<string name="android.permission.ANSWER_PHONE_CALLS">Terminar llamda de teléfono</string>
<string name="settingsReferringToRestrictedFeaturesInGoogle">La configuración y/o las reglas hacen referencia a funciones que no se pueden proporcionar en la versión de Google Play. Entre otras cosas que incluye todo lo relacionado con llamadas telefónicas y mensajes de texto.</string>
<string name="variableCheckStringDeleted">Si la variable %1$s no está establecida</string>
@ -801,4 +801,57 @@
<string name="wifiTriggerDisconnectionHint">Este activador será válido si acabas de desconectarte del wifi especificado anteriormente O mientras el servicio aún se está iniciando y si no estás conectado a ningún wifi. Si desea que el activador se active solo cuando se desconecte explícitamente de una determinada red WiFi, agregue otro activador \"el servicio no se está iniciando\".</string>
<string name="className">Nombre de la clase</string>
<string name="startAppByStartForegroundService">a través de startForegroundService((</string>
<string name="method">Método</string>
<string name="takeScreenshot">Tomar captura de pantalla</string>
<string name="android.permission.BIND_ACCESSIBILITY_SERVICE">Enlazar al servicio de accesibilidad</string>
<string name="bindAccessibilityService">Enlazar al servicio de accesibilidad</string>
<string name="accessibilityApiPermissionHint">Después de hacer clic en Aceptar, se le enviará a un cuadro de diálogo del sistema. Seleccione Automatización allí y permita Permitir API de accesibilidad.</string>
<string name="accessibility_service_explanation">Requerido para ciertas acciones.</string>
<string name="noticeRestrictedPermissions">Si no le otorga a uno el siguiente permiso y un mensaje del sistema como \"Ajuste restringido\", primero debe ir a la configuración de Android, luego a las aplicaciones, elija Automatización. Ahora debería haber 3 puntos en la esquina superior derecha. Haga clic en \"Permitir configuraciones restringidas\". Después de eso, el permiso necesario debería poder otorgarse. Esto solo debería aplicarse a la versión APK de la aplicación, no a las de F-Droid o Play Store.</string>
<string name="setLocationService">Encender/desactivar el servicio de ubicación</string>
<string name="setLocationServiceCapital">Establecer el servicio de ubicación</string>
<string name="writeSecureSettingsNotice">Desafortunadamente, el permiso WRITE_SECURE_SETTINGS no se puede otorgar directamente en su dispositivo Android. En su lugar, debe conectar su dispositivo a una computadora y otorgar el permiso a través de ADB. Haga clic aquí para saber cómo otorgarlo: https://server47.de/automation/adb_hack.php</string>
<string name="actionSetLocationService">Servicio de localización</string>
<string name="triggerUrlVariableHint">El resultado de esta solicitud se almacenará en la variable LAST_TRIGGERURL_RESULT si desea verificarlo desde otra regla. En caso de errores HTTP como 404, el valor será \"HTTP_ERROR\".</string>
<string name="calendarEvent">Evento de calendario</string>
<string name="eventIsCurrentlyHappening">El evento está activo actualmente</string>
<string name="calendarEventCapital">evento de calendario</string>
<string name="location">Lugar</string>
<string name="calendarDescription">Descripción/notas</string>
<string name="availability">Disponibilidad</string>
<string name="eventIsCurrentlyNotHappening">El evento no está ocurriendo actualmente/ha finalizado</string>
<string name="calendarStringBusy">ocupado</string>
<string name="calendarStringFree">libre</string>
<string name="calendarStringTentative">intento</string>
<string name="calendarStringOutOfOffice">fuera de la oficina</string>
<string name="calendarStringWorkingElsewhere">Trabajar en otro lugar</string>
<string name="selectingNoneItemForAllToMatch">Si no selecciona ningún elemento, cualquiera estará bien.</string>
<string name="calendars">Calendarios</string>
<string name="calendarAvailabilityTypesUnsupported">Puede ser que solo los primeros 3 tipos funcionen realmente porque los otros tipos no forman parte de la interfaz de calendario estándar de Android.</string>
<string name="anyCalendar">cualquier calendario</string>
<string name="availabilities">Disponibilidades</string>
<string name="calendarsMissingHint">En este desencadenador, los calendarios con ID %1$s se han configurado previamente, pero se han eliminado desde entonces. Con el siguiente guardado, se eliminarán de este activador. Hasta entonces, este desencadenante/condición nunca se cumplirá.</string>
<string name="account">cuenta</string>
<string name="allDayEvent">Evento de todo el día</string>
<string name="allDayEventTrue">El evento es un evento de todo el día</string>
<string name="allDayEventFalse">El evento no es un evento de todo el día</string>
<string name="permissionCalendarRequired">El permiso para leer el calendario será necesario para un activador de calendario. Ya será necesario rellenar los campos del calendario en esta ventana.</string>
<string name="noCalendarsOnYourDevice">Parece que no se han configurado calendarios en su dispositivo. Puede guardar este desencadenador, pero nunca devolverá true.</string>
<string name="errorReadingCalendars">Se ha producido un error al leer los calendarios de su dispositivo.</string>
<string name="android.permission.SCHEDULE_EXACT_ALARM">Programe alarmas exactas</string>
<string name="alarmsPermissionHint">Después de hacer clic en Aceptar, se abrirá una ventana. Seleccione Automatización allí y permita que la aplicación programe alarmas exactas.</string>
<string name="evaluate">Evaluar</string>
<string name="errorLoadingValues">Se ha producido un error al cargar los valores.</string>
<string name="enterValidDataIntoParametersFields">Introduzca datos válidos en los campos de parámetros.</string>
<string name="reoccurringFalse">El evento no se repite</string>
<string name="reoccurringTrue">El evento se repite</string>
<string name="reoccurring">Recurrente</string>
<string name="calendarTriggerExecutionHints">Si su calendario contiene varios eventos paralelos, superpuestos o directamente posteriores, una regla se ejecutará tantas veces como eventos coincidan con los criterios de la regla. En caso de que una regla tenga varios activadores de calendario y haya varios eventos coincidentes en paralelo, la regla se ejecutará solo una vez.</string>
<string name="charging_AC">cargador</string>
<string name="charging_wireless">inalámbrico</string>
<string name="charging">cargando</string>
<string name="notCharging">no cargando</string>
<string name="triggerChargingComment">El tipo solo se evaluará si el dispositivo se está cargando. Si se elige no cargar, se disparará en cualquier tipo de carga anterior. Si desea evaluar eso, considere la posibilidad de usar las variables trigger/action.</string>
<string name="helpTextProfiles">Un perfil es una colección de ajustes para tonos de llamada, volúmenes y otros ajustes relacionados con el audio que puede aplicar desde reglas o aplicarlo manualmente.\\n\\nTambién es posible consultar el último perfil activado como disparador. En el caso normal, solo consultará si el perfil fue el último activado (independientemente de si se han cambiado configuraciones de audio específicas mientras tanto). Pero también puede comparar los ajustes individuales.</string>
<string name="serviceWontStartNoActivatedRules">No se han definido reglas activadas. El servicio no se inicia.</string>
</resources>

View File

@ -65,7 +65,7 @@
<string name="end">Arrêt</string>
<string name="save">Enregistrer</string>
<string name="urlToTrigger">URL à déclencher :</string>
<string name="urlLegend">Variables :\nVous pouvez utiliser les variables suivantes. Lors du déclenchement, elles seront remplacées par les variables correspondantes sur votre appareil. Insérez les parenthèses dans votre texte.\n\n[uniqueid] - Identifiant unique de votre appareil\n[serialnr] - Numéro de série de votre appareil (&lt; Android 9)\n[latitude] - Latitude de votre appraeil\n[longitude] - Longitude de votre appraeil\n[phonenr] - Numéro des derniers appels entrants ou sortants\n[d] - Jour du mois, @chiffres commençant par 0\n[m] - Valeur numérique du mois, avec @ chiffres\n[Y] - Valeur numérique de lannée, $ chiffres\n[h] - Format horaire 12heures, 2chiffres\n[H] - Format horaire 24heures, 2chiffres\n[i] - Nombre de minutes, 2chiffres\n[s] - Nombre de secondes, 2chiffres\n[ms] - Nombre de millisecondes\n[notificationTitle] - titre de la dernière notification\n[notificationText] - texte de la dernière notification\n[variable-VARIABLENAME] - Valeur de votre variable définie personnalisée</string>
<string name="urlLegend">Variables :\nVous pouvez utiliser les variables suivantes. Lors du déclenchement, elles seront remplacées par les variables correspondantes sur votre appareil. Insérez les parenthèses dans votre texte.\n\n[uniqueid] - Identifiant unique de votre appareil\n[serialnr] - Numéro de série de votre appareil (&lt; Android 9)\n[latitude] - Latitude de votre appraeil\n[longitude] - Longitude de votre appraeil\n[phonenr] - Numéro des derniers appels entrants ou sortants\n[d] - Jour du mois, @chiffres commençant par 0\n[m] - Valeur numérique du mois, avec @ chiffres\n[Y] - Valeur numérique de lannée, $ chiffres\n[h] - Format horaire 12heures, 2chiffres\n[H] - Format horaire 24heures, 2chiffres\n[i] - Nombre de minutes, 2chiffres\n[s] - Nombre de secondes, 2chiffres\n[ms] - Nombre de millisecondes\n[notificationTitle] - titre de la dernière notification\n[notificationText] - texte de la dernière notification\n[last_triggerurl_result] - Résultat de l\'exécution de la dernière action triggerUrl\n[last_run_executable_exit_code] - Le code de sortie de la dernière action exécutable exécutée\n[last_run_executable_output] - La sortie de la dernière action exécutable exécutée (uniquement pour les non-roots)\n[last_calendar_title] - Titre du dernier événement de calendrier déclenchant une règle\n[last_calendar_description] - Description du dernier événement de calendrier déclenchant une règle\n[last_calendar_location] - Emplacement du dernier événement de calendrier déclenchant la règle\n[variable-VARIABLENAME] - Valeur de votre variable définie personnalisée</string>
<string name="wifi">wifi</string>
<string name="activating">Allumer</string>
<string name="deactivating">Éteindre</string>
@ -120,7 +120,7 @@
<string name="soundSettings">Réglages audio</string>
<string name="showHelp">Afficher laide</string>
<string name="rules">Règles</string>
<string name="helpTextRules">Tous les déclencheurs dune règle sont reliés par un lien logique ET, la règle ne sapplique que si tous les déclencheurs sont satisfaits. Pour un lien logique OU, créez une autre règle.\nLes termes déclencheur et condition sont utilisés comme synonymes. Toutes sont des conditions, mais la dernière à atteindre sa valeur requise pourrait être appelée déclencheur car c\'est la dernière pièce du puzzle pour provoquer l\'exécution d\'une règle.</string>
<string name="helpTextRules">Tous les déclencheurs dune règle sont reliés par un lien logique ET, la règle ne sapplique que si tous les déclencheurs sont satisfaits. Pour un lien logique OU, créez une autre règle.\nLes termes déclencheur et condition sont utilisés comme synonymes. Toutes sont des conditions, mais la dernière à atteindre sa valeur requise pourrait être appelée déclencheur car c\'est la dernière pièce du puzzle pour provoquer l\'exécution d\'une règle.\nSi vous souhaitez enregistrer certaines variables d\'une règle et les évaluer dans une autre règle, extrayez le déclencheur/l\'action de la variable.</string>
<string name="timeframes">Délais déxécution</string>
<string name="helpTextTimeFrame">Si vous créez une règle avec une période déxécution vous avez deux options. Vous pouvez choisir déxécuter dans la période OU hors de la période. Quel que soit votre choix laction ne sera déclenchée quune seule fois. Si vous créez une règle avec pour déclencheur \«dans la période xyz\» qui modifie votre profil audio en le passant en mode vibreur cela ne signifie pas que votre téléphone repassera automatiquement en mode sonnerie à la fin de la période. Si vous souhaitez le faire vous devez définir une autre règle avec une autre période.</string>
<string name="helpTextSound">Sur lécran principal vous pouvez utiliser le verrouillage des modifications audio pour temporairement ne pas utiliser les règles de changement des paramètres audio. Par exemple vous pouvez êtes dans un lieu où à un moment où les sonneries peuvent être dérangeantes. Cette fonctionnalité se désactivera automatiquement une fois le temps configuré écoulé. Appuyez sur le bouton +15min pour ajouter la durée souhaitée. Une fois activé vous pouvez le désactiver en appuyant sur le bouton \«OUI\» (la règle de gestion des paramètres audio sera de nouveau active).</string>
@ -801,4 +801,57 @@
<string name="wifiTriggerDisconnectionHint">Ce déclencheur sera valide si vous venez de vous déconnecter du wifi spécifié ci-dessus OU alors que le service est encore en cours de démarrage et si vous n\'êtes connecté à aucun wifi. Si vous souhaitez que le déclencheur ne se déclenche que lorsque vous vous déconnectez explicitement d\'un certain wifi, ajoutez un autre déclencheur « le service ne démarre pas ».</string>
<string name="className">Nom de la classe</string>
<string name="startAppByStartForegroundService">par startForegroundService()</string>
<string name="method">Méthode</string>
<string name="takeScreenshot">Prendre une capture d\'écran</string>
<string name="android.permission.BIND_ACCESSIBILITY_SERVICE">Se lier au service d\'accessibilité</string>
<string name="bindAccessibilityService">Se lier au service d\'accessibilité</string>
<string name="accessibilityApiPermissionHint">Après avoir cliqué sur OK, vous serez redirigé vers une boîte de dialogue système. Sélectionnez Automatisation et autorisez l\'option Autoriser l\'API d\'accessibilité.</string>
<string name="accessibility_service_explanation">Obligatoire pour certaines actions.</string>
<string name="noticeRestrictedPermissions">Si vous ne parvenez pas à accorder à l\'un d\'entre eux l\'autorisation suivante et un message système tel que « Autorisation restreinte », vous devez d\'abord accéder aux paramètres Android, puis aux applications, puis choisir Automatisation. Maintenant, il devrait y avoir 3 points dans le coin supérieur droit. Cliquez sur « Autoriser les paramètres restreints ». Après cela, l\'autorisation nécessaire devrait pouvoir être accordée. Cela ne devrait s\'appliquer qu\'à la version APK de l\'application, pas à celles de F-Droid ou du Play Store.</string>
<string name="setLocationService">Définir le service de localisation</string>
<string name="setLocationServiceCapital">Définir le service de localisation</string>
<string name="writeSecureSettingsNotice">Malheureusement, l\'autorisation WRITE_SECURE_SETTINGS ne peut pas être donnée directement sur votre appareil Android. Au lieu de cela, vous devez connecter votre appareil à un ordinateur et accorder l\'autorisation via ADB. Cliquez ici pour savoir comment l\'accorder : https://server47.de/automation/adb_hack.php</string>
<string name="actionSetLocationService">Service de localisation</string>
<string name="triggerUrlVariableHint">Le résultat de cette requête sera stocké dans la variable LAST_TRIGGERURL_RESULT si vous souhaitez le vérifier à partir d\'une autre règle. En cas d\'erreurs HTTP comme 404, la valeur sera « HTTP_ERROR ».</string>
<string name="calendarEvent">Événement de calendrier</string>
<string name="eventIsCurrentlyHappening">L\'événement est actuellement actif</string>
<string name="calendarEventCapital">Evénement de calendrier</string>
<string name="location">Emplacement</string>
<string name="calendarDescription">Description/notes</string>
<string name="availability">Beschikbaarheid</string>
<string name="eventIsCurrentlyNotHappening">L\'événement n\'a pas lieu ou s\'est terminé</string>
<string name="calendarStringBusy">occupé</string>
<string name="calendarStringFree">libre</string>
<string name="calendarStringTentative">tentative</string>
<string name="calendarStringOutOfOffice">absent du bureau</string>
<string name="calendarStringWorkingElsewhere">Travailler ailleurs</string>
<string name="selectingNoneItemForAllToMatch">Si vous ne sélectionnez aucun élément, n\'importe lequel d\'entre eux sera acceptable.</string>
<string name="calendars">Calendriers</string>
<string name="calendarAvailabilityTypesUnsupported">Il se peut que seuls les 3 premiers types fonctionnent réellement car les autres types ne font pas partie de l\'interface de calendrier standard d\'Android.</string>
<string name="anyCalendar">n\'importe quel calendrier</string>
<string name="availabilities">Disponibilités</string>
<string name="calendarsMissingHint">Dans ce déclencheur, les calendriers avec des ID %1$s ont été configurés précédemment, mais ont été supprimés depuis. Lors de la prochaine sauvegarde, ceux-ci seront supprimés de ce déclencheur. D\'ici là, ce déclencheur/condition ne sera jamais rempli.</string>
<string name="account">compte</string>
<string name="allDayEvent">Événement d\'une journée</string>
<string name="allDayEventTrue">L\'événement est un événement d\'une journée</string>
<string name="allDayEventFalse">L\'événement n\'est pas un événement d\'une journée</string>
<string name="permissionCalendarRequired">event isL\'autorisation de lire votre calendrier sera requise pour un déclencheur de calendrier. Il sera déjà nécessaire de remplir les champs du calendrier dans cette fenêtre. Il ne s\'agit pas d\'un événement qui dure toute la journée</string>
<string name="noCalendarsOnYourDevice">Il semble qu\'aucun calendrier n\'ait été configuré sur votre appareil. Vous pouvez enregistrer ce déclencheur, mais il ne renverra jamais true.</string>
<string name="errorReadingCalendars">Une erreur s\'est produite lors de la lecture des calendriers sur votre appareil.</string>
<string name="android.permission.SCHEDULE_EXACT_ALARM">Programmer des alarmes exactes</string>
<string name="alarmsPermissionHint">Après avoir cliqué sur OK, une fenêtre s\'ouvre. Veuillez sélectionner Automatisation et permettre à l\'application de programmer des alarmes précises.</string>
<string name="evaluate">Évaluer</string>
<string name="errorLoadingValues">Une erreur s\'est produite lors du chargement des valeurs.</string>
<string name="enterValidDataIntoParametersFields">Saisissez des données valides dans les champs de paramètre.</string>
<string name="reoccurringFalse">l\'événement ne se reproduit pas</string>
<string name="reoccurringTrue">l\'événement se reproduit</string>
<string name="reoccurring">Récurrents</string>
<string name="calendarTriggerExecutionHints">Si votre calendrier contient plusieurs événements parallèles, qui se chevauchent ou qui se suivent directement, une règle sera exécutée autant de fois qu\'il y a d\'événements correspondant aux critères de la règle. Dans le cas où une règle a plusieurs déclencheurs de calendrier et qu\'il y a plusieurs événements correspondants en parallèle, la règle ne sera exécutée qu\'une seule fois.</string>
<string name="charging_AC">chargeur</string>
<string name="charging_wireless">sans fil</string>
<string name="charging">Charge</string>
<string name="notCharging">Ne charge pas</string>
<string name="triggerChargingComment">Le type ne sera évalué que si l\'appareil est en charge. Si l\'option Ne pas charger est sélectionnée, elle se déclenchera à n\'importe quel type de charge précédent. Si vous souhaitez évaluer cela, envisagez d\'utiliser les variables déclencheur/action.</string>
<string name="helpTextProfiles">Un profil est un ensemble de paramètres pour les sonneries, les volumes et d\'autres paramètres liés à l\'audio que vous pouvez faire appliquer à partir de règles ou appliquer manuellement.\\n\\nIl est également possible d\'interroger le dernier profil activé en tant que déclencheur. Dans le cas normal, il ne demandera que si le profil était le dernier activé (indépendamment si des paramètres audio spécifiques ont été modifiés entre-temps). Mais vous pouvez également comparer les différents paramètres.</string>
<string name="serviceWontStartNoActivatedRules">Aucune règle activée n\'a été définie. Le service ne démarre pas.</string>
</resources>

View File

@ -228,7 +228,7 @@
<string name="helpTextEnergySaving">Molti produttori di dispositive Android cercano di salvare energia limitando le attività di applicazioni eseguite in secondo piano. Sfortunatamente, questo spesso fa che tali applicazioni non funzionino correttamente e Automation è fra queste. Puoi leggere questa <a href="https://dontkillmyapp.com/">pagina web</a> per scoprire come escludere Automation da queste funzioni di risparmio energetico.</string>
<string name="helpTextPoi">Una posizione è composta da coordinate GPS ed un raggio d\'azione. Dato che il posizionamento realizzato tramite i ripetitori del tuo gestore è piuttosto impreciso (ma veloce e consuma poca batteria), è bene non specificare un raggio troppo piccolo. L\'applicazione suggerisce un raggio minimo quando si crea una nuova posizione.</string>
<string name="helpTextProcessMonitoring">Se si specifica una regola che controlli l\'esecuzione di un processo, Automation eseguirà la verifica ogni x secondi (con x selezionabile nelle impostazioni). Bisogna considerare che un monitoraggio costante provocherebbe un rapido esaurimento della batteria e non esistono notifiche di questo tipo di attività proviste dal sistema operativo.</string>
<string name="helpTextRules">Gli eventi di attivazione sono in AND logico. La regola sarà eseguita solo se tutti gli eventi sono soddisfatti. Per l\'OR logico basta creare un\'altra regola.\nI termini trigger e condizione vengono utilizzati come sinonimi. Tutte sono condizioni, ma l\'ultima a soddisfare il valore richiesto potrebbe essere chiamata trigger perché è il pezzo finale del puzzle per causare l\'esecuzione di una regola.</string>
<string name="helpTextRules">Gli eventi di attivazione sono in AND logico. La regola sarà eseguita solo se tutti gli eventi sono soddisfatti. Per l\'OR logico basta creare un\'altra regola.\nI termini trigger e condizione vengono utilizzati come sinonimi. Tutte sono condizioni, ma l\'ultima a soddisfare il valore richiesto potrebbe essere chiamata trigger perché è il pezzo finale del puzzle per causare l\'esecuzione di una regola.\nSe si desidera salvare determinate variabili da una regola e valutarle in un\'altra regola, eseguire il checkout del trigger/azione della variabile.</string>
<string name="helpTextSound">Nello schermo principale puoi bloccare temporaneamente i cambi ai suoni per evitare l\'esecuzione di regole che facciano cambi alle attività sonore. Per esempio, potresti essere in una situatione o in un luogo dove normalmente ascoltare il suono di una suoneria è ok, ma in questa occasione bisognerebbe evitarlo. Questa funzione si disattiverà automaticamente non appena sia trascorso il tempo selezionato. Fai Click sul bottone + per raggiungere la quantità di tempo desiderata. Una volta attiva, questa si può disattivare nuovamente usando il pulsante di attivazione (e in questo modo, si riattiveranno le regole basate su cambi sonori).</string>
<string name="helpTextTimeFrame">Se si specifica una regola con un intervallo temporale si hanno due scelte. È possibile scegliere se si desidera attivare la regola all\'interno o all\'esterno dell\'intervallo di tempo. In entrambi i casi l\'azione verrà eseguita una sola volta. Quindi, se si crea una regola che imposta il profilo su vibrazione nell\'intervallo temporale xyz, il telefono, passato allo stato vibrazione, rimarrà definitivamente in tale stato anche dopo lo scadere dell\'intervallo di tempo. Se si desidera che ciò avvenga è necessario specificare un\'altra regola con un altro periodo di tempo.</string>
<string name="helpTextToggable">Le regole hanno un segno di spunta chiamato "Reversibile". Ciò significa che, se una regola viene eseguita al verificarsi di un evento e poi quest\'ultimo si verifica una seconda volta, il comando della regola verrà eseguito una ulteriore volta in modalità inversa, se possibile. Attualmente questo avverrà solo in combinazione con etichette NFC. Se le si tocca due volte la regola associata invertirà la situazione attuale. Per esempio una regola “Reversibile” può disattivare il WiFi se attivo e viceversa attivarlo se non attivo.</string>
@ -542,7 +542,7 @@
<string name="tuesday">Martedì</string>
<string name="unknownError">Errore indeterminato.</string>
<string name="until">finchè</string>
<string name="urlLegend">Variabili:\n È possibile utilizzare le seguenti variabili. Quando attivate, saranno sostituite con il valore corrispondente sul tuo dispositivo. Includi le parentesi nel tuo testo.\n\n[uniqueid] - L\'ID unico del tuo dispositivo\n[serialnr] - Il numero di serie del tuo dispositivio (&lt; Android 9)\n[latitude] - La latitudine del tuo dispositivo\n[longitude] - La longitudine del tuo dispositivo\n[phonenr] - Numero dell\'ultima chiamata (entrante o uscente)\n[d] - Il giorno del mese, sempre 2 cifre con zero iniziale \n[m] - Mese in formato numerico, sempre 2 cifre con zero iniziale \n[Y] - L\anno, sempre con 4 cifre\n[h] - Ore in formato 12 ore, sempre 2 cifre con due punti\n[H] - Ore in formato 24 ore, sempre 2 cifre con due punti\n[i] - Minuti, sempre 2 cifre\n[s] - Secondi, sempre 2 cifre\n[ms] - millisecondi, sempre 3 cifre\n[notificationTitle] - titolo dell\'ultima notifica\n[notificationText] - testo dell\'ultima notifica\n[variable-VARIABLENAME] - Il valore della variabile definita in modo personalizzato</string>
<string name="urlLegend">Variabili:\n È possibile utilizzare le seguenti variabili. Quando attivate, saranno sostituite con il valore corrispondente sul tuo dispositivo. Includi le parentesi nel tuo testo.\n\n[uniqueid] - L\'ID unico del tuo dispositivo\n[serialnr] - Il numero di serie del tuo dispositivio (&lt; Android 9)\n[latitude] - La latitudine del tuo dispositivo\n[longitude] - La longitudine del tuo dispositivo\n[phonenr] - Numero dell\'ultima chiamata (entrante o uscente)\n[d] - Il giorno del mese, sempre 2 cifre con zero iniziale \n[m] - Mese in formato numerico, sempre 2 cifre con zero iniziale \n[Y] - L\anno, sempre con 4 cifre\n[h] - Ore in formato 12 ore, sempre 2 cifre con due punti\n[H] - Ore in formato 24 ore, sempre 2 cifre con due punti\n[i] - Minuti, sempre 2 cifre\n[s] - Secondi, sempre 2 cifre\n[ms] - millisecondi, sempre 3 cifre\n[notificationTitle] - titolo dell\'ultima notifica\n[notificationText] - testo dell\'ultima notifica\n[last_triggerurl_result] - Risultato dell\'esecuzione dell\'ultima azione triggerUrl\n[last_run_executable_exit_code] - Codice di uscita dell\'ultima azione eseguibile di esecuzione\n[last_run_executable_output] - L\'output dell\'ultima azione eseguibile eseguita (solo per i non root)\n[last_calendar_title] - Titolo dell\'ultimo evento di calendario che ha attivato la regola\n[last_calendar_description] - Descrizione dell\'ultimo evento del calendario che ha attivato la regola\n[last_calendar_location] - Posizione dell\'ultimo evento del calendario che ha attivato la regola\n[variable-VARIABLENAME] - Il valore della variabile definita in modo personalizzato</string>
<string name="urlToTrigger">URL da caricare:</string>
<string name="urlTooShort">L\'url deve avere almeno 10 caratteri.</string>
<string name="usbTetheringFailForAboveGingerbread">Questo molto probabilmente non funzionerà dato che sei su una versione superiore ad Android 2.3. Tuttavia è possibile utilizzare la connessione wifi tethering per attivare la regola.</string>
@ -802,4 +802,57 @@
<string name="wifiTriggerDisconnectionHint">Questo trigger sarà valido se ti sei appena disconnesso dal Wi-Fi specificato sopra OPPURE mentre il servizio è ancora in fase di avvio e se non sei connesso a nessuna rete Wi-Fi. Se vuoi che il trigger si attivi solo quando ti stai disconnettendo esplicitamente da una determinata rete Wi-Fi, aggiungi un altro trigger \"il servizio non si avvia\".</string>
<string name="className">Nome della classe</string>
<string name="startAppByStartForegroundService">di startForegroundService()</string>
<string name="method">Metodo</string>
<string name="takeScreenshot">Fai uno screenshot</string>
<string name="android.permission.BIND_ACCESSIBILITY_SERVICE">Associare al servizio di accessibilità</string>
<string name="bindAccessibilityService">Associare al servizio di accessibilità</string>
<string name="accessibilityApiPermissionHint">Dopo aver fatto clic su OK, verrà visualizzata una finestra di dialogo di sistema. Seleziona Automazione e consenti Consenti API di accessibilità.</string>
<string name="accessibility_service_explanation">Obbligatorio per determinate azioni.</string>
<string name="noticeRestrictedPermissions">Se non riesci a concedere una delle seguenti autorizzazioni e un messaggio di sistema come \"Autorizzazione limitata\", devi prima andare alle impostazioni di Android, quindi alle applicazioni, scegli Automazione. Ora dovrebbero esserci 3 punti nell\'angolo in alto a destra. Fai clic su \"Consenti impostazioni limitate\". Dopodiché dovrebbe essere concessa l\'autorizzazione necessaria. Questo dovrebbe valere solo per la versione APK dell\'app, non per quelle di F-Droid o Play Store.</string>
<string name="setLocationService">Impostare il servizio di localizzazione</string>
<string name="setLocationServiceCapital">Impostare il servizio di localizzazione</string>
<string name="writeSecureSettingsNotice">Purtroppo l\'autorizzazione WRITE_SECURE_SETTINGS non può essere data direttamente sul tuo dispositivo Android. Invece, devi collegare il tuo dispositivo a un computer e concedere l\'autorizzazione tramite ADB. Clicca qui per scoprire come concederlo: https://server47.de/automation/adb_hack.php</string>
<string name="actionSetLocationService">Servizio di localizzazione</string>
<string name="triggerUrlVariableHint">Il risultato di questa richiesta verrà memorizzato nella variabile LAST_TRIGGERURL_RESULT se si desidera controllarlo da un\'altra regola. In caso di errori HTTP come 404 il valore sarà \"HTTP_ERROR\".</string>
<string name="calendarEvent">Evento del calendario</string>
<string name="eventIsCurrentlyHappening">L\'evento è attualmente attivo</string>
<string name="calendarEventCapital">evento del calendario</string>
<string name="location">Ubicazione</string>
<string name="calendarDescription">Descrizione/note</string>
<string name="availability">Disponibilità</string>
<string name="eventIsCurrentlyNotHappening">L\'evento al momento non è in corso/è terminato</string>
<string name="calendarStringBusy">occupato</string>
<string name="calendarStringFree">gratuito</string>
<string name="calendarStringTentative">tentativo</string>
<string name="calendarStringOutOfOffice">Fuori sede</string>
<string name="calendarStringWorkingElsewhere">Lavorare altrove</string>
<string name="selectingNoneItemForAllToMatch">Se non selezioni nessun elemento, tutti saranno ok.</string>
<string name="calendars">Calendari</string>
<string name="calendarAvailabilityTypesUnsupported">È possibile che solo i primi 3 tipi funzionino effettivamente perché gli altri tipi non fanno parte dell\'interfaccia del calendario standard di Android.</string>
<string name="anyCalendar">qualsiasi calendario</string>
<string name="availabilities">Disponibilità</string>
<string name="calendarsMissingHint">In questo trigger i calendari con ID %1$s sono stati configurati in precedenza, ma sono stati eliminati da allora. Con il prossimo salvataggio, questi verranno rimossi da questo attivatore. Fino ad allora, questa condizione non sarà mai soddisfatta.</string>
<string name="account">conto</string>
<string name="allDayEvent">Evento che dura tutto il giorno</string>
<string name="allDayEventTrue">L\'evento è un evento che dura tutto il giorno</string>
<string name="allDayEventFalse">L\'evento non è un evento che dura tutto il giorno</string>
<string name="permissionCalendarRequired">L\'autorizzazione per leggere il calendario sarà necessaria per un trigger di calendario. Sarà già necessario compilare i campi del calendario in questa finestra.</string>
<string name="noCalendarsOnYourDevice">Sembra che sul tuo dispositivo non sia stato impostato alcun calendario. È possibile salvare questo trigger, ma non restituirà mai true.</string>
<string name="errorReadingCalendars">Si è verificato un errore durante la lettura dei calendari sul dispositivo.</string>
<string name="android.permission.SCHEDULE_EXACT_ALARM">Pianifica allarmi esatti</string>
<string name="alarmsPermissionHint">Dopo aver fatto clic su OK, si aprirà una finestra. Seleziona Automazione lì e consenti all\'app di programmare allarmi esatti.</string>
<string name="evaluate">Valutare</string>
<string name="errorLoadingValues">Si è verificato un errore durante il caricamento dei valori.</string>
<string name="enterValidDataIntoParametersFields">Immettere dati validi nei campi dei parametri.</string>
<string name="reoccurringFalse">l\'evento non si ripete</string>
<string name="reoccurringTrue">l\'evento si ripete</string>
<string name="reoccurring">Reoccurring</string>
<string name="calendarTriggerExecutionHints">Se il calendario contiene più eventi paralleli, sovrapposti o direttamente successivi, una regola verrà eseguita tante volte quanti sono gli eventi che corrispondono ai criteri della regola. Nel caso in cui una regola disponga di più trigger di calendario e siano presenti più eventi corrispondenti in parallelo, la regola verrà eseguita una sola volta.</string>
<string name="charging_AC">caricatore</string>
<string name="charging_wireless">wireless</string>
<string name="charging">caricamento</string>
<string name="notCharging">non in carica</string>
<string name="triggerChargingComment">Il tipo verrà valutato solo se il dispositivo è in carica. Se si sceglie di non caricare, si attiverà a qualsiasi tipo di ricarica precedente. Se si desidera valutarlo, prendere in considerazione l\'utilizzo delle variabili trigger/action.</string>
<string name="helpTextProfiles">Un profilo è una raccolta di impostazioni per suonerie, volumi e altre impostazioni relative all\'audio che è possibile applicare dalle regole o applicare manualmente.\\n\\nÈ anche possibile eseguire una query per l\'ultimo profilo attivato come trigger. In caso normale, chiederà solo se il profilo è stato l\'ultimo attivato (indipendentemente dal fatto che nel frattempo siano state modificate impostazioni audio specifiche). Ma è anche possibile confrontare le singole impostazioni.</string>
<string name="serviceWontStartNoActivatedRules">Nessuna regola attivata definita. Il servizio non si avvia.</string>
</resources>

View File

@ -64,7 +64,7 @@
<string name="end">Einde</string>
<string name="save">Opslaan</string>
<string name="urlToTrigger">URL om te activeren:</string>
<string name="urlLegend">Variabelen:U kunt de volgende variabelen gebruiken. Bij het triggeren zullen ze worden vervangen door de corresponderende waarde op je apparaat. Zet de haakjes in uw tekst. \n[uniqueid] - Het unieke id van uw apparaat[serialnr] - Het serienummer van uw apparaat (&lt; Android 9)[latitude] - De breedtegraad van uw apparaat[longitude] - De lengtegraad van uw apparaat[phonenr] - Nummer van het laatste inkomende of uitgaande gesprek[d] - Dag van de maand, 2 cijfers met voorloopnullen[m] - Numerieke weergave van een maand, met voorloopnullen[Y] - een volledige numerieke weergave van een jaar, 4 cijfers[h] - 12-uurs indeling van een uur, met voorloopnullen[H] - 24-uurs indeling van een uur, met voorloopnullen[i] - minuten, met voorloopnullen[s] - seconden, met voorloopnullen[ms] - milliseconden[notificationTitle] - titel van de laatste melding[notificationText] - tekst van de laatste melding\n[variable-VARIABLENAME] - De waarde van uw aangepaste gedefinieerde variabele</string>
<string name="urlLegend">Variabelen:U kunt de volgende variabelen gebruiken. Bij het triggeren zullen ze worden vervangen door de corresponderende waarde op je apparaat. Zet de haakjes in uw tekst. \n[uniqueid] - Het unieke id van uw apparaat[serialnr] - Het serienummer van uw apparaat (&lt; Android 9)[latitude] - De breedtegraad van uw apparaat[longitude] - De lengtegraad van uw apparaat[phonenr] - Nummer van het laatste inkomende of uitgaande gesprek[d] - Dag van de maand, 2 cijfers met voorloopnullen[m] - Numerieke weergave van een maand, met voorloopnullen[Y] - een volledige numerieke weergave van een jaar, 4 cijfers[h] - 12-uurs indeling van een uur, met voorloopnullen[H] - 24-uurs indeling van een uur, met voorloopnullen[i] - minuten, met voorloopnullen[s] - seconden, met voorloopnullen[ms] - milliseconden[notificationTitle] - titel van de laatste melding[notificationText] - tekst van de laatste melding\n[last_triggerurl_result] - Het resultaat van de laatste uitvoering van de triggerUrl-actie\n[last_run_executable_exit_code] - De afsluitcode van de uitvoerbare actie van de laatste uitvoering\n[last_run_executable_output] - De uitvoer van de uitvoerbare actie van de laatste uitvoering (alleen voor niet-root)\n[last_calendar_title] - Titel van de laatste agenda-afspraak die regels activeert\n[last_calendar_description] - Beschrijving van de laatste agenda-gebeurtenis die regels activeert\n[last_calendar_location] - Locatie van de laatste agenda-gebeurtenis die de regel activeert\n[variable-VARIABLENAME] - De waarde van uw aangepaste gedefinieerde variabele</string>
<string name="wifi">wifi</string>
<string name="activating">Activeren</string>
<string name="deactivating">Deactiveren</string>
@ -118,7 +118,7 @@
<string name="soundSettings">Geluidsinstellingen</string>
<string name="showHelp">Toon help</string>
<string name="rules">Regels</string>
<string name="helpTextRules">Alle triggers in een regel zijn EN-verbonden (AND). De regel zal alleen worden toegepast als aan alle triggers is voldaan. Als je OR wilt, maak dan een andere regel.\nDe termen trigger en condition worden als synoniem gebruikt. Het zijn allemaal voorwaarden, maar de laatste die aan de vereiste waarde voldoet, kan trigger worden genoemd omdat het het laatste stukje van de puzzel is om een regel uit te voeren.</string>
<string name="helpTextRules">Alle triggers in een regel zijn EN-verbonden (AND). De regel zal alleen worden toegepast als aan alle triggers is voldaan. Als je OR wilt, maak dan een andere regel.\nDe termen trigger en condition worden als synoniem gebruikt. Het zijn allemaal voorwaarden, maar de laatste die aan de vereiste waarde voldoet, kan trigger worden genoemd omdat het het laatste stukje van de puzzel is om een regel uit te voeren.\nAls u bepaalde variabelen uit een regel wilt opslaan en deze in een andere regel wilt evalueren, bekijkt u de variabeletrigger/actie.</string>
<string name="timeframes">Tijdsbestek</string>
<string name="helpTextTimeFrame">Als je een regel opgeeft met een tijdsbestek heb je twee keuzes. Je kunt kiezen tussen het binnengaan OF het verlaten van een tijdframe. In beide gevallen wordt een regel slechts eenmaal getriggerd. Dus als je een regel maakt met als trigger "ingaan tijdvak xyz" en je laat je geluidsprofiel veranderen in trillen dan betekent dat niet dat de telefoon automatisch gaat rinkelen als het tijdvak voorbij is. Als je dat wilt moet je een andere regel specificeren met een ander tijdsbestek.</string>
<string name="helpTextSound">Op het hoofdscherm kunt u vergrendelingsgeluiden gebruiken om op regels gebaseerde geluidsveranderingen tijdelijk te vermijden. U kunt bijvoorbeeld in een situatie of plaats zijn waar ringtones normaal gesproken ok zijn, maar deze ene keer zou het storend zijn. De functie zal automatisch worden uitgeschakeld zodra de ingestelde tijd is verstreken. Klik op de + knop om de ingestelde tijd toe te voegen. Zodra het actief is kunt u het weer deactiveren met de toggle knop (en op die manier op regels gebaseerde geluidsveranderingen weer inschakelen).</string>
@ -800,5 +800,58 @@
<string name="wifiTriggerDisconnectionHint">Deze trigger is geldig als je net de verbinding met de hierboven gespecificeerde wifi hebt verbroken OF terwijl de service nog aan het starten is en als je niet verbonden bent met wifi. Als je wilt dat de trigger alleen wordt geactiveerd wanneer je expliciet de verbinding met een bepaalde wifi verbreekt, voeg dan nog een trigger toe \"service start niet\".</string>
<string name="className">Naam van de klasse</string>
<string name="startAppByStartForegroundService">door startForegroundService()</string>
<string name="method">Methode</string>
<string name="takeScreenshot">Screenshot maken</string>
<string name="android.permission.BIND_ACCESSIBILITY_SERVICE">Binden aan toegankelijkheidsservice</string>
<string name="bindAccessibilityService">Binden aan toegankelijkheidsservice</string>
<string name="accessibilityApiPermissionHint">Nadat u op OK hebt geklikt, wordt u naar een systeemdialoogvenster gestuurd. Selecteer daar Automatisering en sta Toegankelijkheids-API toestaan toe.</string>
<string name="accessibility_service_explanation">Vereist voor bepaalde acties.</string>
<string name="noticeRestrictedPermissions">Als u er niet in slaagt om een van de volgende machtigingen en een systeembericht zoals \"Beperkte toestemming\" te verlenen, moet u eerst naar Android-instellingen gaan en vervolgens naar toepassingen en Automatisering kiezen. Nu zouden er 3 stippen in de rechterbovenhoek moeten zijn. Klik op \"Beperkte instellingen toestaan\". Daarna moet de benodigde toestemming aanvaardbaar zijn. Dit zou alleen van toepassing moeten zijn op de APK-versie van de app, niet die van F-Droid of Play Store.</string>
<string name="setLocationService">Locatieservice instellen</string>
<string name="setLocationServiceCapital">Locatieservice instellen</string>
<string name="writeSecureSettingsNotice">Helaas kan de toestemming WRITE_SECURE_SETTINGS niet rechtstreeks op uw Android-apparaat worden gegeven. In plaats daarvan moet u uw apparaat op een computer aansluiten en de toestemming verlenen via ADB. Klik hier om te weten te komen hoe u het kunt toekennen: https://server47.de/automation/adb_hack.php</string>
<string name="actionSetLocationService">Locatie service</string>
<string name="triggerUrlVariableHint">Het resultaat van dit verzoek wordt opgeslagen in de variabele LAST_TRIGGERURL_RESULT als u het vanuit een andere regel wilt controleren. In het geval van HTTP-fouten zoals 404 is de waarde \"HTTP_ERROR\".</string>
<string name="calendarEvent">Agenda-afspraak</string>
<string name="eventIsCurrentlyHappening">Begivenheden er aktiv i øjeblikket</string>
<string name="calendarEventCapital">agenda-afspraak</string>
<string name="location">Plaats</string>
<string name="calendarDescription">Beschrijving/opmerkingen</string>
<string name="availability">Beschikbaarheid</string>
<string name="eventIsCurrentlyNotHappening">Evenement vindt momenteel niet plaats/is afgelopen</string>
<string name="calendarStringBusy">druk</string>
<string name="calendarStringFree">vrij</string>
<string name="calendarStringTentative">proberen</string>
<string name="calendarStringOutOfOffice">Niet op kantoor</string>
<string name="calendarStringWorkingElsewhere">elders werken</string>
<string name="selectingNoneItemForAllToMatch">Als u geen item selecteert, is elk item in orde.</string>
<string name="calendars">Kalenders</string>
<string name="calendarAvailabilityTypesUnsupported">Het kan zijn dat alleen de eerste 3 typen daadwerkelijk werken omdat de andere typen geen deel uitmaken van de standaard agenda-interface van Android.</string>
<string name="anyCalendar">elke kalender</string>
<string name="availabilities">Beschikbaarheid</string>
<string name="calendarsMissingHint">In deze trigger zijn kalenders met ID\'s %1$s eerder geconfigureerd, maar sindsdien verwijderd. Bij de volgende save worden die uit deze trigger verwijderd. Tot die tijd zal nooit aan deze trigger/voorwaarde worden voldaan.</string>
<string name="account">rekening</string>
<string name="allDayEvent">Evenement dat de hele dag duurt</string>
<string name="allDayEventTrue">evenement is een evenement dat de hele dag duurt</string>
<string name="allDayEventFalse">evenement is niet een evenement dat de hele dag duurt</string>
<string name="permissionCalendarRequired">De toestemming om uw agenda te lezen is vereist voor een agendatrigger. Het is al nodig om de kalendervelden in dit venster in te vullen.</string>
<string name="noCalendarsOnYourDevice">Het lijkt erop dat er geen agenda\'s zijn ingesteld op uw apparaat. U kunt deze trigger opslaan, maar deze wordt nooit waar geretourneerd.</string>
<string name="errorReadingCalendars">Er is een fout opgetreden bij het lezen van de agenda\'s op uw apparaat.</string>
<string name="android.permission.SCHEDULE_EXACT_ALARM">Plan exacte alarmen</string>
<string name="alarmsPermissionHint">Nadat u op OK hebt geklikt, wordt een venster geopend. Selecteer daar Automatisering en laat de app exacte alarmen plannen.</string>
<string name="evaluate">Evalueren</string>
<string name="errorLoadingValues">Er is een fout opgetreden tijdens het laden van waarden.</string>
<string name="enterValidDataIntoParametersFields">Voer geldige gegevens in de parametervelden in.</string>
<string name="reoccurringFalse">gebeurtenis zich niet opnieuw voordoet</string>
<string name="reoccurringTrue">gebeurtenis zich opnieuw voordoet</string>
<string name="reoccurring">Terugkerende</string>
<string name="calendarTriggerExecutionHints">Als uw agenda meerdere parallelle, overlappende of direct volgende gebeurtenissen bevat, wordt een regel net zo vaak uitgevoerd als er afspraken zijn die voldoen aan de criteria van de regel. Als een regel meerdere agendatriggers heeft en er meerdere overeenkomende gebeurtenissen parallel zijn, wordt de regel slechts één keer uitgevoerd.</string>
<string name="charging_AC">lader</string>
<string name="charging_wireless">draadloos</string>
<string name="charging">Opladen</string>
<string name="notCharging">laadt niet op</string>
<string name="triggerChargingComment">Het type wordt alleen geëvalueerd als het apparaat wordt opgeladen. Als er niet wordt gekozen voor opladen, wordt het geactiveerd bij elk eerder oplaadtype. Als je dat wilt evalueren, overweeg dan om de variabelen trigger/actie te gebruiken.</string>
<string name="helpTextProfiles">Een profiel is een verzameling instellingen voor beltonen, volumes en andere audiogerelateerde instellingen die u kunt laten toepassen vanuit regels of handmatig kunt toepassen.\\n\\nHet is ook mogelijk om het laatst geactiveerde profiel als trigger op te vragen. In het normale geval zal het alleen opvragen of het profiel het laatst geactiveerde profiel was (ongeacht of specifieke audio-instellingen in de tussentijd zijn gewijzigd). Maar u kunt ook de individuele instellingen laten vergelijken.</string>
<string name="serviceWontStartNoActivatedRules">Er zijn geen geactiveerde regels gedefinieerd. De service wordt niet gestart.</string>
</resources>

View File

@ -70,7 +70,7 @@
<string name="end">Koniec</string>
<string name="save">Zapisz</string>
<string name="urlToTrigger">Adres URL do uruchomienia:</string>
<string name="urlLegend">Zmienne:\nMożesz użyć następujących zmiennych. Po uruchomieniu zostaną one zastąpione odpowiednią wartością na Twoim urządzeniu. Umieść nawiasy w tekście.\n\n[uniqueid] unikalny identyfikator Twojego urządzenia\n[serialnr] numer seryjny Twojego urządzenia (&lt; Android 9)\n[latitude] Twoje urządzenie\ szerokość geograficzna użytkownika\n[longitude] długość geograficzna Twojego urządzenia\n[phonenr] numer ostatniego połączenia przychodzącego lub wychodzącego\n[d] dzień miesiąca, 2 cyfry z zerami na początku\n[m] Numeryczna reprezentacja miesiąca z zerami na początku\n[Y] — pełna cyfrowa reprezentacja roku, 4 cyfry\n[h] — godzina w formacie 12-godzinnym z zerami na początku\n[H] — format 24-godzinny format godziny z wiodącymi zerami\n[i] - minuty z wiodącymi zerami\n[s] - sekundy z wiodącymi zerami\n[ms] - milisekundy\n[notificationTitle] - tytuł ostatniego powiadomienia\n[notificationText] - tekst ostatniego powiadomienia\n[variable-VARIABLENAME] - Wartość niestandardowej zmiennej zdefiniowanej przez Ciebie</string>
<string name="urlLegend">Zmienne:\nMożesz użyć następujących zmiennych. Po uruchomieniu zostaną one zastąpione odpowiednią wartością na Twoim urządzeniu. Umieść nawiasy w tekście.\n\n[uniqueid] unikalny identyfikator Twojego urządzenia\n[serialnr] numer seryjny Twojego urządzenia (&lt; Android 9)\n[latitude] Twoje urządzenie\ szerokość geograficzna użytkownika\n[longitude] długość geograficzna Twojego urządzenia\n[phonenr] numer ostatniego połączenia przychodzącego lub wychodzącego\n[d] dzień miesiąca, 2 cyfry z zerami na początku\n[m] Numeryczna reprezentacja miesiąca z zerami na początku\n[Y] — pełna cyfrowa reprezentacja roku, 4 cyfry\n[h] — godzina w formacie 12-godzinnym z zerami na początku\n[H] — format 24-godzinny format godziny z wiodącymi zerami\n[i] - minuty z wiodącymi zerami\n[s] - sekundy z wiodącymi zerami\n[ms] - milisekundy\n[notificationTitle] - tytuł ostatniego powiadomienia\n[notificationText] - tekst ostatniego powiadomienia\n[last_triggerurl_result] - Wynik ostatniego wykonania akcji triggerUrl\n[last_run_executable_exit_code] - Kod zakończenia ostatniej uruchomionej akcji wykonywalnej\n[last_run_executable_output] - Dane wyjściowe ostatniej akcji wykonywalnej uruchomienia (tylko dla użytkowników innych niż root)\n[last_calendar_title] - Tytuł ostatniego wydarzenia w kalendarzu wyzwalającego regułę\n[last_calendar_description] - opis ostatniego wydarzenia w kalendarzu wyzwalającego regułę\n[last_calendar_location] - Lokalizacja ostatniego zdarzenia w kalendarzu wyzwalającego regułę\n[variable-VARIABLENAME] - Wartość niestandardowej zmiennej zdefiniowanej przez Ciebie</string>
<string name="wifi">wifi</string>
<string name="activating">Aktywowanie</string>
<string name="deactivating">Dezaktywowanie</string>
@ -125,7 +125,7 @@
<string name="soundSettings">Ustawienia dźwięku</string>
<string name="showHelp">Pokaż pomoc</string>
<string name="rules">Reguły</string>
<string name="helpTextRules">Wszystkie wyzwalacze w regule są połączone operatorem AND. Reguła zostanie zastosowana tylko wtedy, gdy zostaną spełnione wszystkie warunki wyzwalające. Jeśli chcesz LUB, utwórz inną regułę.\nWyzwalacz i warunek są używane zamiennie. Wszystkie z nich są warunkami, ale ostatni, który spełnia wymaganą wartość, można nazwać wyzwalaczem, ponieważ jest to ostatni element układanki, który powoduje wykonanie reguły.</string>
<string name="helpTextRules">Wszystkie wyzwalacze w regule są połączone operatorem AND. Reguła zostanie zastosowana tylko wtedy, gdy zostaną spełnione wszystkie warunki wyzwalające. Jeśli chcesz LUB, utwórz inną regułę.\nWyzwalacz i warunek są używane zamiennie. Wszystkie z nich są warunkami, ale ostatni, który spełnia wymaganą wartość, można nazwać wyzwalaczem, ponieważ jest to ostatni element układanki, który powoduje wykonanie reguły.\nJeśli chcesz zapisać pewne zmienne z reguły i ocenić je w innej regule, sprawdź wyzwalacz/akcję zmiennej.</string>
<string name="timeframes">Ramy czasowe</string>
<string name="helpTextTimeFrame">Jeśli określisz regułę z przedziałem czasowym, masz dwie możliwości. Możesz wybrać między wprowadzeniem LUB opuszczeniem przedziału czasowego. Tak czy inaczej reguła jest uruchamiana tylko raz. Więc jeśli utworzysz regułę, która jako wyzwalacz ma „wprowadzanie przedziału czasowego xyz” i pozwolisz jej zmienić profil dźwiękowy na wibracje, nie oznacza to, że telefon automatycznie zadzwoni, gdy przedział czasowy się skończy. Jeśli chcesz, musisz określić inną regułę z innym przedziałem czasowym.</string>
<string name="helpTextSound">On the main screen you can use lock sound changes to temporarily avoid rule based sound changes. E.g. you may be in a situation or place where usually ringtones are ok, but this one time it would be disturbing. The feature will automatically deactivate once the configured time has elapsed. Click the + button to add the given amount of time. Once it is active you may deactivate it again using the toggle button (and that way enable rule based sound changes again).</string>
@ -212,16 +212,16 @@
<string name="wifiName">Nazwa WiFi</string>
<string name="enterWifiName">Wprowadź nazwę Wi-Fi. Pozostaw puste dla dowolnej sieci Wi-Fi.</string>
<string name="cancel">Anuluj</string>
<string name="ruleDoesntApplyWeAreSlowerThan" translatable="false">Rule %1$s doesn\'t apply. We are slower than</string>
<string name="ruleDoesntApplyWeAreFasterThan" translatable="false">Rule %1$s doesn\'t apply. We are faster than</string>
<string name="ruleDoesntApplyItsQuieterThan" translatable="false">Rule %1$s doesn\'t apply. It\'s quieter than</string>
<string name="ruleDoesntApplyItsLouderThan" translatable="false">Rule %1$s doesn\'t apply. It\'s louder than</string>
<string name="ruleDoesntApplyBatteryLowerThan" translatable="false">Rule %1$s doesn\'t apply. Battery level is lower than</string>
<string name="ruleDoesntApplyBatteryHigherThan" translatable="false">Rule %1$s doesn\'t apply. Battery level is higher than</string>
<string name="ruleDoesntApplyNotTheCorrectSsid" translatable="false">Rule %1$s doesn\'t apply. Not the correct SSID (demanded: \"%2$s\", given: \"%3$s\").</string>
<string name="ruleDoesntApplyNoTagLabel" translatable="false">Rule %1$s doesn\'t apply. There is no tag label or not tag at all.</string>
<string name="ruleDoesntApplyWrongTagLabel" translatable="false">Rule %1$s doesn\'t apply. Wrong tag label.</string>
<string name="ruleIsDeactivatedCantApply" translatable="false">Rule %1$s is deactivated, can\'t apply.</string>
<string name="ruleDoesntApplyWeAreSlowerThan" translatable="false">Rule \"%1$s\" doesn\'t apply. We are slower than</string>
<string name="ruleDoesntApplyWeAreFasterThan" translatable="false">Rule \"%1$s\" doesn\'t apply. We are faster than</string>
<string name="ruleDoesntApplyItsQuieterThan" translatable="false">Rule \"%1$s\" doesn\'t apply. It\'s quieter than</string>
<string name="ruleDoesntApplyItsLouderThan" translatable="false">Rule \"%1$s\" doesn\'t apply. It\'s louder than</string>
<string name="ruleDoesntApplyBatteryLowerThan" translatable="false">Rule \"%1$s\" doesn\'t apply. Battery level is lower than</string>
<string name="ruleDoesntApplyBatteryHigherThan" translatable="false">Rule \"%1$s\" doesn\'t apply. Battery level is higher than</string>
<string name="ruleDoesntApplyNotTheCorrectSsid" translatable="false">Rule \"%1$s\" doesn\'t apply. Not the correct SSID (demanded: \"%2$s\", given: \"%3$s\").</string>
<string name="ruleDoesntApplyNoTagLabel" translatable="false">Rule \"%1$s\" doesn\'t apply. There is no tag label or not tag at all.</string>
<string name="ruleDoesntApplyWrongTagLabel" translatable="false">Rule \"%1$s\" doesn\'t apply. Wrong tag label.</string>
<string name="ruleIsDeactivatedCantApply" translatable="false">Rule \"%1$s\" is deactivated, can\'t apply.</string>
<string name="starting">uruchamianie</string>
<string name="stopping">wyłączanie</string>
<string name="connecting">łączenie</string>
@ -383,8 +383,8 @@
<string name="toggle">przełącznik</string>
<string name="overlapBetweenPois">Wykryto nakładanie się do lokalizacji %1$s z %2$s metrów. Zmniejsz promień przynajmniej o tyle.</string>
<string name="noOverLap" translatable="false">No overlap to other locations detected.</string>
<string name="ruleToggable" translatable="false">Rule %1$s is toggable.</string>
<string name="ruleNotToggable" translatable="false">Rule %1$s is not suitable for toggling.</string>
<string name="ruleToggable" translatable="false">Rule \"%1$s\" is toggable.</string>
<string name="ruleNotToggable" translatable="false">Rule \"%1$s\" is not suitable for toggling.</string>
<string name="none">nic</string>
<string name="anyLocation">dowolna lokalizacjan</string>
<string name="invalidPoiName">Błędna nazwadla lokalizacji.</string>
@ -405,8 +405,8 @@
<string name="detectedActivityWalking">Spacer</string>
<string name="detectedActivityRunning">Bieganie</string>
<string name="detectedActivityInvalidStatus">Nieprawidłowa aktywność</string>
<string name="ruleDoesntApplyActivityGivenButTooLowProbability" translatable="false">Rule %1$s doesn\'t apply. Detected activity %2$s given, but too low probability (%3$s %%), required %4$s %%.</string>
<string name="ruleDoesntApplyActivityNotPresent" translatable="false">Rule %1$s doesn\'t apply. Required activity %2$s not present.</string>
<string name="ruleDoesntApplyActivityGivenButTooLowProbability" translatable="false">Rule \"%1$s\" doesn\'t apply. Detected activity %2$s given, but too low probability (%3$s %%), required %4$s %%.</string>
<string name="ruleDoesntApplyActivityNotPresent" translatable="false">Rule \"%1$s\" doesn\'t apply. Required activity %2$s not present.</string>
<string name="selectTypeOfActivity">Wybierz rodzaj aktywności</string>
<string name="triggerOnlyAvailableIfPlayServicesInstalled">Ten wyzwalacz jest dostępny tylko wtedy, gdy są zainstalowane Usługi Google Play.</string>
<string name="activityDetectionFrequencyTitle">Częstotliwość wykrywania aktywności [sec]</string>
@ -426,8 +426,8 @@
<string name="bluetoothDeviceInRange">Bluetooth device %1$s in range.</string>
<string name="bluetoothDeviceOutOfRange">Urządzenie Bluetooth %1$s w zasięgu.</string>
<string name="anyDevice">dowolne urządzenie</string>
<string name="ruleDoesntApplyNotTheCorrectDeviceName" translatable="false">Rule %1$s doesn\'t apply. Not the correct bluetooth device name.</string>
<string name="ruleDoesntApplyNotTheCorrectDeviceAddress" translatable="false">Rule %1$s doesn\'t apply. Not the correct bluetooth device address.</string>
<string name="ruleDoesntApplyNotTheCorrectDeviceName" translatable="false">Rule \"%1$s\" doesn\'t apply. Not the correct bluetooth device name.</string>
<string name="ruleDoesntApplyNotTheCorrectDeviceAddress" translatable="false">Rule \"%1$s\" doesn\'t apply. Not the correct bluetooth device address.</string>
<string name="noDevice">bez urządzenia</string>
<string name="selectDeviceFromList">jedne z listy</string>
<string name="connectionToDevice">połączenie z urządzeniem</string>
@ -436,8 +436,8 @@
<string name="deviceOutOfRange">urządzenie poza zasięgiem</string>
<string name="selectDeviceOption">Wybierz opcję urządzenia.</string>
<string name="selectConnectionOption">Wybierz opcję połączenia.</string>
<string name="ruleDoesntApplyDeviceInRangeButShouldNotBe" translatable="false">Rule %1$s doesn\'t apply. Device is in range, but should not be.</string>
<string name="ruleDoesntApplyStateNotCorrect" translatable="false">Rule %1$s doesn\'t apply. Wrong state.</string>
<string name="ruleDoesntApplyDeviceInRangeButShouldNotBe" translatable="false">Rule \"%1$s\" doesn\'t apply. Device is in range, but should not be.</string>
<string name="ruleDoesntApplyStateNotCorrect" translatable="false">Rule \"%1$s\" doesn\'t apply. Wrong state.</string>
<string name="triggerHeadsetPlugged">Połączenie zestawu słuchawkowego</string>
<string name="actionPlayMusic">Otwórz odtwarzacz muzyki</string>
<string name="headsetConnected">Zestaw słuchawkowy (typ: %1$s) podłączony</string>
@ -446,7 +446,7 @@
<string name="headphoneMicrophone">Mikrofon</string>
<string name="headphoneAny">Albo</string>
<string name="headphoneSelectType">Wybierz typ słuchawek</string>
<string name="ruleDoesntApplyWrongHeadphoneType" translatable="false">Rule %1$s doesn\'t apply. Wrong headphone type.</string>
<string name="ruleDoesntApplyWrongHeadphoneType" translatable="false">Rule \"%1$s\" doesn\'t apply. Wrong headphone type.</string>
<string name="ignoringActivityDetectionUpdateTooSoon" translatable="false">Ignoring activity detection update. Came in sooner that %1$s seconds.</string>
<string name="whatsThis">Co to jest?</string>
<string name="atLeastRuleXisUsingY" translatable="false">At least rule \"%1$s\" is using a trigger of type \"%2$s\".</string>
@ -899,4 +899,57 @@
<string name="wifiTriggerDisconnectionHint">Ten wyzwalacz będzie prawidłowy, jeśli właśnie rozłączyłeś się z Wi-Fi określonym powyżej LUB gdy usługa jest nadal uruchomiona i jeśli nie masz połączenia z żadną siecią Wi-Fi. Jeśli chcesz, aby wyzwalacz uruchamiał się tylko wtedy, gdy jawnie rozłączasz się z określoną siecią Wi-Fi, dodaj kolejny wyzwalacz \"usługa nie uruchamia się\".</string>
<string name="className">nazwa klasy</string>
<string name="startAppByStartForegroundService">przez startForegroundService()</string>
<string name="method">Metoda</string>
<string name="takeScreenshot">Zrób zrzut ekranu</string>
<string name="android.permission.BIND_ACCESSIBILITY_SERVICE">Powiąż z usługą ułatwień dostępu</string>
<string name="bindAccessibilityService">Powiąż z usługą ułatwień dostępu</string>
<string name="accessibilityApiPermissionHint">Po kliknięciu OK zostaniesz przekierowany do systemowego okna dialogowego. Wybierz tam Automatyzację i zezwól na Zezwalaj na interfejs API ułatwień dostępu.</string>
<string name="accessibility_service_explanation">Wymagane w przypadku niektórych działań.</string>
<string name="noticeRestrictedPermissions">Jeśli nie uda Ci się przyznać następującego uprawnienia i komunikatu systemowego, takiego jak \"Ograniczone uprawnienia\", musisz najpierw przejść do ustawień Androida, a następnie aplikacji, wybrać Automatyzacja. Teraz w prawym górnym rogu powinny znajdować się 3 kropki. Kliknij \"Zezwól na ustawienia z ograniczeniami\". Następnie powinno być możliwe udzielenie niezbędnego pozwolenia. Powinno to dotyczyć tylko wersji APK aplikacji, a nie tych z F-Droid lub Sklepu Play.</string>
<string name="setLocationService">Ustawianie usługi lokalizacyjnej</string>
<string name="setLocationServiceCapital">Ustawianie usługi lokalizacyjnej</string>
<string name="writeSecureSettingsNotice">Niestety WRITE_SECURE_SETTINGS uprawnień nie można nadać bezpośrednio na urządzeniu z Androidem. Zamiast tego musisz podłączyć urządzenie do komputera i przyznać uprawnienia przez ADB. Kliknij tutaj, aby dowiedzieć się, jak go przyznać: https://server47.de/automation/adb_hack.php</string>
<string name="actionSetLocationService">Usługa lokalizacyjna</string>
<string name="triggerUrlVariableHint">Wynik tego żądania zostanie zapisany w zmiennej LAST_TRIGGERURL_RESULT, jeśli chcesz go sprawdzić z innej reguły. W przypadku błędów HTTP, takich jak 404, wartość będzie wynosić \"HTTP_ERROR\".</string>
<string name="calendarEvent">Wydarzenie w kalendarzu</string>
<string name="eventIsCurrentlyHappening">Wydarzenie jest obecnie aktywne</string>
<string name="calendarEventCapital">wydarzenie w kalendarzu</string>
<string name="location">Lokalizacja</string>
<string name="calendarDescription">Opis/uwagi</string>
<string name="availability">Dostępność</string>
<string name="eventIsCurrentlyNotHappening">Wydarzenie obecnie się nie odbywa/zakończyło</string>
<string name="calendarStringBusy">zajęty</string>
<string name="calendarStringFree">wolny</string>
<string name="calendarStringTentative">próba</string>
<string name="calendarStringOutOfOffice">poza biurem</string>
<string name="calendarStringWorkingElsewhere">praca w innym miejscu</string>
<string name="selectingNoneItemForAllToMatch">Jeśli nie wybierzesz żadnego elementu, każdy będzie w porządku.</string>
<string name="calendars">Kalendarze</string>
<string name="calendarAvailabilityTypesUnsupported">Może się zdarzyć, że tylko pierwsze 3 typy faktycznie działają, ponieważ inne typy nie są częścią standardowego interfejsu kalendarza Androida.</string>
<string name="anyCalendar">dowolny kalendarz</string>
<string name="availabilities">Dostępność</string>
<string name="calendarsMissingHint">W tym wyzwalaczu kalendarze o identyfikatorach %1$s zostały wcześniej skonfigurowane, ale od tego czasu zostały usunięte. Przy następnym zapisie zostaną one usunięte z tego wyzwalacza. Do tego czasu ten wyzwalacz/warunek nigdy nie zostanie spełniony.</string>
<string name="account">rachunek</string>
<string name="allDayEvent">Wydarzenie całodniowe</string>
<string name="allDayEventTrue">Wydarzenie jest wydarzeniem całodniowym</string>
<string name="allDayEventFalse">Wydarzenie nie jest wydarzeniem całodniowym</string>
<string name="permissionCalendarRequired">Uprawnienie do odczytu kalendarza będzie wymagane dla wyzwalacza kalendarza. Wymagane będzie już wypełnienie pól kalendarza w tym oknie.</string>
<string name="noCalendarsOnYourDevice">Wygląda na to, że na urządzeniu nie skonfigurowano żadnych kalendarzy. Możesz zapisać ten wyzwalacz, ale nigdy nie zwróci on wartości true.</string>
<string name="errorReadingCalendars">Wystąpił błąd podczas odczytywania kalendarzy na urządzeniu.</string>
<string name="android.permission.SCHEDULE_EXACT_ALARM">Zaplanuj dokładne alarmy</string>
<string name="alarmsPermissionHint">Po kliknięciu OK otworzy się okno. Wybierz tam Automatyzacja i zezwól aplikacji na zaplanowanie dokładnych alarmów.</string>
<string name="evaluate">Oceniać</string>
<string name="errorLoadingValues">Wystąpił błąd podczas ładowania wartości.</string>
<string name="enterValidDataIntoParametersFields">Wprowadź prawidłowe dane w polach parametrów.</string>
<string name="reoccurringFalse">zdarzenie nie powtarza się</string>
<string name="reoccurringTrue">zdarzenie powtarza się</string>
<string name="reoccurring">Cyklicznych</string>
<string name="calendarTriggerExecutionHints">Jeśli Twój kalendarz zawiera wiele równoległych, nakładających się na siebie lub bezpośrednio następujących wydarzeń, reguła zostanie wykonana tyle razy, ile jest wydarzeń spełniających kryteria reguły. Jeśli reguła ma wiele wyzwalaczy kalendarza i równolegle występuje wiele pasujących zdarzeń, reguła zostanie wykonana tylko raz.</string>
<string name="charging_AC">Ładowarka</string>
<string name="charging_wireless">bezprzewodowy</string>
<string name="charging">Ładowania</string>
<string name="notCharging">Nie ładuje się</string>
<string name="triggerChargingComment">Typ zostanie oceniony tylko wtedy, gdy urządzenie się ładuje. Jeśli nie zostanie wybrane ładowanie, zostanie uruchomione przy dowolnym poprzednim typie ładowania. Jeśli chcesz to ocenić, rozważ użycie zmiennych trigger/action.</string>
<string name="helpTextProfiles">Profil jest zbiorem ustawień dzwonków, głośności i innych ustawień związanych z dźwiękiem, które można zastosować z reguł lub zastosować ręcznie.\\n\\nMożliwe jest również zapytanie o ostatnio aktywowany profil jako wyzwalacz. W normalnym przypadku zapyta tylko, czy profil był ostatnio aktywowany (niezależnie od tego, czy określone ustawienia dźwięku zostały zmienione w międzyczasie). Ale możesz także porównać poszczególne ustawienia.</string>
<string name="serviceWontStartNoActivatedRules">Nie zdefiniowano aktywowanych reguł. Usługa nie uruchamia się.</string>
</resources>

View File

@ -65,7 +65,7 @@
<string name="end">Конец</string>
<string name="save">Сохранить</string>
<string name="urlToTrigger">URL для вызова:</string>
<string name="urlLegend">Переменные:\nВы можете использовать следующие переменные. При срабатывании они будут заменены соответствующим значением на вашем устройстве. Скобки- часть переменной.\n\n[uniqueid] - уникальный идентификатор\n[serialnr] - серийный номер(&lt; Android 9)\n[latitude] - широта\n[longitude] - долгота\n[phonenr] - Номер последнего входящего или исходящего вызова\n[d] - День месяца, 2 цифры с начальными нулями\n[m] Месяц, 2 цифры с начальными нулями\n[Y] - Год, 4 цифры\n[h] - 12-часовой формат часа с начальными нулями\n[H] - 24-часовой формат часа с начальными нулями\n[i] - Минуты с начальными нулями\n[s] - Секунды с начальными нулями\n[ms] - миллисекунды\n[notificationTitle] - заголовок последнего уведомления\n[notificationText] - текст последнего уведомления\n[variable-VARIABLENAME] - Значение переменной, определенной пользователем</string>
<string name="urlLegend">Переменные:\nВы можете использовать следующие переменные. При срабатывании они будут заменены соответствующим значением на вашем устройстве. Скобки- часть переменной.\n\n[uniqueid] - уникальный идентификатор\n[serialnr] - серийный номер(&lt; Android 9)\n[latitude] - широта\n[longitude] - долгота\n[phonenr] - Номер последнего входящего или исходящего вызова\n[d] - День месяца, 2 цифры с начальными нулями\n[m] Месяц, 2 цифры с начальными нулями\n[Y] - Год, 4 цифры\n[h] - 12-часовой формат часа с начальными нулями\n[H] - 24-часовой формат часа с начальными нулями\n[i] - Минуты с начальными нулями\n[s] - Секунды с начальными нулями\n[ms] - миллисекунды\n[notificationTitle] - заголовок последнего уведомления\n[notificationText] - текст последнего уведомления\n[last_triggerurl_result] - Результат последнего выполнения действия triggerUrl\n[last_run_executable_exit_code] - Код выхода последнего выполняемого действия\n[last_run_executable_output] - Выходные данные последнего выполняемого действия (только для некорневых пользователей)\n[last_calendar_title] - Заголовок последнего календарного события, запускающего правило\n[last_calendar_description] - Описание последнего события календаря, активировавшего правило\n[last_calendar_location] - Местоположение последнего календарного события, запускающего правило\n[variable-VARIABLENAME] - Значение переменной, определенной пользователем</string>
<string name="wifi">Wi-Fi</string>
<string name="activating">Активация</string>
<string name="deactivating">Деактивация</string>
@ -120,7 +120,7 @@
<string name="soundSettings">Настройки звука</string>
<string name="showHelp">Показать справку</string>
<string name="rules">Правила</string>
<string name="helpTextRules">Все триггеры в правиле связаны логикой И. Правило будет применяться только в том случае, если будут выполнены все триггеры. Если вы хотите логику ИЛИ, создайте другое правило.\nТермины триггер и условие используются как синонимы. Все они являются условиями, но последний, отвечающий требуемому значению, может быть назван триггером, потому что это последняя часть паззла, которая вызывает выполнение правила.</string>
<string name="helpTextRules">Все триггеры в правиле связаны логикой И. Правило будет применяться только в том случае, если будут выполнены все триггеры. Если вы хотите логику ИЛИ, создайте другое правило.\nТермины триггер и условие используются как синонимы. Все они являются условиями, но последний, отвечающий требуемому значению, может быть назван триггером, потому что это последняя часть паззла, которая вызывает выполнение правила.\nЕсли вы хотите сохранить определенные переменные из правила и оценить их в другом правиле, извлеките переменную trigger/action.</string>
<string name="timeframes">Временные интервалы</string>
<string name="helpTextTimeFrame">Если вы указываете правило с временными интервалами, у вас есть два варианта. Вы можете выбрать между началом ИЛИ окончанием временного интервала. Правило срабатывает только один раз. Поэтому, если вы создадите правило с &quot;начало временного интервала&quot; в качестве триггера и позволите ему изменить ваш звуковой профиль на вибрацию, это не означает, что телефон автоматически перейдет в обычный режим, когда временной интервал закончится. Если вам это необходимо,создайте другое правило с другим временным интервалом.</string>
<string name="helpTextSound">На главном экране есть возможность заблокировать изменение уровня громкости вызова сконфигурированными правилами, например, вы можете быть в ситуации или месте, где необходим обычный режим звука, но в настоящее время его использовать нельзя. Эта функция автоматически отключится по истечении заданного времени. Нажмите кнопку +, чтобы задать необходимый период времени. После включения, вы можете вручную выключить его с помощью кнопки переключения (и таким образом снова включить изменения громкости звука).</string>
@ -859,4 +859,57 @@
<string name="wifiTriggerDisconnectionHint">Этот триггер будет действителен, если вы только что отключились от Wi-Fi, указанного выше, ИЛИ во время запуска службы и если вы не подключены ни к одному Wi-Fi. Если вы хотите, чтобы триггер срабатывал только тогда, когда вы явно отключаетесь от определенного Wi-Fi, добавьте еще один триггер «сервис не запускается».</string>
<string name="className">Имя класса</string>
<string name="startAppByStartForegroundService">no startForegroundService()</string>
<string name="method">Метод</string>
<string name="takeScreenshot">Сделать снимок экрана</string>
<string name="android.permission.BIND_ACCESSIBILITY_SERVICE">Привязка к службе специальных возможностей</string>
<string name="bindAccessibilityService">Привязка к службе специальных возможностей</string>
<string name="accessibilityApiPermissionHint">После нажатия кнопки «ОК» вы попадете в системное диалоговое окно. Выберите там «Автоматизация» и разрешите «Разрешить API специальных возможностей».</string>
<string name="accessibility_service_explanation">Required for certain actions.</string>
<string name="noticeRestrictedPermissions">Если вы не можете предоставить одно из следующих разрешений и системное сообщение типа «Ограниченное разрешение», вам нужно сначала перейти в настройки Android, затем в приложения, выбрать «Автоматизация». Теперь в правом верхнем углу должно быть 3 точки. Нажмите «Разрешить ограниченные настройки». После этого необходимо получить необходимое разрешение. Это должно относиться только к APK-версии приложения, а не к версии из F-Droid или Play Store.</string>
<string name="setLocationService">Настройка службы определения местоположения</string>
<string name="setLocationServiceCapital">Настройка службы определения местоположения</string>
<string name="writeSecureSettingsNotice">К сожалению, разрешение WRITE_SECURE_SETTINGS не может быть дано непосредственно на вашем Android-устройстве. Вместо этого вам нужно подключить устройство к компьютеру и предоставить разрешение через ADB. Нажмите здесь, чтобы узнать, как его получить: https://server47.de/automation/adb_hack.php</string>
<string name="actionSetLocationService">Служба определения местоположения</string>
<string name="triggerUrlVariableHint">Результат этого запроса будет сохранен в переменной LAST_TRIGGERURL_RESULT если вы захотите проверить его из другого правила. В случае ошибок HTTP, таких как 404, значение будет \"HTTP_ERROR\".</string>
<string name="calendarEvent">Событие календаря</string>
<string name="eventIsCurrentlyHappening">Событие в данный момент активно</string>
<string name="calendarEventCapital">Событие календаря</string>
<string name="location">Местоположение</string>
<string name="calendarDescription">Описание/примечания</string>
<string name="availability">Наличие</string>
<string name="eventIsCurrentlyNotHappening">Событие в настоящее время не происходит/завершилось</string>
<string name="calendarStringBusy">занятый</string>
<string name="calendarStringFree">свободный</string>
<string name="calendarStringTentative">попытка</string>
<string name="calendarStringOutOfOffice">Вне офиса</string>
<string name="calendarStringWorkingElsewhere">Работа в другом месте</string>
<string name="selectingNoneItemForAllToMatch">Если вы не выберете ни одного элемента, подойдет любой.</string>
<string name="calendars">Календари</string>
<string name="calendarAvailabilityTypesUnsupported">Возможно, на самом деле работают только первые 3 типа, потому что остальные типы не являются частью стандартного интерфейса календаря Android.</string>
<string name="anyCalendar">Любой календарь</string>
<string name="availabilities">Наличии</string>
<string name="calendarsMissingHint">В этом триггере календари с идентификаторами %1$s были настроены ранее, но с тех пор были удалены. При следующем сохранении они будут удалены из этого триггера. До тех пор этот триггер/условие никогда не будет выполнен.</string>
<string name="account">счет</string>
<string name="allDayEvent">Мероприятие в течение всего дня</string>
<string name="allDayEventTrue">Событие - это событие на весь день</string>
<string name="allDayEventFalse">Событие не является событием на весь день</string>
<string name="permissionCalendarRequired">Для триггера календаря потребуется разрешение на чтение календаря. Уже потребуется заполнить поля календаря в этом окне.</string>
<string name="noCalendarsOnYourDevice">Похоже, что на вашем устройстве не настроены календари. Вы можете сохранить этот триггер, но он никогда не вернет true.</string>
<string name="errorReadingCalendars">Произошла ошибка при чтении календарей на вашем устройстве.</string>
<string name="android.permission.SCHEDULE_EXACT_ALARM">Планирование точных сигналов тревоги</string>
<string name="alarmsPermissionHint">После нажатия кнопки ОК откроется окно. Выберите там «Автоматизация» и разрешите приложению планировать точные сигналы тревоги.</string>
<string name="evaluate">Оценивать</string>
<string name="errorLoadingValues">Произошла ошибка при загрузке значений.</string>
<string name="enterValidDataIntoParametersFields">Введите допустимые данные в поля параметров.</string>
<string name="reoccurringFalse">событие не повторяется</string>
<string name="reoccurringTrue">Событие повторяется</string>
<string name="reoccurring">Повторяющиеся</string>
<string name="calendarTriggerExecutionHints">Если календарь содержит несколько параллельных, перекрывающихся или непосредственно следующих событий, правило будет выполняться столько раз, сколько событий соответствует критериям правила. В случае, если правило имеет несколько календарных триггеров и параллельно существует несколько совпадающих событий, то правило будет выполнено только один раз.</string>
<string name="charging_AC">обвинитель</string>
<string name="charging_wireless">беспроволочный</string>
<string name="charging">зарядка</string>
<string name="notCharging">не заряжается</string>
<string name="triggerChargingComment">Тип будет оцениваться только в том случае, если устройство заряжается. Если зарядка не выбрана, он будет срабатывать при любом предыдущем типе зарядки. Если вы хотите это оценить, подумайте об использовании переменных trigger/action.</string>
<string name="helpTextProfiles">Профиль — это набор настроек рингтонов, громкости и других настроек, связанных со звуком, которые можно применить из правил или вручную.\\n\\nТакже в качестве триггера можно запросить последний активированный профиль. В обычном случае он будет запрашивать только то, был ли профиль последним активированным (независимо от того, были ли за это время изменены определенные настройки звука). Но вы также можете сравнить отдельные настройки.</string>
<string name="serviceWontStartNoActivatedRules">Активированные правила не определены. Служба не запускается.</string>
</resources>

View File

@ -56,7 +56,7 @@
<string name="end">结束</string>
<string name="save">保存</string>
<string name="urlToTrigger">触发网址:</string>
<string name="urlLegend">变量:\n您可以使用以下变量。触发后它们将替换为您设备上的对应值。文本中要包含方括号。\n\n[uniqueid] - 您设备的唯一 ID\n[serialnr] - 您设备的序列号(&lt; Android 9\n[latitude] - 您设备的纬度\n[longitude] - 您设备的经度\n[phonenr] - 最后来电或去电的号码\n[d] - 日2 位数字,带前导零\n[m] - 月,数字表示,带前导零\n[Y] - 年完整数字表示4 位数字\n[h] - 时12 小时制,带前导零\n[H] - 时24 小时制,带前导零\n[i] - 分,带前导零\n[s] - 秒,带前导零\n[ms] - 毫秒\n[notificationTitle] - 最后通知的标题\n[notificationText] - 最后通知的文本\n[variable-变量名] - 自定义变量的值</string>
<string name="urlLegend">变量:\n您可以使用以下变量。触发后它们将替换为您设备上的对应值。文本中要包含方括号。\n\n[uniqueid] - 您设备的唯一 ID\n[serialnr] - 您设备的序列号(&lt; Android 9\n[latitude] - 您设备的纬度\n[longitude] - 您设备的经度\n[phonenr] - 最后来电或去电的号码\n[d] - 日2 位数字,带前导零\n[m] - 月,数字表示,带前导零\n[Y] - 年完整数字表示4 位数字\n[h] - 时12 小时制,带前导零\n[H] - 时24 小时制,带前导零\n[i] - 分,带前导零\n[s] - 秒,带前导零\n[ms] - 毫秒\n[notificationTitle] - 最后通知的标题\n[notificationText] - 最后通知的文本\n[last_triggerurl_result] - 上次 triggerUrl 操作执行的结果\n[last_run_executable_exit_code] - 上次运行可执行操作的退出代码\n[last_run_executable_output] - 上次运行可执行操作的输出(仅适用于非 root\n[variable-变量名] - 自定义变量的值</string>
<string name="wifi">WLAN</string>
<string name="activating">启用</string>
<string name="deactivating">停用</string>
@ -111,7 +111,7 @@
<string name="soundSettings">声音设置</string>
<string name="showHelp">显示帮助</string>
<string name="rules">规则</string>
<string name="helpTextRules">规则中的所有触发器都是用“与”连接的。规则仅在满足所有触发器时才应用。如果您想要“或”,请创建另一个规则。\n触发器和条件是作为同义词使用的。所有的触发器都是条件而最后一个满足其要求值的条件可以称为触发器因为它是导致规则执行的“最后一块拼图”。</string>
<string name="helpTextRules">规则中的所有触发器都是用“与”连接的。规则仅在满足所有触发器时才应用。如果您想要“或”,请创建另一个规则。\n触发器和条件是作为同义词使用的。所有的触发器都是条件而最后一个满足其要求值的条件可以称为触发器因为它是导致规则执行的“最后一块拼图”。\n如果要保存规则中的某些变量并在另一个规则中评估它们请查看变量触发器/操作。</string>
<string name="timeframes">时间范围</string>
<string name="helpTextTimeFrame">指定时间范围规则时有两种选择。您可以选择进入或离开时间范围。无论哪种方式,规则都只会触发一次。因此,如果您创建一个使用触发器“进入时间范围 XYZ”的规则让它将响铃模式更改为振动这并不意味着手机会在时间范围结束时自动更改为响铃。如果想要的话您需要指定另一个规则使用另一个时间范围。</string>
<string name="helpTextSound">在主屏幕上,您可以使用“锁定声音更改”来暂时禁用基于规则的声音更改。例如,您可能在通常允许响铃的情况或地点,但这一次响铃会打扰。一旦配置的时间过去,此功能将自动停用。点击 + 按钮以添加给定的时间。当此功能启用时,您可以使用切换按钮将其停用(即重新启用基于规则的声音更改)。</string>
@ -800,4 +800,57 @@
<string name="wifiTriggerDisconnectionHint">如果您刚刚断开了与上面指定的 wifi 的连接,或者在服务仍在启动并且您没有连接到任何 wifi则此触发器将有效。 如果您希望触发器仅在您明确断开与某个 wifi 的连接时触发,请添加另一个触发器\"服务未启动\"。</string>
<string name="className">类名</string>
<string name="startAppByStartForegroundService">来自 startForegroundService()</string>
<string name="method">方法</string>
<string name="takeScreenshot">截屏</string>
<string name="android.permission.BIND_ACCESSIBILITY_SERVICE">绑定到辅助功能服务</string>
<string name="bindAccessibilityService">绑定到辅助功能服务</string>
<string name="accessibilityApiPermissionHint">单击\"确定\"后,您将被发送到系统对话框。请在此处选择\"自动化\",并允许\"允许辅助功能 API\"。</string>
<string name="accessibility_service_explanation">对于某些操作是必需的。</string>
<string name="noticeRestrictedPermissions">如果您未能授予以下权限和\"受限权限\"之类的系统消息,则需要先转到 Android 设置,然后转到应用程序,选择自动化。现在右上角应该有 3 个点。单击\"允许受限设置\"。之后,应该可以授予必要的权限。这应该仅适用于应用的 APK 版本,而不适用于 F-Droid 或 Play 商店中的版本。</string>
<string name="setLocationService">设置位置服务</string>
<string name="setLocationServiceCapital">设置位置服务</string>
<string name="writeSecureSettingsNotice">不幸的是WRITE_SECURE_SETTINGS无法直接在您的 Android 设备上授予权限。相反,您需要将设备连接到计算机并通过 ADB 授予权限。单击此处了解如何授予它: https://server47.de/automation/adb_hack.php</string>
<string name="actionSetLocationService">定位服务</string>
<string name="triggerUrlVariableHint">此请求的结果将存储在变量 LAST_TRIGGERURL_RESULT 中,如果您希望从其他规则中检查它。如果出现像 404 这样的 HTTP 错误,则该值将为\"HTTP_ERROR\"。</string>
<string name="calendarEvent">日历事件</string>
<string name="eventIsCurrentlyHappening">活动当前处于活动状态</string>
<string name="calendarEventCapital">日历事件</string>
<string name="location">位置</string>
<string name="calendarDescription">描述/注释</string>
<string name="availability">可用性</string>
<string name="eventIsCurrentlyNotHappening">活动当前未发生/已结束</string>
<string name="calendarStringBusy"></string>
<string name="calendarStringFree">自由</string>
<string name="calendarStringTentative">尝试</string>
<string name="calendarStringOutOfOffice">不在办公室</string>
<string name="calendarStringWorkingElsewhere">在其他地方工作</string>
<string name="selectingNoneItemForAllToMatch">如果您不选择任何项目,则任何一个都可以。</string>
<string name="calendars">日历</string>
<string name="calendarAvailabilityTypesUnsupported">可能只有前 3 种类型真正有效,因为其他类型不是 Android 标准日历界面的一部分。</string>
<string name="anyCalendar">任何日历</string>
<string name="availabilities">可用性</string>
<string name="calendarsMissingHint">在此触发器中,以前已配置了 ID 为 %1$s 的日历,但此后已被删除。在下次保存时,这些将从此触发器中删除。在此之前,此触发器/条件将永远不会得到满足。</string>
<string name="account">帐户</string>
<string name="allDayEvent">全天活动</string>
<string name="allDayEventTrue">活动是全天活动</string>
<string name="allDayEventFalse">活动不是一整天的活动</string>
<string name="permissionCalendarRequired">日历触发器需要读取日历的权限。在此窗口中填充日历字段已经是必需的。</string>
<string name="noCalendarsOnYourDevice">您的设备上似乎没有设置日历。您可以保存此触发器,但它永远不会返回 true。</string>
<string name="errorReadingCalendars">读取设备上的日历时出错。</string>
<string name="android.permission.SCHEDULE_EXACT_ALARM">安排确切的警报</string>
<string name="alarmsPermissionHint">单击\"确定\"后,将打开一个窗口。请在那里选择自动化,并允许应用程序安排确切的警报。</string>
<string name="evaluate">评价</string>
<string name="errorLoadingValues">加载值时发生错误。</string>
<string name="enterValidDataIntoParametersFields">在参数字段中输入有效数据。</string>
<string name="reoccurringFalse">事件不会再次发生</string>
<string name="reoccurringTrue">事件再次发生</string>
<string name="reoccurring">重复发生</string>
<string name="calendarTriggerExecutionHints">如果您的日历包含多个平行、重叠或直接跟随的事件,则规则的执行次数将与规则条件匹配的事件次数相同。如果规则具有多个日历触发器,并且并行有多个匹配事件,则该规则将仅执行一次。</string>
<string name="charging_AC">充电器</string>
<string name="charging_wireless">无线电</string>
<string name="charging">充电</string>
<string name="notCharging">不充电</string>
<string name="triggerChargingComment">仅当设备正在充电时,才会评估类型。如果未选择充电,它将以任何以前的充电类型点火。如果要对此进行评估,请考虑使用变量 trigger/action。</string>
<string name="helpTextProfiles">配置文件是铃声、音量和其他音频相关设置的集合,您可以从规则中应用这些设置,也可以手动应用。\\n\\n还可以查询上次激活的配置文件作为触发器。在正常情况下它只会查询配置文件是否是上次激活的配置文件无论在此期间是否更改了特定的音频设置。但您也可以比较各个设置。</string>
<string name="serviceWontStartNoActivatedRules">未定义已激活的规则。服务无法启动。</string>
</resources>

View File

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name" translatable="false">Automation</string>
<string name="ruleActivate">Activating rule %1$s</string>
<string name="ruleActivate">Activating Rule \"%1$s\"</string>
<string name="profileActivate">Activating profile %1$s</string>
<string name="ruleActivateToggle">Activating rule %1$s in Togglemode</string>
<string name="ruleActivateToggle">Activating Rule \"%1$s\" in Togglemode</string>
<string name="addPoi">Add location</string>
<string name="addRule">Add Rule</string>
<string name="poiList">Location List:</string>
@ -12,6 +12,7 @@
<string name="pleaseSpecifiyTrigger">Please specify at least one trigger.</string>
<string name="pleaseSpecifiyAction">Please specify at least one action.</string>
<string name="serviceWontStart">No rules defined. Service won\'t start.</string>
<string name="serviceWontStartNoActivatedRules">No activated rules defined. Service won\'t start.</string>
<string name="serviceStarted">Automation Service started.</string>
<string name="version">Version %1$s.</string>
<string name="logServiceStarting" translatable="false">Starting service.</string>
@ -70,7 +71,7 @@
<string name="end">End</string>
<string name="save">Save</string>
<string name="urlToTrigger">URL to trigger:</string>
<string name="urlLegend">Variables:\nYou can use the following variables. Upon triggering they will be replaced with the corresponding value on your device. Include the brackets in your text.\n\n[uniqueid] - Your device\'s unique id\n[serialnr] - Your device\'s serial number (&lt; Android 9)\n[latitude] - Your device\'s latitude\n[longitude] - Your device\'s longitude\n[phonenr] - Number of last incoming or outgoing call\n[d] - Day of the month, 2 digits with leading zeros\n[m] - Numeric representation of a month, with leading zeros\n[Y] - A full numeric representation of a year, 4 digits\n[h] - 12-hour format of an hour with leading zeros\n[H] - 24-hour format of an hour with leading zeros\n[i] - Minutes with leading zeros\n[s] - Seconds, with leading zeros\n[ms] - milliseconds\n[notificationTitle] - title of last notification\n[notificationText] - text of last notification\n[variable-VARIABLENAME] - The value of your custom defined variable</string>
<string name="urlLegend">Variables:\nYou can use the following variables. Upon triggering they will be replaced with the corresponding value on your device. Include the brackets in your text.\n\n[uniqueid] - Your device\'s unique id\n[serialnr] - Your device\'s serial number (&lt; Android 9)\n[latitude] - Your device\'s latitude\n[longitude] - Your device\'s longitude\n[phonenr] - Number of last incoming or outgoing call\n[d] - Day of the month, 2 digits with leading zeros\n[m] - Numeric representation of a month, with leading zeros\n[Y] - A full numeric representation of a year, 4 digits\n[h] - 12-hour format of an hour with leading zeros\n[H] - 24-hour format of an hour with leading zeros\n[i] - Minutes with leading zeros\n[s] - Seconds, with leading zeros\n[ms] - milliseconds\n[notificationTitle] - title of last notification\n[notificationText] - text of last notification\n[last_triggerurl_result] - The result of the last triggerUrl action execution\n[last_run_executable_exit_code] - The exit code of the last run executable action\n[last_run_executable_output] - The output of the last run executable action (only for non-root)\n[last_calendar_title] - Title of the last rule-triggering calendar event\n[last_calendar_description] - Description of the last rule-triggering calendar event\n[last_calendar_location] - Location of the last rule-triggering calendar event\n[variable-VARIABLENAME] - The value of your custom defined variable</string>
<string name="wifi">wifi</string>
<string name="activating">Activating</string>
<string name="deactivating">Deactivating</string>
@ -125,7 +126,7 @@
<string name="soundSettings">Sound settings</string>
<string name="showHelp">Show help</string>
<string name="rules">Rules</string>
<string name="helpTextRules">All triggers in a rule are AND-connected. The rule will only apply if all triggers are met. If you want OR, create another rule.\nThe terms trigger and condition are being used synonymously. All of them are conditions, but the last one to meet its required value could be called trigger because it is the final piece of the puzzle to cause a rule to be executed.</string>
<string name="helpTextRules">All triggers in a rule are AND-connected. The rule will only apply if all triggers are met. If you want OR, create another rule.\nThe terms trigger and condition are being used synonymously. All of them are conditions, but the last one to meet its required value could be called trigger because it is the final piece of the puzzle to cause a rule to be executed.\nIf you\'d like to save certain variables from a rule and evaluate them in another rule, checkout the variable trigger/action.</string>
<string name="timeframes">TimeFrames</string>
<string name="helpTextTimeFrame">If you specify a rule with a timeframe you have two choices. You can choose between entering OR leaving a timeframe. Either way a rule is triggered only once. So if you create a rule that has \"entering timeframe xyz\" as trigger and let it change your sound profile to vibrate that does not mean that the phone will automatically go to ring if the timeframe is over. If you want that you need to specify another rule with another timeframe.</string>
<string name="helpTextSound">On the main screen you can use lock sound changes to temporarily avoid rule based sound changes. E.g. you may be in a situation or place where usually ringtones are ok, but this one time it would be disturbing. The feature will automatically deactivate once the configured time has elapsed. Click the + button to add the given amount of time. Once it is active you may deactivate it again using the toggle button (and that way enable rule based sound changes again).</string>
@ -212,16 +213,16 @@
<string name="wifiName">Wifi name</string>
<string name="enterWifiName">Enter a wifi name. Leave empty for any wifi.</string>
<string name="cancel">Cancel</string>
<string name="ruleDoesntApplyWeAreSlowerThan" translatable="false">Rule %1$s doesn\'t apply. We are slower than</string>
<string name="ruleDoesntApplyWeAreFasterThan" translatable="false">Rule %1$s doesn\'t apply. We are faster than</string>
<string name="ruleDoesntApplyItsQuieterThan" translatable="false">Rule %1$s doesn\'t apply. It\'s quieter than</string>
<string name="ruleDoesntApplyItsLouderThan" translatable="false">Rule %1$s doesn\'t apply. It\'s louder than</string>
<string name="ruleDoesntApplyBatteryLowerThan" translatable="false">Rule %1$s doesn\'t apply. Battery level is lower than</string>
<string name="ruleDoesntApplyBatteryHigherThan" translatable="false">Rule %1$s doesn\'t apply. Battery level is higher than</string>
<string name="ruleDoesntApplyNotTheCorrectSsid" translatable="false">Rule %1$s doesn\'t apply. Not the correct SSID (demanded: \"%2$s\", given: \"%3$s\").</string>
<string name="ruleDoesntApplyNoTagLabel" translatable="false">Rule %1$s doesn\'t apply. There is no tag label or not tag at all.</string>
<string name="ruleDoesntApplyWrongTagLabel" translatable="false">Rule %1$s doesn\'t apply. Wrong tag label.</string>
<string name="ruleIsDeactivatedCantApply" translatable="false">Rule %1$s is deactivated, can\'t apply.</string>
<string name="ruleDoesntApplyWeAreSlowerThan" translatable="false">Rule \"%1$s\" doesn\'t apply. We are slower than</string>
<string name="ruleDoesntApplyWeAreFasterThan" translatable="false">Rule \"%1$s\" doesn\'t apply. We are faster than</string>
<string name="ruleDoesntApplyItsQuieterThan" translatable="false">Rule \"%1$s\" doesn\'t apply. It\'s quieter than</string>
<string name="ruleDoesntApplyItsLouderThan" translatable="false">Rule \"%1$s\" doesn\'t apply. It\'s louder than</string>
<string name="ruleDoesntApplyBatteryLowerThan" translatable="false">Rule \"%1$s\" doesn\'t apply. Battery level is lower than</string>
<string name="ruleDoesntApplyBatteryHigherThan" translatable="false">Rule \"%1$s\" doesn\'t apply. Battery level is higher than</string>
<string name="ruleDoesntApplyNotTheCorrectSsid" translatable="false">Rule \"%1$s\" doesn\'t apply. Not the correct SSID (demanded: \"%2$s\", given: \"%3$s\").</string>
<string name="ruleDoesntApplyNoTagLabel" translatable="false">Rule \"%1$s\" doesn\'t apply. There is no tag label or not tag at all.</string>
<string name="ruleDoesntApplyWrongTagLabel" translatable="false">Rule \"%1$s\" doesn\'t apply. Wrong tag label.</string>
<string name="ruleIsDeactivatedCantApply" translatable="false">Rule \"%1$s\" is deactivated, can\'t apply.</string>
<string name="starting">starting</string>
<string name="stopping">stopping</string>
<string name="connecting">connecting</string>
@ -308,7 +309,7 @@
<string name="wifiNameSpecifiedCheckingThat" translatable="false">Wifi name specified, checking that.</string>
<string name="wifiNameMatchesRuleWillApply" translatable="false">Wifi name matches. Rule will apply.</string>
<string name="noWifiNameSpecifiedAnyWillDo" translatable="false">No wifi name specified, any will do.</string>
<string name="ruleCheckOf" translatable="false">RuleCheck of %1$s</string>
<string name="ruleCheckOf" translatable="false">RuleCheck of \"%1$s\"</string>
<string name="airplaneMode">Airplane mode</string>
<string name="activate">Activate</string>
<string name="deactivate">Deactivate</string>
@ -383,8 +384,8 @@
<string name="toggle">toggle</string>
<string name="overlapBetweenPois">Overlap detected to location %1$s of %2$s meters. Reduce radius by at least that.</string>
<string name="noOverLap" translatable="false">No overlap to other locations detected.</string>
<string name="ruleToggable" translatable="false">Rule %1$s is toggable.</string>
<string name="ruleNotToggable" translatable="false">Rule %1$s is not suitable for toggling.</string>
<string name="ruleToggable" translatable="false">Rule \"%1$s\" is toggable.</string>
<string name="ruleNotToggable" translatable="false">Rule \"%1$s\" is not suitable for toggling.</string>
<string name="none">none</string>
<string name="anyLocation">any location</string>
<string name="invalidPoiName">Invalid name for location.</string>
@ -405,8 +406,8 @@
<string name="detectedActivityWalking">Walking</string>
<string name="detectedActivityRunning">Running</string>
<string name="detectedActivityInvalidStatus">Invalid activity</string>
<string name="ruleDoesntApplyActivityGivenButTooLowProbability" translatable="false">Rule %1$s doesn\'t apply. Detected activity %2$s given, but too low probability (%3$s %%), required %4$s %%.</string>
<string name="ruleDoesntApplyActivityNotPresent" translatable="false">Rule %1$s doesn\'t apply. Required activity %2$s not present.</string>
<string name="ruleDoesntApplyActivityGivenButTooLowProbability" translatable="false">Rule \"%1$s\" doesn\'t apply. Detected activity %2$s given, but too low probability (%3$s %%), required %4$s %%.</string>
<string name="ruleDoesntApplyActivityNotPresent" translatable="false">Rule \"%1$s\" doesn\'t apply. Required activity %2$s not present.</string>
<string name="selectTypeOfActivity">Select type of activity</string>
<string name="triggerOnlyAvailableIfPlayServicesInstalled">This trigger is only available if Google Play Services is installed.</string>
<string name="activityDetectionFrequencyTitle">Activity detection frequency [sec]</string>
@ -426,8 +427,8 @@
<string name="bluetoothDeviceInRange">Bluetooth device %1$s in range.</string>
<string name="bluetoothDeviceOutOfRange">Bluetooth device %1$s out of range.</string>
<string name="anyDevice">any device</string>
<string name="ruleDoesntApplyNotTheCorrectDeviceName" translatable="false">Rule %1$s doesn\'t apply. Not the correct bluetooth device name.</string>
<string name="ruleDoesntApplyNotTheCorrectDeviceAddress" translatable="false">Rule %1$s doesn\'t apply. Not the correct bluetooth device address.</string>
<string name="ruleDoesntApplyNotTheCorrectDeviceName" translatable="false">Rule \"%1$s\" doesn\'t apply. Not the correct bluetooth device name.</string>
<string name="ruleDoesntApplyNotTheCorrectDeviceAddress" translatable="false">Rule \"%1$s\" doesn\'t apply. Not the correct bluetooth device address.</string>
<string name="noDevice">no device</string>
<string name="selectDeviceFromList">one from list</string>
<string name="connectionToDevice">connection to device</string>
@ -436,8 +437,8 @@
<string name="deviceOutOfRange">device out of range</string>
<string name="selectDeviceOption">Select a device option.</string>
<string name="selectConnectionOption">Select a connection option.</string>
<string name="ruleDoesntApplyDeviceInRangeButShouldNotBe" translatable="false">Rule %1$s doesn\'t apply. Device is in range, but should not be.</string>
<string name="ruleDoesntApplyStateNotCorrect" translatable="false">Rule %1$s doesn\'t apply. Wrong state.</string>
<string name="ruleDoesntApplyDeviceInRangeButShouldNotBe" translatable="false">Rule \"%1$s\" doesn\'t apply. Device is in range, but should not be.</string>
<string name="ruleDoesntApplyStateNotCorrect" translatable="false">Rule \"%1$s\" doesn\'t apply. Wrong state.</string>
<string name="triggerHeadsetPlugged">Headset connection</string>
<string name="actionPlayMusic">Open music player</string>
<string name="headsetConnected">Headset (type: %1$s) connected</string>
@ -446,7 +447,7 @@
<string name="headphoneMicrophone">Microphone</string>
<string name="headphoneAny">Either</string>
<string name="headphoneSelectType">Select type of headphone</string>
<string name="ruleDoesntApplyWrongHeadphoneType" translatable="false">Rule %1$s doesn\'t apply. Wrong headphone type.</string>
<string name="ruleDoesntApplyWrongHeadphoneType" translatable="false">Rule \"%1$s\" doesn\'t apply. Wrong headphone type.</string>
<string name="ignoringActivityDetectionUpdateTooSoon" translatable="false">Ignoring activity detection update. Came in sooner that %1$s seconds.</string>
<string name="whatsThis">What\'s this?</string>
<string name="atLeastRuleXisUsingY" translatable="false">At least rule \"%1$s\" is using a trigger of type \"%2$s\".</string>
@ -522,7 +523,7 @@
<string name="ok">Ok</string>
<string name="disabledFeatures">Disabled features</string>
<string name="theFollowingPermissionsHaveBeenDenied">The following permissions have been denied:</string>
<string name="permissionsExplanationGeneric">The app is current running in limited mode and has deactivated some features. To fully function it requires permissions. If you want to use all functionality you have to grant the permissions in the following rights dialogues. If you do not certain rules can not be executed. In the following you are given an explanation for the requested permissions. Click "continue", when you are ready to proceed.</string>
<string name="permissionsExplanationGeneric">The app is current running in limited mode and has deactivated some features. To fully function it requires permissions. If you want to use all functionality you have to grant the permissions in the following rights dialogues. If you do, not certain rules can not be executed. In the following you are given an explanation for the requested permissions. Click "continue", when you are ready to proceed.</string>
<string name="permissionsExplanationSmall">To enable the feature you just tried to use more permissions are required. Click continue to request them.</string>
<string name="continueText">continue</string>
<string name="rule">Rule</string>
@ -560,7 +561,7 @@
<string name="android.permission.GET_TASKS">Detect running processes</string>
<string name="android.permission.WRITE_SETTINGS">Change device settings</string>
<string name="android.permission.RECEIVE_BOOT_COMPLETED">Detect device reboot</string>
<string name="android.permission.WRITE_SECURE_SETTINGS">Change device settings</string>
<string name="android.permission.WRITE_SECURE_SETTINGS">Change secure device settings</string>
<string name="android.permission.BATTERY_STATS">Read battery state</string>
<string name="android.permission.CHANGE_BACKGROUND_DATA_SETTING">Change data connection</string>
<string name="android.permission.SEND_SMS">Send text messages</string>
@ -746,7 +747,7 @@
<string name="profileActive">profile %1$s is active</string>
<string name="profileNotActive">profile %1$s is not active</string>
<string name="profileTriggerCheckSettings">If this checkbox is not disabled, it will only be checked if the selected profile has been the last one to be activated. It doesn\'t matter if any audio related settings have been changed externally. However if the checkbox is enabled, the current audio settings really need to be like defined in the profile. BEWARE: Checking the ringtone file is currently not supported, yet.</string>
<string name="ruleXIsUsingProfileY">Cannot delete this profile. Rule %1$s is referencing profile %2$s.</string>
<string name="ruleXIsUsingProfileY">Cannot delete this profile. Rule \"%1$s\" is referencing profile %2$s.</string>
<string name="profileCouldNotBeDeleted">Profile could not be deleted.</string>
<string name="noRepetition">no repetition</string>
<string name="usingAuthentication">using authentication</string>
@ -889,4 +890,61 @@
<string name="wifiTriggerDisconnectionHint">This trigger will be valid if you just disconnected from the wifi specified above OR while the service is still starting and if you\'re not connected to any wifi. If you want the trigger to fire only when you\'re explicitly disconnecting from a certain wifi, add another trigger \"service is not starting\".</string>
<string name="className">Class full name</string>
<string name="startAppByStartForegroundService">by startForegroundService()</string>
<string name="method">Method</string>
<string name="methodGet" translatable="false">GET</string>
<string name="methodPost" translatable="false">POST</string>
<string name="takeScreenshot">Take screenshot</string>
<string name="android.permission.BIND_ACCESSIBILITY_SERVICE">Bind to accessibility service</string>
<string name="bindAccessibilityService">Bind to accessibility service</string>
<string name="accessibilityApiPermissionHint">After clicking OK you\'ll be sent to a system dialog. Please select Automation there and allow "Allow accessibility API".</string>
<string name="accessibility_service_explanation">Required for certain actions.</string>
<string name="noticeRestrictedPermissions">If you fail to grant one the following permission and a system message like \"Restricted permission\" you need to go to Android settings first, then applications, choose Automation. Now there should be 3 dots in the upper right corner. Click \"Allow restricted settings\". After that the necessary permission should be grant-able. This should only apply to the APK version of the app, not the ones from F-Droid or Play Store.</string>
<string name="setLocationService">set location service</string>
<string name="setLocationServiceCapital">Set location service</string>
<string name="writeSecureSettingsNotice">Unfortunately the permission WRITE_SECURE_SETTINGS cannot be given directly on your Android device. Instead you need to connect your device to a computer and grant the permission via ADB. Click here to find out how to grant it: https://server47.de/automation/adb_hack.php</string>
<string name="actionSetLocationService">Location service</string>
<string name="LOCATION_MODE_SENSOR_ONLY" translatable="false">SENSOR_ONLY</string>
<string name="LOCATION_MODE_BATTERY_SAVING" translatable="false">BATTERY_SAVING</string>
<string name="LOCATION_MODE_HIGH_ACCURACY" translatable="false">HIGH_ACCURACY</string>
<string name="triggerUrlVariableHint">The result of this request will be stored in the variable LAST_TRIGGERURL_RESULT if you wish to check it from another rule. In case of HTTP errors like 404 the value will be \"HTTP_ERROR\".</string>
<string name="calendarEvent">calendar event</string>
<string name="eventIsCurrentlyHappening">Event is currently active</string>
<string name="calendarEventCapital">Calendar event</string>
<string name="location">Location</string>
<string name="calendarDescription">Description/notes</string>
<string name="availability">Availability</string>
<string name="eventIsCurrentlyNotHappening">Event is currently not happening/has ended</string>
<string name="calendarStringBusy">busy</string>
<string name="calendarStringFree">free</string>
<string name="calendarStringTentative">tentative</string>
<string name="calendarStringOutOfOffice">out of office</string>
<string name="calendarStringWorkingElsewhere">working elsewhere</string>
<string name="selectingNoneItemForAllToMatch">If you select no item, any one will be ok.</string>
<string name="calendars">Calendars</string>
<string name="calendarAvailabilityTypesUnsupported">It may be that only the first 3 types are actually working because the other types are not part of Android\'s standard calendar interface.</string>
<string name="anyCalendar">any calender</string>
<string name="availabilities">availabilities</string>
<string name="calendarsMissingHint">In this trigger calendars with IDs %1$s have been previously configured, but have been deleted since. With the next save those will be removed from this trigger. Until then this trigger/condition will never be met.</string>
<string name="account">account</string>
<string name="allDayEvent">All day event</string>
<string name="allDayEventTrue">event is an all day event</string>
<string name="allDayEventFalse">event is not an all day event</string>
<string name="permissionCalendarRequired">The permission to read your calendar will be required for a calendar trigger. It will already be required to populate the calendar fields in this window.</string>
<string name="noCalendarsOnYourDevice">It appears like no calendars have been set up on your device. You can save this trigger, but it will never return true.</string>
<string name="errorReadingCalendars">There was an error reading the calendars on your device.</string>
<string name="android.permission.SCHEDULE_EXACT_ALARM">Schedule exact alarms</string>
<string name="alarmsPermissionHint">After clicking OK a window will open. Please select Automation there and allow the app to schedule exact alarms.</string>
<string name="evaluate">Evaluate</string>
<string name="errorLoadingValues">An error occur occured while loading values.</string>
<string name="enterValidDataIntoParametersFields">Enter valid data into the parameter fields.</string>
<string name="reoccurringFalse">event is not reoccurring</string>
<string name="reoccurringTrue">event is reoccurring</string>
<string name="reoccurring">reoccurring</string>
<string name="calendarTriggerExecutionHints">If your calendar holds multiple parallel, overlapping or directly following events, a rule will get executed as many times as there are events matching the rule\'s criteria. In case a rule has multiple calendar triggers and there are multiple matching events in parallel, then the rule will get executed only once.</string>
<string name="charging_AC">AC</string>
<string name="charging_wireless">wireless</string>
<string name="charging">charging</string>
<string name="notCharging">not charging</string>
<string name="triggerChargingComment">The type will only be evaluated if the device is charging. If not charging is chosen, it will fire at any previous charging type. If you want to evaluate that, consider using the variables trigger/action.</string>
<string name="helpTextProfiles">A profile is a collection of settings for ringtones, volumes and other audio related settings that you can have applied from rules or apply it manually.\n\nIt is also possible to query for the last activated profile as a trigger. In the normal case it will only query if the profile was the last activated one (regardless if specific audio settings have been changed in the meantime). But you can also have the individual settings compared.</string>
</resources>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeAllMask"
android:accessibilityFlags="flagDefault"
android:accessibilityFeedbackType="feedbackSpoken"
android:canPerformGestures="false"
android:canRequestFilterKeyEvents="false"
android:canRequestFingerprintGestures="false"
android:canRetrieveWindowContent="false"
android:canTakeScreenshot="true"
android:notificationTimeout="0"
android:description="@string/accessibility_service_explanation" />

View File

@ -0,0 +1 @@
* Fixed: Crashes at service start that only affected the Google Play version because of a higher targetSdk

View File

@ -15,14 +15,22 @@ Mögliche Auslöser:
* Flugzeugmodus
* Roaming aktiv oder nicht
* NFC tags
* Aktivitätserkennung (nicht in F-Droid Version)
* Bluetooth Gerät verbunden
* Headset verbunden
* Telefongespräch im Gange
* Benachrichtigungen anderer Anwendungen
* Geräteausrichtung (Gyroskop)
* Profile aktiv oder nicht
* Bildschirmzustand (aus-/eingeschaltet)
* Musikwiedergabestatus
* Gerät startet
* Dienst startet
* Broadcasts anderer Anwendungen
* Router-Zustand
* Zustände (Bluetooth/WLAN aus oder an)
* Variablen, die gesetzt wurden
* Kalendertermine
* Telefongespräch im Gange
Mögliche Aktionen:
* WLAN ein-/ausschalten
@ -37,15 +45,25 @@ Mögliche Aktionen:
* Warten (zwischen anderen Aktionen)
* Bildschirm ein-/ausschalten
* Flugzeugmodus ein-/ausschalten
* Datenverbindung ein-/ausschalten
* Mobile Daten ein-/ausschalten
* Text sprechen (TTS)
* Musikplayer öffnen
* Medienwiedergabe steuern
* Bildschirmhelligkeit ändern
* SMS verschicken
* Sounddatei abspielen.
* Sounddatei abspielen
* Vibrieren
* Benachrichtigungen erstellen
* Benachrichtigungen schließen
* Broadcast verschicken
* Script/Befehl ausführen
* Bildschirm aktiv halten
* Variablen setzen
* Telefonanrufe starten
* Telefonanrufe beenden
* Text in Zwischenablage kopieren
* Screenshot erstellen
* GPS Einstellungen setzen
* SMS verschicken
Es ist ziemlich schwierig diese Anwendung über die vielen verschiedenen Geräte und Android Versionen am Laufen zu halten. Ich kann vieles im Emulator testen, aber eben nicht alles.
Wenn also eine bestimmte Funktion nicht so tut wie sie sollte - lassen Sie es mich wissen. Über die Jahre habe ich noch alle Fehler behoben, die mir vernünftig gemeldet wurden. Aber dafür bin ich auf Ihre Mithilfe angewiesen.

View File

@ -0,0 +1,14 @@
* Fixed: Overlay permission for start other program action only required if startByActivity() is selected
* Fixed: Broadcast receiver trigger would not trigger anything, but crash
* Fixed: Bug in Android 14 (not in Automation!!!) required a change when dialing MMI codes containing a # character.
* Fixed: Storage permission might be displayed as not granted even if it was
* Fixed: Applied a very old bugfix also to F-Droid and Google-Play editions that had by mistake been implemented only in the APK edition (timeFrame trigger with repetitions)
* Fixed: Rare crash while starting service
* Fixed: Compensated for Android changes, time-based triggers are now precise again
* Added: new action -> take screenshot
* Added: Location service (GPS) can be toggled between states if WRITE_SECURE_SETTINGS has been granted from a computer
* Added: triggerUrl action can now be used with POST and parameters
* Added: Result of triggerUrl action is now stored in a variable if you wish to check it
* Added: New trigger: Calendar events
* Added: Result of runExecutable action is now stored in a variable if you wish to check it
* Added: Charging trigger can now differentiate between types (AC, USB, wirelessly)

View File

@ -8,21 +8,29 @@ Supported triggers:
* Charging state
* Battery level
* USB connection to computer established
* Your current speed
* Current speed
* Background noise (only until Android 7)
* Wifi connection
* Other applications running
* Airplane mode
* Roaming status
* NFC tags
* Activity detection (not in F-Droid version)
* Bluetooth connection
* Headset connected
* Phone call running
* Notifications of other apps
* Device orientation (gyroscope)
* Profile active or not
* Screen state (on or off)
* Status of media playback
* Device is starting
* Service is starting
* Broadcasts of other apps
* Router state
* System states (Bluetooth/wifi)
* Variables that have been set
* Calendar appointments
* Phone call running
Supported actions:
* Change wifi state
@ -40,12 +48,21 @@ Supported actions:
* Toggle mobile data connection
* Speak text
* Open music player
* Control media playback
* Change screen brightness
* Send text message
* Play sound file
* Create notifications
* Close notifications
* Send broadcasts
* Run script/command
* Maintain screen active
* Set variables
* Initiate phone calls
* Terminate phone calls
* Copy text to clipboard
* Make screenshot
* Change location setting
* Send text message
It's quite hard to keep this app working across the many different hardwares as well as the many changes Android undergoes over the versions. I can test it in the emulator, but that cannot show all bugs.
So if a certain feature is not working on your device - let me know. Over the years I have fixed almost all bugs that have been reasonably reported to me. But for that I'm dependend on your input.

View File

@ -15,14 +15,22 @@ Disparadores:
* Modo de vuelo
* Estado de roaming
* NFC tags
* Detection de actividad (no en la versión F-Droid)
* Bluetooth conexión
* Headset conectado
* Llamado de teléfono activo
* Notificaciónes de otras apps
* Orientación del dispositivo (giroscopio)
* Perfil activado o no
* Estado de la pantalla
* Estado de la reprodución de audio
* Dispositivo está enciendo
* Servicio está enciendo
* Broadcasts de otras apps
* Estado del router
* Estados (Bluetooth/Wifi)
* Variables que se han establecido
* Citas en el calendar
* Llamado de teléfono activo
Aciónes:
* Pasar de wifi
@ -40,12 +48,22 @@ Aciónes:
* Pasar datos móviles
* Leer texto
* Abrir reproductor de música
* Cambiar luminosidad del monitor
* Enviar mensaje
* Tocar archivo sonido
* Controllar reproducion de música
* Cambiar luminosidad de la pantalla
* Reproducir audio
* Vibrar
* Crear notificaciones
* Cerrar notificationes
* Enviar broadcast
* Ejecutar script/programa
* Mantener pantalla encendido
* Establecer variables
* Iniciar llamadas telefónicas
* Terminar llamadas telefónicas
* Copiar texto al portapapeles
* Hacer screenshot
* Cambiar ajustes de localización
* Enviar mensaje
Es muy dificil mantener esta applicación functionando en todos los hardwares y versiónes de Android. Puedo probrar mucho en el emulator, pero no puedo enviar todos los errores.
Si una función no funcióna - digame. En muchos años resolvaba la mayoria de los errores que los halladores me informaron bien. Pero dependo en su ayuda.

View File

@ -26,6 +26,7 @@ Déclencheurs :
* Appareil démarré
* Service démarré
* Variables qui ont été définies
...et bien plus encore
Actions :
* Basculer Wifi (supprimé des appareils plus récents en raison des restrictions Google)
@ -47,6 +48,7 @@ Actions :
* Fermer les notifications
* Définir des variables
* Initier des appels téléphoniques
...et bien plus encore
Explications sur l'utilisation des autorisations :
https://server47.de/automation/permissions.php

View File

@ -23,6 +23,7 @@ Eventi supportati:
* Profilo attivo o meno
* Broadcasts di altre app
* Variabili che sono state impostate
...e molto altro ancora
Azioni supportate:
* Cambia lo stato del wifi
@ -46,6 +47,7 @@ Azioni supportate:
* Creare notifiche
* Imposta variabili
* Avviare telefonate
...e molto altro ancora
È piuttosto difficile mantere questa applicazione funzionante su tutti gli hardware esistenti ed includendo tutti i cambi che Android riceve fra una versione e l'altra. Posso effettuare tests nell'emulatore, ma non sarà possibile trovare tutti gli errori.
Pertanto, se una certa funzione non funziona sul tuo dispositivo - fammelo sapere. Nel corso degli anni ho potuto risolvere tutti gli errori che sono stati riportati in maniera ragionevole. Infatti, per questo, dipendo dalle informazioni condivise.

View File

@ -25,6 +25,7 @@ Ondersteunde triggers:
* Profiel actief of niet
* Broadcasts van andere apps
* Variabelen die zijn ingesteld
...en nog veel meer
Ondersteunde acties:
* Wijzig wifi status
@ -48,6 +49,7 @@ Ondersteunde acties:
* Meldingen maken
* Stel variabelen in
* Start telefoongesprekken
...en nog veel meer
Het is lastig om deze App werkend te houden over de vele verschillende hardware en de vele veranderingen die Android ondergaat in de loop der versies.
Ik test het in een emulator, maar dat kan niet alle bugs laten zien.

View File

@ -1,23 +1,77 @@
Skaner kodów kreskowych to darmowa i otwarta aplikacja, która umożliwia odczytywanie i generowanie kodów kreskowych. Może gromadzić informacje o produktach spożywczych, kosmetykach i książkach.
Twórz reguły składające się z wyzwalaczy i akcji. Wybitnym przykładem może być coś takiego jak "Wycisz telefon w pracy".
Różne formaty kodów kreskowych są zarządzane przez aplikację:
• dwuwymiarowe kody kreskowych: QR Code, Data Matrix, PDF 417, AZTEC
• jednowymiarowe kody kreskowe: EAN 13, EAN 8, UPC A, UPC E, Code 128, Code 93, Code 39, Codabar, IT
Oto lista obsługiwanych wyzwalaczy i akcji:
Zbiera informacje o produkcie podczas skanowania:
• Produkty spożywcze z Open Food Facts
• Kosmetyki z otwartymi faktami na temat urody
• Produkty spożywcze dla zwierząt domowych z Open Pet Food Fakty
• Książki z Open Library
Obsługiwane wyzwalacze:
* Lokalizacja
* Dzień/godzina
* Stan ładowania
* Poziom naładowania baterii
* Nawiązano połączenie USB z komputerem
* Aktualna prędkość
* Szum tła (tylko do Androida 7)
* Połączenie Wi-Fi
* Inne uruchomione aplikacje
* Tryb samolotowy
* Status roamingu
* Tagi NFC
* Wykrywanie aktywności (nie w wersji F-Droid)
* Połączenie Bluetooth
* Podłączony zestaw słuchawkowy
* Powiadomienia o innych aplikacjach
* Orientacja urządzenia (żyroskop)
* Profil aktywny lub nie
* Stan ekranu (włączony lub wyłączony)
* Stan odtwarzania multimediów
* Urządzenie się uruchamia
* Usługa jest uruchamiana
* Transmisje innych aplikacji
* Stan routera
* Stany systemu (Bluetooth/Wi-Fi)
* Zmienne, które zostały ustawione
* Spotkania w kalendarzu
* Rozmowa telefoniczna uruchomiona
Funkcje aplikacji :
• Wystarczy skierować aparat smartfona na kod kreskowy i natychmiast otrzymać o nim informację. Możesz także skanować kody kreskowe za pomocą obrazu w smartfonie.
• Za pomocą prostego skanowania czytaj wizytówki, dodawaj nowe kontakty, dodawaj nowe wydarzenia do swojego planu, otwieraj adresy URL, a nawet łącz się z Wi-Fi.
• Skanuj kody kreskowe produktów spożywczych, aby otrzymywać informacje o ich składzie dzięki bazom danych Open Food Facts i Open Beauty Facts.
• Wyszukaj informacje o skanowanym produkcie, dzięki szybkiemu badaniu na różnych stronach internetowych, takich jak Amazon lub Fnac.
• Śledź wszystkie zeskanowane kody kreskowe za pomocą narzędzia historii.
• Generuj własne kody kreskowe
• Dostosuj interfejs za pomocą różnych kolorów, jasnego motywu lub ciemnego. Aplikacja integruje funkcje Androida 12, umożliwiając dostosowanie kolorów w zależności od tapety.
• Teksty są w całości tłumaczone na język angielski, hiszpański, francuski, niemiecki, polski, rosyjski i chiński.
Obsługiwane działania:
* Zmień stan Wi-Fi
* Zmień stan bluetooth
* Przełącz tethering USB
* Przełącz tethering Wi-Fi
* Przełącz tethering Bluetooth
* Przełącz automatyczne obracanie ekranu
* Wyślij żądanie HTTP
* Zmień ustawienie dzwonka / dźwięku
* Uruchom inną aplikację
* Czekaj (pomiędzy innymi czynnościami)
* Włącz lub wyłącz ekran
* Przełącz tryb samolotowy
* Przełącz komórkowe połączenie transmisji danychc
* Odczytaj tekst
* Otwórz odtwarzacz muzyki
* Kontroluj odtwarzanie multimediów
* Zmień jasność ekranu
* Odtwórz plik dźwiękowy
* Tworzenie powiadomień
* Zamknij powiadomienia
* Wysyłaj transmisje
* Uruchom skrypt/polecenie
* Utrzymuj aktywny ekran
* Ustawianie zmiennych
* Inicjowanie połączeń telefonicznych
* Zakończ połączenia telefoniczne
* Skopiuj tekst do schowka
* Zrób zrzut ekranu
* Zmień ustawienie lokalizacji
* Wyślij wiadomość tekstową
Ta aplikacja szanuje Twoją prywatność. Nie zawiera żadnych trackerów i nie zbiera żadnych danych.
Dość trudno jest utrzymać tę aplikację działającą na wielu różnych urządzeniach, a także na wielu zmianach, jakie Android przechodzi w wersjach. Mogę to przetestować w emulatorze, ale to nie może pokazać wszystkich błędów.
Więc jeśli jakaś funkcja nie działa na Twoim urządzeniu - daj mi znać. Przez lata naprawiłem prawie wszystkie błędy, które zostały mi rozsądnie zgłoszone. Ale w tym zakresie jestem zależny od twojego wkładu. Jeśli masz problem i myślisz o skontaktowaniu się ze mną, proszę - Najpierw zaktualizuj do najnowszej wersji i sprawdź, czy problem nadal występuje. - Najpierw sprawdź listę znanych problemów: https://server47.de/automation/index.php#knownProblems
Darowizny to z pewnością dobry, ale nie jedyny sposób na zmotywowanie mnie :-)
* Jeśli chcesz mnie wesprzeć, możesz również wystawić pozytywną recenzję aplikacji w Google Play (https://play.google.com/store/apps/details?id=com.jens.automation2).
* Jeśli podoba Ci się aplikacja, zawsze mile widziane są ciepłe słowa za pośrednictwem poczty elektronicznej.
* Ponadto zawsze mogę skorzystać z pomocy w tłumaczeniu aplikacji. Angielski, niemiecki i trochę hiszpański należą do moich własnych umiejętności. Italiano e russo sono già coperti. Ale wszystko inne jest więcej niż mile widziane.
* Jeśli masz talent/doświadczenie w projektowaniu graficznym i masz jakieś pomysły na ładniejsze ikony, daj mi znać.
* Jeśli masz ciekawy przypadek użycia lub znalazłeś sposób na połączenie wyzwalaczy i akcji, aby osiągnąć coś intrygującego i uważasz, że warto umieścić to na stronie przykładów (https://server47.de/automation/examples.html), daj mi znać.
Wyjaśnienie wielu uprawnień można znaleźć tutaj: https://server47.de/automation/permissions.php

View File

@ -1 +1 @@
Darmowa i otwartoźródłowa aplikacja do odycztywania i tworzenia kodów QR.
Zautomatyzuj rzeczy na swoim urządzeniu, tworząc reguły.

View File

@ -23,6 +23,7 @@
* Состояние профиля
* Broadcast от других приложений
* Переменные, которые были установлены
...и многое другое
Действия:
* Вкл/Выкл Wi-Fi
@ -45,6 +46,7 @@
* Создать уведомление
* Установка переменных
* Инициирование телефонных звонков
...и многое другое
Достаточно сложно поддерживать работоспособность этого приложения на всех версиях устройств и Android. Я проверяю его в эмуляторе, но это не может обнаружить все ошибки.
Поэтому если какая-то функция не рабоатет на вашем устройстве- дайте мне знать. Я постоянно устраняю ошибки, полученные от пользователей, но для этого мне нужна обратная связь.

View File

@ -23,6 +23,7 @@
* 情景模式是否激活
* 其他应用的广播
* 已设置的变量
...以及更多
支持的动作:
* 更改 WLAN 状态
@ -46,6 +47,7 @@
* 创建通知
* 设置变量
* 发起通话
...以及更多
保持这个应用在各种不同硬件、Android 版本的大量更改中正常运行是很困难的。我可以在模拟器中测试,但这样不能显示所有的错误。
因此,如果某个功能无法在您的设备上运行——请告诉我。多年来,我已经修复了几乎所有合理地报告给我的错误。但为此我依赖于您的输入。