97 Commits

Author SHA1 Message Date
5ca7295c30 date time repetition 2024-01-27 17:03:27 +01:00
e2027a457a Merge remote-tracking branch 'origin/development' into development 2024-01-25 16:54:00 +01:00
6c31b67b14 Battery charging type differentiation and other fixes 2024-01-25 16:53:43 +01:00
04fe674cf6 Battery charging type differentiation 2024-01-25 14:03:39 +01:00
17b3b8fafc New version prep, fix attempt in notification listener 2024-01-24 23:16:24 +01:00
0d38c8bbe0 New version prep, fix attempt in notification listener 2024-01-24 14:00:34 +01:00
f7ff8a38e1 New version prep, fix attempt in notification listener 2024-01-21 23:46:08 +01:00
b7677bdcce Calendar trigger 2024-01-20 23:47:32 +01:00
1ff4a15818 Calendar trigger 2024-01-18 16:28:42 +01:00
bd42507521 Bugfix in triggerUrl action 2024-01-15 16:42:16 +01:00
fe924f6fe9 Calendar trigger 2024-01-14 23:18:12 +01:00
dfe8594f06 Calendar trigger 2024-01-14 15:56:44 +01:00
553d14b05f Calendar trigger 2024-01-10 20:01:24 +01:00
b38ca31df5 Calendar trigger 2024-01-09 22:56:42 +01:00
6e566c664d Calendar trigger 2024-01-08 23:10:27 +01:00
8c4b75232e Calendar trigger 2024-01-07 23:56:55 +01:00
4521bc7d4e Calendar trigger 2024-01-07 15:15:56 +01:00
eaecf63724 Calendar trigger 2024-01-06 23:57:52 +01:00
ec62b91449 Calendar trigger 2024-01-06 17:25:27 +01:00
223cca442d wifi trigger 2024-01-06 11:49:49 +01:00
f3613f8eb0 triggerUrl with POST params 2024-01-03 16:24:21 +01:00
8b193aa89c triggerUrl with POST params 2024-01-02 16:36:10 +01:00
58ec35aae5 calendar trigger 2024-01-01 13:35:21 +01:00
c61c5ba14c if brackets 2023-12-31 16:53:59 +01:00
d75cf137ba Merge branch 'calendar_trigger' into development 2023-12-31 16:00:13 +01:00
5e3d268815 date time trigger set to wakeup 2023-12-31 15:59:02 +01:00
3bcf90277f calendar trigger 2023-12-31 15:54:24 +01:00
81a205a8db Calendar trigger 2023-12-30 23:26:27 +01:00
97a3344e81 calendar trigger 2023-12-29 19:43:50 +01:00
cd47b33449 calendar trigger 2023-12-28 17:17:08 +01:00
2ba25a9e65 Calendar trigger 2023-12-28 00:25:55 +01:00
d2606b72cd calendar trigger 2023-12-27 14:48:27 +01:00
584495ef61 Calendar trigger 2023-12-27 13:33:09 +01:00
9b28aeef8b calendar trigger 2023-12-26 11:56:02 +01:00
b6bf31589a calendar trigger 2023-12-25 14:28:48 +01:00
67238bd2f0 Calendar trigger 2023-12-25 11:57:55 +01:00
5f278a6ba0 calendar trigger 2023-12-23 13:55:02 +01:00
a21f90acb5 Wifi receiver 2023-12-21 23:16:21 +01:00
5f8ed5765a TriggerUrl result stored in variable 2023-12-21 16:40:11 +01:00
605f85d215 Howto for write_secure_settings linked and translations updated 2023-12-21 15:37:55 +01:00
21f4a7fd5c Set location service 2023-12-20 23:54:36 +01:00
2219164869 Set location service 2023-12-19 23:52:28 +01:00
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
f641de9893 Take screenshot action added 2023-12-19 16:54:10 +01:00
bca8b44ad6 Bugfix for Android 14 for auto dialing mmi codes 2023-12-18 23:13:18 +01:00
c34dfa4af4 Bugfix for Android 14 for auto dialing mmi codes 2023-12-18 22:55:18 +01:00
38644cee28 Take screenshot action added 2023-12-16 13:52:18 +01:00
47898e84ea Comment added 2023-12-14 17:46:55 +01:00
ac74b52aed Accessibility API 2023-12-14 00:15:59 +01:00
3f76813e80 Http method selectable 2023-12-12 23:40:12 +01:00
1b8dc5de5f Http method selectable 2023-12-11 22:50:07 +01:00
3c8c0f14f2 Fixed bug in broadcast receiver trigger 2023-12-06 23:44:40 +01:00
9ead47bdf7 Permissions for startActivity() reduced 2023-12-03 23:24:58 +01:00
e4828a9720 Fixes for Google Play version 2023-11-30 00:00:34 +01:00
4f971e8a1b New version 2023-11-25 23:23:58 +01:00
34fbc1d005 New version prepared 2023-11-24 23:57:26 +01:00
b72049defc Start other service bugfix attempt 2023-11-22 23:20:26 +01:00
54f3cc84c4 Start other service bugfix attempt 2023-11-19 23:44:10 +01:00
7884358564 Start other service bugfix attempt 2023-11-08 00:15:39 +01:00
f24c9f99dc startService() experiments 2023-11-05 16:20:48 +01:00
64b97c650d Small changes 2023-10-28 23:20:07 +02:00
9daf4c4747 Small changes 2023-10-27 23:59:12 +02:00
94f7936c4a ActivityDetection permission fixed 2023-10-26 23:30:45 +02:00
02f7b642cf Wifi trigger hint 2023-10-23 23:44:21 +02:00
8d10bf05af Escaped variables when triggering 2023-10-19 22:30:13 +02:00
8c0cee9589 Wifi trigger fix attempt 2023-10-15 23:54:27 +02:00
6b23bd6733 Icon restored 2023-08-31 15:21:55 +02:00
1a60c88f35 Merge remote-tracking branch 'origin/development' into development
# Conflicts:
#	fastlane/metadata/android/en-US/changelogs/134.txt
2023-08-30 23:25:13 +02:00
3312d99177 Changes icon in Play store version 2023-08-30 23:23:58 +02:00
ea01806915 Charging trigger bug fixed 2023-08-24 20:04:05 +02:00
36173f2fcb device admin permission added for start phone call action 2023-08-01 22:59:05 +02:00
4c66fe906e Merge remote-tracking branch 'origin/development-stable' 2023-07-30 22:24:40 +02:00
60cfa150b5 Missing translations added 2023-07-25 23:31:32 +02:00
bd2231b075 Changelogs translated 2023-07-24 23:52:25 +02:00
158f5f2e04 Merge remote-tracking branch 'origin/development' into development 2023-07-23 20:10:52 +02:00
f1315dc742 Chinese translation added. 2023-07-23 18:57:38 +02:00
28aa0c3e4b Imports optimized 2023-07-11 00:07:07 +02:00
6b9dbca7ab Merge remote-tracking branch 'origin/development' into development
# Conflicts:
#	fastlane/metadata/android/en-US/changelogs/133.txt
2023-07-02 00:33:59 +02:00
291e0c41af Fixed bug 2023-07-02 00:31:09 +02:00
c9eedd5d87 Chinese translation added. 2023-06-08 19:43:41 +02:00
2470321e15 Merge remote-tracking branch 'origin/development-stable' 2023-06-05 14:46:05 +02:00
d85a199117 New version 2023-05-21 23:24:54 +02:00
b047cde4ea Minor corrections 2023-05-21 14:21:09 +02:00
9a1796f2eb Merge remote-tracking branch 'origin/development' into development 2023-05-17 23:24:24 +02:00
7e8a6b121e Minor fix for seconds variable missing leading zero 2023-05-17 23:22:32 +02:00
810c7488c4 Polish translation 2023-05-15 11:53:32 +02:00
8af24695fd Polish translated added 2023-05-11 23:30:10 +02:00
533a9bf54d Comment added 2023-05-10 23:24:47 +02:00
8653e4853b Close notification fix 2023-05-08 23:21:44 +02:00
c464a9d71f Battery receiver toasts removed 2023-05-07 22:59:45 +02:00
26e4851c0d Russian translation updated 2023-05-07 22:28:00 +02:00
11f0ee25bf bugfixes 2023-05-06 23:32:43 +02:00
a76cafc6e2 Enabled variables as intent parameters 2023-05-05 23:26:32 +02:00
bd2920e6d9 Russian translation updated 2023-05-05 22:54:16 +02:00
5caf33b45d revert 6a74d070ebf515470c34d05ab5b3215036ac1148
revert Fixed: Crash when managing phone call action in the F-Droid version
2023-05-05 22:48:39 +02:00
6a74d070eb Fixed: Crash when managing phone call action in the F-Droid version 2023-05-05 22:38:17 +02:00
eba02ade08 Fixed: Crash when managing phone call action in the F-Droid version 2023-04-29 01:14:52 +02:00
178 changed files with 7070 additions and 733 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 130
versionName "1.7.14"
versionCode 138
versionName "1.8"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
@ -36,9 +36,15 @@ android {
{
dimension "version"
versionNameSuffix "-googlePlay"
targetSdkVersion 31
targetSdkVersion 33
}
/*
targetSdkVersion is kept at 28 for as long as possible.
If raised wifi cannot be switched on or off anymore without root permissions.
In the Google version I'm forced to raise the value regularly.
*/
fdroidFlavor
{
dimension "version"

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"
@ -87,7 +96,7 @@
<application
android:allowBackup="true"
android:allowClearUserData="true"
android:icon="@drawable/gears"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme"
android:networkSecurityConfig="@xml/network_security_config">
@ -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"
@ -85,7 +93,7 @@
<application
android:allowBackup="true"
android:allowClearUserData="true"
android:icon="@drawable/gears"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme"
android:networkSecurityConfig="@xml/network_security_config">
@ -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" >
@ -173,12 +184,16 @@
<activity android:name=".ActivityManageTriggerTethering" />
<activity android:name=".ActivityManageActionWakeLock" />
<activity android:name=".ActivityManageTriggerSubSystemState" />
<activity android:name=".ActivityManageMakePhoneCall" />
<activity android:name=".ActivityManageActionMakePhoneCall" />
<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,12 +66,19 @@
<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_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"/>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<!--android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />-->
<application
android:allowBackup="true"
android:allowClearUserData="true"
android:icon="@drawable/gears"
android:icon="@drawable/crane"
android:label="@string/app_name"
android:theme="@style/AppTheme"
android:networkSecurityConfig="@xml/network_security_config">
@ -100,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" />-->
@ -122,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"
@ -163,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"
@ -203,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" />
@ -211,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"
@ -223,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"/>
@ -246,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,34 +700,55 @@ 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
else // compatibility for very old versions which haven't upgraded, yet.
url = components[0];
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;
@ -10,8 +11,7 @@ import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.ActivityNotFoundException;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.media.AudioManager;
@ -95,6 +95,7 @@ public class Actions
Miscellaneous.logEvent("w", "createNotification", "Creating notification with title " + elements[0] + " and text " + elements[1], 3);
// Create a new notification ID each time
int notificationId = Math.round(Calendar.getInstance().getTimeInMillis()/1000);
try
@ -113,8 +114,8 @@ public class Actions
public static void closeNotification(Action action)
{
NotificationManager nm = (NotificationManager) Miscellaneous.getAnyContext().getSystemService(Context.NOTIFICATION_SERVICE);
for(StatusBarNotification n : nm.getActiveNotifications())
{
// for(StatusBarNotification n : nm.getActiveNotifications())
// {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
{
String[] params = action.getParameter2().split(Action.actionParameter2Split);
@ -194,7 +195,7 @@ public class Actions
Miscellaneous.logEvent("i", "NotificationCloseCheck", "NotificationListener instance is null. Can\'t close notification.", 3);
}
}
}
// }
}
public static void sendBroadcast(Context context, String action)
@ -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,11 +1053,16 @@ 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
{
Intent externalActivityIntent;
Intent externalApplicationIntent;
if (!startByAction)
{
@ -1060,15 +1075,15 @@ public class Actions
Miscellaneous.logEvent("i", "StartOtherApp", "Starting app by activity: " + packageName + " " + className, 3);
externalActivityIntent = new Intent(Intent.ACTION_MAIN);
externalActivityIntent.addCategory(Intent.CATEGORY_LAUNCHER);
externalApplicationIntent = new Intent(Intent.ACTION_MAIN);
externalApplicationIntent.addCategory(Intent.CATEGORY_LAUNCHER);
// if(packageName.equals("dummyPkg"))
// externalActivityIntent.setAction(className);
// else
externalActivityIntent.setClassName(packageName, className);
if(packageName.equals("dummyPkg"))
externalApplicationIntent.setAction(className);
if (!Miscellaneous.doesActivityExist(externalActivityIntent, Miscellaneous.getAnyContext()))
externalApplicationIntent.setClassName(packageName, className);
if (!Miscellaneous.doesActivityExist(externalApplicationIntent, Miscellaneous.getAnyContext()))
Miscellaneous.logEvent("w", "StartOtherApp", "Activity not found: " + className, 2);
}
else
@ -1076,25 +1091,32 @@ public class Actions
// selected by action
Miscellaneous.logEvent("i", "StartOtherApp", "Starting app by action: " + param, 3);
externalActivityIntent = new Intent();
externalApplicationIntent = new Intent();
if (!params[0].equals(dummyPackageString))
externalActivityIntent.setPackage(params[0]);
externalApplicationIntent.setPackage(params[0]);
externalActivityIntent.setAction(params[1]);
externalApplicationIntent.setAction(params[1]);
if (params[2].equals(ActivityManageActionStartActivity.startByServiceString) || params[2].equals(ActivityManageActionStartActivity.startByForegroundServiceString))
{
externalApplicationIntent.setComponent(new ComponentName(params[0], params[2]));
}
}
externalActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
externalApplicationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// Pack intents
externalActivityIntent = packParametersIntoIntent(externalActivityIntent, params, 3);
externalApplicationIntent = packParametersIntoIntent(externalApplicationIntent, params, 3);
if (params[2].equals(ActivityManageActionStartActivity.startByActivityString))
automationServerRef.startActivity(externalActivityIntent);
if (params[2].equals(ActivityManageActionStartActivity.startByServiceString))
automationServerRef.startService(externalActivityIntent);
automationServerRef.startActivity(externalApplicationIntent);
else if (params[2].equals(ActivityManageActionStartActivity.startByServiceString))
automationServerRef.startService(externalApplicationIntent);
else if (params[2].equals(ActivityManageActionStartActivity.startByForegroundServiceString) && Build.VERSION.SDK_INT >= 26)
automationServerRef.startForegroundService(externalApplicationIntent);
else
automationServerRef.sendBroadcast(externalActivityIntent);
automationServerRef.sendBroadcast(externalApplicationIntent);
}
catch (Exception e)
{
@ -1166,21 +1188,36 @@ public class Actions
}
else if (singleParam[0].equals("Uri"))
{
if (singleParam[1].equalsIgnoreCase("IntentData"))
try
{
Miscellaneous.logEvent("i", "StartOtherApp", "Adding parameter of type " + singleParam[0] + " with value " + singleParam[2] + " as standard data parameter.", 3);
intent.setData(Uri.parse(singleParam[2]));
if (singleParam[1].equalsIgnoreCase("IntentData"))
{
Miscellaneous.logEvent("i", "StartOtherApp", "Adding parameter of type " + singleParam[0] + " with value " + singleParam[2] + " as standard data parameter.", 3);
intent.setData(Uri.parse(Miscellaneous.replaceVariablesInText(singleParam[2], context)));
}
else
{
Miscellaneous.logEvent("i", "StartOtherApp", "Adding parameter of type " + singleParam[0] + " with name " + singleParam[1] + " and value " + singleParam[2], 3);
intent.putExtra(singleParam[1], Uri.parse(Miscellaneous.replaceVariablesInText(singleParam[2], context)));
}
}
else
catch (Exception e)
{
Miscellaneous.logEvent("i", "StartOtherApp", "Adding parameter of type " + singleParam[0] + " with name " + singleParam[1] + " and value " + singleParam[2], 3);
intent.putExtra(singleParam[1], Uri.parse(singleParam[2]));
throw new RuntimeException(e);
}
}
else if (singleParam[0].equals("String"))
{
Miscellaneous.logEvent("i", "StartOtherApp", "Adding parameter of type " + singleParam[0] + " with name " + singleParam[1] + " and value " + singleParam[2], 3);
intent.putExtra(singleParam[1], singleParam[2]);
try
{
intent.putExtra(singleParam[1], Miscellaneous.replaceVariablesInText(singleParam[2], context));
}
catch (Exception e)
{
intent.putExtra(singleParam[1], singleParam[2]);
}
}
else
Miscellaneous.logEvent("w", "StartOtherApp", "Unknown type of parameter " + singleParam[0] + " found. Name " + singleParam[1] + " and value " + singleParam[2], 3);
@ -1955,7 +1992,6 @@ public class Actions
boolean suAvailable = false;
String suVersion = null;
String suVersionInternal = null;
// List<String> suResult = null;
int suResult;
boolean success = false;
@ -1969,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);
@ -2038,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;
}
@ -2086,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
@ -2163,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;
}
@ -2259,7 +2284,18 @@ public class Actions
public static void startPhoneCall(Context context, String phoneNumber)
{
Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + 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);
@ -2312,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

@ -39,8 +39,10 @@ public class ActivityControlCenter extends Activity
protected void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
setContentView(R.layout.activity_control_center);
bVolumeTest = (Button) findViewById(R.id.bVolumeTest);
bVolumeTest.setOnClickListener(new View.OnClickListener()
{
@ -384,6 +386,7 @@ public class ActivityControlCenter extends Activity
protected void onResume()
{
super.onResume();
Miscellaneous.setDisplayLanguage(this);
String folder = Miscellaneous.getWriteableFolder();
if (folder != null && folder.length() > 0)

View File

@ -21,6 +21,7 @@ public class ActivityDisplayLongMessage extends Activity
protected void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
setContentView(R.layout.activity_display_long_message);
tvMessageTitle = (TextView)findViewById(R.id.tvMessageTitle);

View File

@ -13,6 +13,7 @@ public class ActivityHelp extends Activity
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
setContentView(layout.activity_help_text);
TextView tvHelpTextEnergySaving = (TextView) findViewById(R.id.tvHelpTextEnergySaving);

View File

@ -44,7 +44,7 @@ public class ActivityMainPoi extends ActivityGeneric
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(ActivityMainPoi.this);
Miscellaneous.setDisplayLanguage(this);
setContentView(R.layout.main_poi_layout);
instance = this;
@ -108,6 +108,13 @@ public class ActivityMainPoi extends ActivityGeneric
this.storeServiceReferenceInVariable();
}
@Override
protected void onResume()
{
super.onResume();
Miscellaneous.setDisplayLanguage(this);
}
private void buttonAddPoi()
{
poiToEdit = null;

View File

@ -40,7 +40,7 @@ public class ActivityMainProfiles extends ActivityGeneric
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(ActivityMainProfiles.this);
Miscellaneous.setDisplayLanguage(this);
setContentView(R.layout.main_profile_layout);
instance = this;
@ -155,6 +155,13 @@ public class ActivityMainProfiles extends ActivityGeneric
}
}
@Override
protected void onResume()
{
super.onResume();
Miscellaneous.setDisplayLanguage(this);
}
private AlertDialog getProfileDialog(final Profile profile)
{
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);

View File

@ -48,7 +48,7 @@ public class ActivityMainRules extends ActivityGeneric
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(ActivityMainRules.this);
Miscellaneous.setDisplayLanguage(this);
setContentView(R.layout.main_rule_layout);
instance = this;
@ -154,6 +154,13 @@ public class ActivityMainRules extends ActivityGeneric
return v;
}
}
@Override
protected void onResume()
{
super.onResume();
Miscellaneous.setDisplayLanguage(this);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)

View File

@ -55,7 +55,7 @@ public class ActivityMainScreen extends ActivityGeneric
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(ActivityMainScreen.this);
Miscellaneous.setDisplayLanguage(this);
setContentView(R.layout.main_overview_layout);
activityMainScreenInstance = this;
@ -434,7 +434,7 @@ public class ActivityMainScreen extends ActivityGeneric
else
activityMainScreenInstance.checkForNews();
if(BuildConfig.FLAVOR.equals("apkFlavor") && Settings.automaticUpdateCheck)
if(BuildConfig.FLAVOR.equals(AutomationService.flavor_name_apk) && Settings.automaticUpdateCheck)
{
Calendar now = Calendar.getInstance();
if (Settings.lastUpdateCheck == Settings.default_lastUpdateCheck || now.getTimeInMillis() >= Settings.lastUpdateCheck + (long)(Settings.updateCheckFrequencyDays * 24 * 60 * 60 * 1000))
@ -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);
@ -571,6 +579,7 @@ public class ActivityMainScreen extends ActivityGeneric
protected void onResume()
{
super.onResume();
Miscellaneous.setDisplayLanguage(this);
toggleService.setChecked(AutomationService.isMyServiceRunning(this));
ActivityMainScreen.updateMainScreen();

View File

@ -23,7 +23,7 @@ public class ActivityMainTabLayout extends TabActivity
{
super.onCreate(savedInstanceState);
Settings.readFromPersistentStorage(ActivityMainTabLayout.this);
Miscellaneous.setDisplayLanguage(ActivityMainTabLayout.this);
Miscellaneous.setDisplayLanguage(this);
if(Settings.tabsPlacement == 1)
setContentView(R.layout.main_tab_layout_tabs_at_bottom);
@ -65,6 +65,7 @@ public class ActivityMainTabLayout extends TabActivity
protected void onResume()
{
super.onResume();
Miscellaneous.setDisplayLanguage(this);
// Miscellaneous.logEvent("i", "NFC", "ActivityMainTabLayout.onResume().", 5);
NfcReceiver.checkIntentForNFC(this, getIntent());
// NfcReceiver.checkIntentForNFC(this, new Intent(this.getApplicationContext(), this.getClass()));

View File

@ -26,6 +26,7 @@ public class ActivityManageActionBrightnessSetting extends Activity
protected void onCreate(@Nullable Bundle savedInstanceState)
{
setContentView(R.layout.activity_manage_action_brightness_settings);
Miscellaneous.setDisplayLanguage(this);
super.onCreate(savedInstanceState);
chkAutoBrightness = (CheckBox)findViewById(R.id.chkAutoBrightness);

View File

@ -259,6 +259,7 @@ public class ActivityManageActionCloseNotification extends Activity
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
setContentView(R.layout.activity_manage_action_close_notification);
etNotificationTitle = (EditText)findViewById(R.id.etNotificationTitle);

View File

@ -19,6 +19,7 @@ public class ActivityManageActionControlMedia extends Activity
protected void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
setContentView(R.layout.activity_manage_action_control_media);
rbMediaPlayPause = (RadioButton)findViewById(R.id.rbMediaPlayPause);

View File

@ -19,6 +19,7 @@ public class ActivityManageActionCopyToClipboard extends Activity
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
this.setContentView(R.layout.activity_manage_action_copy_to_clipboard);
bSaveCopyToClipboard = (Button) findViewById(R.id.bSaveCopyToClipboard);

View File

@ -24,6 +24,7 @@ public class ActivityManageActionCreateNotification extends Activity
protected void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
setContentView(R.layout.activity_manage_action_create_notification);
etNotificationTitle = (EditText) findViewById(R.id.etNotificationTitle);

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

@ -21,6 +21,7 @@ public class ActivityManageActionMakePhoneCall extends Activity
protected void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
setContentView(R.layout.activity_manage_action_make_phone_call);
etTargetPhoneNumber = (EditText)findViewById(R.id.etTargetPhoneNumber);

View File

@ -26,6 +26,7 @@ public class ActivityManageActionPlaySound extends Activity
protected void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
setContentView(R.layout.activity_manage_action_play_sound);
chkPlaySoundAlwaysPlay = (CheckBox)findViewById(R.id.chkPlaySoundAlwaysPlay);

View File

@ -28,6 +28,7 @@ public class ActivityManageActionRunExecutable extends Activity
protected void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
setContentView(R.layout.activity_manage_action_run_executable);
chkRunExecAsRoot = (CheckBox)findViewById(R.id.chkRunExecAsRoot);
@ -57,6 +58,15 @@ public class ActivityManageActionRunExecutable extends Activity
saveExecSettings();
}
});
if(getIntent().hasExtra(ActivityManageRule.intentNameActionParameter2))
{
String[] parts = getIntent().getStringExtra(ActivityManageRule.intentNameActionParameter2).split(Action.actionParameter2Split);
etRunExecutablePath.setText(parts[0]);
if(parts.length > 1)
etRunExecutableParameters.setText(parts[1]);
}
}
void saveExecSettings()

View File

@ -37,6 +37,7 @@ public class ActivityManageActionSendBroadcast extends Activity
protected void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
setContentView(R.layout.activity_manage_action_send_broadcast);
etBroadcastToSend = (EditText)findViewById(R.id.etBroadcastToSend);
@ -235,8 +236,6 @@ public class ActivityManageActionSendBroadcast extends Activity
@Override
public void onNothingSelected(AdapterView<?> arg0)
{
// TODO Auto-generated method stub
}
});
}

View File

@ -48,6 +48,7 @@ public class ActivityManageActionSendTextMessage extends Activity
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
this.setContentView(R.layout.activity_manage_action_send_textmessage);
etSendTextMessage = (EditText)findViewById(R.id.etSendTextMessage);

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;
@ -24,6 +24,7 @@ public class ActivityManageActionSetVariable extends Activity
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
this.setContentView(R.layout.activity_manage_action_set_variable);
etVariableSetKey = (EditText)findViewById(R.id.etVariableSetKey);

View File

@ -22,6 +22,7 @@ public class ActivityManageActionSpeakText extends Activity
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
this.setContentView(R.layout.activity_manage_action_speak_text);
etSpeakText = (EditText)findViewById(R.id.etTextToSpeak);

View File

@ -29,6 +29,7 @@ import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.Spinner;
import android.widget.Toast;
@ -48,17 +49,19 @@ public class ActivityManageActionStartActivity extends Activity
*/
ListView lvIntentPairs;
EditText etParameterName, etParameterValue, etPackageName, etActivityOrActionPath;
EditText etParameterName, etParameterValue, etPackageName, etActivityOrActionPath, etClassName;
Button bSelectApp, bAddIntentPair, bSaveActionStartOtherActivity, showStartProgramExamples;
Spinner spinnerParameterType;
RadioGroup rgAppStartupType;
boolean edit = false;
ProgressDialog progressDialog = null;
RadioButton rbStartAppSelectByActivity, rbStartAppSelectByAction, rbStartAppByActivity, rbStartAppByBroadcast, rbStartAppByService;
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";
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;
@ -66,11 +69,13 @@ public class ActivityManageActionStartActivity extends Activity
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
setContentView(R.layout.activity_manage_action_start_activity);
lvIntentPairs = (ListView)findViewById(R.id.lvIntentPairs);
etParameterName = (EditText)findViewById(R.id.etParameterName);
etParameterValue = (EditText)findViewById(R.id.etParameterValue);
etClassName = (EditText)findViewById(R.id.etClassName);
bSelectApp = (Button)findViewById(R.id.bSelectApp);
bAddIntentPair = (Button)findViewById(R.id.bAddIntentPair);
bSaveActionStartOtherActivity = (Button)findViewById(R.id.bSaveActionStartOtherActivity);
@ -83,13 +88,16 @@ public class ActivityManageActionStartActivity extends Activity
rbStartAppByActivity = (RadioButton)findViewById(R.id.rbStartAppByActivity);
rbStartAppByBroadcast = (RadioButton)findViewById(R.id.rbStartAppByBroadcast);
rbStartAppByService = (RadioButton)findViewById(R.id.rbStartAppByService);
rbStartAppByForegroundService = (RadioButton)findViewById(R.id.rbStartAppByForegroundService);
rgAppStartupType = (RadioGroup)findViewById(R.id.rgAppStartupType);
intentTypeSpinnerAdapter = new ArrayAdapter<String>(this, R.layout.text_view_for_poi_listview_mediumtextsize, ActivityManageActionStartActivity.supportedIntentTypes);
spinnerParameterType.setAdapter(intentTypeSpinnerAdapter);
intentTypeSpinnerAdapter.notifyDataSetChanged();
intentPairAdapter = new ArrayAdapter<String>(this, R.layout.text_view_for_poi_listview_mediumtextsize, intentPairList);
etClassName.setEnabled(false);
intentPairAdapter = new ArrayAdapter<String>(this, R.layout.text_view_for_poi_listview_mediumtextsize, intentPairList);
bSelectApp.setOnClickListener(new OnClickListener()
{
@Override
@ -226,23 +234,28 @@ public class ActivityManageActionStartActivity extends Activity
String parameter2 = "";
if (rbStartAppSelectByActivity.isChecked())
parameter2 += etPackageName.getText().toString() + ";" + etActivityOrActionPath.getText().toString();
else {
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();
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 += 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);
@ -278,8 +291,6 @@ public class ActivityManageActionStartActivity extends Activity
@Override
public void onNothingSelected(AdapterView<?> arg0)
{
// TODO Auto-generated method stub
}
});
@ -289,7 +300,9 @@ public class ActivityManageActionStartActivity extends Activity
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
{
if(isChecked)
{
bSelectApp.setEnabled(isChecked);
}
}
});
@ -303,6 +316,23 @@ public class ActivityManageActionStartActivity extends Activity
}
});
rgAppStartupType.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener()
{
@Override
public void onCheckedChanged(RadioGroup radioGroup, int i)
{
if(rbStartAppByActivity.isChecked())
etClassName.setEnabled(false);
else if (rbStartAppByBroadcast.isChecked())
etClassName.setEnabled(false);
else if(rbStartAppByService.isChecked())
etClassName.setEnabled(true);
else if(rbStartAppByForegroundService.isChecked())
etClassName.setEnabled(true);
}
});
Intent i = getIntent();
if(i.hasExtra(ActivityManageRule.intentNameActionParameter1))
loadValuesIntoGui(i);
@ -595,11 +625,27 @@ 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);
rbStartAppByActivity.setChecked(params[2].equals(startByActivityString));
rbStartAppByBroadcast.setChecked(params[2].equals(startByBroadcastString));
rbStartAppByService.setChecked(params[2].equals(startByServiceString));
if(partsString.contains(Action.actionParameter2Split))
params = partsString.split(Action.actionParameter2Split);
else
params = partsString.split(";");
if(Miscellaneous.isNumeric(params[2])) // old configuration file
{
rbStartAppByActivity.setChecked(params[2].equals(startByActivityString));
rbStartAppByBroadcast.setChecked(params[2].equals(startByBroadcastString));
rbStartAppByService.setChecked(params[2].equals(startByServiceString));
}
else
{
rbStartAppByActivity.setChecked(params[3].equals(startByActivityString));
rbStartAppByBroadcast.setChecked(params[3].equals(startByBroadcastString));
rbStartAppByService.setChecked(params[3].equals(startByServiceString));
rbStartAppByForegroundService.setChecked(params[3].equals(startByForegroundServiceString));
}
int startIndex = -1;
@ -614,10 +660,11 @@ public class ActivityManageActionStartActivity extends Activity
etPackageName.setText(params[0]);
etActivityOrActionPath.setText(params[1]);
etClassName.setText(params[2]);
}
if (params.length >= 3)
startIndex = 3;
if (params.length >= 4)
startIndex = 4;
if(startIndex > -1 && params.length > startIndex)
{

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,32 +17,43 @@ 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)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
this.setContentView(R.layout.activity_manage_action_trigger_url);
etTriggerUrl = (EditText)findViewById(R.id.etTriggerUrl);
@ -48,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
@ -55,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);
@ -109,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);
@ -162,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

@ -27,6 +27,7 @@ public class ActivityManageActionVibrate extends Activity
protected void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
setContentView(R.layout.activity_manage_action_vibrate);
etVibratePattern = (EditText)findViewById(R.id.etVibratePattern);

View File

@ -27,6 +27,7 @@ public class ActivityManageActionWakeLock extends Activity
protected void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
setContentView(R.layout.activity_manage_action_wakelock);
rbWakeLockActivate = (RadioButton)findViewById(R.id.rbWakeLockActivate);

View File

@ -23,6 +23,7 @@ public class ActivityManageActionWifi extends Activity
protected void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
setContentView(R.layout.activity_manage_action_wifi);
chkWifiRunAsRoot = (CheckBox)findViewById(R.id.chkWifiRunAsRoot);

View File

@ -59,6 +59,7 @@ public class ActivityManagePoi extends Activity
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
this.setContentView(R.layout.activity_manage_specific_poi);
myLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
@ -410,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
}
}
@ -453,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

@ -86,6 +86,7 @@ public class ActivityManageProfile extends Activity
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
this.setContentView(R.layout.activity_manage_specific_profile);
checkBoxChangeSoundMode = (CheckBox)findViewById(R.id.checkBoxChangeSoundMode);

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()
{
@ -154,6 +160,7 @@ public class ActivityManageRule extends Activity
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
setContentView(R.layout.activity_manage_specific_rule);
context = this;
@ -344,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;
}
@ -385,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:
@ -477,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;
@ -627,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));
}
@ -635,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);
@ -687,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)};
@ -852,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();
@ -1354,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();
}
}
@ -1364,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();
}
}
@ -1421,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
@ -1985,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)
@ -2024,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)
@ -2046,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();
}
}
@ -2125,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));
}
@ -2161,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);
}
@ -2351,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

@ -32,6 +32,7 @@ public class ActivityManageTriggerBluetooth extends Activity
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
setContentView(R.layout.activity_manage_trigger_bluetooth);
radioAnyBluetoothDevice = (RadioButton)findViewById(R.id.radioAnyBluetoothDevice);

View File

@ -28,6 +28,7 @@ public class ActivityManageTriggerBroadcast extends Activity
protected void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
setContentView(R.layout.activity_manage_trigger_broadcasts);
bBroadcastShowSuggestions = findViewById(R.id.bBroadcastShowSuggestions);

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

@ -20,6 +20,7 @@ public class ActivityManageTriggerCheckVariable extends Activity
protected void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
setContentView(R.layout.activity_manage_trigger_check_variable);
etVariableKeyTrigger = (EditText) findViewById(R.id.etVariableKeyTrigger);

View File

@ -104,6 +104,7 @@ public class ActivityManageTriggerDeviceOrientation extends Activity
protected void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
setContentView(R.layout.activity_manage_trigger_device_orientation);
currentAzimuth = (TextView) findViewById(R.id.tvCurrentAzimuth);

View File

@ -39,6 +39,7 @@ public class ActivityManageTriggerNfc extends Activity
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
setContentView(R.layout.activity_manage_trigger_nfc);
etNewNfcIdValue = (EditText)findViewById(R.id.etNewNfcIdValue);

View File

@ -258,6 +258,7 @@ public class ActivityManageTriggerNotification extends Activity
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
setContentView(R.layout.activity_manage_trigger_notification);
etNotificationTitle = (EditText)findViewById(R.id.etNotificationTitle);

View File

@ -35,6 +35,7 @@ public class ActivityManageTriggerPhoneCall extends Activity
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
setContentView(R.layout.activity_manage_trigger_phone_call);
etTriggerPhoneCallPhoneNumber = (EditText)findViewById(R.id.etTriggerPhoneCallPhoneNumber);

View File

@ -31,6 +31,7 @@ public class ActivityManageTriggerProfile extends Activity
protected void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
setContentView(R.layout.activity_manage_trigger_profile);
bSaveTriggerProfile = (Button)findViewById(R.id.bSaveTriggerProfile);

View File

@ -21,6 +21,7 @@ public class ActivityManageTriggerSubSystemState extends Activity
protected void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
setContentView(R.layout.activity_manage_trigger_subsystemstate);
rbSubSystemStateWifi = (RadioButton)findViewById(R.id.rbSubSystemStateWifi);

View File

@ -26,6 +26,7 @@ public class ActivityManageTriggerTethering extends Activity
protected void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
setContentView(R.layout.activity_manage_trigger_tethering);
rbTetheringOn = (RadioButton) findViewById(R.id.rbTetheringOn);

View File

@ -35,6 +35,7 @@ public class ActivityManageTriggerTimeFrame extends Activity
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
setContentView(R.layout.activity_manage_trigger_timeframe);
startPicker = (TimePicker)findViewById(R.id.tpTimeFrameStart);

View File

@ -12,11 +12,15 @@ import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.Spinner;
@ -43,12 +47,13 @@ public class ActivityManageTriggerWifi extends Activity
List<String> wifiList = new ArrayList<>();
ArrayAdapter<String> wifiSpinnerAdapter;
private final static int requestCodeLocationPermission = 124;
TextView tvWifiTriggerNameLocationNotice;
TextView tvWifiTriggerNameLocationNotice, tvWifiTriggerDisconnectionHint;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
setContentView(R.layout.activity_manage_trigger_wifi);
rbTriggerWifiConnected = (RadioButton) findViewById(R.id.rbTriggerWifiConnected);
@ -58,6 +63,9 @@ public class ActivityManageTriggerWifi extends Activity
bTriggerWifiSave = (Button) findViewById(R.id.bTriggerWifiSave);
bLoadWifiList = (Button) findViewById(R.id.bLoadWifiList);
tvWifiTriggerNameLocationNotice = (TextView)findViewById(R.id.tvWifiTriggerNameLocationNotice);
tvWifiTriggerDisconnectionHint = (TextView)findViewById(R.id.tvWifiTriggerDisconnectionHint);
tvWifiTriggerDisconnectionHint.setVisibility(View.GONE);
wifiSpinnerAdapter = new ArrayAdapter<String>(this, R.layout.text_view_for_poi_listview_mediumtextsize, wifiList);
spinnerWifiList.setAdapter(wifiSpinnerAdapter);
@ -100,6 +108,11 @@ public class ActivityManageTriggerWifi extends Activity
public void onItemSelected(AdapterView<?> parent, View view, int position, long id)
{
etTriggerWifiName.setText(wifiList.get(position));
if(etTriggerWifiName.getText().toString().length() > 0 && rbTriggerWifiDisconnected.isChecked())
tvWifiTriggerDisconnectionHint.setVisibility(View.VISIBLE);
else
tvWifiTriggerDisconnectionHint.setVisibility(View.GONE);
}
@Override
@ -117,6 +130,41 @@ public class ActivityManageTriggerWifi extends Activity
loadWifis();
}
});
rbTriggerWifiDisconnected.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener()
{
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b)
{
if(etTriggerWifiName.getText().toString().length() > 0 && b)
tvWifiTriggerDisconnectionHint.setVisibility(View.VISIBLE);
else
tvWifiTriggerDisconnectionHint.setVisibility(View.GONE);
}
});
etTriggerWifiName.addTextChangedListener(new TextWatcher()
{
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2)
{
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2)
{
if(etTriggerWifiName.getText().toString().length() > 0 && rbTriggerWifiDisconnected.isChecked())
tvWifiTriggerDisconnectionHint.setVisibility(View.VISIBLE);
else
tvWifiTriggerDisconnectionHint.setVisibility(View.GONE);
}
@Override
public void afterTextChanged(Editable editable)
{
}
});
}
public void loadWifis()

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";
@ -79,6 +83,7 @@ public class ActivityPermissions extends Activity
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
setContentView(R.layout.permissions_activity);
bCancelPermissions = (Button)findViewById(R.id.bCancelPermissions);
@ -86,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()
{
@ -160,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)
{
@ -304,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);
@ -322,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())
@ -369,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)
@ -406,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()]);
@ -455,7 +501,8 @@ public class ActivityPermissions extends Activity
{
case activityDetection:
addToArrayListUnique(permissionNameGoogleActivityDetection, requiredPermissions);
addToArrayListUnique(Manifest.permission.ACTIVITY_RECOGNITION, requiredPermissions);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
addToArrayListUnique(Manifest.permission.ACTIVITY_RECOGNITION, requiredPermissions);
break;
case airplaneMode:
addToArrayListUnique(Manifest.permission.ACCESS_NETWORK_STATE, requiredPermissions);
@ -518,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);
@ -540,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;
}
@ -648,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);
@ -704,11 +769,17 @@ public class ActivityPermissions extends Activity
break;
case startPhoneCall:
addToArrayListUnique(Manifest.permission.CALL_PHONE, requiredPermissions);
// addToArrayListUnique(Manifest.permission.SYSTEM_ALERT_WINDOW, requiredPermissions);
addToArrayListUnique(Manifest.permission.SYSTEM_ALERT_WINDOW, requiredPermissions);
break;
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;
}
@ -771,14 +842,19 @@ 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));
break;
case permissionNameGoogleActivityDetection:
for(String ruleName : getRulesUsing(Trigger.Trigger_Enum.activityDetection))
for(String ruleName : getRulesUsing(Action.Action_Enum.closeNotification))
usingElements.add(String.format(getResources().getString(R.string.ruleXrequiresThis), ruleName));
break;
case permissionNameGoogleActivityDetection:
case Manifest.permission.ACTIVITY_RECOGNITION:
for(String ruleName : getRulesUsing(Trigger.Trigger_Enum.activityDetection))
usingElements.add(String.format(getResources().getString(R.string.ruleXrequiresThis), ruleName));
@ -909,6 +985,8 @@ public class ActivityPermissions extends Activity
case Manifest.permission.SYSTEM_ALERT_WINDOW:
for(String ruleName : getRulesUsing(Action.Action_Enum.startOtherActivity))
usingElements.add(String.format(getResources().getString(R.string.ruleXrequiresThis), ruleName));
for(String ruleName : getRulesUsing(Action.Action_Enum.startPhoneCall))
usingElements.add(String.format(getResources().getString(R.string.ruleXrequiresThis), ruleName));
break;
case Manifest.permission.ANSWER_PHONE_CALLS:
for(String ruleName : getRulesUsing(Action.Action_Enum.stopPhoneCall))
@ -957,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;
@ -965,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)
@ -1012,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);
}
}
@ -1071,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))
@ -1093,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)
@ -1119,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);
@ -1148,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;
}
}
}
@ -1197,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();
@ -1575,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

@ -16,6 +16,7 @@ public class ActivitySettings extends PreferenceActivity
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
addPreferencesFromResource(layout.activity_settings);
if(BuildConfig.FLAVOR.equals(AutomationService.flavor_name_apk))
@ -24,4 +25,11 @@ public class ActivitySettings extends PreferenceActivity
chkPrefUpdateCheck.setEnabled(true);
}
}
@Override
protected void onResume()
{
super.onResume();
Miscellaneous.setDisplayLanguage(this);
}
}

View File

@ -30,6 +30,7 @@ public class ActivityVolumeTest extends Activity
instance = this;
super.onCreate(savedInstanceState);
Miscellaneous.setDisplayLanguage(this);
setContentView(R.layout.activity_volume_calibration);
tvCurrentVolume = (TextView)findViewById(R.id.tvCurrentVolume);
@ -48,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

@ -4,7 +4,6 @@ import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;
import java.util.ArrayList;
import java.util.Calendar;
public class AsyncTasks
@ -23,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

@ -12,8 +12,6 @@ import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.media.AudioManager;
import android.os.Binder;
import android.os.Build;
@ -22,7 +20,6 @@ import android.os.Environment;
import android.os.IBinder;
import android.speech.tts.TextToSpeech;
import android.speech.tts.TextToSpeech.OnInitListener;
import android.util.DisplayMetrics;
import android.util.Log;
import android.widget.Toast;
@ -31,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;
@ -39,7 +37,6 @@ import java.util.Calendar;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
@SuppressLint("NewApi")
public class AutomationService extends Service implements OnInitListener
@ -131,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)
@ -227,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();
@ -310,6 +321,7 @@ public class AutomationService extends Service implements OnInitListener
ReceiverCoordinator.applySettingsAndRules();
DateTimeListener.reloadAlarms();
CalendarReceiver.armOrRearmTimer();
}
@Override
@ -522,7 +534,12 @@ public class AutomationService extends Service implements OnInitListener
builder.setContentTitle("Automation");
if(Settings.showIconWhenServiceIsRunning)
builder.setSmallIcon(R.drawable.ic_launcher);
{
if(BuildConfig.FLAVOR.equalsIgnoreCase(AutomationService.flavor_name_googleplay))
builder.setSmallIcon(R.drawable.crane);
else
builder.setSmallIcon(R.drawable.ic_launcher);
}
builder.setCategory(Notification.CATEGORY_SERVICE);
builder.setWhen(System.currentTimeMillis());
@ -530,7 +547,7 @@ public class AutomationService extends Service implements OnInitListener
Notification defaultNotification = builder.build();
defaultNotification.icon = R.drawable.ic_launcher;
defaultNotification.icon = R.drawable.crane;
defaultNotification.when = System.currentTimeMillis();
// defaultNotification.defaults |= Notification.DEFAULT_VIBRATE;
@ -577,7 +594,12 @@ public class AutomationService extends Service implements OnInitListener
builder.setOnlyAlertOnce(true);
if(Settings.showIconWhenServiceIsRunning)
builder.setSmallIcon(R.drawable.ic_launcher);
{
if (BuildConfig.FLAVOR.equals(AutomationService.flavor_name_googleplay))
builder.setSmallIcon(R.drawable.crane);
else
builder.setSmallIcon(R.drawable.ic_launcher);
}
// builder.setContentText(textToDisplay);
// builder.setSmallIcon(icon);
@ -670,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,7 +75,9 @@ 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;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@ -77,6 +85,8 @@ import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.DigestInputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
@ -91,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;
@ -110,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;
@ -117,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();
@ -145,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;
@ -170,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)
{
@ -208,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
// {
@ -234,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
@ -289,7 +338,6 @@ public class Miscellaneous extends Service
{
logCleanerRunning = true;
long maxSizeInBytes = (long)Settings.logFileMaxSize * 1024 * 1024;
if(logFile.exists() && logFile.length() > (maxSizeInBytes))
@ -692,7 +740,7 @@ public class Miscellaneous extends Service
if(result.length() < 2)
result = "0" + result;
source = source.replace("[s]", String.valueOf(cal.get(Calendar.SECOND)));
source = source.replace("[s]", result);
}
if(source.contains("[ms]"))
@ -708,7 +756,7 @@ public class Miscellaneous extends Service
String notificationTitle = NotificationListener.getLastNotification().getTitle();
if (notificationTitle != null && notificationTitle.length() > 0)
source = source.replace("[notificationTitle]", notificationTitle);
source = source.replace("[notificationTitle]", escapeStringForUrl(notificationTitle));
else
{
source = source.replace("[notificationTitle]", "notificationTitle unknown");
@ -729,7 +777,7 @@ public class Miscellaneous extends Service
String notificationText = NotificationListener.getLastNotification().getText();
if (notificationText != null && notificationText.length() > 0)
source = source.replace("[notificationText]", notificationText);
source = source.replace("[notificationText]", escapeStringForUrl(notificationText));
else
{
source = source.replace("[notificationText]", "notificationText unknown");
@ -743,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-");
@ -760,7 +880,7 @@ public class Miscellaneous extends Service
else
replacement = "unknownVariable";
source = source.substring(0, pos1) + replacement + source.substring(pos2);
source = source.substring(0, pos1) + escapeStringForUrl(replacement) + source.substring(pos2 +1);
}
// Miscellaneous.logEvent("i", "URL after replace", source);
@ -789,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)
{
@ -825,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
@ -902,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()
@ -1164,7 +1282,12 @@ public class Miscellaneous extends Service
builder.setOnlyAlertOnce(true);
if(Settings.showIconWhenServiceIsRunning && notificationChannelId.equals(AutomationService.NOTIFICATION_CHANNEL_ID_SERVICE))
builder.setSmallIcon(R.drawable.ic_launcher);
{
if(BuildConfig.FLAVOR.equals(AutomationService.flavor_name_googleplay))
builder.setSmallIcon(R.drawable.crane);
else
builder.setSmallIcon(R.drawable.ic_launcher);
}
else if(!notificationChannelId.equals(AutomationService.NOTIFICATION_CHANNEL_ID_SERVICE))
builder.setSmallIcon(R.drawable.info);
@ -2014,7 +2137,16 @@ public class Miscellaneous extends Service
{
if(!Settings.displayLanguage.equals(Settings.default_displayLanguage))
{
Locale myLocale = new Locale(Settings.displayLanguage);
Locale myLocale;
if(Settings.displayLanguage.contains("_"))
{
String[] parts = Settings.displayLanguage.split("_");
myLocale = new Locale(parts[0], parts[1]);
}
else
myLocale = new Locale(Settings.displayLanguage);
Resources res = context.getResources();
DisplayMetrics dm = res.getDisplayMetrics();
Configuration conf = res.getConfiguration();
@ -2025,4 +2157,34 @@ public class Miscellaneous extends Service
//startActivity(refresh);
}
}
public static String escapeStringForUrl(String input)
{
String output;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
{
try
{
output = URLEncoder.encode(input, String.valueOf(StandardCharsets.UTF_8));
}
catch (UnsupportedEncodingException e)
{
Miscellaneous.logEvent("e", "URLEncoder", "Error encoding string for URL. Leaving as it is. Error details: " + Log.getStackTraceString(e), 3);
output = input;
}
}
else
{
output = Uri.encode(input);
}
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)
{
@ -391,11 +397,11 @@ public class ReceiverCoordinator
}
}
if(Rule.isAnyRuleUsing(Trigger.Trigger_Enum.headsetPlugged))
if(Rule.isAnyRuleUsing(Trigger.Trigger_Enum.headsetPlugged))
{
if(!HeadphoneJackListener.isHeadphoneJackListenerActive())
{
Miscellaneous.logEvent("i", "LocationProvider", "Starting HeadphoneJackListener because used in a new/changed rule.", 4);
Miscellaneous.logEvent("i", "HeadphoneJackListener", "Starting HeadphoneJackListener because used in a new/changed rule.", 4);
if(HeadphoneJackListener.getInstance().haveAllPermission())
HeadphoneJackListener.getInstance().startListener(AutomationService.getInstance());
}
@ -404,7 +410,7 @@ public class ReceiverCoordinator
{
if(HeadphoneJackListener.isHeadphoneJackListenerActive())
{
Miscellaneous.logEvent("i", "LocationProvider", "Shutting down HeadphoneJackListener because not used in any rule.", 4);
Miscellaneous.logEvent("i", "HeadphoneJackListener", "Shutting down HeadphoneJackListener because not used in any rule.", 4);
HeadphoneJackListener.getInstance().stopListener(AutomationService.getInstance());
}
}
@ -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);
@ -803,13 +955,29 @@ public class Trigger
{
Miscellaneous.logEvent("i", Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), String.format("Wifi name specified, checking that.", this.getParentRule().getName()), 4);
if(!WifiBroadcastReceiver.getLastWifiSsid().equals(this.getTriggerParameter2()) && !(Miscellaneous.isRegularExpression(this.getTriggerParameter2()) && WifiBroadcastReceiver.getLastWifiSsid().matches(this.getTriggerParameter2())))
if(WifiBroadcastReceiver.lastConnectedState) //when connected
{
Miscellaneous.logEvent("i", Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), String.format(String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.ruleDoesntApplyNotTheCorrectSsid), getParentRule().getName(), this.getTriggerParameter2(), WifiBroadcastReceiver.getLastWifiSsid()),this.getParentRule().getName()), 3);
return false;
if (!WifiBroadcastReceiver.getLastWifiSsid().equals(this.getTriggerParameter2()) && !(Miscellaneous.isRegularExpression(this.getTriggerParameter2()) && WifiBroadcastReceiver.getLastWifiSsid().matches(this.getTriggerParameter2())))
{
Miscellaneous.logEvent("i", Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), String.format(String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.ruleDoesntApplyNotTheCorrectSsid), getParentRule().getName(), this.getTriggerParameter2(), WifiBroadcastReceiver.getLastWifiSsid()), this.getParentRule().getName()), 3);
return false;
}
else
Miscellaneous.logEvent("i", Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), String.format("Wifi name matches. Rule will apply.", this.getParentRule().getName()), 4);
}
else
Miscellaneous.logEvent("i", Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), String.format("Wifi name matches. Rule will apply.", this.getParentRule().getName()), 4);
{
if (
!Settings.serviceStartDone
||
(!WifiBroadcastReceiver.getLastWifiSsidReal().equals(this.getTriggerParameter2()) && !(Miscellaneous.isRegularExpression(this.getTriggerParameter2()) && WifiBroadcastReceiver.getLastWifiSsidReal().matches(this.getTriggerParameter2()))))
{
Miscellaneous.logEvent("i", Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), String.format(String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.ruleDoesntApplyNotTheCorrectSsid), getParentRule().getName(), this.getTriggerParameter2(), WifiBroadcastReceiver.getLastWifiSsidReal()), this.getParentRule().getName()), 3);
return false;
}
else
Miscellaneous.logEvent("i", Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), String.format("Wifi name matches. Rule will apply.", this.getParentRule().getName()), 4);
}
}
else
Miscellaneous.logEvent("i", Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), String.format("No wifi name specified, any will do.", this.getParentRule().getName()), 4);
@ -932,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;
}
}
@ -964,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;
}
// }
@ -973,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;
}
}
@ -1004,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()
@ -1458,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));
@ -1797,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
@ -400,12 +402,12 @@ public class LocationProvider
Miscellaneous.logEvent("i", "LocationProvider", this.getParentService().getResources().getString(R.string.applyingSettingsAndRules), 3);
// *********** SETTING CHANGES ***********
if(Settings.useWifiForPositioning && !WifiBroadcastReceiver.isWifiListenerActive())
if(Settings.useWifiForPositioning && !WifiBroadcastReceiver.isWifiListenerActive() || Rule.isAnyRuleUsing(Trigger_Enum.wifiConnection))
{
Miscellaneous.logEvent("i", "LocationProvider", "Starting WifiReceiver because settings now allow to.", 4);
WifiBroadcastReceiver.startWifiReceiver(this);
}
else if(!Settings.useWifiForPositioning && WifiBroadcastReceiver.isWifiListenerActive())
else if(!Settings.useWifiForPositioning && WifiBroadcastReceiver.isWifiListenerActive() && !Rule.isAnyRuleUsing(Trigger_Enum.wifiConnection))
{
Miscellaneous.logEvent("i", "LocationProvider", "Shutting down WifiReceiver because settings forbid to.", 4);
WifiBroadcastReceiver.stopWifiReceiver();

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
@ -25,11 +26,19 @@ public class WifiBroadcastReceiver extends BroadcastReceiver
public static LocationProvider parentLocationProvider;
public static Boolean wasConnected = false;
protected static String lastWifiSsid = "";
protected static String lastWifiSsidReal = "";
public static boolean lastConnectedState = false;
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>";
public static String getLastWifiSsidReal()
{
return lastWifiSsidReal;
}
public static String getLastWifiSsid()
{
@ -38,11 +47,18 @@ 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;
WifiBroadcastReceiver.lastWifiSsid = newWifiSsid;
}
}
public static boolean isWifiListenerActive()
@ -60,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();
@ -93,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.
*/
}
@ -120,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;
@ -214,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)
@ -32,21 +34,19 @@ public class BatteryReceiver extends BroadcastReceiver implements AutomationList
if(!batteryReceiverActive)
{
BatteryReceiver.automationServiceRef = automationServiceRef;
if(batteryInfoReceiverInstance == null)
batteryInfoReceiverInstance = new BatteryReceiver();
if(batteryIntentFilter == null)
{
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);
batteryReceiverActive = true;
}
}
@ -59,16 +59,16 @@ public class BatteryReceiver extends BroadcastReceiver implements AutomationList
automationServiceRef.unregisterReceiver(batteryInfoReceiverInstance);
batteryInfoReceiverInstance = null;
}
batteryReceiverActive = false;
}
}
public static boolean isBatteryReceiverActive()
{
return batteryReceiverActive;
}
public static boolean isUsbHostConnected()
{
return usbHostConnected;
@ -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;
@ -90,11 +88,11 @@ public class BatteryReceiver extends BroadcastReceiver implements AutomationList
public void onReceive(Context context, Intent intent)
{
Miscellaneous.logEvent("i", "BatteryReceiver", "Received event " + intent.getAction(), 5);
if (intent == null)
return;
if (context == null)
return;
return;
if(intent.getAction().equals(Intent.ACTION_BATTERY_LOW))
{
@ -105,12 +103,12 @@ public class BatteryReceiver extends BroadcastReceiver implements AutomationList
try
{
batteryLevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
// int scale = -1;
// int voltage = -1;
// int temp = -1;
// scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
// temp = intent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, -1);
// voltage = intent.getIntExtra(BatteryManager.EXTRA_VOLTAGE, -1);
// int scale = -1;
// int voltage = -1;
// int temp = -1;
// scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
// temp = intent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, -1);
// voltage = intent.getIntExtra(BatteryManager.EXTRA_VOLTAGE, -1);
Log.i("Battery", "Level: " + String.valueOf(batteryLevel));
this.actionBatteryLevel(context);
@ -121,9 +119,14 @@ public class BatteryReceiver extends BroadcastReceiver implements AutomationList
switch(statusPlugged)
{
case BatteryManager.BATTERY_PLUGGED_AC:
// Toast.makeText(context, "Regular charging", Toast.LENGTH_LONG).show();
// 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,10 +137,11 @@ 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:
this.actionDischarging(context);
break;
}
@ -148,34 +152,39 @@ public class BatteryReceiver extends BroadcastReceiver implements AutomationList
}
}
}
public static int isDeviceCharging(Context context)
{
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))
@ -183,7 +192,7 @@ public class BatteryReceiver extends BroadcastReceiver implements AutomationList
}
}
}
private void actionBatteryLevel(Context context)
{
Miscellaneous.logEvent("i", "BatteryReceiver", "Battery level has changed.", 3);
@ -195,7 +204,7 @@ public class BatteryReceiver extends BroadcastReceiver implements AutomationList
ruleCandidates.get(i).activate(automationServiceRef, false);
}
}
private void actionDischarging(Context context)
{
if(currentChargingState != BatteryManager.BATTERY_STATUS_UNKNOWN) // Avoid flooding the log. This event will occur on a regular basis even though charging state wasn't changed.
@ -210,44 +219,43 @@ public class BatteryReceiver extends BroadcastReceiver implements AutomationList
if(ruleCandidates.get(i).getsGreenLight(context))
ruleCandidates.get(i).activate(automationServiceRef, false);
}
this.actionUsbDisconnected(context);
}
}
private void actionUsbConnected(Context context)
{
// Event usbConnected
// Miscellaneous.logEvent("i", "BatteryReceiver", "BATTERY_PLUGGED_USB");
if(!usbHostConnected)
{
usbHostConnected = true;
Miscellaneous.logEvent("i", "BatteryReceiver", "Connected to computer.", 3);
Toast.makeText(context, "Connected to computer.", Toast.LENGTH_LONG).show();
// 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);
}
}
private void actionUsbDisconnected(Context context)
{
// Event usbDisConnected
if(usbHostConnected)
{
usbHostConnected = false;
Miscellaneous.logEvent("i", "BatteryReceiver", "Disconnected from computer.", 3);
Toast.makeText(context, "Disconnected from computer.", Toast.LENGTH_LONG).show();
// Toast.makeText(context, "Disconnected from computer.", Toast.LENGTH_LONG).show();
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidates(Trigger_Enum.usb_host_connection);
// ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByUsbHost(false);

View File

@ -94,20 +94,21 @@ public class BluetoothReceiver extends BroadcastReceiver implements AutomationLi
@Override
public void onReceive(Context context, Intent intent)
{
// Miscellaneous.logEvent("i", "BluetoothReceiver", "Bluetooth event.", 4);
String action = intent.getAction();
Miscellaneous.logEvent("i", "BluetoothReceiver", "Bluetooth event: " + action, 5);
BluetoothDevice bluetoothDevice = null;
if(action.equals(BluetoothDevice.ACTION_ACL_CONNECTED) | action.equals("android.bluetooth.device.action.ACL_CONNECTED"))
{
if(action.equals(BluetoothDevice.ACTION_ACL_CONNECTED) || action.equals("android.bluetooth.device.action.ACL_CONNECTED"))
{
bluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
lastAffectedDevice = bluetoothDevice;
lastAction = action;
connectedDevices.add(bluetoothDevice);
Miscellaneous.logEvent("i", "BluetoothReceiver", String.format(context.getResources().getString(R.string.bluetoothConnectionTo), bluetoothDevice.getName()), 3);
}
else if(action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED) | action.equals(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED) | action.equals("android.bluetooth.device.ACTION_ACL_DISCONNECTED") | action.equals("android.bluetooth.device.ACTION_ACL_DISCONNECT_REQUESTED"))
else if(action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED) || action.equals(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED) || action.equals("android.bluetooth.device.ACTION_ACL_DISCONNECTED") || action.equals("android.bluetooth.device.ACTION_ACL_DISCONNECT_REQUESTED"))
{
bluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
lastAffectedDevice = bluetoothDevice;
@ -115,7 +116,7 @@ public class BluetoothReceiver extends BroadcastReceiver implements AutomationLi
connectedDevices.remove(bluetoothDevice);
Miscellaneous.logEvent("i", "BluetoothReceiver", String.format(context.getResources().getString(R.string.bluetoothDisconnectFrom), bluetoothDevice.getName()), 3);
}
else if(action.equals(BluetoothDevice.ACTION_FOUND) | action.equals("android.bluetooth.device.ACTION_FOUND"))
else if(action.equals(BluetoothDevice.ACTION_FOUND) || action.equals("android.bluetooth.device.ACTION_FOUND"))
{
bluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
lastAffectedDevice = bluetoothDevice;

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

@ -20,7 +20,7 @@ public class HeadphoneJackListener extends BroadcastReceiver implements Automati
private static boolean headsetConnected = false;
private static int headphoneType = -1;
protected static boolean headphoneJackListenerActive=false;
protected static boolean headphoneJackListenerActive = false;
protected static IntentFilter headphoneJackListenerIntentFilter = null;
protected static HeadphoneJackListener instance;
@ -108,7 +108,7 @@ public class HeadphoneJackListener extends BroadcastReceiver implements Automati
}
catch(Exception ex)
{
Miscellaneous.logEvent("e", "ActivityDetectionReceiver", "Error starting HeadsetJackListener: " + Log.getStackTraceString(ex), 3);
Miscellaneous.logEvent("e", "HeadsetJackListener", "Error starting HeadsetJackListener: " + Log.getStackTraceString(ex), 3);
}
}

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.

After

Width:  |  Height:  |  Size: 13 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 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

@ -113,6 +113,7 @@
android:text="@string/startAppStartType" />
<RadioGroup
android:id="@+id/rgAppStartupType"
android:layout_width="match_parent"
android:layout_height="wrap_content">
@ -135,6 +136,12 @@
android:layout_height="wrap_content"
android:text="@string/startAppByStartService" />
<RadioButton
android:id="@+id/rbStartAppByForegroundService"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/startAppByStartForegroundService" />
</RadioGroup>
</TableRow>
@ -187,6 +194,25 @@
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/className" />
<EditText
android:id="@+id/etClassName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textMultiLine"
android:text=""
android:textAppearance="?android:attr/textAppearanceMedium" />
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content">
@ -267,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" />
@ -304,19 +329,38 @@
android:layout_height="wrap_content"
android:text="@string/addIntentValue" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
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"
android:textSize="25dp"
android:text="@string/variablesOnlyForTypes" />
<TextView
android:id="@+id/tvLegend"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/urlLegend" />
<ImageView
android:layout_width="match_parent"
android:layout_height="1dp"
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

@ -103,6 +103,14 @@
</TableLayout>
<TextView
android:id="@+id/tvWifiTriggerDisconnectionHint"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="@dimen/default_margin"
android:textColor="@color/red"
android:text="@string/wifiTriggerDisconnectionHint" />
<Button
android:id="@+id/bTriggerWifiSave"
android:layout_marginTop="@dimen/default_margin"

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>
@ -602,7 +602,7 @@
<string name="tabsPlacement">Position der Tableiste</string>
<string name="top">Oben</string>
<string name="bottom">Unten</string>
<string name="tabsPlacementSummary">Wol soll die Taskleiste angezeigt werden?</string>
<string name="tabsPlacementSummary">Wo soll die Taskleiste angezeigt werden?</string>
<string name="tones">Klingeltöne</string>
<string name="miscellaneous">Verschiedenes</string>
<string name="dnd">Nicht stören</string>
@ -795,4 +795,64 @@
<string name="textToCopy">Text, der kopiert werden soll</string>
<string name="android.permission.SYSTEM_ALERT_WINDOW">Über anderen Anwendungen anzeigen</string>
<string name="overlayPermissionHint">Nachdem Sie auf OK geklickt haben, werden Sie zu einem Systemdialog weitergeleitet. Bitte wählen Sie dort Automation aus und erlauben Sie die Anzeige über anderen Apps.</string>
<string name="variablesOnlyForTypes">Variablen sind nur für die Parametertypen String und URI verfügbar</string>
<string name="intentParametersHint">Wenn Sie einen Parameter angeben möchten, müssen Sie auch auf \"Intent-Paar hinzufügen\" klicken. Andernfalls werden Ihre Änderungen nicht gespeichert.</string>
<string name="languagePolish">Polnisch</string>
<string name="languageChineseChina">Chinesisch (China)</string>
<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>
@ -794,4 +794,64 @@
<string name="textToCopy">Texto para copiar</string>
<string name="android.permission.SYSTEM_ALERT_WINDOW">Dibujar encima otras aplicaciones</string>
<string name="overlayPermissionHint">Después de hacer cliquear en Aceptar, se le enviará a un cuadro de diálogo del sistema. Seleccione Automation allí y permita dibujar encima otras aplicaciones.</string>
<string name="variablesOnlyForTypes">Las variables solo están disponibles para los tipos de parámetro String y URI</string>
<string name="intentParametersHint">Si desea especificar un parámetro, también debe hacer clic en \"Agregar par de intención\". De lo contrario, los cambios no se guardarán.</string>
<string name="languagePolish">Polaco</string>
<string name="languageChineseChina">Chino (China)</string>
<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>

Some files were not shown because too many files have changed in this diff Show More