75 Commits

Author SHA1 Message Date
5ae193847e Merge remote-tracking branch 'origin/development' into development
# Conflicts:
#	app/src/main/java/com/jens/automation2/Actions.java
2021-12-09 18:05:58 +01:00
391479b164 Rework 2021-12-09 18:03:00 +01:00
fa578b175d Refactoring 2021-12-08 23:08:05 +01:00
0008642044 Rework 2021-12-08 19:57:27 +01:00
359dd545c7 Merge remote-tracking branch 'origin/transfer_applies_to_trigger' into development 2021-12-08 17:22:33 +01:00
89ac69fd4b Rework 2021-12-08 17:22:18 +01:00
b88801500f Refactoring 2021-12-07 23:10:37 +01:00
128116025f Rework 2021-12-07 16:45:05 +01:00
5d3e89595f description 2021-12-05 22:28:30 +01:00
8e5ad15c34 Rework 2021-12-05 17:24:47 +01:00
8b29dd0985 Rework 2021-12-05 14:51:00 +01:00
c34ec83425 Rework 2021-12-04 13:24:43 +01:00
cdf1a8baa8 Rework 2021-12-04 02:39:37 +01:00
d28ee8d00d Fixed infinite loop 2021-12-03 22:30:34 +01:00
2bb6f81596 Position trigger 2021-11-30 18:25:51 +01:00
6f0dbc9555 Position trigger 2021-11-29 20:14:09 +01:00
a9bd7b9561 Position trigger 2021-11-28 20:01:58 +01:00
81d6ab7b5f Position trigger 2021-11-27 20:22:13 +01:00
034c76fe30 Translations and integrated BT tethering 2021-11-27 02:03:51 +01:00
15637e914d Translations and integrated BT tethering 2021-11-27 01:52:57 +01:00
cd6ed7543c Translations and integrated BT tethering 2021-11-26 19:26:42 +01:00
f991325566 Merge remote-tracking branch 'origin/BT_tethering' into development 2021-11-26 18:56:28 +01:00
b744e76b07 Negative location coordinates allowed 2021-11-23 13:27:09 +01:00
06d63826e6 Donate button 2021-11-20 16:14:21 +01:00
fb87d5e42d BT tethering 2021-11-17 21:46:56 +01:00
17109b12d4 BT tethering 2021-11-15 20:28:38 +01:00
92ca6d6cb4 BT tethering 2021-11-13 14:48:56 +01:00
5fdc68e396 Merge remote-tracking branch 'origin/reoccuring_time_trigger' into development 2021-11-13 12:31:27 +01:00
ab0f2d88b4 Reoccuring time trigger 2021-11-13 02:32:39 +01:00
06a6651fae Reoccuring time trigger 2021-11-13 02:17:36 +01:00
473c464bf7 BT tethering 2021-11-13 01:00:36 +01:00
a5b9ced9ba line break 2021-11-11 10:28:46 +01:00
9cea3f4285 reocc time 2021-11-10 21:47:09 +01:00
0438a58f3e translation 2021-11-09 11:10:06 +01:00
97f32bd012 Reoccuring time 2021-11-08 20:13:11 +01:00
6588443459 reoccuring time 2021-11-07 17:29:00 +01:00
604ab0eb43 miscellaneous 2021-11-07 15:38:42 +01:00
31c4f6c1d1 Fixed crash of edit wifi trigger 2021-11-07 02:09:09 +01:00
0c646b55fc Fixed infinite loop 2021-11-05 22:47:48 +01:00
88cdc366c5 Changelogs 2021-11-04 18:01:30 +01:00
2bd94e8a3d Changelogs 2021-11-03 15:30:49 +01:00
074f75ed20 permission for play sound 2021-11-03 15:25:21 +01:00
d988e1f43d permission for play sound 2021-11-03 15:15:26 +01:00
23502f52bb permission for play sound 2021-11-03 15:15:06 +01:00
9a6083247f permission for play sound 2021-10-31 13:27:45 +01:00
ba2a340bdf permission for play sound 2021-10-28 17:58:55 +02:00
9e2f7c16f6 vibrateWhenRinging 2021-10-09 02:19:34 +02:00
d042b3f35a Translations 2021-10-04 20:18:09 +02:00
220d2d316e Fix in data switch 2021-10-03 21:38:33 +02:00
4aa095e801 Fix in data switch 2021-10-03 21:20:47 +02:00
b5bd332ff5 data with root 2021-10-03 15:09:07 +02:00
969937f8a0 vibrate for calls 2021-09-27 20:12:40 +02:00
e3598cc475 DND 2021-09-26 19:54:17 +02:00
e63d97be0c DND 2021-09-26 13:58:48 +02:00
e60fb1535a bugspray 2021-09-25 02:03:44 +02:00
8563234db3 bugspray 2021-09-24 19:15:41 +02:00
448942e4e8 bugspray 2021-09-20 19:58:11 +02:00
dcdb770d9f bugspray 2021-09-15 21:58:18 +02:00
b5040cedb3 var replacement 2021-09-14 17:56:45 +02:00
423839fa43 Sound settings 2021-09-12 20:05:12 +02:00
a6edab75ce Location without Cell Radio 2021-09-07 17:30:45 +02:00
cb430b957f fixes 2021-09-07 10:01:30 +02:00
b6a0f6dd91 fixes 2021-09-02 17:56:17 +02:00
bc32cbc179 encoding related typos 2021-09-02 10:48:50 +02:00
d9cc604bdd gradle update 2021-09-01 21:28:36 +02:00
db21011b7f Notification fixed 2021-08-31 23:13:59 +02:00
dc35c8b7fb stacked notification almost fixed 2021-08-31 18:53:26 +02:00
5a7cbfcdc9 Enabled http cleartext traffic 2021-08-21 11:48:04 +02:00
913a37a320 disallow http again because wouldn't compile 2021-08-20 13:46:04 +02:00
14655fe55d allow http 2021-08-20 13:25:36 +02:00
cfc145c6c4 allow http 2021-08-18 10:00:41 +02:00
325bff305c Wifi fix 2021-08-14 14:11:19 +02:00
4371fb56f7 Merge remote-tracking branch 'origin/master' into development 2021-08-14 01:55:50 +02:00
6593f6c923 Compile fix 2021-08-14 01:53:48 +02:00
7fbac92360 New release 2021-07-29 14:19:20 +02:00
85 changed files with 4151 additions and 2514 deletions

1
.gitignore vendored
View File

@ -148,3 +148,4 @@ fabric.properties
/app/app-release.apk
Automation_settings.xml
/app/googlePlayFlavor/

View File

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="com.android.tools.idea.compose.preview.runconfiguration.ComposePreviewRunConfigurationProducer" />
</set>
</option>
</component>
</project>

View File

@ -11,8 +11,8 @@ android {
compileSdkVersion 29
buildToolsVersion '29.0.2'
useLibrary 'org.apache.http.legacy'
versionCode 107
versionName "1.6.36"
versionCode 113
versionName "1.6.43"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
@ -36,27 +36,27 @@ android {
flavorDimensions "version"
productFlavors
{
googlePlayFlavor
{
dimension "version"
versionNameSuffix "-googlePlay"
targetSdkVersion 29
}
{
googlePlayFlavor
{
dimension "version"
versionNameSuffix "-googlePlay"
targetSdkVersion 30
}
fdroidFlavor
{
dimension "version"
targetSdkVersion 28
}
fdroidFlavor
{
dimension "version"
targetSdkVersion 28
}
apkFlavor
{
dimension "version"
versionNameSuffix "-apk"
targetSdkVersion 28
}
}
apkFlavor
{
dimension "version"
versionNameSuffix "-apk"
targetSdkVersion 28
}
}
}
dependencies {

View File

@ -1,5 +1,5 @@
{
"version": 2,
"version": 3,
"artifactType": {
"type": "APK",
"kind": "Directory"
@ -10,9 +10,11 @@
{
"type": "SINGLE",
"filters": [],
"versionCode": 106,
"versionName": "1.6.35-googlePlay",
"attributes": [],
"versionCode": 113,
"versionName": "1.6.43-googlePlay",
"outputFile": "app-googlePlayFlavor-release.apk"
}
]
],
"elementType": "File"
}

View File

@ -132,7 +132,7 @@
android:scheme="package" />-->
</intent-filter>
</receiver>
<receiver android:name=".receivers.AlarmListener" />
<receiver android:name=".receivers.DateTimeListener" />
<receiver android:name=".receivers.ConnectivityReceiver" />
<receiver android:name=".receivers.TimeZoneListener" />
@ -145,6 +145,7 @@
<activity android:name=".ActivityMaintenance" />
<activity android:name=".ActivityManageTriggerPhoneCall" />
<activity android:name=".ActivityManageActionBrightnessSetting" />
<activity android:name=".ActivityManageTriggerDevicePosition" />
<activity android:name=".ActivityHelp" />
<activity android:name=".ActivityManageActionVibrate" />
<activity

View File

@ -1,39 +1,22 @@
package com.jens.automation2;
import static com.jens.automation2.Trigger.triggerParameter2Split;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Looper;
import android.service.notification.StatusBarNotification;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.widget.Toast;
import com.google.android.gms.location.DetectedActivity;
import com.jens.automation2.location.LocationProvider;
import com.jens.automation2.location.WifiBroadcastReceiver;
import com.jens.automation2.receivers.ActivityDetectionReceiver;
import com.jens.automation2.receivers.BatteryReceiver;
import com.jens.automation2.receivers.BluetoothReceiver;
import com.jens.automation2.receivers.ConnectivityReceiver;
import com.jens.automation2.receivers.HeadphoneJackListener;
import com.jens.automation2.receivers.NfcReceiver;
import com.jens.automation2.receivers.NoiseListener;
import com.jens.automation2.receivers.NotificationListener;
import com.jens.automation2.receivers.PhoneStatusListener;
import com.jens.automation2.receivers.ProcessListener;
import java.sql.Time;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import static com.jens.automation2.Trigger.triggerParameter2Split;
import static com.jens.automation2.receivers.NotificationListener.EXTRA_TEXT;
import static com.jens.automation2.receivers.NotificationListener.EXTRA_TITLE;
public class Rule implements Comparable<Rule>
{
@ -342,6 +325,8 @@ public class Rule implements Comparable<Rule>
return true;
case setWifiTethering:
return true;
case setBluetoothTethering:
return true;
default:
break;
}
@ -349,12 +334,38 @@ public class Rule implements Comparable<Rule>
return false;
}
public boolean hasNotAppliedSinceLastExecution()
{
for(Trigger oneTrigger : this.getTriggerSet())
{
if (oneTrigger.hasStateNotAppliedSinceLastRuleExecution())
return true;
}
return false;
}
public boolean getsGreenLight(Context context)
{
if(applies(context))
{
if(hasNotAppliedSinceLastExecution())
return true;
else
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);
return false;
}
public boolean applies(Context context)
{
if(AutomationService.getInstance() == null)
{
Miscellaneous.logEvent("i", "RuleCheck", "Automation service not running. Rule cannot apply.", 3);
Miscellaneous.logEvent("i", "RuleCheck", "Automation service not running. Rule " + getName() + " cannot apply.", 3);
return false;
}
@ -362,533 +373,8 @@ public class Rule implements Comparable<Rule>
{
for(Trigger oneTrigger : this.getTriggerSet())
{
if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.pointOfInterest))
{
// Am I here?
PointOfInterest activePoi = PointOfInterest.getActivePoi();
if(activePoi != null) //entering one
{
if(oneTrigger.getPointOfInterest() != null)
{
if(activePoi.equals(oneTrigger.getPointOfInterest()))
{
if(!oneTrigger.getTriggerParameter())
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Rule doesn't apply. We're entering POI: " + oneTrigger.getPointOfInterest().getName() + ", not leaving it.", 4);
return false;
}
}
else
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Rule doesn't apply. This is " + activePoi.getName() + ", not " + oneTrigger.getPointOfInterest().getName() + ".", 4);
return false;
}
}
else if(oneTrigger.getPointOfInterest() == null)
{
if(oneTrigger.getTriggerParameter())
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Rule doesn't apply. We're at a POI. Rule specifies not at none, so leaving any.", 4);
return false;
}
}
}
else //leaving one
{
// We are not at any POI. But if this trigger requires us NOT to be there, that may be fine.
if(oneTrigger.getPointOfInterest() != null)
{
// if(activePoi.equals(oneTrigger.getPointOfInterest()))
// {
if(!oneTrigger.getTriggerParameter())
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "We are not at POI \"" + oneTrigger.getPointOfInterest().getName() + "\". But since that's required by this rule that's fine.", 4);
}
else
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Rule doesn't apply. We're not at POI \"" + oneTrigger.getPointOfInterest().getName() + "\".", 3);
return false;
}
// }
}
else if(oneTrigger.getPointOfInterest() == null)
{
if(!oneTrigger.getTriggerParameter())
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Rule doesn't apply. We're at no POI. Rule specifies to be at anyone.", 5);
return false;
}
}
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.timeFrame))
{
Date now = new Date();
String timeString = String.valueOf(now.getHours()) + ":" + String.valueOf(now.getMinutes()) + ":" + String.valueOf(now.getSeconds());
Time nowTime = Time.valueOf(timeString);
Calendar calNow = Calendar.getInstance();
if(oneTrigger.getTimeFrame().getDayList().contains(calNow.get(Calendar.DAY_OF_WEEK)))
{
if(
// Regular case, start time is lower than end time
(
Miscellaneous.compareTimes(oneTrigger.getTimeFrame().getTriggerTimeStart(), nowTime) >= 0
&&
Miscellaneous.compareTimes(nowTime, oneTrigger.getTimeFrame().getTriggerTimeStop()) > 0
)
||
// Other case, start time higher than end time, timeframe goes over midnight
(
Miscellaneous.compareTimes(oneTrigger.getTimeFrame().getTriggerTimeStart(), oneTrigger.getTimeFrame().getTriggerTimeStop()) < 0
&&
(Miscellaneous.compareTimes(oneTrigger.getTimeFrame().getTriggerTimeStart(), nowTime) >= 0
||
Miscellaneous.compareTimes(nowTime, oneTrigger.getTimeFrame().getTriggerTimeStop()) > 0)
)
)
{
// We are in the timeframe
Miscellaneous.logEvent("i", "TimeFrame", "We're currently (" + calNow.getTime().toString() + ") in the specified TimeFrame (" + oneTrigger.getTimeFrame().toString() + "). Trigger of Rule " + this.getName() + " applies.", 3);
if(oneTrigger.getTriggerParameter())
{
Miscellaneous.logEvent("i", "TimeFrame", "That's what's specified. Trigger of Rule " + this.getName() + " applies.", 3);
//return true;
}
else
{
Miscellaneous.logEvent("i", "TimeFrame", "That's not what's specified. Trigger of Rule " + this.getName() + " doesn't apply.", 3);
return false;
}
}
else
{
Miscellaneous.logEvent("i", "TimeFrame", "We're currently (" + calNow.getTime().toString() + ", Day: " + String.valueOf(calNow.get(Calendar.DAY_OF_WEEK)) + ") not in the specified TimeFrame (" + oneTrigger.getTimeFrame().toString() + ") because of the time. Trigger of Rule " + this.getName() + " doesn\'t apply..", 5);
if(!oneTrigger.getTriggerParameter())
{
Miscellaneous.logEvent("i", "TimeFrame", "That's what's specified. Trigger of Rule " + this.getName() + " applies.", 5);
//return true;
}
else
{
Miscellaneous.logEvent("i", "TimeFrame", "That's not what's specified. Trigger of Rule " + this.getName() + " doesn't apply.", 5);
return false;
}
// return false;
}
}
else
{
Miscellaneous.logEvent("i", "TimeFrame", "We're currently (" + calNow.getTime().toString() + ", Day: " + String.valueOf(calNow.get(Calendar.DAY_OF_WEEK)) + ") not in the specified TimeFrame (" + oneTrigger.getTimeFrame().toString() + ") because of the day. Trigger of Rule " + this.getName() + " doesn\'t apply.", 5);
return false;
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.charging))
{
if(BatteryReceiver.isDeviceCharging(context) == 0)
{
return false; // unknown charging state, can't activate rule under these conditions
}
else if(BatteryReceiver.isDeviceCharging(context) == 1)
{
if(oneTrigger.getTriggerParameter()) //rule says when charging, but we're currently discharging
return false;
}
else if(BatteryReceiver.isDeviceCharging(context) == 2)
{
if(!oneTrigger.getTriggerParameter()) //rule says when discharging, but we're currently charging
return false;
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.usb_host_connection))
{
if(BatteryReceiver.isUsbHostConnected() != oneTrigger.getTriggerParameter())
{
return false;
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.batteryLevel))
{
if(oneTrigger.getTriggerParameter())
{
if(BatteryReceiver.getBatteryLevel() <= oneTrigger.getBatteryLevel())
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyBatteryLowerThan) + " " + String.valueOf(oneTrigger.getBatteryLevel()), 3);
return false;
}
}
else
{
if(oneTrigger.getBatteryLevel() >= oneTrigger.getBatteryLevel())
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyBatteryHigherThan) + " " + String.valueOf(oneTrigger.getBatteryLevel()), 3);
return false;
}
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.speed))
{
if(oneTrigger.getTriggerParameter())
{
if(LocationProvider.getSpeed() < oneTrigger.getSpeed())
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyWeAreSlowerThan) + " " + String.valueOf(oneTrigger.getSpeed()), 3);
return false;
}
}
else
{
if(LocationProvider.getSpeed() > oneTrigger.getSpeed())
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyWeAreFasterThan) + " " + String.valueOf(oneTrigger.getSpeed()), 3);
return false;
}
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.noiseLevel))
{
if(oneTrigger.getTriggerParameter())
{
if(NoiseListener.getNoiseLevelDb() < oneTrigger.getNoiseLevelDb())
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyItsQuieterThan) + " " + String.valueOf(oneTrigger.getNoiseLevelDb()), 3);
return false;
}
}
else
{
if(NoiseListener.getNoiseLevelDb() > oneTrigger.getNoiseLevelDb())
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyItsLouderThan) + " " + String.valueOf(oneTrigger.getNoiseLevelDb()), 3);
return false;
}
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.wifiConnection))
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Checking for wifi state", 4);
if(oneTrigger.getTriggerParameter() == WifiBroadcastReceiver.lastConnectedState) // connected / disconnected
{
if(oneTrigger.getTriggerParameter2().length() > 0) // only check if any wifi name specified, otherwise any wifi will do
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Wifi name specified, checking that.", 4);
if(!WifiBroadcastReceiver.getLastWifiSsid().equals(oneTrigger.getTriggerParameter2()))
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), String.format(context.getResources().getString(R.string.ruleDoesntApplyNotTheCorrectSsid), oneTrigger.getTriggerParameter2(), WifiBroadcastReceiver.getLastWifiSsid()), 3);
return false;
}
else
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Wifi name matches. Rule will apply.", 4);
}
else
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "No wifi name specified, any will do.", 4);
}
else
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Wifi state not correct, demanded " + String.valueOf(oneTrigger.getTriggerParameter() + ", got " + String.valueOf(WifiBroadcastReceiver.lastConnectedState)), 4);
return false;
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.process_started_stopped))
{
boolean running = ProcessListener.getRunningApps().contains(oneTrigger.getProcessName());
if(running)
Miscellaneous.logEvent("i", "ProcessMonitoring", "App " + oneTrigger.getProcessName() + " is currently running.", 4);
else
Miscellaneous.logEvent("i", "ProcessMonitoring", "App " + oneTrigger.getProcessName() + " is not running.", 4);
if(running != oneTrigger.getTriggerParameter())
{
Miscellaneous.logEvent("i", "ProcessMonitoring", "Trigger doesn't apply.", 4);
return false;
}
Miscellaneous.logEvent("i", "ProcessMonitoring", "Trigger applies.", 4);
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.airplaneMode))
{
if(ConnectivityReceiver.isAirplaneMode(context) != oneTrigger.getTriggerParameter())
{
return false;
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.roaming))
{
if(ConnectivityReceiver.isRoaming(context) != oneTrigger.getTriggerParameter())
{
return false;
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.phoneCall))
{
String[] elements = oneTrigger.getTriggerParameter2().split(triggerParameter2Split);
// state dir number
if(elements[2].equals(Trigger.triggerPhoneCallNumberAny) || Miscellaneous.comparePhoneNumbers(PhoneStatusListener.getLastPhoneNumber(), elements[2]) || (Miscellaneous.isRegularExpression(elements[2]) && PhoneStatusListener.getLastPhoneNumber().matches(elements[2])))
{
//if(PhoneStatusListener.isInACall() == oneTrigger.getTriggerParameter())
if(
(elements[0].equals(Trigger.triggerPhoneCallStateRinging) && PhoneStatusListener.getCurrentState() == TelephonyManager.CALL_STATE_RINGING)
||
(elements[0].equals(Trigger.triggerPhoneCallStateStarted) && PhoneStatusListener.getCurrentState() == TelephonyManager.CALL_STATE_OFFHOOK)
||
(elements[0].equals(Trigger.triggerPhoneCallStateStopped) && PhoneStatusListener.getCurrentState() == TelephonyManager.CALL_STATE_IDLE)
)
{
if(
elements[1].equals(Trigger.triggerPhoneCallDirectionAny)
||
(elements[1].equals(Trigger.triggerPhoneCallDirectionIncoming) && PhoneStatusListener.getLastPhoneDirection() == 1)
||
(elements[1].equals(Trigger.triggerPhoneCallDirectionOutgoing) && PhoneStatusListener.getLastPhoneDirection() == 2)
)
{
// Trigger conditions are met
}
else
{
Miscellaneous.logEvent("i", "Rule", "Rule doesn't apply. Wrong direction. Demanded: " + String.valueOf(oneTrigger.getPhoneDirection()) + ", got: " + String.valueOf(PhoneStatusListener.getLastPhoneDirection()), 4);
return false;
}
}
else
{
Miscellaneous.logEvent("i", "Rule", "Rule doesn't apply. Wrong call status. Demanded: " + String.valueOf(oneTrigger.getTriggerParameter()) + ", got: " + String.valueOf(PhoneStatusListener.isInACall()), 4);
return false;
}
}
else
{
Miscellaneous.logEvent("i", "Rule", "Rule doesn't apply. Wrong phone number. Demanded: " + oneTrigger.getPhoneNumber() + ", got: " + PhoneStatusListener.getLastPhoneNumber(), 4);
return false;
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.nfcTag))
{
if(NfcReceiver.lastReadLabel == null)
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyNoTagLabel), 3);
return false;
}
else if(!NfcReceiver.lastReadLabel.equals(oneTrigger.getNfcTagId()))
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyWrongTagLabel) + " " + NfcReceiver.lastReadLabel + " / " + oneTrigger.getNfcTagId(), 3);
return false;
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.activityDetection))
{
if(ActivityDetectionReceiver.getActivityDetectionLastResult() != null)
{
boolean found = false;
for(DetectedActivity oneDetectedActivity : ActivityDetectionReceiver.getActivityDetectionLastResult().getProbableActivities())
{
if(oneDetectedActivity.getType() == oneTrigger.getActivityDetectionType())
found = true;
}
if(!found)
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), String.format(context.getResources().getString(R.string.ruleDoesntApplyActivityNotPresent), ActivityDetectionReceiver.getDescription(oneTrigger.getActivityDetectionType())), 3);
return false;
}
else
{
for(DetectedActivity oneDetectedActivity : ActivityDetectionReceiver.getActivityDetectionLastResult().getProbableActivities())
{
if(oneDetectedActivity.getType() == oneTrigger.getActivityDetectionType() && oneDetectedActivity.getConfidence() < Settings.activityDetectionRequiredProbability)
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), String.format(context.getResources().getString(R.string.ruleDoesntApplyActivityGivenButTooLowProbability), ActivityDetectionReceiver.getDescription(oneDetectedActivity.getType()), String.valueOf(oneDetectedActivity.getConfidence()), String.valueOf(Settings.activityDetectionRequiredProbability)), 3);
return false;
}
}
}
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.bluetoothConnection))
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Checking for bluetooth...", 4);
if(oneTrigger.getBluetoothDeviceAddress().equals("<any>"))
{
if(oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED))
{
if(BluetoothReceiver.isAnyDeviceConnected() != oneTrigger.getTriggerParameter())
return false;
}
else if((oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)))
{
if(BluetoothReceiver.isAnyDeviceConnected() != oneTrigger.getTriggerParameter())
return false;
}
else
{
// range
if(BluetoothReceiver.isAnyDeviceInRange() != oneTrigger.getTriggerParameter())
return false;
}
}
else if(oneTrigger.getBluetoothDeviceAddress().equals("<none>"))
{
if(oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED))
{
if(BluetoothReceiver.isAnyDeviceConnected() == oneTrigger.getTriggerParameter())
return false;
}
else if((oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)))
{
if(BluetoothReceiver.isAnyDeviceConnected() == oneTrigger.getTriggerParameter())
return false;
}
else
{
// range
if(BluetoothReceiver.isAnyDeviceInRange() == oneTrigger.getTriggerParameter())
return false;
}
}
else if(oneTrigger.getBluetoothDeviceAddress().length() > 0)
{
if(oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED))
{
if(BluetoothReceiver.isDeviceCurrentlyConnected(BluetoothReceiver.getDeviceByAddress(oneTrigger.getBluetoothDeviceAddress())) != oneTrigger.getTriggerParameter())
return false;
}
else if((oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)))
{
if(BluetoothReceiver.isDeviceCurrentlyConnected(BluetoothReceiver.getDeviceByAddress(oneTrigger.getBluetoothDeviceAddress())) != oneTrigger.getTriggerParameter())
return false;
}
else
{
// range
if(BluetoothReceiver.isDeviceInRange(BluetoothReceiver.getDeviceByAddress(oneTrigger.getBluetoothDeviceAddress())) != oneTrigger.getTriggerParameter())
return false;
}
}
else
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyStateNotCorrect), 3);
return false;
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.headsetPlugged))
{
if(HeadphoneJackListener.isHeadsetConnected() != oneTrigger.getTriggerParameter())
return false;
else
if(oneTrigger.getHeadphoneType() != 2 && oneTrigger.getHeadphoneType() != HeadphoneJackListener.getHeadphoneType())
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyWrongHeadphoneType), 3);
return false;
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.notification))
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
{
String[] params = oneTrigger.getTriggerParameter2().split(triggerParameter2Split);
String myApp = params[0];
String myTitleDir = params[1];
String myTitle = params[2];
String myTextDir = params[3];
String myText;
if (params.length >= 5)
myText = params[4];
else
myText = "";
if(oneTrigger.getTriggerParameter())
{
// Check an active notification that is still there
boolean foundMatch = false;
for (StatusBarNotification sbn : NotificationListener.getInstance().getActiveNotifications())
{
if(getLastExecution() == null || sbn.getPostTime() > this.lastExecution.getTimeInMillis())
{
String app = sbn.getPackageName();
String title = sbn.getNotification().extras.getString(EXTRA_TITLE);
String text = sbn.getNotification().extras.getString(EXTRA_TEXT);
Miscellaneous.logEvent("i", "NotificationCheck", "Checking if this notification matches our rule " + this.getName() + ". App: " + app + ", title: " + title + ", text: " + text, 5);
if (!myApp.equals("-1"))
{
if (!app.equalsIgnoreCase(myApp))
{
Miscellaneous.logEvent("i", "NotificationCheck", "Notification app name does not match rule.", 5);
continue;
}
}
if (myTitle.length() > 0)
{
if (!Miscellaneous.compare(myTitleDir, myTitle, title))
{
Miscellaneous.logEvent("i", "NotificationCheck", "Notification title does not match rule.", 5);
continue;
}
}
if (myText.length() > 0)
{
if (!Miscellaneous.compare(myTextDir, myText, text))
{
Miscellaneous.logEvent("i", "NotificationCheck", "Notification text does not match rule.", 5);
continue;
}
}
foundMatch = true;
break;
}
}
if(!foundMatch)
return false;
}
else
{
// check a notification that is gone
if(NotificationListener.getLastNotification() != null)
{
if(!NotificationListener.getLastNotification().isCreated())
{
String app = NotificationListener.getLastNotification().getApp();
String title = NotificationListener.getLastNotification().getTitle();
String text = NotificationListener.getLastNotification().getText();
if (!myApp.equals("-1"))
{
if (!app.equalsIgnoreCase(myApp))
return false;
}
if (myTitle.length() > 0)
{
if (!Miscellaneous.compare(myTitleDir, title, myTitle))
return false;
}
if (myText.length() > 0)
{
if (!Miscellaneous.compare(myTextDir, text, myText))
return false;
}
}
else
return false;
}
}
}
}
if (!oneTrigger.applies(null, context))
return false;
}
return true;
@ -898,6 +384,44 @@ public class Rule implements Comparable<Rule>
return false;
}
/**
* This is actually a function of the class Trigger, but Rule is already distinguished by flavors, Trigger is not.
* Hence it is here.
* @param oneTrigger
* @return
*/
boolean checkActivityDetection(Trigger oneTrigger)
{
if (ActivityDetectionReceiver.getActivityDetectionLastResult() != null)
{
boolean found = false;
for (DetectedActivity oneDetectedActivity : ActivityDetectionReceiver.getActivityDetectionLastResult().getProbableActivities())
{
if (oneDetectedActivity.getType() == oneTrigger.getActivityDetectionType())
found = true;
}
if (!found)
{
Miscellaneous.logEvent("i", String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), this.getName()), String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.ruleDoesntApplyActivityNotPresent), getName(), ActivityDetectionReceiver.getDescription(oneTrigger.getActivityDetectionType())), 3);
return false;
}
else
{
for (DetectedActivity oneDetectedActivity : ActivityDetectionReceiver.getActivityDetectionLastResult().getProbableActivities())
{
if (oneDetectedActivity.getType() == oneTrigger.getActivityDetectionType() && oneDetectedActivity.getConfidence() < Settings.activityDetectionRequiredProbability)
{
Miscellaneous.logEvent("i", String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), this.getName()), String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.ruleDoesntApplyActivityGivenButTooLowProbability), getName(), ActivityDetectionReceiver.getDescription(oneDetectedActivity.getType()), String.valueOf(oneDetectedActivity.getConfidence()), String.valueOf(Settings.activityDetectionRequiredProbability)), 3);
return false;
}
}
}
}
return true;
}
private class ActivateRuleTask extends AsyncTask<Object, String, Void>
{
boolean wasActivated = false;
@ -915,7 +439,8 @@ public class Rule implements Comparable<Rule>
if (Looper.myLooper() == null)
Looper.prepare();
setLastExecution(Calendar.getInstance());
wasActivated = activateInternally((AutomationService)params[0], (Boolean)params[1]);
return null;
@ -940,7 +465,7 @@ public class Rule implements Comparable<Rule>
*/
if(wasActivated)
{
setLastExecution(Calendar.getInstance());
// setLastExecution(Calendar.getInstance());
AutomationService.updateNotification();
ActivityMainScreen.updateMainScreen();
super.onPostExecute(result);
@ -958,8 +483,9 @@ public class Rule implements Comparable<Rule>
boolean notLastActive = getLastActivatedRule() == null || !getLastActivatedRule().equals(Rule.this);
boolean doToggle = ruleToggle && isActuallyToggable;
if(notLastActive || force || doToggle)
{
//if(notLastActive || force || doToggle)
// if(force || doToggle)
// {
String message;
if(!doToggle)
message = String.format(automationService.getResources().getString(R.string.ruleActivate), Rule.this.getName());
@ -988,6 +514,7 @@ public class Rule implements Comparable<Rule>
{
Rule.ruleRunHistory.add(0, Rule.this); // add at beginning for better visualization
Rule.lastActivatedRuleActivationTime = new Date();
while(ruleRunHistory.size() > Settings.rulesThatHaveBeenRanHistorySize)
ruleRunHistory.remove(ruleRunHistory.size()-1);
String history = "";
@ -1003,12 +530,12 @@ public class Rule implements Comparable<Rule>
}
Miscellaneous.logEvent("i", "Rule", String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.ruleActivationComplete), Rule.this.getName()), 2);
}
else
{
Miscellaneous.logEvent("i", "Rule", "Request to activate rule " + Rule.this.getName() + ", but it is the last one that was activated. Won't do it again.", 3);
return false;
}
// }
// else
// {
// Miscellaneous.logEvent("i", "Rule", "Request to activate rule " + Rule.this.getName() + ", but it is the last one that was activated. Won't do it again.", 3);
// return false;
// }
return true;
}
@ -1017,15 +544,7 @@ public class Rule implements Comparable<Rule>
public void activate(AutomationService automationService, boolean force)
{
ActivateRuleTask task = new ActivateRuleTask();
// if(Settings.startNewThreadForRuleActivation)
task.execute(automationService, force);
// else
// {
// task.activateInternally(automationService, force);
// AutomationService.updateNotification();
// ActivityMainScreen.updateMainScreen();
// }
task.execute(automationService, force);
}
public static ArrayList<Rule> findRuleCandidatesByPoi(PointOfInterest searchPoi, boolean triggerParameter)
@ -1110,7 +629,7 @@ public class Rule implements Comparable<Rule>
if(oneTrigger.getTimeFrame().getTriggerTimeStart().getTime() > oneTrigger.getTimeFrame().getTriggerTimeStop().getTime())
{
Miscellaneous.logEvent("i", "Timeframe search", "Rule goes over midnight.", 5);
Miscellaneous.logEvent("i", "Timeframe search", "Rule (" + oneRule.getName() + ") stretches over midnight.", 5);
if(oneTrigger.getTimeFrame().getTriggerTimeStart().getTime() <= searchTime.getTime() || searchTime.getTime() <= oneTrigger.getTimeFrame().getTriggerTimeStop().getTime()+20000) //add 20 seconds because of delay
{
ruleCandidates.add(oneRule);
@ -1119,7 +638,7 @@ public class Rule implements Comparable<Rule>
}
else if(oneTrigger.getTimeFrame().getTriggerTimeStart().getTime() <= searchTime.getTime() && searchTime.getTime() <= oneTrigger.getTimeFrame().getTriggerTimeStop().getTime()+20000) //add 20 seconds because of delay
{
Miscellaneous.logEvent("i", "RuleSearch", "Rule found with TimeFrame with time " + searchTime.toString(), 3);
Miscellaneous.logEvent("i", "RuleSearch", "Rule found (" + oneRule.getName() + ") with TimeFrame with time " + searchTime.toString(), 3);
ruleCandidates.add(oneRule);
break innerloop; //if the poi is found we don't need to search the other triggers in the same rule
}

View File

@ -294,7 +294,7 @@ public class ActivityDetectionReceiver extends IntentService implements Automati
ArrayList<Rule> allRulesWithActivityDetection = Rule.findRuleCandidatesByActivityDetection();
for(int i=0; i<allRulesWithActivityDetection.size(); i++)
{
if(allRulesWithActivityDetection.get(i).applies(Miscellaneous.getAnyContext()))
if(allRulesWithActivityDetection.get(i).getsGreenLight(Miscellaneous.getAnyContext()))
allRulesWithActivityDetection.get(i).activate(AutomationService.getInstance(), false);
}
}

View File

@ -129,7 +129,7 @@
android:scheme="package" />-->
</intent-filter>
</receiver>
<receiver android:name=".receivers.AlarmListener" />
<receiver android:name=".receivers.DateTimeListener" />
<receiver android:name=".receivers.ConnectivityReceiver" />
<receiver android:name=".receivers.TimeZoneListener" />

View File

@ -1,36 +1,18 @@
package com.jens.automation2;
import static com.jens.automation2.Trigger.triggerParameter2Split;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Looper;
import android.service.notification.StatusBarNotification;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.widget.Toast;
import com.jens.automation2.location.LocationProvider;
import com.jens.automation2.location.WifiBroadcastReceiver;
import com.jens.automation2.receivers.BatteryReceiver;
import com.jens.automation2.receivers.BluetoothReceiver;
import com.jens.automation2.receivers.ConnectivityReceiver;
import com.jens.automation2.receivers.HeadphoneJackListener;
import com.jens.automation2.receivers.NfcReceiver;
import com.jens.automation2.receivers.NoiseListener;
import com.jens.automation2.receivers.NotificationListener;
import com.jens.automation2.receivers.PhoneStatusListener;
import com.jens.automation2.receivers.ProcessListener;
import java.sql.Time;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import static com.jens.automation2.Trigger.triggerParameter2Split;
import static com.jens.automation2.receivers.NotificationListener.EXTRA_TEXT;
import static com.jens.automation2.receivers.NotificationListener.EXTRA_TITLE;
public class Rule implements Comparable<Rule>
{
@ -224,6 +206,19 @@ public class Rule implements Comparable<Rule>
return XmlFileInterface.writeFile();
}
public boolean cloneRule(Context context)
{
Rule newRule = new Rule();
newRule.setName(this.getName() + " - clone");
newRule.setRuleActive(this.isRuleActive());
newRule.setRuleToggle(this.isRuleToggle());
newRule.setTriggerSet(this.getTriggerSet());
newRule.setActionSet(this.getActionSet());
return newRule.create(context);
}
private boolean checkBeforeSaving(Context context, boolean changeExistingRule)
{
@ -326,6 +321,8 @@ public class Rule implements Comparable<Rule>
return true;
case setWifiTethering:
return true;
case setBluetoothTethering:
return true;
default:
break;
}
@ -333,6 +330,22 @@ public class Rule implements Comparable<Rule>
return false;
}
public boolean hasNotAppliedSinceLastExecution()
{
for(Trigger oneTrigger : this.getTriggerSet())
{
if (oneTrigger.hasStateNotAppliedSinceLastRuleExecution())
return true;
}
return false;
}
public boolean getsGreenLight(Context context)
{
return isRuleActive() && applies(context) && hasNotAppliedSinceLastExecution();
}
public boolean applies(Context context)
{
@ -346,504 +359,8 @@ public class Rule implements Comparable<Rule>
{
for(Trigger oneTrigger : this.getTriggerSet())
{
if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.pointOfInterest))
{
// Am I here?
PointOfInterest activePoi = PointOfInterest.getActivePoi();
if(activePoi != null) //entering one
{
if(oneTrigger.getPointOfInterest() != null)
{
if(activePoi.equals(oneTrigger.getPointOfInterest()))
{
if(!oneTrigger.getTriggerParameter())
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Rule doesn't apply. We're entering POI: " + oneTrigger.getPointOfInterest().getName() + ", not leaving it.", 4);
return false;
}
}
else
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Rule doesn't apply. This is " + activePoi.getName() + ", not " + oneTrigger.getPointOfInterest().getName() + ".", 4);
return false;
}
}
else if(oneTrigger.getPointOfInterest() == null)
{
if(oneTrigger.getTriggerParameter())
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Rule doesn't apply. We're at a POI. Rule specifies not at none, so leaving any.", 4);
return false;
}
}
}
else //leaving one
{
// We are not at any POI. But if this trigger requires us NOT to be there, that may be fine.
if(oneTrigger.getPointOfInterest() != null)
{
// if(activePoi.equals(oneTrigger.getPointOfInterest()))
// {
if(!oneTrigger.getTriggerParameter())
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "We are not at POI \"" + oneTrigger.getPointOfInterest().getName() + "\". But since that's required by this rule that's fine.", 4);
}
else
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Rule doesn't apply. We're not at POI \"" + oneTrigger.getPointOfInterest().getName() + "\".", 3);
return false;
}
// }
}
else if(oneTrigger.getPointOfInterest() == null)
{
if(!oneTrigger.getTriggerParameter())
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Rule doesn't apply. We're at no POI. Rule specifies to be at anyone.", 5);
return false;
}
}
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.timeFrame))
{
Date now = new Date();
String timeString = String.valueOf(now.getHours()) + ":" + String.valueOf(now.getMinutes()) + ":" + String.valueOf(now.getSeconds());
Time nowTime = Time.valueOf(timeString);
Calendar calNow = Calendar.getInstance();
if(oneTrigger.getTimeFrame().getDayList().contains(calNow.get(Calendar.DAY_OF_WEEK)))
{
if(
// Regular case, start time is lower than end time
(
Miscellaneous.compareTimes(oneTrigger.getTimeFrame().getTriggerTimeStart(), nowTime) >= 0
&&
Miscellaneous.compareTimes(nowTime, oneTrigger.getTimeFrame().getTriggerTimeStop()) > 0
)
||
// Other case, start time higher than end time, timeframe goes over midnight
(
Miscellaneous.compareTimes(oneTrigger.getTimeFrame().getTriggerTimeStart(), oneTrigger.getTimeFrame().getTriggerTimeStop()) < 0
&&
(Miscellaneous.compareTimes(oneTrigger.getTimeFrame().getTriggerTimeStart(), nowTime) >= 0
||
Miscellaneous.compareTimes(nowTime, oneTrigger.getTimeFrame().getTriggerTimeStop()) > 0)
)
)
{
// We are in the timeframe
Miscellaneous.logEvent("i", "TimeFrame", "We're currently (" + calNow.getTime().toString() + ") in the specified TimeFrame (" + oneTrigger.getTimeFrame().toString() + "). Trigger of Rule " + this.getName() + " applies.", 3);
if(oneTrigger.getTriggerParameter())
{
Miscellaneous.logEvent("i", "TimeFrame", "That's what's specified. Trigger of Rule " + this.getName() + " applies.", 3);
//return true;
}
else
{
Miscellaneous.logEvent("i", "TimeFrame", "That's not what's specified. Trigger of Rule " + this.getName() + " doesn't apply.", 3);
return false;
}
}
else
{
Miscellaneous.logEvent("i", "TimeFrame", "We're currently (" + calNow.getTime().toString() + ", Day: " + String.valueOf(calNow.get(Calendar.DAY_OF_WEEK)) + ") not in the specified TimeFrame (" + oneTrigger.getTimeFrame().toString() + ") because of the time. Trigger of Rule " + this.getName() + " doesn\'t apply..", 5);
if(!oneTrigger.getTriggerParameter())
{
Miscellaneous.logEvent("i", "TimeFrame", "That's what's specified. Trigger of Rule " + this.getName() + " applies.", 5);
//return true;
}
else
{
Miscellaneous.logEvent("i", "TimeFrame", "That's not what's specified. Trigger of Rule " + this.getName() + " doesn't apply.", 5);
return false;
}
// return false;
}
}
else
{
Miscellaneous.logEvent("i", "TimeFrame", "We're currently (" + calNow.getTime().toString() + ", Day: " + String.valueOf(calNow.get(Calendar.DAY_OF_WEEK)) + ") not in the specified TimeFrame (" + oneTrigger.getTimeFrame().toString() + ") because of the day. Trigger of Rule " + this.getName() + " doesn\'t apply.", 5);
return false;
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.charging))
{
if(BatteryReceiver.isDeviceCharging(context) == 0)
{
return false; // unknown charging state, can't activate rule under these conditions
}
else if(BatteryReceiver.isDeviceCharging(context) == 1)
{
if(oneTrigger.getTriggerParameter()) //rule says when charging, but we're currently discharging
return false;
}
else if(BatteryReceiver.isDeviceCharging(context) == 2)
{
if(!oneTrigger.getTriggerParameter()) //rule says when discharging, but we're currently charging
return false;
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.usb_host_connection))
{
if(BatteryReceiver.isUsbHostConnected() != oneTrigger.getTriggerParameter())
{
return false;
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.batteryLevel))
{
if(oneTrigger.getTriggerParameter())
{
if(BatteryReceiver.getBatteryLevel() <= oneTrigger.getBatteryLevel())
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyBatteryLowerThan) + " " + String.valueOf(oneTrigger.getBatteryLevel()), 3);
return false;
}
}
else
{
if(oneTrigger.getBatteryLevel() >= oneTrigger.getBatteryLevel())
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyBatteryHigherThan) + " " + String.valueOf(oneTrigger.getBatteryLevel()), 3);
return false;
}
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.speed))
{
if(oneTrigger.getTriggerParameter())
{
if(LocationProvider.getSpeed() < oneTrigger.getSpeed())
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyWeAreSlowerThan) + " " + String.valueOf(oneTrigger.getSpeed()), 3);
return false;
}
}
else
{
if(LocationProvider.getSpeed() > oneTrigger.getSpeed())
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyWeAreFasterThan) + " " + String.valueOf(oneTrigger.getSpeed()), 3);
return false;
}
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.noiseLevel))
{
if(oneTrigger.getTriggerParameter())
{
if(NoiseListener.getNoiseLevelDb() < oneTrigger.getNoiseLevelDb())
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyItsQuieterThan) + " " + String.valueOf(oneTrigger.getNoiseLevelDb()), 3);
return false;
}
}
else
{
if(NoiseListener.getNoiseLevelDb() > oneTrigger.getNoiseLevelDb())
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyItsLouderThan) + " " + String.valueOf(oneTrigger.getNoiseLevelDb()), 3);
return false;
}
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.wifiConnection))
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Checking for wifi state", 4);
if(oneTrigger.getTriggerParameter() == WifiBroadcastReceiver.lastConnectedState) // connected / disconnected
{
if(oneTrigger.getTriggerParameter2().length() > 0) // only check if any wifi name specified, otherwise any wifi will do
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Wifi name specified, checking that.", 4);
if(!WifiBroadcastReceiver.getLastWifiSsid().equals(oneTrigger.getTriggerParameter2()))
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), String.format(context.getResources().getString(R.string.ruleDoesntApplyNotTheCorrectSsid), oneTrigger.getTriggerParameter2(), WifiBroadcastReceiver.getLastWifiSsid()), 3);
return false;
}
else
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Wifi name matches. Rule will apply.", 4);
}
else
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "No wifi name specified, any will do.", 4);
}
else
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Wifi state not correct, demanded " + String.valueOf(oneTrigger.getTriggerParameter() + ", got " + String.valueOf(WifiBroadcastReceiver.lastConnectedState)), 4);
return false;
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.process_started_stopped))
{
boolean running = ProcessListener.getRunningApps().contains(oneTrigger.getProcessName());
if(running)
Miscellaneous.logEvent("i", "ProcessMonitoring", "App " + oneTrigger.getProcessName() + " is currently running.", 4);
else
Miscellaneous.logEvent("i", "ProcessMonitoring", "App " + oneTrigger.getProcessName() + " is not running.", 4);
if(running != oneTrigger.getTriggerParameter())
{
Miscellaneous.logEvent("i", "ProcessMonitoring", "Trigger doesn't apply.", 4);
return false;
}
Miscellaneous.logEvent("i", "ProcessMonitoring", "Trigger applies.", 4);
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.airplaneMode))
{
if(ConnectivityReceiver.isAirplaneMode(context) != oneTrigger.getTriggerParameter())
{
return false;
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.roaming))
{
if(ConnectivityReceiver.isRoaming(context) != oneTrigger.getTriggerParameter())
{
return false;
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.phoneCall))
{
String[] elements = oneTrigger.getTriggerParameter2().split(triggerParameter2Split);
// state dir number
if(elements[2].equals(Trigger.triggerPhoneCallNumberAny) || Miscellaneous.comparePhoneNumbers(PhoneStatusListener.getLastPhoneNumber(), elements[2]) || (Miscellaneous.isRegularExpression(elements[2]) && PhoneStatusListener.getLastPhoneNumber().matches(elements[2])))
{
//if(PhoneStatusListener.isInACall() == oneTrigger.getTriggerParameter())
if(
(elements[0].equals(Trigger.triggerPhoneCallStateRinging) && PhoneStatusListener.getCurrentState() == TelephonyManager.CALL_STATE_RINGING)
||
(elements[0].equals(Trigger.triggerPhoneCallStateStarted) && PhoneStatusListener.getCurrentState() == TelephonyManager.CALL_STATE_OFFHOOK)
||
(elements[0].equals(Trigger.triggerPhoneCallStateStopped) && PhoneStatusListener.getCurrentState() == TelephonyManager.CALL_STATE_IDLE)
)
{
if(
elements[1].equals(Trigger.triggerPhoneCallDirectionAny)
||
(elements[1].equals(Trigger.triggerPhoneCallDirectionIncoming) && PhoneStatusListener.getLastPhoneDirection() == 1)
||
(elements[1].equals(Trigger.triggerPhoneCallDirectionOutgoing) && PhoneStatusListener.getLastPhoneDirection() == 2)
)
{
// Trigger conditions are met
}
else
{
Miscellaneous.logEvent("i", "Rule", "Rule doesn't apply. Wrong direction. Demanded: " + String.valueOf(oneTrigger.getPhoneDirection()) + ", got: " + String.valueOf(PhoneStatusListener.getLastPhoneDirection()), 4);
return false;
}
}
else
{
Miscellaneous.logEvent("i", "Rule", "Rule doesn't apply. Wrong call status. Demanded: " + String.valueOf(oneTrigger.getTriggerParameter()) + ", got: " + String.valueOf(PhoneStatusListener.isInACall()), 4);
return false;
}
}
else
{
Miscellaneous.logEvent("i", "Rule", "Rule doesn't apply. Wrong phone number. Demanded: " + oneTrigger.getPhoneNumber() + ", got: " + PhoneStatusListener.getLastPhoneNumber(), 4);
return false;
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.nfcTag))
{
if(NfcReceiver.lastReadLabel == null)
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyNoTagLabel), 3);
return false;
}
else if(!NfcReceiver.lastReadLabel.equals(oneTrigger.getNfcTagId()))
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyWrongTagLabel) + " " + NfcReceiver.lastReadLabel + " / " + oneTrigger.getNfcTagId(), 3);
return false;
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.bluetoothConnection))
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Checking for bluetooth...", 4);
if(oneTrigger.getBluetoothDeviceAddress().equals("<any>"))
{
if(oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED))
{
if(BluetoothReceiver.isAnyDeviceConnected() != oneTrigger.getTriggerParameter())
return false;
}
else if((oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)))
{
if(BluetoothReceiver.isAnyDeviceConnected() != oneTrigger.getTriggerParameter())
return false;
}
else
{
// range
if(BluetoothReceiver.isAnyDeviceInRange() != oneTrigger.getTriggerParameter())
return false;
}
}
else if(oneTrigger.getBluetoothDeviceAddress().equals("<none>"))
{
if(oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED))
{
if(BluetoothReceiver.isAnyDeviceConnected() == oneTrigger.getTriggerParameter())
return false;
}
else if((oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)))
{
if(BluetoothReceiver.isAnyDeviceConnected() == oneTrigger.getTriggerParameter())
return false;
}
else
{
// range
if(BluetoothReceiver.isAnyDeviceInRange() == oneTrigger.getTriggerParameter())
return false;
}
}
else if(oneTrigger.getBluetoothDeviceAddress().length() > 0)
{
if(oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED))
{
if(BluetoothReceiver.isDeviceCurrentlyConnected(BluetoothReceiver.getDeviceByAddress(oneTrigger.getBluetoothDeviceAddress())) != oneTrigger.getTriggerParameter())
return false;
}
else if((oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)))
{
if(BluetoothReceiver.isDeviceCurrentlyConnected(BluetoothReceiver.getDeviceByAddress(oneTrigger.getBluetoothDeviceAddress())) != oneTrigger.getTriggerParameter())
return false;
}
else
{
// range
if(BluetoothReceiver.isDeviceInRange(BluetoothReceiver.getDeviceByAddress(oneTrigger.getBluetoothDeviceAddress())) != oneTrigger.getTriggerParameter())
return false;
}
}
else
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyStateNotCorrect), 3);
return false;
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.headsetPlugged))
{
if(HeadphoneJackListener.isHeadsetConnected() != oneTrigger.getTriggerParameter())
return false;
else
if(oneTrigger.getHeadphoneType() != 2 && oneTrigger.getHeadphoneType() != HeadphoneJackListener.getHeadphoneType())
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyWrongHeadphoneType), 3);
return false;
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.notification))
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
{
String[] params = oneTrigger.getTriggerParameter2().split(triggerParameter2Split);
String myApp = params[0];
String myTitleDir = params[1];
String myTitle = params[2];
String myTextDir = params[3];
String myText;
if (params.length >= 5)
myText = params[4];
else
myText = "";
if(oneTrigger.getTriggerParameter())
{
// Check an active notification that is still there
boolean foundMatch = false;
for (StatusBarNotification sbn : NotificationListener.getInstance().getActiveNotifications())
{
if(getLastExecution() == null || sbn.getPostTime() > this.lastExecution.getTimeInMillis())
{
String app = sbn.getPackageName();
String title = sbn.getNotification().extras.getString(EXTRA_TITLE);
String text = sbn.getNotification().extras.getString(EXTRA_TEXT);
Miscellaneous.logEvent("i", "NotificationCheck", "Checking if this notification matches our rule " + this.getName() + ". App: " + app + ", title: " + title + ", text: " + text, 5);
if (!myApp.equals("-1"))
{
if (!app.equalsIgnoreCase(myApp))
{
Miscellaneous.logEvent("i", "NotificationCheck", "Notification app name does not match rule.", 5);
continue;
}
}
if (myTitle.length() > 0)
{
if (!Miscellaneous.compare(myTitleDir, myTitle, title))
{
Miscellaneous.logEvent("i", "NotificationCheck", "Notification title does not match rule.", 5);
continue;
}
}
if (myText.length() > 0)
{
if (!Miscellaneous.compare(myTextDir, myText, text))
{
Miscellaneous.logEvent("i", "NotificationCheck", "Notification text does not match rule.", 5);
continue;
}
}
foundMatch = true;
break;
}
}
if(!foundMatch)
return false;
}
else
{
// check a notification that is gone
if(NotificationListener.getLastNotification() != null)
{
if(!NotificationListener.getLastNotification().isCreated())
{
String app = NotificationListener.getLastNotification().getApp();
String title = NotificationListener.getLastNotification().getTitle();
String text = NotificationListener.getLastNotification().getText();
if (!myApp.equals("-1"))
{
if (!app.equalsIgnoreCase(myApp))
return false;
}
if (myTitle.length() > 0)
{
if (!Miscellaneous.compare(myTitleDir, title, myTitle))
return false;
}
if (myText.length() > 0)
{
if (!Miscellaneous.compare(myTextDir, text, myText))
return false;
}
}
else
return false;
}
}
}
}
if (!oneTrigger.applies(null, context))
return false;
}
return true;
@ -852,7 +369,21 @@ public class Rule implements Comparable<Rule>
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), String.format(context.getResources().getString(R.string.ruleIsDeactivatedCantApply), this.getName()), 3);
return false;
}
/**
* This is actually a function of the class Trigger, but Rule is already distinguished by flavors, Trigger is not.
* Hence it is here.
* @param oneTrigger
* @return
*/
boolean checkActivityDetection(Trigger oneTrigger)
{
/*
Feature not present in FOSS edition.
*/
return false;
}
private class ActivateRuleTask extends AsyncTask<Object, String, Void>
{
boolean wasActivated = false;
@ -870,7 +401,8 @@ public class Rule implements Comparable<Rule>
if (Looper.myLooper() == null)
Looper.prepare();
setLastExecution(Calendar.getInstance());
wasActivated = activateInternally((AutomationService)params[0], (Boolean)params[1]);
return null;
@ -895,7 +427,7 @@ public class Rule implements Comparable<Rule>
*/
if(wasActivated)
{
setLastExecution(Calendar.getInstance());
// setLastExecution(Calendar.getInstance());
AutomationService.updateNotification();
ActivityMainScreen.updateMainScreen();
super.onPostExecute(result);
@ -913,8 +445,9 @@ public class Rule implements Comparable<Rule>
boolean notLastActive = getLastActivatedRule() == null || !getLastActivatedRule().equals(Rule.this);
boolean doToggle = ruleToggle && isActuallyToggable;
if(notLastActive || force || doToggle)
{
//if(notLastActive || force || doToggle)
// if(force || doToggle)
// {
String message;
if(!doToggle)
message = String.format(automationService.getResources().getString(R.string.ruleActivate), Rule.this.getName());
@ -958,12 +491,12 @@ public class Rule implements Comparable<Rule>
}
Miscellaneous.logEvent("i", "Rule", String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.ruleActivationComplete), Rule.this.getName()), 2);
}
else
{
Miscellaneous.logEvent("i", "Rule", "Request to activate rule " + Rule.this.getName() + ", but it is the last one that was activated. Won't do it again.", 3);
return false;
}
// }
// else
// {
// Miscellaneous.logEvent("i", "Rule", "Request to activate rule " + Rule.this.getName() + ", but it is the last one that was activated. Won't do it again.", 3);
// return false;
// }
return true;
}

View File

@ -123,7 +123,7 @@
android:scheme="package" />-->
</intent-filter>
</receiver>
<receiver android:name=".receivers.AlarmListener" />
<receiver android:name=".receivers.DateTimeListener" />
<receiver android:name=".receivers.ConnectivityReceiver" />
<receiver android:name=".receivers.TimeZoneListener" />

View File

@ -1,38 +1,22 @@
package com.jens.automation2;
import static com.jens.automation2.Trigger.triggerParameter2Split;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Looper;
import android.service.notification.StatusBarNotification;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.widget.Toast;
import com.google.android.gms.location.DetectedActivity;
import com.jens.automation2.location.LocationProvider;
import com.jens.automation2.location.WifiBroadcastReceiver;
import com.jens.automation2.receivers.ActivityDetectionReceiver;
import com.jens.automation2.receivers.BatteryReceiver;
import com.jens.automation2.receivers.BluetoothReceiver;
import com.jens.automation2.receivers.ConnectivityReceiver;
import com.jens.automation2.receivers.HeadphoneJackListener;
import com.jens.automation2.receivers.NfcReceiver;
import com.jens.automation2.receivers.NoiseListener;
import com.jens.automation2.receivers.NotificationListener;
import com.jens.automation2.receivers.PhoneStatusListener;
import com.jens.automation2.receivers.ProcessListener;
import java.sql.Time;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import static com.jens.automation2.Trigger.triggerParameter2Split;
import static com.jens.automation2.receivers.NotificationListener.EXTRA_TEXT;
import static com.jens.automation2.receivers.NotificationListener.EXTRA_TITLE;
public class Rule implements Comparable<Rule>
{
@ -341,6 +325,8 @@ public class Rule implements Comparable<Rule>
return true;
case setWifiTethering:
return true;
case setBluetoothTethering:
return true;
default:
break;
}
@ -348,6 +334,22 @@ public class Rule implements Comparable<Rule>
return false;
}
public boolean hasNotAppliedSinceLastExecution()
{
for(Trigger oneTrigger : this.getTriggerSet())
{
if (oneTrigger.hasStateNotAppliedSinceLastRuleExecution())
return true;
}
return false;
}
public boolean getsGreenLight(Context context)
{
return isRuleActive() && applies(context) && hasNotAppliedSinceLastExecution();
}
public boolean applies(Context context)
{
@ -361,533 +363,8 @@ public class Rule implements Comparable<Rule>
{
for(Trigger oneTrigger : this.getTriggerSet())
{
if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.pointOfInterest))
{
// Am I here?
PointOfInterest activePoi = PointOfInterest.getActivePoi();
if(activePoi != null) //entering one
{
if(oneTrigger.getPointOfInterest() != null)
{
if(activePoi.equals(oneTrigger.getPointOfInterest()))
{
if(!oneTrigger.getTriggerParameter())
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Rule doesn't apply. We're entering POI: " + oneTrigger.getPointOfInterest().getName() + ", not leaving it.", 4);
return false;
}
}
else
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Rule doesn't apply. This is " + activePoi.getName() + ", not " + oneTrigger.getPointOfInterest().getName() + ".", 4);
return false;
}
}
else if(oneTrigger.getPointOfInterest() == null)
{
if(oneTrigger.getTriggerParameter())
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Rule doesn't apply. We're at a POI. Rule specifies not at none, so leaving any.", 4);
return false;
}
}
}
else //leaving one
{
// We are not at any POI. But if this trigger requires us NOT to be there, that may be fine.
if(oneTrigger.getPointOfInterest() != null)
{
// if(activePoi.equals(oneTrigger.getPointOfInterest()))
// {
if(!oneTrigger.getTriggerParameter())
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "We are not at POI \"" + oneTrigger.getPointOfInterest().getName() + "\". But since that's required by this rule that's fine.", 4);
}
else
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Rule doesn't apply. We're not at POI \"" + oneTrigger.getPointOfInterest().getName() + "\".", 3);
return false;
}
// }
}
else if(oneTrigger.getPointOfInterest() == null)
{
if(!oneTrigger.getTriggerParameter())
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Rule doesn't apply. We're at no POI. Rule specifies to be at anyone.", 5);
return false;
}
}
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.timeFrame))
{
Date now = new Date();
String timeString = String.valueOf(now.getHours()) + ":" + String.valueOf(now.getMinutes()) + ":" + String.valueOf(now.getSeconds());
Time nowTime = Time.valueOf(timeString);
Calendar calNow = Calendar.getInstance();
if(oneTrigger.getTimeFrame().getDayList().contains(calNow.get(Calendar.DAY_OF_WEEK)))
{
if(
// Regular case, start time is lower than end time
(
Miscellaneous.compareTimes(oneTrigger.getTimeFrame().getTriggerTimeStart(), nowTime) >= 0
&&
Miscellaneous.compareTimes(nowTime, oneTrigger.getTimeFrame().getTriggerTimeStop()) > 0
)
||
// Other case, start time higher than end time, timeframe goes over midnight
(
Miscellaneous.compareTimes(oneTrigger.getTimeFrame().getTriggerTimeStart(), oneTrigger.getTimeFrame().getTriggerTimeStop()) < 0
&&
(Miscellaneous.compareTimes(oneTrigger.getTimeFrame().getTriggerTimeStart(), nowTime) >= 0
||
Miscellaneous.compareTimes(nowTime, oneTrigger.getTimeFrame().getTriggerTimeStop()) > 0)
)
)
{
// We are in the timeframe
Miscellaneous.logEvent("i", "TimeFrame", "We're currently (" + calNow.getTime().toString() + ") in the specified TimeFrame (" + oneTrigger.getTimeFrame().toString() + "). Trigger of Rule " + this.getName() + " applies.", 3);
if(oneTrigger.getTriggerParameter())
{
Miscellaneous.logEvent("i", "TimeFrame", "That's what's specified. Trigger of Rule " + this.getName() + " applies.", 3);
//return true;
}
else
{
Miscellaneous.logEvent("i", "TimeFrame", "That's not what's specified. Trigger of Rule " + this.getName() + " doesn't apply.", 3);
return false;
}
}
else
{
Miscellaneous.logEvent("i", "TimeFrame", "We're currently (" + calNow.getTime().toString() + ", Day: " + String.valueOf(calNow.get(Calendar.DAY_OF_WEEK)) + ") not in the specified TimeFrame (" + oneTrigger.getTimeFrame().toString() + ") because of the time. Trigger of Rule " + this.getName() + " doesn\'t apply..", 5);
if(!oneTrigger.getTriggerParameter())
{
Miscellaneous.logEvent("i", "TimeFrame", "That's what's specified. Trigger of Rule " + this.getName() + " applies.", 5);
//return true;
}
else
{
Miscellaneous.logEvent("i", "TimeFrame", "That's not what's specified. Trigger of Rule " + this.getName() + " doesn't apply.", 5);
return false;
}
// return false;
}
}
else
{
Miscellaneous.logEvent("i", "TimeFrame", "We're currently (" + calNow.getTime().toString() + ", Day: " + String.valueOf(calNow.get(Calendar.DAY_OF_WEEK)) + ") not in the specified TimeFrame (" + oneTrigger.getTimeFrame().toString() + ") because of the day. Trigger of Rule " + this.getName() + " doesn\'t apply.", 5);
return false;
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.charging))
{
if(BatteryReceiver.isDeviceCharging(context) == 0)
{
return false; // unknown charging state, can't activate rule under these conditions
}
else if(BatteryReceiver.isDeviceCharging(context) == 1)
{
if(oneTrigger.getTriggerParameter()) //rule says when charging, but we're currently discharging
return false;
}
else if(BatteryReceiver.isDeviceCharging(context) == 2)
{
if(!oneTrigger.getTriggerParameter()) //rule says when discharging, but we're currently charging
return false;
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.usb_host_connection))
{
if(BatteryReceiver.isUsbHostConnected() != oneTrigger.getTriggerParameter())
{
return false;
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.batteryLevel))
{
if(oneTrigger.getTriggerParameter())
{
if(BatteryReceiver.getBatteryLevel() <= oneTrigger.getBatteryLevel())
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyBatteryLowerThan) + " " + String.valueOf(oneTrigger.getBatteryLevel()), 3);
return false;
}
}
else
{
if(oneTrigger.getBatteryLevel() >= oneTrigger.getBatteryLevel())
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyBatteryHigherThan) + " " + String.valueOf(oneTrigger.getBatteryLevel()), 3);
return false;
}
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.speed))
{
if(oneTrigger.getTriggerParameter())
{
if(LocationProvider.getSpeed() < oneTrigger.getSpeed())
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyWeAreSlowerThan) + " " + String.valueOf(oneTrigger.getSpeed()), 3);
return false;
}
}
else
{
if(LocationProvider.getSpeed() > oneTrigger.getSpeed())
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyWeAreFasterThan) + " " + String.valueOf(oneTrigger.getSpeed()), 3);
return false;
}
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.noiseLevel))
{
if(oneTrigger.getTriggerParameter())
{
if(NoiseListener.getNoiseLevelDb() < oneTrigger.getNoiseLevelDb())
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyItsQuieterThan) + " " + String.valueOf(oneTrigger.getNoiseLevelDb()), 3);
return false;
}
}
else
{
if(NoiseListener.getNoiseLevelDb() > oneTrigger.getNoiseLevelDb())
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyItsLouderThan) + " " + String.valueOf(oneTrigger.getNoiseLevelDb()), 3);
return false;
}
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.wifiConnection))
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Checking for wifi state", 4);
if(oneTrigger.getTriggerParameter() == WifiBroadcastReceiver.lastConnectedState) // connected / disconnected
{
if(oneTrigger.getTriggerParameter2().length() > 0) // only check if any wifi name specified, otherwise any wifi will do
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Wifi name specified, checking that.", 4);
if(!WifiBroadcastReceiver.getLastWifiSsid().equals(oneTrigger.getTriggerParameter2()))
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), String.format(context.getResources().getString(R.string.ruleDoesntApplyNotTheCorrectSsid), oneTrigger.getTriggerParameter2(), WifiBroadcastReceiver.getLastWifiSsid()), 3);
return false;
}
else
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Wifi name matches. Rule will apply.", 4);
}
else
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "No wifi name specified, any will do.", 4);
}
else
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Wifi state not correct, demanded " + String.valueOf(oneTrigger.getTriggerParameter() + ", got " + String.valueOf(WifiBroadcastReceiver.lastConnectedState)), 4);
return false;
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.process_started_stopped))
{
boolean running = ProcessListener.getRunningApps().contains(oneTrigger.getProcessName());
if(running)
Miscellaneous.logEvent("i", "ProcessMonitoring", "App " + oneTrigger.getProcessName() + " is currently running.", 4);
else
Miscellaneous.logEvent("i", "ProcessMonitoring", "App " + oneTrigger.getProcessName() + " is not running.", 4);
if(running != oneTrigger.getTriggerParameter())
{
Miscellaneous.logEvent("i", "ProcessMonitoring", "Trigger doesn't apply.", 4);
return false;
}
Miscellaneous.logEvent("i", "ProcessMonitoring", "Trigger applies.", 4);
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.airplaneMode))
{
if(ConnectivityReceiver.isAirplaneMode(context) != oneTrigger.getTriggerParameter())
{
return false;
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.roaming))
{
if(ConnectivityReceiver.isRoaming(context) != oneTrigger.getTriggerParameter())
{
return false;
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.phoneCall))
{
String[] elements = oneTrigger.getTriggerParameter2().split(triggerParameter2Split);
// state dir number
if(elements[2].equals(Trigger.triggerPhoneCallNumberAny) || Miscellaneous.comparePhoneNumbers(PhoneStatusListener.getLastPhoneNumber(), elements[2]) || (Miscellaneous.isRegularExpression(elements[2]) && PhoneStatusListener.getLastPhoneNumber().matches(elements[2])))
{
//if(PhoneStatusListener.isInACall() == oneTrigger.getTriggerParameter())
if(
(elements[0].equals(Trigger.triggerPhoneCallStateRinging) && PhoneStatusListener.getCurrentState() == TelephonyManager.CALL_STATE_RINGING)
||
(elements[0].equals(Trigger.triggerPhoneCallStateStarted) && PhoneStatusListener.getCurrentState() == TelephonyManager.CALL_STATE_OFFHOOK)
||
(elements[0].equals(Trigger.triggerPhoneCallStateStopped) && PhoneStatusListener.getCurrentState() == TelephonyManager.CALL_STATE_IDLE)
)
{
if(
elements[1].equals(Trigger.triggerPhoneCallDirectionAny)
||
(elements[1].equals(Trigger.triggerPhoneCallDirectionIncoming) && PhoneStatusListener.getLastPhoneDirection() == 1)
||
(elements[1].equals(Trigger.triggerPhoneCallDirectionOutgoing) && PhoneStatusListener.getLastPhoneDirection() == 2)
)
{
// Trigger conditions are met
}
else
{
Miscellaneous.logEvent("i", "Rule", "Rule doesn't apply. Wrong direction. Demanded: " + String.valueOf(oneTrigger.getPhoneDirection()) + ", got: " + String.valueOf(PhoneStatusListener.getLastPhoneDirection()), 4);
return false;
}
}
else
{
Miscellaneous.logEvent("i", "Rule", "Rule doesn't apply. Wrong call status. Demanded: " + String.valueOf(oneTrigger.getTriggerParameter()) + ", got: " + String.valueOf(PhoneStatusListener.isInACall()), 4);
return false;
}
}
else
{
Miscellaneous.logEvent("i", "Rule", "Rule doesn't apply. Wrong phone number. Demanded: " + oneTrigger.getPhoneNumber() + ", got: " + PhoneStatusListener.getLastPhoneNumber(), 4);
return false;
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.nfcTag))
{
if(NfcReceiver.lastReadLabel == null)
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyNoTagLabel), 3);
return false;
}
else if(!NfcReceiver.lastReadLabel.equals(oneTrigger.getNfcTagId()))
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyWrongTagLabel) + " " + NfcReceiver.lastReadLabel + " / " + oneTrigger.getNfcTagId(), 3);
return false;
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.activityDetection))
{
if(ActivityDetectionReceiver.getActivityDetectionLastResult() != null)
{
boolean found = false;
for(DetectedActivity oneDetectedActivity : ActivityDetectionReceiver.getActivityDetectionLastResult().getProbableActivities())
{
if(oneDetectedActivity.getType() == oneTrigger.getActivityDetectionType())
found = true;
}
if(!found)
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), String.format(context.getResources().getString(R.string.ruleDoesntApplyActivityNotPresent), ActivityDetectionReceiver.getDescription(oneTrigger.getActivityDetectionType())), 3);
return false;
}
else
{
for(DetectedActivity oneDetectedActivity : ActivityDetectionReceiver.getActivityDetectionLastResult().getProbableActivities())
{
if(oneDetectedActivity.getType() == oneTrigger.getActivityDetectionType() && oneDetectedActivity.getConfidence() < Settings.activityDetectionRequiredProbability)
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), String.format(context.getResources().getString(R.string.ruleDoesntApplyActivityGivenButTooLowProbability), ActivityDetectionReceiver.getDescription(oneDetectedActivity.getType()), String.valueOf(oneDetectedActivity.getConfidence()), String.valueOf(Settings.activityDetectionRequiredProbability)), 3);
return false;
}
}
}
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.bluetoothConnection))
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Checking for bluetooth...", 4);
if(oneTrigger.getBluetoothDeviceAddress().equals("<any>"))
{
if(oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED))
{
if(BluetoothReceiver.isAnyDeviceConnected() != oneTrigger.getTriggerParameter())
return false;
}
else if((oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)))
{
if(BluetoothReceiver.isAnyDeviceConnected() != oneTrigger.getTriggerParameter())
return false;
}
else
{
// range
if(BluetoothReceiver.isAnyDeviceInRange() != oneTrigger.getTriggerParameter())
return false;
}
}
else if(oneTrigger.getBluetoothDeviceAddress().equals("<none>"))
{
if(oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED))
{
if(BluetoothReceiver.isAnyDeviceConnected() == oneTrigger.getTriggerParameter())
return false;
}
else if((oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)))
{
if(BluetoothReceiver.isAnyDeviceConnected() == oneTrigger.getTriggerParameter())
return false;
}
else
{
// range
if(BluetoothReceiver.isAnyDeviceInRange() == oneTrigger.getTriggerParameter())
return false;
}
}
else if(oneTrigger.getBluetoothDeviceAddress().length() > 0)
{
if(oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED))
{
if(BluetoothReceiver.isDeviceCurrentlyConnected(BluetoothReceiver.getDeviceByAddress(oneTrigger.getBluetoothDeviceAddress())) != oneTrigger.getTriggerParameter())
return false;
}
else if((oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)))
{
if(BluetoothReceiver.isDeviceCurrentlyConnected(BluetoothReceiver.getDeviceByAddress(oneTrigger.getBluetoothDeviceAddress())) != oneTrigger.getTriggerParameter())
return false;
}
else
{
// range
if(BluetoothReceiver.isDeviceInRange(BluetoothReceiver.getDeviceByAddress(oneTrigger.getBluetoothDeviceAddress())) != oneTrigger.getTriggerParameter())
return false;
}
}
else
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyStateNotCorrect), 3);
return false;
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.headsetPlugged))
{
if(HeadphoneJackListener.isHeadsetConnected() != oneTrigger.getTriggerParameter())
return false;
else
if(oneTrigger.getHeadphoneType() != 2 && oneTrigger.getHeadphoneType() != HeadphoneJackListener.getHeadphoneType())
{
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyWrongHeadphoneType), 3);
return false;
}
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.notification))
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
{
String[] params = oneTrigger.getTriggerParameter2().split(triggerParameter2Split);
String myApp = params[0];
String myTitleDir = params[1];
String myTitle = params[2];
String myTextDir = params[3];
String myText;
if (params.length >= 5)
myText = params[4];
else
myText = "";
if(oneTrigger.getTriggerParameter())
{
// Check an active notification that is still there
boolean foundMatch = false;
for (StatusBarNotification sbn : NotificationListener.getInstance().getActiveNotifications())
{
if(getLastExecution() == null || sbn.getPostTime() > this.lastExecution.getTimeInMillis())
{
String app = sbn.getPackageName();
String title = sbn.getNotification().extras.getString(EXTRA_TITLE);
String text = sbn.getNotification().extras.getString(EXTRA_TEXT);
Miscellaneous.logEvent("i", "NotificationCheck", "Checking if this notification matches our rule " + this.getName() + ". App: " + app + ", title: " + title + ", text: " + text, 5);
if (!myApp.equals("-1"))
{
if (!app.equalsIgnoreCase(myApp))
{
Miscellaneous.logEvent("i", "NotificationCheck", "Notification app name does not match rule.", 5);
continue;
}
}
if (myTitle.length() > 0)
{
if (!Miscellaneous.compare(myTitleDir, myTitle, title))
{
Miscellaneous.logEvent("i", "NotificationCheck", "Notification title does not match rule.", 5);
continue;
}
}
if (myText.length() > 0)
{
if (!Miscellaneous.compare(myTextDir, myText, text))
{
Miscellaneous.logEvent("i", "NotificationCheck", "Notification text does not match rule.", 5);
continue;
}
}
foundMatch = true;
break;
}
}
if(!foundMatch)
return false;
}
else
{
// check a notification that is gone
if(NotificationListener.getLastNotification() != null)
{
if(!NotificationListener.getLastNotification().isCreated())
{
String app = NotificationListener.getLastNotification().getApp();
String title = NotificationListener.getLastNotification().getTitle();
String text = NotificationListener.getLastNotification().getText();
if (!myApp.equals("-1"))
{
if (!app.equalsIgnoreCase(myApp))
return false;
}
if (myTitle.length() > 0)
{
if (!Miscellaneous.compare(myTitleDir, title, myTitle))
return false;
}
if (myText.length() > 0)
{
if (!Miscellaneous.compare(myTextDir, text, myText))
return false;
}
}
else
return false;
}
}
}
}
if (!oneTrigger.applies(null, context))
return false;
}
return true;
@ -896,6 +373,44 @@ public class Rule implements Comparable<Rule>
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), String.format(context.getResources().getString(R.string.ruleIsDeactivatedCantApply), this.getName()), 3);
return false;
}
/**
* This is actually a function of the class Trigger, but Rule is already distinguished by flavors, Trigger is not.
* Hence it is here.
* @param oneTrigger
* @return
*/
boolean checkActivityDetection(Trigger oneTrigger)
{
if (ActivityDetectionReceiver.getActivityDetectionLastResult() != null)
{
boolean found = false;
for (DetectedActivity oneDetectedActivity : ActivityDetectionReceiver.getActivityDetectionLastResult().getProbableActivities())
{
if (oneDetectedActivity.getType() == oneTrigger.getActivityDetectionType())
found = true;
}
if (!found)
{
Miscellaneous.logEvent("i", String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), this.getName()), String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.ruleDoesntApplyActivityNotPresent), ActivityDetectionReceiver.getDescription(oneTrigger.getActivityDetectionType())), 3);
return false;
}
else
{
for (DetectedActivity oneDetectedActivity : ActivityDetectionReceiver.getActivityDetectionLastResult().getProbableActivities())
{
if (oneDetectedActivity.getType() == oneTrigger.getActivityDetectionType() && oneDetectedActivity.getConfidence() < Settings.activityDetectionRequiredProbability)
{
Miscellaneous.logEvent("i", String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), this.getName()), String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.ruleDoesntApplyActivityGivenButTooLowProbability), ActivityDetectionReceiver.getDescription(oneDetectedActivity.getType()), String.valueOf(oneDetectedActivity.getConfidence()), String.valueOf(Settings.activityDetectionRequiredProbability)), 3);
return false;
}
}
}
}
return true;
}
private class ActivateRuleTask extends AsyncTask<Object, String, Void>
{
@ -914,7 +429,8 @@ public class Rule implements Comparable<Rule>
if (Looper.myLooper() == null)
Looper.prepare();
setLastExecution(Calendar.getInstance());
wasActivated = activateInternally((AutomationService)params[0], (Boolean)params[1]);
return null;
@ -939,7 +455,7 @@ public class Rule implements Comparable<Rule>
*/
if(wasActivated)
{
setLastExecution(Calendar.getInstance());
// setLastExecution(Calendar.getInstance());
AutomationService.updateNotification();
ActivityMainScreen.updateMainScreen();
super.onPostExecute(result);
@ -957,8 +473,9 @@ public class Rule implements Comparable<Rule>
boolean notLastActive = getLastActivatedRule() == null || !getLastActivatedRule().equals(Rule.this);
boolean doToggle = ruleToggle && isActuallyToggable;
if(notLastActive || force || doToggle)
{
//if(notLastActive || force || doToggle)
// if(force || doToggle)
// {
String message;
if(!doToggle)
message = String.format(automationService.getResources().getString(R.string.ruleActivate), Rule.this.getName());
@ -1002,12 +519,12 @@ public class Rule implements Comparable<Rule>
}
Miscellaneous.logEvent("i", "Rule", String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.ruleActivationComplete), Rule.this.getName()), 2);
}
else
{
Miscellaneous.logEvent("i", "Rule", "Request to activate rule " + Rule.this.getName() + ", but it is the last one that was activated. Won't do it again.", 3);
return false;
}
// }
// else
// {
// Miscellaneous.logEvent("i", "Rule", "Request to activate rule " + Rule.this.getName() + ", but it is the last one that was activated. Won't do it again.", 3);
// return false;
// }
return true;
}

View File

@ -5,6 +5,7 @@ import android.os.AsyncTask;
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;
@ -13,6 +14,8 @@ import java.util.Locale;
public class Action
{
Rule parentRule = null;
public static final String actionParameter2Split = "ap2split";
public static final String intentPairSeperator = "intPairSplit";
public static final String vibrateSeparator = ",";
@ -22,6 +25,7 @@ public class Action
setBluetooth,
setUsbTethering,
setWifiTethering,
setBluetoothTethering,
setDisplayRotation,
turnWifiOn,turnWifiOff,
turnBluetoothOn,turnBluetoothOff,
@ -29,10 +33,11 @@ public class Action
changeSoundProfile,
turnUsbTetheringOn,turnUsbTetheringOff,
turnWifiTetheringOn,turnWifiTetheringOff,
enableScreenRotation, disableScreenRotation,
enableScreenRotation,disableScreenRotation,
startOtherActivity,
waitBeforeNextAction,
wakeupDevice,
turnScreenOnOrOff,
setAirplaneMode,
setDataConnection,
speakText,
@ -52,6 +57,8 @@ public class Action
return context.getResources().getString(R.string.actionSetBluetooth);
case setWifiTethering:
return context.getResources().getString(R.string.actionSetWifiTethering);
case setBluetoothTethering:
return context.getResources().getString(R.string.actionSetBluetoothTethering);
case setUsbTethering:
return context.getResources().getString(R.string.actionSetUsbTethering);
case setDisplayRotation:
@ -86,6 +93,8 @@ public class Action
return context.getResources().getString(R.string.waitBeforeNextAction);
case wakeupDevice:
return context.getResources().getString(R.string.wakeupDevice);
case turnScreenOnOrOff:
return context.getResources().getString(R.string.turnScreenOnOrOff);
case vibrate:
return context.getResources().getString(R.string.vibrate);
case setAirplaneMode:
@ -176,6 +185,13 @@ public class Action
else
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.actionTurnWifiTetheringOff));
}
else if(this.getAction().equals(Action_Enum.setBluetoothTethering))
{
if(this.getParameter1())
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.actionTurnBluetoothTetheringOn));
else
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.actionTurnBluetoothTetheringOff));
}
else if(this.getAction().equals(Action_Enum.setDisplayRotation))
{
if(this.getParameter1())
@ -221,6 +237,13 @@ public class Action
{
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.wakeupDevice));
}
else if(this.getAction().equals(Action_Enum.turnScreenOnOrOff))
{
if(getParameter1())
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.turnScreenOn));
else
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.turnScreenOff));
}
else if(this.getAction().equals(Action_Enum.playSound))
{
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.playSound));
@ -273,6 +296,16 @@ public class Action
return returnString.toString();
}
public Rule getParentRule()
{
return parentRule;
}
public void setParentRule(Rule parentRule)
{
this.parentRule = parentRule;
}
public static CharSequence[] getActionTypesAsArray()
{
ArrayList<String> actionTypesList = new ArrayList<String>();
@ -365,11 +398,14 @@ public class Action
Actions.setUsbTethering(context, getParameter1(), toggleActionIfPossible);
break;
case setWifi:
Actions.setWifi(context, getParameter1(), toggleActionIfPossible);
Actions.WifiStuff.setWifi(context, getParameter1(), toggleActionIfPossible);
break;
case setWifiTethering:
Actions.setWifiTethering(context, getParameter1(), toggleActionIfPossible);
break;
case setBluetoothTethering:
Actions.BluetoothTetheringClass.setBluetoothTethering(context, getParameter1(), toggleActionIfPossible);
break;
case setDisplayRotation:
Actions.setDisplayRotation(context, getParameter1(), toggleActionIfPossible);
break;
@ -381,7 +417,7 @@ public class Action
break;
case wakeupDevice:
Actions.wakeupDevice(Long.parseLong(this.getParameter2()));
// wakeupDevice() will create a seperate thread. That'll take some time, we wait 100ms.
// wakeupDevice() will create a separate thread. That'll take some time, we wait 100ms.
try
{
Thread.sleep(100);
@ -391,6 +427,28 @@ public class Action
e.printStackTrace();
}
break;
case turnScreenOnOrOff:
if(getParameter1())
{
if(StringUtils.isNumeric(this.getParameter2()))
Actions.wakeupDevice(Long.parseLong(this.getParameter2()));
else
Actions.wakeupDevice((long)1000);
// wakeupDevice() will create a separate thread. That'll take some time, we wait 100ms.
try
{
Thread.sleep(100);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
else
{
Actions.turnOffScreen();
}
break;
case setAirplaneMode:
Actions.setAirplaneMode(this.getParameter1(), toggleActionIfPossible);
break;

View File

@ -3,8 +3,13 @@ package com.jens.automation2;
import android.Manifest;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.admin.DevicePolicyManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
@ -23,10 +28,11 @@ import android.telephony.SmsManager;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import android.widget.Toast;
import androidx.annotation.RequiresApi;
import com.jens.automation2.actions.wifi_router.MyOnStartTetheringCallback;
import com.jens.automation2.actions.wifi_router.MyOreoWifiManager;
import com.jens.automation2.location.WifiBroadcastReceiver;
@ -41,13 +47,16 @@ import org.apache.http.conn.util.InetAddressUtils;
import org.apache.http.impl.client.DefaultHttpClient;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.security.KeyStore;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import javax.net.ssl.SSLContext;
@ -70,48 +79,85 @@ public class Actions
public static final String wireguard_tunnel_down = "com.wireguard.android.action.SET_TUNNEL_DOWN";
public static final String wireguard_tunnel_refresh = "com.wireguard.android.action.REFRESH_TUNNEL_STATES";
public static Boolean setWifi(Context context, Boolean desiredState, boolean toggleActionIfPossible)
public static class WifiStuff
{
Miscellaneous.logEvent("i", "Wifi", "Changing Wifi to " + String.valueOf(desiredState), 4);
if (desiredState && Settings.useWifiForPositioning)
WifiBroadcastReceiver.startWifiReceiver(autoMationServerRef.getLocationProvider());
WifiManager myWifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
// toggle
if (toggleActionIfPossible)
public static Boolean setWifi(Context context, Boolean desiredState, boolean toggleActionIfPossible)
{
Toast.makeText(context, context.getResources().getString(R.string.toggling) + " " + context.getResources().getString(R.string.wifi), Toast.LENGTH_LONG).show();
desiredState = !myWifi.isWifiEnabled();
if(context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.Q)
return setWifiWithRoot(context, desiredState, toggleActionIfPossible);
else
return setWifiOldFashioned(context, desiredState, toggleActionIfPossible);
}
// Only perform action if necessary
if ((!myWifi.isWifiEnabled() && desiredState) | (myWifi.isWifiEnabled() && !desiredState))
public static Boolean setWifiWithRoot(Context context, Boolean desiredState, boolean toggleActionIfPossible)
{
String wifiString = "";
Miscellaneous.logEvent("i", "Wifi", "Changing wifi to " + String.valueOf(desiredState) + ", but with root permissions.", 4);
if (desiredState)
{
wifiString = context.getResources().getString(R.string.activating) + " " + context.getResources().getString(R.string.wifi);
}
String command = null;
int state = 0;
String desiredStateString;
if(desiredState)
desiredStateString = "enable";
else
desiredStateString = "disable";
try
{
wifiString = context.getResources().getString(R.string.deactivating) + " " + context.getResources().getString(R.string.wifi);
command = "svc wifi " + desiredStateString;
Miscellaneous.logEvent("i", "setWifiWithRoot()", "Running command as root: " + command.toString(), 5);
return executeCommandViaSu(new String[]{command});
}
catch (Exception e)
{
// Oops! Something went wrong, so we throw the exception here.
throw e;
}
Toast.makeText(context, wifiString, Toast.LENGTH_LONG).show();
boolean returnValue = myWifi.setWifiEnabled(desiredState);
if (!returnValue)
Miscellaneous.logEvent("i", "Wifi", "Error changing Wifi to " + String.valueOf(desiredState), 2);
else
Miscellaneous.logEvent("i", "Wifi", "Wifi changed to " + String.valueOf(desiredState), 2);
return returnValue;
}
return true;
public static Boolean setWifiOldFashioned(Context context, Boolean desiredState, boolean toggleActionIfPossible)
{
Miscellaneous.logEvent("i", "Wifi", "Changing wifi to " + String.valueOf(desiredState), 4);
if (desiredState && Settings.useWifiForPositioning)
WifiBroadcastReceiver.startWifiReceiver(autoMationServerRef.getLocationProvider());
WifiManager myWifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
// toggle
if (toggleActionIfPossible)
{
Toast.makeText(context, context.getResources().getString(R.string.toggling) + " " + context.getResources().getString(R.string.wifi), Toast.LENGTH_LONG).show();
desiredState = !myWifi.isWifiEnabled();
}
// Only perform action if necessary
if ((!myWifi.isWifiEnabled() && desiredState) | (myWifi.isWifiEnabled() && !desiredState))
{
String wifiString = "";
if (desiredState)
{
wifiString = context.getResources().getString(R.string.activating) + " " + context.getResources().getString(R.string.wifi);
}
else
{
wifiString = context.getResources().getString(R.string.deactivating) + " " + context.getResources().getString(R.string.wifi);
}
Toast.makeText(context, wifiString, Toast.LENGTH_LONG).show();
boolean returnValue = myWifi.setWifiEnabled(desiredState);
if (!returnValue)
Miscellaneous.logEvent("i", "Wifi", "Error changing Wifi to " + String.valueOf(desiredState), 2);
else
Miscellaneous.logEvent("i", "Wifi", "Wifi changed to " + String.valueOf(desiredState), 2);
return returnValue;
}
return true;
}
}
public static void setDisplayRotation(Context myContext, Boolean desiredState, boolean toggleActionIfPossible)
@ -265,6 +311,149 @@ public class Actions
return true;
}
public static class BluetoothTetheringClass
{
static Object instance = null;
static Method setTetheringOn = null;
static Method isTetheringOn = null;
static Object mutex = new Object();
public static Boolean setBluetoothTethering(Context context, Boolean desiredState, boolean toggleActionIfPossible)
{
Miscellaneous.logEvent("i", "Bluetooth Tethering", "Changing Bluetooth Tethering to " + String.valueOf(desiredState), 4);
// boolean state = isTetheringOn(context);
// if (toggleActionIfPossible)
// {
// Miscellaneous.logEvent("i", "Bluetooth Tethering", context.getResources().getString(R.string.toggling), 2);
// desiredState = !state;
// }
// if (((state && !desiredState) || (!state && desiredState)))
// {
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
Class<?> classBluetoothPan = null;
Constructor<?> BTPanCtor = null;
Object BTSrvInstance = null;
Method mBTPanConnect = null;
String sClassName = "android.bluetooth.BluetoothPan";
try
{
classBluetoothPan = Class.forName(sClassName);
Constructor<?> ctor = classBluetoothPan.getDeclaredConstructor(Context.class, BluetoothProfile.ServiceListener.class);
ctor.setAccessible(true);
// Set Tethering ON
Class[] paramSet = new Class[1];
paramSet[0] = boolean.class;
synchronized (mutex)
{
setTetheringOn = classBluetoothPan.getDeclaredMethod("setBluetoothTethering", paramSet);
isTetheringOn = classBluetoothPan.getDeclaredMethod("isTetheringOn", null);
instance = ctor.newInstance(context, new BTPanServiceListener(context));
}
classBluetoothPan = Class.forName("android.bluetooth.BluetoothPan");
mBTPanConnect = classBluetoothPan.getDeclaredMethod("connect", BluetoothDevice.class);
BTPanCtor = classBluetoothPan.getDeclaredConstructor(Context.class, BluetoothProfile.ServiceListener.class);
BTPanCtor.setAccessible(true);
BTSrvInstance = BTPanCtor.newInstance(context, new BTPanServiceListener(context));
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
// If there are paired devices
if (pairedDevices.size() > 0)
{
// Loop through paired devices
for (BluetoothDevice device : pairedDevices)
{
try
{
mBTPanConnect.invoke(BTSrvInstance, device);
}
catch (Exception e)
{
Miscellaneous.logEvent("e", "Bluetooth Tethering", Log.getStackTraceString(e), 1);
}
}
}
return true;
}
catch (NoSuchMethodException e)
{
Miscellaneous.logEvent("e", "Bluetooth Tethering", Log.getStackTraceString(e), 1);
}
catch (ClassNotFoundException e)
{
Miscellaneous.logEvent("e", "Bluetooth Tethering", Log.getStackTraceString(e), 1);
}
catch(InvocationTargetException e)
{
/*
Exact error message: "Bluetooth binder is null"
This means this device doesn't have bluetooth.
*/
Miscellaneous.logEvent("e", "Bluetooth Tethering", "Device probably doesn't have bluetooth. " + Log.getStackTraceString(e), 1);
Toast.makeText(context, context.getResources().getString(R.string.deviceDoesNotHaveBluetooth), Toast.LENGTH_SHORT).show();
}
catch (Exception e)
{
Miscellaneous.logEvent("e", "Bluetooth Tethering", Log.getStackTraceString(e), 1);
}
return false;
}
public static class BTPanServiceListener implements BluetoothProfile.ServiceListener
{
private final Context context;
public BTPanServiceListener(final Context context)
{
this.context = context;
}
@Override
public void onServiceConnected(final int profile, final BluetoothProfile proxy)
{
//Some code must be here or the compiler will optimize away this callback.
try
{
synchronized (mutex)
{
setTetheringOn.invoke(instance, true);
if ((Boolean) isTetheringOn.invoke(instance, null))
{
Miscellaneous.logEvent("e", "Bluetooth Tethering", "BT Tethering is on", 1);
}
else
{
Miscellaneous.logEvent("e", "Bluetooth Tethering", "BT Tethering is off", 1);
}
}
}
catch (InvocationTargetException e)
{
Miscellaneous.logEvent("e", "Bluetooth Tethering", Log.getStackTraceString(e), 1);
}
catch (IllegalAccessException e)
{
Miscellaneous.logEvent("e", "Bluetooth Tethering", Log.getStackTraceString(e), 1);
}
}
@Override
public void onServiceDisconnected(final int profile)
{
}
}
}
public static boolean setUsbTethering(Context context2, Boolean desiredState, boolean toggleActionIfPossible)
{
//TODO:toggle not really implemented, yet
@ -459,12 +648,53 @@ public class Actions
return false;
}
public static void setSound(Context context, int soundSetting)
@RequiresApi(api = Build.VERSION_CODES.M)
public static void setDoNotDisturb(Context context, int desiredSetting)
{
Miscellaneous.logEvent("i", context.getResources().getString(R.string.soundSettings), "Changing sound to " + String.valueOf(soundSetting), 4);
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
// Check if the notification policy access has been granted for the app.
/* if (!notificationManager.isNotificationPolicyAccessGranted())
{
Intent intent = new Intent(android.provider.Settings.ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS);
startActivity(intent);
return;
}*/
notificationManager.setInterruptionFilter(desiredSetting);
/*if (notificationManager.getCurrentInterruptionFilter() == NotificationManager.INTERRUPTION_FILTER_ALL)
{
notificationManager.setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_NONE);
}
else
{
notificationManager.setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL);
}*/
}
@RequiresApi(api = Build.VERSION_CODES.M)
public static boolean isDoNotDisturbActive(Context context)
{
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
int result = notificationManager.getCurrentInterruptionFilter();
return (notificationManager.getCurrentInterruptionFilter() != NotificationManager.INTERRUPTION_FILTER_ALL);
}
public static void setSound(Context context, int desiredSoundSetting)
{
Miscellaneous.logEvent("i", context.getResources().getString(R.string.soundSettings), "Changing sound to " + String.valueOf(desiredSoundSetting), 4);
AudioManager myAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
myAudioManager.setRingerMode(soundSetting);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && desiredSoundSetting == AudioManager.RINGER_MODE_SILENT)
{
AudioManager am = (AudioManager) Miscellaneous.getAnyContext().getSystemService(Context.AUDIO_SERVICE);
am.setStreamVolume(AudioManager.STREAM_NOTIFICATION, 0, AudioManager.FLAG_PLAY_SOUND);
am.setVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER, AudioManager.VIBRATE_SETTING_OFF);
}
else
myAudioManager.setRingerMode(desiredSoundSetting);
}
private static String getIPAddressUsb(final boolean useIPv4)
@ -577,7 +807,19 @@ public class Actions
}
}
public void useDownloadedWebpage(String result)
public static void setDND(Context context, int desiredDndMode)
{
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
{
Miscellaneous.logEvent("i", context.getResources().getString(R.string.soundSettings), "Changing DND to " + String.valueOf(desiredDndMode), 4);
NotificationManager mNotificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.setInterruptionFilter(desiredDndMode);
}
else
Miscellaneous.logEvent("w", context.getResources().getString(R.string.soundSettings), "Cannot change DND to " + String.valueOf(desiredDndMode) + ". This Android version is too and doesn\'t have that feature, yet.", 4);
}
public void useDownloadedWebpage(String result)
{
// Toast.makeText(context, "Result: " + result, Toast.LENGTH_LONG).show();
}
@ -853,23 +1095,81 @@ public class Actions
@Override
public void run()
{
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
WakeLock wakeLock = pm.newWakeLock((WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP), "Automation:Wakelock");
wakeLock.acquire();
try
{
Thread.sleep(awakeTime);
}
catch (InterruptedException e)
{
Miscellaneous.logEvent("w", context.getResources().getString(R.string.wakeupDevice), "Error keeping device awake: " + Log.getStackTraceString(e), 4);
}
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
WakeLock wakeLock = pm.newWakeLock((PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP), "Automation:Wakelock");
wakeLock.acquire();
wakeLock.release();
try
{
Thread.sleep(awakeTime);
}
catch (InterruptedException e)
{
Miscellaneous.logEvent("w", context.getResources().getString(R.string.wakeupDevice), "Error keeping device awake: " + Log.getStackTraceString(e), 4);
}
wakeLock.release();
}
catch(Exception e)
{
Miscellaneous.logEvent("e", "Wakeup device action", "Error while waking up device: " + Log.getStackTraceString(e), 1);
}
}
}
public static void turnOnScreen()
{
// turn on screen
Miscellaneous.logEvent("i", "Actions", "Turning screen on.", 3);
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
WakeLock wakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, AutomationService.NOTIFICATION_CHANNEL_ID + ":turnOffScreen");
wakeLock.acquire();
}
@TargetApi(21) //Suppress lint error for PROXIMITY_SCREEN_OFF_WAKE_LOCK
public static void turnOffScreen()
{
Miscellaneous.logEvent("i", "Actions", "Turning screen off.", 3);
DevicePolicyManager deviceManger = (DevicePolicyManager)Miscellaneous.getAnyContext().getSystemService(Context. DEVICE_POLICY_SERVICE);
deviceManger.lockNow();
/*params.flags |= LayoutParams.FLAG_KEEP_SCREEN_ON;
params.screenBrightness = 0;
getWindow().setAttributes(params);
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
WakeLock wakeLock = pm.newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK,AutomationService.NOTIFICATION_CHANNEL_ID + ":turnOffScreen");
// WakeLock wakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK , AutomationService.NOTIFICATION_CHANNEL_ID + ":turnOffScreen");
wakeLock.acquire();
WakeLock wakeLock = pm.newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK, "tag");
// WakeLock wakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK , "tag");
wakeLock.acquire();*/
}
// using root
/*private void turnOffScreen()
{
try
{
Class c = Class.forName("android.os.PowerManager");
PowerManager mPowerManager = (PowerManager) this.getSystemService(Context.POWER_SERVICE);
for(Method m : c.getDeclaredMethods()){
if(m.getName().equals("goToSleep")){
m.setAccessible(true);
if(m.getParameterTypes().length == 1){
m.invoke(mPowerManager,SystemClock.uptimeMillis()-2);
}
}
}
}
catch (Exception e)
{
}
}*/
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
@SuppressLint("NewApi")
public static boolean setAirplaneMode(boolean desiredState, boolean toggleActionIfPossible)
@ -1143,7 +1443,7 @@ public class Actions
desiredState = !isEnabled;
}
if (Build.VERSION.SDK_INT <= 20)
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT_WATCH)
{
for (Method m : iConnectivityManagerClass.getDeclaredMethods())
{
@ -1169,23 +1469,48 @@ public class Actions
}
}
protected static boolean setDataConnectionWithRoot(boolean enable)
protected static boolean setDataConnectionWithRoot(boolean desiredState)
{
try
{
int desiredState = 0;
if (enable)
desiredState = 1;
if (MobileDataStuff.setMobileNetworkFromLollipop(desiredState, autoMationServerRef))
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.O_MR1)
{
Miscellaneous.logEvent("i", "setDataConnectionWithRoot()", Miscellaneous.getAnyContext().getResources().getString(R.string.dataConWithRootSuccess), 2);
return true;
if(MobileDataStuff.setMobileNetworkFromAndroid9(desiredState, autoMationServerRef))
{
Miscellaneous.logEvent("i", "setDataConnectionWithRoot()", Miscellaneous.getAnyContext().getResources().getString(R.string.dataConWithRootSuccess), 2);
return true;
}
else
{
Miscellaneous.logEvent("e", "setDataConnectionWithRoot()", Miscellaneous.getAnyContext().getResources().getString(R.string.dataConWithRootFail), 2);
return false;
}
}
else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP)
{
if (MobileDataStuff.setMobileNetworkTillAndroid5(desiredState, autoMationServerRef))
{
Miscellaneous.logEvent("i", "setDataConnectionWithRoot()", Miscellaneous.getAnyContext().getResources().getString(R.string.dataConWithRootSuccess), 2);
return true;
}
else
{
Miscellaneous.logEvent("e", "setDataConnectionWithRoot()", Miscellaneous.getAnyContext().getResources().getString(R.string.dataConWithRootFail), 2);
return false;
}
}
else
{
Miscellaneous.logEvent("e", "setDataConnectionWithRoot()", Miscellaneous.getAnyContext().getResources().getString(R.string.dataConWithRootFail), 2);
return false;
if (MobileDataStuff.setMobileNetworkAndroid6Till8(desiredState, autoMationServerRef))
{
Miscellaneous.logEvent("i", "setDataConnectionWithRoot()", Miscellaneous.getAnyContext().getResources().getString(R.string.dataConWithRootSuccess), 2);
return true;
}
else
{
Miscellaneous.logEvent("e", "setDataConnectionWithRoot()", Miscellaneous.getAnyContext().getResources().getString(R.string.dataConWithRootFail), 2);
return false;
}
}
}
catch (Exception e)
@ -1202,43 +1527,35 @@ public class Actions
}
@SuppressLint("NewApi")
public static boolean setMobileNetworkFromLollipop(int desiredState, Context context) throws Exception
public static boolean setMobileNetworkAndroid6Till8(boolean desiredState, Context context) throws Exception
{
String command = null;
int state = 0;
try
{
int desiredStateString;
if(desiredState)
desiredStateString = 1;
else
desiredStateString = 0;
// Get the current state of the mobile network.
state = isMobileDataEnabled() ? 0 : 1;
// boolean state = isMobileDataEnabled() ? 0 : 1;
// Get the value of the "TRANSACTION_setDataEnabled" field.
String transactionCode = getTransactionCode(context);
// Android 5.1+ (API 22) and later.
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP)
SubscriptionManager mSubscriptionManager = (SubscriptionManager) context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
// Loop through the subscription list i.e. SIM list.
for (int i = 0; i < mSubscriptionManager.getActiveSubscriptionInfoCountMax(); i++)
{
SubscriptionManager mSubscriptionManager = (SubscriptionManager) context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
// Loop through the subscription list i.e. SIM list.
for (int i = 0; i < mSubscriptionManager.getActiveSubscriptionInfoCountMax(); i++)
{
if (transactionCode != null && transactionCode.length() > 0)
{
// Get the active subscription ID for a given SIM card.
int subscriptionId = mSubscriptionManager.getActiveSubscriptionInfoList().get(i).getSubscriptionId();
// Execute the command via `su` to turn off
// mobile network for a subscription service.
command = "service call phone " + transactionCode + " i32 " + subscriptionId + " i32 " + desiredState;
Miscellaneous.logEvent("i", "setDataConnectionWithRoot()", "Running command: " + command.toString(), 5);
return executeCommandViaSu(new String[]{command});
}
}
}
else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP)
{
// Android 5.0 (API 21) only.
if (transactionCode != null && transactionCode.length() > 0)
{
// Execute the command via `su` to turn off mobile network.
command = "service call phone " + transactionCode + " i32 " + desiredState;
// Get the active subscription ID for a given SIM card.
int subscriptionId = mSubscriptionManager.getActiveSubscriptionInfoList().get(i).getSubscriptionId();
// Execute the command via `su` to turn off
// mobile network for a subscription service.
command = "service call phone " + transactionCode + " i32 " + subscriptionId + " i32 " + desiredStateString;
Miscellaneous.logEvent("i", "setMobileNetworkAndroid6Till8()", "Running command: " + command.toString(), 5);
return executeCommandViaSu(new String[]{command});
}
}
@ -1252,6 +1569,75 @@ public class Actions
return false;
}
@SuppressLint("NewApi")
public static boolean setMobileNetworkTillAndroid5(boolean desiredState, Context context) throws Exception
{
String command = null;
try
{
int desiredStateString;
if(desiredState)
desiredStateString = 1;
else
desiredStateString = 0;
// Get the current state of the mobile network.
// int currentState = isMobileDataEnabled() ? 0 : 1;
// Get the value of the "TRANSACTION_setDataEnabled" field.
String transactionCode = getTransactionCode(context);
// Android 5.0 (API 21) only.
if (transactionCode != null && transactionCode.length() > 0)
{
// Execute the command via `su` to turn off mobile network.
command = "service call phone " + transactionCode + " i32 " + desiredStateString;
Miscellaneous.logEvent("i", "setMobileNetworkTillAndroid5()", "Running command: " + command.toString(), 5);
return executeCommandViaSu(new String[]{command});
}
}
catch (Exception e)
{
// Oops! Something went wrong, so we throw the exception here.
throw e;
}
return false;
}
@SuppressLint("NewApi")
public static boolean setMobileNetworkFromAndroid9(boolean desiredState, Context context) throws Exception
{
String command = null;
String desiredStateString;
if(desiredState)
desiredStateString = "enable";
else
desiredStateString = "disable";
try
{
/*
Android 8.1 is the last version on which the transaction code can be determined
with the below method. From 9.0 on the field TRANSACTION_setDataEnabled does not
exist anymore. Usually it was 83 and we'll just try this number hardcoded.
Alternatively the bottom of this might be an approach:
https://stackoverflow.com/questions/26539445/the-setmobiledataenabled-method-is-no-longer-callable-as-of-android-l-and-later
*/
// Execute the command via `su` to turn off
// mobile network for a subscription service.
command = "svc data " + desiredStateString;
Miscellaneous.logEvent("i", "setMobileNetworkFromAndroid9()", "Running command: " + command.toString(), 5);
return executeCommandViaSu(new String[]{command});
}
catch (Exception e)
{
// Oops! Something went wrong, so we throw the exception here.
throw e;
}
}
@SuppressLint("NewApi")
public static boolean isMobileDataEnabled()
{

View File

@ -19,7 +19,7 @@ import android.widget.TextView;
import android.widget.Toast;
import com.jens.automation2.AutomationService.serviceCommands;
import com.jens.automation2.receivers.AlarmListener;
import com.jens.automation2.receivers.DateTimeListener;
import java.util.ArrayList;
@ -254,7 +254,7 @@ public class ActivityMainRules extends ActivityGeneric
try
{
if(AutomationService.isMyServiceRunning(this))
AlarmListener.reloadAlarms();
DateTimeListener.reloadAlarms();
}
catch(NullPointerException e)
{

View File

@ -29,6 +29,7 @@ import androidx.core.text.HtmlCompat;
import com.jens.automation2.AutomationService.serviceCommands;
import com.jens.automation2.Trigger.Trigger_Enum;
import com.jens.automation2.location.CellLocationChangedReceiver;
import com.jens.automation2.location.LocationProvider;
import java.io.File;
@ -43,7 +44,7 @@ public class ActivityMainScreen extends ActivityGeneric
private static ActivityMainScreen activityMainScreenInstance = null;
private ToggleButton toggleService, tbLockSound;
private Button bShowHelp, bPrivacy, bSettingsErase, bAddSoundLockTIme;
private Button bShowHelp, bPrivacy, bSettingsErase, bAddSoundLockTIme, bDonate;
private TextView tvActivePoi, tvClosestPoi, tvLastRule, tvMainScreenNotePermissions, tvMainScreenNoteFeaturesFromOtherFlavor, tvMainScreenNoteLocationImpossibleBlameGoogle, tvMainScreenNoteNews, tvlockSoundDuration;
private static boolean updateNoteDisplayed = false;
@ -81,6 +82,12 @@ public class ActivityMainScreen extends ActivityGeneric
tvlockSoundDuration = (TextView)findViewById(R.id.tvlockSoundDuration);
tbLockSound = (ToggleButton) findViewById(R.id.tbLockSound);
toggleService = (ToggleButton) findViewById(R.id.tbArmMastListener);
bDonate = (Button)findViewById(R.id.bDonate);
if(!BuildConfig.FLAVOR.equalsIgnoreCase("googlePlayFlavor"))
bDonate.setVisibility(View.VISIBLE);
toggleService.setChecked(AutomationService.isMyServiceRunning(this));
toggleService.setOnCheckedChangeListener(new OnCheckedChangeListener()
{
@ -110,6 +117,18 @@ public class ActivityMainScreen extends ActivityGeneric
}
});
bDonate.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
String privacyPolicyUrl = "https://server47.de/donate";
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(privacyPolicyUrl));
startActivity(browserIntent);
}
});
tbLockSound.setOnCheckedChangeListener(new OnCheckedChangeListener()
{
@Override

View File

@ -72,4 +72,4 @@ public class ActivityMainTabLayout extends TabActivity
// setIntent(intent);
NfcReceiver.checkIntentForNFC(this, intent);
}
}
}

View File

@ -201,6 +201,9 @@ public class ActivityMaintenance extends Activity
try
{
XmlFileInterface.readFile();
ActivityMainPoi.getInstance().updateListView();
ActivityMainRules.getInstance().updateListView();
ActivityMainProfiles.getInstance().updateListView();
}
catch (Exception e)
{
@ -314,18 +317,9 @@ public class ActivityMaintenance extends Activity
String subject = "Automation logs";
StringBuilder emailBody = new StringBuilder();
emailBody.append("Device details" + Miscellaneous.lineSeparator);
emailBody.append("OS version: " + System.getProperty("os.version") + Miscellaneous.lineSeparator);
emailBody.append("API Level: " + android.os.Build.VERSION.SDK + Miscellaneous.lineSeparator);
emailBody.append("Device: " + android.os.Build.DEVICE + Miscellaneous.lineSeparator);
emailBody.append("Model: " + android.os.Build.MODEL + Miscellaneous.lineSeparator);
emailBody.append("Product: " + android.os.Build.PRODUCT);
emailBody.append("Flavor: " + BuildConfig.FLAVOR);
Uri uri = Uri.parse("content://com.jens.automation2/" + Settings.zipFileName);
Miscellaneous.sendEmail(ActivityMaintenance.this, "android-development@gmx.de", "Automation logs", emailBody.toString(), uri);
Miscellaneous.sendEmail(ActivityMaintenance.this, "android-development@gmx.de", "Automation logs", getSystemInfo(), uri);
}
});
alertDialogBuilder.setNegativeButton(context.getResources().getString(R.string.no), null);
@ -334,6 +328,19 @@ public class ActivityMaintenance extends Activity
return alertDialog;
}
public static String getSystemInfo()
{
StringBuilder systemInfoText = new StringBuilder();
systemInfoText.append("Device details" + Miscellaneous.lineSeparator);
systemInfoText.append("OS version: " + System.getProperty("os.version") + Miscellaneous.lineSeparator);
systemInfoText.append("API Level: " + android.os.Build.VERSION.SDK + Miscellaneous.lineSeparator);
systemInfoText.append("Device: " + android.os.Build.DEVICE + Miscellaneous.lineSeparator);
systemInfoText.append("Model: " + android.os.Build.MODEL + Miscellaneous.lineSeparator);
systemInfoText.append("Product: " + android.os.Build.PRODUCT + Miscellaneous.lineSeparator);
systemInfoText.append("Flavor: " + BuildConfig.FLAVOR);
return systemInfoText.toString();
}
@Override
protected void onResume()
{

View File

@ -22,6 +22,8 @@ import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.Toast;
import com.jens.automation2.receivers.ConnectivityReceiver;
import java.util.Calendar;
import java.util.Timer;
import java.util.TimerTask;
@ -163,7 +165,7 @@ public class ActivityManagePoi extends Activity
locationSearchStart = Calendar.getInstance();
startTimeout();
if(!Settings.privacyLocationing)
if(!Settings.privacyLocationing || !ConnectivityReceiver.isDataConnectionAvailable(AutomationService.getInstance()))
{
Miscellaneous.logEvent("i", "POI Manager", getResources().getString(R.string.logGettingPositionWithProvider) + " " + provider1, 3);
myLocationManager.requestLocationUpdates(provider1, 500, Settings.satisfactoryAccuracyNetwork, myLocationListenerNetwork);

View File

@ -1,6 +1,7 @@
package com.jens.automation2;
import android.app.Activity;
import android.app.NotificationManager;
import android.app.ProgressDialog;
import android.content.ActivityNotFoundException;
import android.content.Context;
@ -37,8 +38,8 @@ public class ActivityManageProfile extends Activity
final static int intentCodeRingtonePickerNotificationsFile = 9020;
final static int intentCodeRingtonePickerNotificationsRingtone = 9021;
CheckBox checkBoxChangeSoundMode, checkBoxChangeVolumeMusicVideoGameMedia, checkBoxChangeVolumeNotifications, checkBoxChangeVolumeAlarms, checkBoxChangeIncomingCallsRingtone, checkBoxChangeNotificationRingtone, checkBoxChangeAudibleSelection, checkBoxChangeScreenLockUnlockSound, checkBoxChangeHapticFeedback, checkBoxChangeVibrateWhenRinging, checkBoxVibrateWhenRinging, checkBoxAudibleSelection, checkBoxScreenLockUnlockSound, checkBoxHapticFeedback;
Spinner spinnerSoundMode;
CheckBox checkBoxChangeSoundMode, checkBoxChangeVolumeMusicVideoGameMedia, checkBoxChangeVolumeNotifications, checkBoxChangeVolumeAlarms, checkBoxChangeIncomingCallsRingtone, checkBoxChangeNotificationRingtone, checkBoxChangeAudibleSelection, checkBoxChangeScreenLockUnlockSound, checkBoxChangeHapticFeedback, checkBoxChangeVibrateWhenRinging, checkBoxVibrateWhenRinging, checkBoxAudibleSelection, checkBoxScreenLockUnlockSound, checkBoxHapticFeedback, checkBoxChangeDnd;
Spinner spinnerSoundMode, spinnerDndMode;
SeekBar seekBarVolumeMusic, seekBarVolumeNotifications, seekBarVolumeAlarms;
Button bChangeSoundIncomingCalls, bChangeSoundNotifications, bSaveProfile;
TextView tvIncomingCallsRingtone, tvNotificationsRingtone;
@ -47,6 +48,7 @@ public class ActivityManageProfile extends Activity
File incomingCallsRingtone = null, notificationsRingtone = null;
ArrayAdapter<String> soundModeAdapter;
ArrayAdapter<String> dndModeAdapter;
public void setIncomingCallsRingtone(File incomingCallsRingtone)
{
@ -85,6 +87,7 @@ public class ActivityManageProfile extends Activity
this.setContentView(R.layout.activity_manage_specific_profile);
checkBoxChangeSoundMode = (CheckBox)findViewById(R.id.checkBoxChangeSoundMode);
checkBoxChangeDnd = (CheckBox)findViewById(R.id.checkBoxChangeDnd);
checkBoxChangeVolumeMusicVideoGameMedia = (CheckBox)findViewById(R.id.checkBoxChangeVolumeMusicVideoGameMedia);
checkBoxChangeVolumeNotifications = (CheckBox)findViewById(R.id.checkBoxChangeVolumeNotifications);
checkBoxChangeVolumeAlarms = (CheckBox)findViewById(R.id.checkBoxChangeVolumeAlarms);
@ -99,6 +102,7 @@ public class ActivityManageProfile extends Activity
checkBoxHapticFeedback = (CheckBox)findViewById(R.id.checkBoxHapticFeedback);
checkBoxVibrateWhenRinging = (CheckBox)findViewById(R.id.checkBoxVibrateWhenRinging);
spinnerSoundMode = (Spinner)findViewById(R.id.spinnerSoundMode);
spinnerDndMode = (Spinner)findViewById(R.id.spinnerDndMode);
seekBarVolumeMusic = (SeekBar)findViewById(R.id.seekBarVolumeMusic);
seekBarVolumeNotifications = (SeekBar)findViewById(R.id.seekBarVolumeNotifications);
seekBarVolumeAlarms = (SeekBar)findViewById(R.id.seekBarVolumeAlarms);
@ -114,6 +118,7 @@ public class ActivityManageProfile extends Activity
checkBoxScreenLockUnlockSound.setEnabled(false);
checkBoxHapticFeedback.setEnabled(false);
spinnerSoundMode.setEnabled(false);
spinnerDndMode.setEnabled(false);
seekBarVolumeMusic.setEnabled(false);
seekBarVolumeNotifications.setEnabled(false);
seekBarVolumeAlarms.setEnabled(false);
@ -121,6 +126,14 @@ public class ActivityManageProfile extends Activity
bChangeSoundNotifications.setEnabled(false);
spinnerSoundMode.setSelection(0);
spinnerDndMode.setSelection(0);
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.M)
{
// Disable DND controls
checkBoxChangeDnd.setEnabled(false);
spinnerDndMode.setEnabled(false);
}
// Scale SeekBars to the system's maximum volume values
AudioManager am = (AudioManager) Miscellaneous.getAnyContext().getSystemService(Context.AUDIO_SERVICE);
@ -128,8 +141,30 @@ public class ActivityManageProfile extends Activity
seekBarVolumeNotifications.setMax(am.getStreamMaxVolume(AudioManager.STREAM_NOTIFICATION));
seekBarVolumeAlarms.setMax(am.getStreamMaxVolume(AudioManager.STREAM_ALARM));
soundModeAdapter = new ArrayAdapter<String>(this, R.layout.text_view_for_poi_listview_mediumtextsize, new String[] { getResources().getString(R.string.soundModeSilent), getResources().getString(R.string.soundModeVibrate), getResources().getString(R.string.soundModeNormal) });
soundModeAdapter = new ArrayAdapter<String>(this, R.layout.text_view_for_poi_listview_mediumtextsize, new String[]
{
getResources().getString(R.string.soundModeSilent),
getResources().getString(R.string.soundModeVibrate),
getResources().getString(R.string.soundModeNormal)
});
spinnerSoundMode.setAdapter(soundModeAdapter);
dndModeAdapter = new ArrayAdapter<String>(this, R.layout.text_view_for_poi_listview_mediumtextsize, new String[]
{
getResources().getString(R.string.dndOff),
getResources().getString(R.string.dndPriority),
getResources().getString(R.string.dndNothing),
getResources().getString(R.string.dndAlarms)
});
spinnerDndMode.setAdapter(dndModeAdapter);
/*
Order in spinner: 1, 2, 4, 3
NotificationManager.INTERRUPTION_FILTER_UNKNOWN -> Returned when the value is unavailable for any reason.
NotificationManager.INTERRUPTION_FILTER_ALL -> 1 -> Normal interruption filter - no notifications are suppressed. -> essentially turn off DND
NotificationManager.INTERRUPTION_FILTER_PRIORITY -> 2 -> Priority interruption filter - all notifications are suppressed except those that match the priority criteria.
NotificationManager.INTERRUPTION_FILTER_ALARMS -> 4 -> Alarms only interruption filter - all notifications except those of category
NotificationManager.INTERRUPTION_FILTER_NONE -> 3 -> No interruptions filter - all notifications are suppressed and all audio streams (except those used for phone calls) and vibrations are muted.
*/
checkBoxChangeSoundMode.setOnCheckedChangeListener(new OnCheckedChangeListener()
{
@ -139,6 +174,14 @@ public class ActivityManageProfile extends Activity
spinnerSoundMode.setEnabled(isChecked);
}
});
checkBoxChangeDnd.setOnCheckedChangeListener(new OnCheckedChangeListener()
{
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
{
spinnerDndMode.setEnabled(isChecked);
}
});
checkBoxChangeVolumeMusicVideoGameMedia.setOnCheckedChangeListener(new OnCheckedChangeListener()
{
@Override
@ -327,6 +370,7 @@ public class ActivityManageProfile extends Activity
{
etName.setText(ActivityMainProfiles.profileToEdit.getName());
checkBoxChangeSoundMode.setChecked(ActivityMainProfiles.profileToEdit.getChangeSoundMode());
checkBoxChangeDnd.setChecked(ActivityMainProfiles.profileToEdit.getChangeDndMode());
checkBoxChangeVolumeMusicVideoGameMedia.setChecked(ActivityMainProfiles.profileToEdit.getChangeVolumeMusicVideoGameMedia());
checkBoxChangeVolumeNotifications.setChecked(ActivityMainProfiles.profileToEdit.getChangeVolumeNotifications());
checkBoxChangeVolumeAlarms.setChecked(ActivityMainProfiles.profileToEdit.getChangeVolumeAlarms());
@ -338,6 +382,7 @@ public class ActivityManageProfile extends Activity
checkBoxChangeVibrateWhenRinging.setChecked(ActivityMainProfiles.profileToEdit.getChangeVibrateWhenRinging());
spinnerSoundMode.setSelection(ActivityMainProfiles.profileToEdit.getSoundMode());
spinnerDndMode.setSelection(ActivityMainProfiles.profileToEdit.getDndMode()-1);
seekBarVolumeMusic.setProgress(ActivityMainProfiles.profileToEdit.getVolumeMusic());
seekBarVolumeNotifications.setProgress(ActivityMainProfiles.profileToEdit.getVolumeNotifications());
seekBarVolumeAlarms.setProgress(ActivityMainProfiles.profileToEdit.getVolumeAlarms());
@ -359,6 +404,7 @@ public class ActivityManageProfile extends Activity
ActivityMainProfiles.profileToEdit.setName(etName.getText().toString());
ActivityMainProfiles.profileToEdit.setChangeSoundMode(checkBoxChangeSoundMode.isChecked());
ActivityMainProfiles.profileToEdit.setChangeDndMode(checkBoxChangeDnd.isChecked());
ActivityMainProfiles.profileToEdit.setChangeVolumeMusicVideoGameMedia(checkBoxChangeVolumeMusicVideoGameMedia.isChecked());
ActivityMainProfiles.profileToEdit.setChangeVolumeNotifications(checkBoxChangeVolumeNotifications.isChecked());
ActivityMainProfiles.profileToEdit.setChangeVolumeAlarms(checkBoxChangeVolumeAlarms.isChecked());
@ -374,6 +420,7 @@ public class ActivityManageProfile extends Activity
ActivityMainProfiles.profileToEdit.setHapticFeedback(checkBoxHapticFeedback.isChecked());
ActivityMainProfiles.profileToEdit.setVibrateWhenRinging(checkBoxVibrateWhenRinging.isChecked());
ActivityMainProfiles.profileToEdit.setSoundMode(spinnerSoundMode.getSelectedItemPosition());
ActivityMainProfiles.profileToEdit.setDndMode(spinnerDndMode.getSelectedItemPosition()+1);
ActivityMainProfiles.profileToEdit.setVolumeMusic(seekBarVolumeMusic.getProgress());
ActivityMainProfiles.profileToEdit.setVolumeNotifications(seekBarVolumeNotifications.getProgress());
ActivityMainProfiles.profileToEdit.setVolumeAlarms(seekBarVolumeAlarms.getProgress());
@ -401,21 +448,23 @@ public class ActivityManageProfile extends Activity
}
if(!checkBoxChangeSoundMode.isChecked()
&
&&
!checkBoxChangeDnd.isChecked()
&&
!checkBoxChangeVolumeMusicVideoGameMedia.isChecked()
&
&&
!checkBoxChangeVolumeNotifications.isChecked()
&
&&
!checkBoxChangeVolumeAlarms.isChecked()
&
&&
!checkBoxChangeIncomingCallsRingtone.isChecked()
&
&&
!checkBoxChangeNotificationRingtone.isChecked()
&
&&
!checkBoxChangeAudibleSelection.isChecked()
&
&&
!checkBoxChangeScreenLockUnlockSound.isChecked()
&
&&
!checkBoxChangeHapticFeedback.isChecked()
)
{

View File

@ -1,5 +1,6 @@
package com.jens.automation2;
import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
@ -48,6 +49,7 @@ import java.util.Collections;
public class ActivityManageRule extends Activity
{
final static String activityDetectionClassPath = "com.jens.automation2.receivers.ActivityDetectionReceiver";
public final static String intentNameTriggerParameter1 = "triggerParameter1";
public Context context;
private Button cmdTriggerAdd, cmdActionAdd, cmdSaveRule;
@ -88,13 +90,14 @@ public class ActivityManageRule extends Activity
final static int requestCodeActionStartActivityEdit = 3001;
final static int requestCodeTriggerNfcTagAdd = 4000;
final static int requestCodeTriggerNfcTagEdit = 4001;
final static int requestCodeActionSpeakTextAdd = 5000;
final static int requestCodeActionSpeakTextEdit = 1001;
final static int requestCodeActionSpeakTextAdd = 5101;
final static int requestCodeActionSpeakTextEdit = 5102;
final static int requestCodeTriggerBluetoothAdd = 6000;
final static int requestCodeTriggerBluetoothEdit = 6001;
final static int requestCodeActionScreenBrightnessAdd = 401;
final static int requestCodeActionScreenBrightnessEdit = 402;
final static int requestCodeActionSendTextMessage = 7001;
final static int requestCodeTriggerDevicePositionAdd = 301;
final static int requestCodeTriggerDevicePositionEdit = 302;
final static int requestCodeTriggerNotificationAdd = 8000;
final static int requestCodeTriggerNfcNotificationEdit = 8001;
final static int requestCodeActionPlaySoundAdd = 501;
@ -104,6 +107,7 @@ public class ActivityManageRule extends Activity
final static int requestCodeTriggerWifiAdd = 723;
final static int requestCodeTriggerWifiEdit = 724;
final static int requestCodeActionSendTextMessageAdd = 5001;
final static int requestCodeActionSendTextMessageEdit = 5002;
final static int requestCodeActionVibrateAdd = 801;
final static int requestCodeActionVibrateEdit = 802;
@ -120,7 +124,7 @@ public class ActivityManageRule extends Activity
{
context = this;
super.onCreate(savedInstanceState);
setContentView(R.layout.manage_specific_rule);
setContentView(R.layout.activity_manage_specific_rule);
instance = this;
@ -179,7 +183,7 @@ public class ActivityManageRule extends Activity
});
cmdSaveRule.setOnClickListener(new OnClickListener()
{
{
@Override
public void onClick(View v)
{
@ -260,6 +264,12 @@ public class ActivityManageRule extends Activity
wifiEditor.putExtra("wifiName", selectedTrigger.getTriggerParameter2());
startActivityForResult(wifiEditor, requestCodeTriggerWifiEdit);
break;
case devicePosition:
Intent devicePositionEditor = new Intent(ActivityManageRule.this, ActivityManageTriggerDevicePosition.class);
devicePositionEditor.putExtra(ActivityManageRule.intentNameTriggerParameter1, selectedTrigger.getTriggerParameter());
devicePositionEditor.putExtra(ActivityManageTriggerDevicePosition.vectorFieldName, selectedTrigger.getTriggerParameter2());
startActivityForResult(devicePositionEditor, requestCodeTriggerDevicePositionEdit);
break;
default:
break;
}
@ -315,7 +325,7 @@ public class ActivityManageRule extends Activity
Intent activitySendTextMessageIntent = new Intent(ActivityManageRule.this, ActivityManageActionSendTextMessage.class);
ActivityManageActionSendTextMessage.resultingAction = a;
activitySendTextMessageIntent.putExtra("edit", true);
startActivityForResult(activitySendTextMessageIntent, requestCodeActionSendTextMessage);
startActivityForResult(activitySendTextMessageIntent, requestCodeActionSendTextMessageEdit);
break;
case setScreenBrightness:
Intent activityEditScreenBrightnessIntent = new Intent(ActivityManageRule.this, ActivityManageActionBrightnessSetting.class);
@ -402,6 +412,11 @@ public class ActivityManageRule extends Activity
ruleToEdit.setName(etRuleName.getText().toString());
ruleToEdit.setRuleActive(chkRuleActive.isChecked());
ruleToEdit.setRuleToggle(chkRuleToggle.isChecked());
for(Trigger t : ruleToEdit.getTriggerSet())
t.setParentRule(ruleToEdit);
for(Action a : ruleToEdit.getActionSet())
a.setParentRule(ruleToEdit);
}
private void loadVariablesIntoGui()
@ -464,6 +479,8 @@ public class ActivityManageRule extends Activity
items.add(new Item(typesLong[i].toString(), R.drawable.headphone));
else if(types[i].toString().equals(Trigger_Enum.notification.toString()))
items.add(new Item(typesLong[i].toString(), R.drawable.notification));
else if(types[i].toString().equals(Trigger_Enum.devicePosition.toString()))
items.add(new Item(typesLong[i].toString(), R.drawable.smartphone));
else
items.add(new Item(typesLong[i].toString(), R.drawable.placeholder));
}
@ -536,6 +553,14 @@ public class ActivityManageRule extends Activity
Intent wifiTriggerEditor = new Intent(myContext, ActivityManageTriggerWifi.class);
startActivityForResult(wifiTriggerEditor, requestCodeTriggerWifiAdd);
return;
// booleanChoices = new String[]{getResources().getString(R.string.started), getResources().getString(R.string.stopped)};
}
else if(triggerType == Trigger_Enum.devicePosition)
{
newTrigger.setTriggerType(Trigger_Enum.devicePosition);
Intent devicePositionTriggerEditor = new Intent(myContext, ActivityManageTriggerDevicePosition.class);
startActivityForResult(devicePositionTriggerEditor, requestCodeTriggerDevicePositionAdd);
return;
// booleanChoices = new String[]{getResources().getString(R.string.started), getResources().getString(R.string.stopped)};
}
// else if(triggerType == Trigger_Enum.wifiConnection)
@ -613,16 +638,16 @@ public class ActivityManageRule extends Activity
if(triggerType == Trigger_Enum.nfcTag)
{
if (NfcReceiver.checkNfcRequirements(ActivityManageRule.this, true))
getTriggerParamterDialog(context, booleanChoices).show();
getTriggerParameterDialog(context, booleanChoices).show();
}
else
getTriggerParamterDialog(context, booleanChoices).show();
getTriggerParameterDialog(context, booleanChoices).show();
}
});
return builder.create();
}
private AlertDialog getTriggerParamterDialog(final Context myContext, final String[] choices)
private AlertDialog getTriggerParameterDialog(final Context myContext, final String[] choices)
{
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(context);
alertDialogBuilder.setTitle(getResources().getString(R.string.selectTypeOfTrigger));
@ -1112,9 +1137,7 @@ public class ActivityManageRule extends Activity
{
//edit TimeFrame
if(resultCode == RESULT_OK && ActivityManageTriggerTimeFrame.editedTimeFrameTrigger != null)
{
this.refreshTriggerList();
}
else
Miscellaneous.logEvent("w", "TimeFrameEdit", "No timeframe returned. Assuming abort.", 5);
}
@ -1132,8 +1155,11 @@ public class ActivityManageRule extends Activity
{
if(resultCode == RESULT_OK)
{
newTrigger.setTriggerParameter(data.getBooleanExtra("wifiState", false));
newTrigger.setTriggerParameter2(data.getStringExtra("wifiName"));
Trigger editedTrigger = new Trigger();
editedTrigger.setTriggerType(Trigger_Enum.wifiConnection);
editedTrigger.setTriggerParameter(data.getBooleanExtra("wifiState", false));
editedTrigger.setTriggerParameter2(data.getStringExtra("wifiName"));
ruleToEdit.getTriggerSet().set(editIndex, editedTrigger);
this.refreshTriggerList();
}
}
@ -1176,6 +1202,7 @@ public class ActivityManageRule extends Activity
{
ruleToEdit.getTriggerSet().add(newTrigger);
newTrigger.setTriggerParameter(data.getBooleanExtra("direction", false));
newTrigger.setTriggerParameter2(
data.getStringExtra("app") + Trigger.triggerParameter2Split +
data.getStringExtra("titleDir") + Trigger.triggerParameter2Split +
@ -1224,8 +1251,8 @@ public class ActivityManageRule extends Activity
{
if(resultCode == RESULT_OK)
{
//add SpeakText
ruleToEdit.getActionSet().add(ActivityManageActionSendTextMessage.resultingAction);
//edit SpeakText
newAction = ActivityManageActionSpeakText.resultingAction;
this.refreshActionList();
}
}
@ -1315,17 +1342,49 @@ public class ActivityManageRule extends Activity
this.refreshActionList();
}
}
//TODO: Check with has data been changed or something like that.
/*try
else if(requestCode == requestCodeActionSendTextMessageAdd)
{
Miscellaneous.logEvent("i", "ActivityManageSpecificRule", getResources().getString(R.string.noDataChangedReadingAnyway), 4);
XmlFileInterface.readFile();
if(resultCode == RESULT_OK)
{
//add SendTextMessage
ruleToEdit.getActionSet().add(ActivityManageActionSendTextMessage.resultingAction);
this.refreshActionList();
}
}
catch (FileNotFoundException e)
else if(requestCode == requestCodeActionSendTextMessageEdit)
{
Miscellaneous.logEvent("e", "ActivityManageSpecificRule", getResources().getString(R.string.errorReadingPoisAndRulesFromFile) + ": " + Log.getStackTraceString(e), 5);
}*/
if(resultCode == RESULT_OK)
{
//edit SendTextMessage
newAction = ActivityManageActionSendTextMessage.resultingAction;
//ruleToEdit.getActionSet().add(ActivityManageActionSendTextMessage.resultingAction);
this.refreshActionList();
}
}
else if(requestCode == requestCodeTriggerDevicePositionAdd)
{
if(resultCode == RESULT_OK)
{
// newTrigger.setTriggerParameter(data.getBooleanExtra("wifiState", false));
newTrigger.setTriggerParameter2(data.getStringExtra(ActivityManageTriggerDevicePosition.vectorFieldName));
newTrigger.setParentRule(ruleToEdit);
ruleToEdit.getTriggerSet().add(newTrigger);
this.refreshTriggerList();
}
}
else if(requestCode == requestCodeTriggerDevicePositionEdit)
{
if(resultCode == RESULT_OK)
{
Trigger editedTrigger = new Trigger();
editedTrigger.setTriggerType(Trigger_Enum.devicePosition);
editedTrigger.setTriggerParameter(data.getBooleanExtra(ActivityManageRule.intentNameTriggerParameter1, true));
editedTrigger.setTriggerParameter2(data.getStringExtra(ActivityManageTriggerDevicePosition.vectorFieldName));
editedTrigger.setParentRule(ruleToEdit);
ruleToEdit.getTriggerSet().set(editIndex, editedTrigger);
this.refreshTriggerList();
}
}
}
protected Dialog getActionTypeDialog()
@ -1345,6 +1404,8 @@ public class ActivityManageRule extends Activity
items.add(new Item(typesLong[i].toString(), R.drawable.router));
else if(types[i].toString().equals(Action_Enum.setWifiTethering.toString()))
items.add(new Item(typesLong[i].toString(), R.drawable.router));
else if(types[i].toString().equals(Action_Enum.setBluetoothTethering.toString()))
items.add(new Item(typesLong[i].toString(), R.drawable.router));
else if(types[i].toString().equals(Action_Enum.setDisplayRotation.toString()))
items.add(new Item(typesLong[i].toString(), R.drawable.displayrotation));
else if(types[i].toString().equals(Action_Enum.waitBeforeNextAction.toString()))
@ -1353,6 +1414,8 @@ public class ActivityManageRule extends Activity
items.add(new Item(typesLong[i].toString(), R.drawable.plane));
else if(types[i].toString().equals(Action_Enum.wakeupDevice.toString()))
items.add(new Item(typesLong[i].toString(), R.drawable.alarm));
else if(types[i].toString().equals(Action_Enum.turnScreenOnOrOff.toString()))
items.add(new Item(typesLong[i].toString(), R.drawable.smartphone));
else if(types[i].toString().equals(Action_Enum.changeSoundProfile.toString()))
items.add(new Item(typesLong[i].toString(), R.drawable.sound));
else if(types[i].toString().equals(Action_Enum.triggerUrl.toString()))
@ -1374,7 +1437,7 @@ public class ActivityManageRule extends Activity
else if(types[i].toString().equals(Action_Enum.sendTextMessage.toString()))
{
// if(ActivityPermissions.isPermissionDeclaratedInManifest(ActivityManageSpecificRule.this, "android.permission.SEND_SMS") && !Miscellaneous.isGooglePlayInstalled(ActivityManageSpecificRule.this))
if(ActivityPermissions.isPermissionDeclaratedInManifest(ActivityManageRule.this, "android.permission.SEND_SMS"))
if(ActivityPermissions.isPermissionDeclaratedInManifest(ActivityManageRule.this, Manifest.permission.SEND_SMS))
items.add(new Item(typesLong[i].toString(), R.drawable.message));
}
else
@ -1415,14 +1478,15 @@ public class ActivityManageRule extends Activity
newAction.setAction(Action_Enum.triggerUrl);
ActivityManageActionTriggerUrl.resultingAction = null;
Intent editTriggerIntent = new Intent(context, ActivityManageActionTriggerUrl.class);
startActivityForResult(editTriggerIntent, 1000);
startActivityForResult(editTriggerIntent, requestCodeActionTriggerUrlAdd);
}
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.setWifi.toString()))
{
newAction.setAction(Action_Enum.setWifi);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
Toast.makeText(context, context.getResources().getString(R.string.android10WifiToggleNotice), Toast.LENGTH_LONG).show();
getActionParameter1Dialog(ActivityManageRule.this).show();
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
Miscellaneous.messageBox(context.getResources().getString(R.string.app_name), context.getResources().getString(R.string.android10WifiToggleNotice), context).show();
}
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.setBluetooth.toString()))
{
@ -1434,15 +1498,27 @@ public class ActivityManageRule extends Activity
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.setUsbTethering.toString()))
{
newAction.setAction(Action_Enum.setUsbTethering);
getActionParameter1Dialog(ActivityManageRule.this).show();
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.GINGERBREAD_MR1)
Miscellaneous.messageBox(context.getResources().getString(R.string.warning), context.getResources().getString(R.string.usbTetheringFailForAboveGingerbread), context).show();
getActionParameter1Dialog(ActivityManageRule.this).show();
}
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.setWifiTethering.toString()))
{
newAction.setAction(Action_Enum.setWifiTethering);
getActionParameter1Dialog(ActivityManageRule.this).show();
}
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.setBluetoothTethering.toString()))
{
newAction.setAction(Action_Enum.setBluetoothTethering);
getActionParameter1Dialog(ActivityManageRule.this).show();
if(!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH))
Miscellaneous.messageBox("Bluetooth", getResources().getString(R.string.deviceDoesNotHaveBluetooth), ActivityManageRule.this).show();;
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.O)
Miscellaneous.messageBox(context.getResources().getString(R.string.notice), context.getResources().getString(R.string.btTetheringNotice), context).show();
}
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.setDisplayRotation.toString()))
{
newAction.setAction(Action_Enum.setDisplayRotation);
@ -1462,7 +1538,7 @@ public class ActivityManageRule extends Activity
{
newAction.setAction(Action_Enum.startOtherActivity);
Intent intent = new Intent(ActivityManageRule.this, ActivityManageActionStartActivity.class);
startActivityForResult(intent, 3000);
startActivityForResult(intent, requestCodeActionStartActivityAdd);
}
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.waitBeforeNextAction.toString()))
{
@ -1474,6 +1550,11 @@ public class ActivityManageRule extends Activity
newAction.setAction(Action_Enum.wakeupDevice);
getActionWakeupDeviceDialog(ActivityManageRule.this).show();
}
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.turnScreenOnOrOff.toString()))
{
newAction.setAction(Action_Enum.turnScreenOnOrOff);
getActionParameter1Dialog(ActivityManageRule.this).show();
}
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.setAirplaneMode.toString()))
{
newAction.setAction(Action_Enum.setAirplaneMode);
@ -1496,7 +1577,7 @@ public class ActivityManageRule extends Activity
newAction.setAction(Action_Enum.speakText);
ActivityManageActionSpeakText.resultingAction = null;
Intent editTriggerIntent = new Intent(context, ActivityManageActionSpeakText.class);
startActivityForResult(editTriggerIntent, 5000);
startActivityForResult(editTriggerIntent, requestCodeActionSpeakTextAdd);
}
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.sendTextMessage.toString()))
{

View File

@ -0,0 +1,295 @@
package com.jens.automation2;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.text.InputFilter;
import android.text.Spanned;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.Nullable;
import com.jens.automation2.receivers.DevicePositionListener;
import org.apache.commons.lang3.StringUtils;
public class ActivityManageTriggerDevicePosition extends Activity
{
TextView currentAzimuth, currentPitch, currentRoll, tvAppliesAzimuth, tvAppliesPitch, tvAppliesRoll;
Button bApplyPositionValues, bSavePositionValues;
EditText etDesiredAzimuth, etDesiredAzimuthTolerance, etDesiredPitch, etDesiredPitchTolerance, etDesiredRoll, etDesiredRollTolerance;
CheckBox chkDevicePositionApplies;
public static String vectorFieldName = "deviceVector";
boolean editMode = false;
float desiredAzimuth, desiredPitch, desiredRoll, desiredAzimuthTolerance, desiredPitchTolerance, desiredRollTolerance;
public void updateFields(float azimuth, float pitch, float roll)
{
currentAzimuth.setText(Float.toString(azimuth));
currentPitch.setText(Float.toString(pitch));
currentRoll.setText(Float.toString(roll));
try
{
desiredAzimuth = Float.parseFloat(etDesiredAzimuth.getText().toString());
desiredAzimuthTolerance = Float.parseFloat(etDesiredAzimuthTolerance.getText().toString());
if (Math.abs(azimuth) <= Math.abs(desiredAzimuth - desiredAzimuthTolerance) || Math.abs(azimuth) <= desiredAzimuth + desiredAzimuthTolerance)
{
tvAppliesAzimuth.setText(getResources().getString(R.string.yes));
tvAppliesAzimuth.setTextColor(Color.GREEN);
}
else
{
tvAppliesAzimuth.setText(getResources().getString(R.string.no));
tvAppliesAzimuth.setTextColor(Color.RED);
}
}
catch(Exception e)
{
tvAppliesAzimuth.setText("");
}
try
{
desiredPitch = Float.parseFloat(etDesiredPitch.getText().toString());
desiredPitchTolerance = Float.parseFloat(etDesiredPitchTolerance.getText().toString());
if (Math.abs(pitch) <= Math.abs(desiredPitch - desiredPitchTolerance) || Math.abs(pitch) <= desiredPitch + desiredPitchTolerance)
{
tvAppliesPitch.setText(getResources().getString(R.string.yes));
tvAppliesPitch.setTextColor(Color.GREEN);
}
else
{
tvAppliesPitch.setText(getResources().getString(R.string.no));
tvAppliesPitch.setTextColor(Color.RED);
}
}
catch(Exception e)
{
tvAppliesPitch.setText("");
}
try
{
desiredRoll = Float.parseFloat(etDesiredRoll.getText().toString());
desiredRollTolerance = Float.parseFloat(etDesiredRollTolerance.getText().toString());
if (Math.abs(roll) <= Math.abs(desiredRoll - desiredRollTolerance) || Math.abs(roll) <= desiredRoll + desiredRollTolerance)
{
tvAppliesRoll.setText(getResources().getString(R.string.yes));
tvAppliesRoll.setTextColor(Color.GREEN);
}
else
{
tvAppliesRoll.setText(getResources().getString(R.string.no));
tvAppliesRoll.setTextColor(Color.RED);
}
}
catch(Exception e)
{
tvAppliesRoll.setText("");
}
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_manage_trigger_device_position);
currentAzimuth = (TextView) findViewById(R.id.tvCurrentAzimuth);
currentPitch = (TextView) findViewById(R.id.tvCurrentOrientationPitch);
currentRoll = (TextView) findViewById(R.id.tvCurrentRoll);
tvAppliesAzimuth = (TextView) findViewById(R.id.tvAppliesAzimuth);
tvAppliesPitch = (TextView) findViewById(R.id.tvAppliesPitch);
tvAppliesRoll = (TextView) findViewById(R.id.tvAppliesRoll);
bApplyPositionValues = (Button) findViewById(R.id.bApplyPositionValues);
bSavePositionValues = (Button) findViewById(R.id.bSavePositionValues);
etDesiredAzimuth = (EditText) findViewById(R.id.etDesiredAzimuth);
etDesiredAzimuthTolerance = (EditText) findViewById(R.id.etDesiredAzimuthTolerance);
etDesiredPitch = (EditText) findViewById(R.id.etDesiredPitch);
etDesiredPitchTolerance = (EditText) findViewById(R.id.etDesiredPitchTolerance);
etDesiredRoll = (EditText) findViewById(R.id.etDesiredRoll);
etDesiredRollTolerance = (EditText) findViewById(R.id.etDesiredRollTolerance);
chkDevicePositionApplies = (CheckBox)findViewById(R.id.chkDevicePositionApplies);
// etDesiredAzimuth.setFilters(new InputFilter[]{new InputFilterMinMax(-180, 180)});
// etDesiredPitch.setFilters(new InputFilter[]{new InputFilterMinMax(-180, 180)});
// etDesiredRoll.setFilters(new InputFilter[]{new InputFilterMinMax(-180, 180)});
etDesiredAzimuthTolerance.setFilters(new InputFilter[]{new InputFilterMinMax(0, 180)});
etDesiredPitchTolerance.setFilters(new InputFilter[]{new InputFilterMinMax(0, 180)});
etDesiredRollTolerance.setFilters(new InputFilter[]{new InputFilterMinMax(0, 180)});
if(getIntent().hasExtra(vectorFieldName))
{
editMode = true;
try
{
boolean chkValue = getIntent().getBooleanExtra(ActivityManageRule.intentNameTriggerParameter1, true);
chkDevicePositionApplies.setChecked(chkValue);
String values[] = getIntent().getStringExtra(vectorFieldName).split(Trigger.triggerParameter2Split);
etDesiredAzimuth.setText(values[0]);
etDesiredAzimuthTolerance.setText(values[1]);
etDesiredPitch.setText(values[2]);
etDesiredPitchTolerance.setText(values[3]);
etDesiredRoll.setText(values[4]);
etDesiredRollTolerance.setText(values[5]);
}
catch(Exception e)
{
Toast.makeText(ActivityManageTriggerDevicePosition.this, getResources().getString(R.string.triggerWrong), Toast.LENGTH_SHORT).show();
Miscellaneous.logEvent("e", "DevicePositionTrigger", "There\'s something wrong with a device position trigger. Content: " + getIntent().getStringExtra(vectorFieldName) + ", " + Log.getStackTraceString(e), 1);
}
}
bApplyPositionValues.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
if(!StringUtils.isEmpty(currentAzimuth.getText()))
etDesiredAzimuth.setText(currentAzimuth.getText());
if(!StringUtils.isEmpty(currentPitch.getText()))
etDesiredPitch.setText(currentPitch.getText());
if(!StringUtils.isEmpty(currentRoll.getText()))
etDesiredRoll.setText(currentRoll.getText());
}
});
bSavePositionValues.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
if(!checkInputs(true))
{
Toast.makeText(ActivityManageTriggerDevicePosition.this, getResources().getString(R.string.enterValidNumbersIntoAllFields), Toast.LENGTH_LONG).show();
}
else
{
// Save
Intent returnData = new Intent();
returnData.putExtra(ActivityManageRule.intentNameTriggerParameter1, chkDevicePositionApplies.isChecked());
returnData.putExtra(vectorFieldName,
etDesiredAzimuth.getText().toString() + Trigger.triggerParameter2Split +
etDesiredAzimuthTolerance.getText().toString() + Trigger.triggerParameter2Split +
etDesiredPitch.getText().toString() + Trigger.triggerParameter2Split +
etDesiredPitchTolerance.getText().toString() + Trigger.triggerParameter2Split +
etDesiredRoll.getText().toString() + Trigger.triggerParameter2Split +
etDesiredRollTolerance.getText().toString());
setResult(RESULT_OK, returnData);
finish();
}
}
});
}
boolean checkInputs(boolean showMessages)
{
if(
!StringUtils.isEmpty(etDesiredAzimuth.getText().toString()) && Miscellaneous.isNumeric(etDesiredAzimuth.getText().toString())
&&
!StringUtils.isEmpty(etDesiredAzimuthTolerance.getText().toString()) && Miscellaneous.isNumeric(etDesiredAzimuthTolerance.getText().toString())
&&
!StringUtils.isEmpty(etDesiredPitch.getText().toString()) && Miscellaneous.isNumeric(etDesiredPitch.getText().toString())
&&
!StringUtils.isEmpty(etDesiredPitchTolerance.getText().toString()) && Miscellaneous.isNumeric(etDesiredPitchTolerance.getText().toString())
&&
!StringUtils.isEmpty(etDesiredRoll.getText().toString()) && Miscellaneous.isNumeric(etDesiredRoll.getText().toString())
&&
!StringUtils.isEmpty(etDesiredRollTolerance.getText().toString()) && Miscellaneous.isNumeric(etDesiredRollTolerance.getText().toString())
)
{
float da = Float.parseFloat(etDesiredAzimuth.getText().toString());
float dp = Float.parseFloat(etDesiredPitch.getText().toString());
float dr = Float.parseFloat(etDesiredRoll.getText().toString());
if(Math.abs(da) > 180 || Math.abs(dp) > 180 || Math.abs(dr) > 180)
{
return false;
}
if(showMessages)
{
float dat = Float.parseFloat(etDesiredAzimuthTolerance.getText().toString());
float dpt = Float.parseFloat(etDesiredPitchTolerance.getText().toString());
float drt = Float.parseFloat(etDesiredRollTolerance.getText().toString());
/*
The user may enter a tolerance of 180° for two directions, but not all three.
Otherwise this trigger would always apply.
*/
if (Math.abs(dat) >= 180 && Math.abs(dpt) >= 180 && Math.abs(drt) >= 180)
{
Miscellaneous.messageBox(getResources().getString(R.string.warning), getResources().getString(R.string.toleranceOf180OnlyAllowedIn2Fields), ActivityManageTriggerDevicePosition.this).show();
return false;
}
}
return true;
}
return false;
}
@Override
protected void onResume()
{
super.onResume();
DevicePositionListener.getInstance().startSensorFromConfigActivity(ActivityManageTriggerDevicePosition.this, this);
}
@Override
protected void onPause()
{
super.onPause();
DevicePositionListener.getInstance().stopSensorFromConfigActivity();
}
public class InputFilterMinMax implements InputFilter
{
private float minimumValue;
private float maximumValue;
public InputFilterMinMax(float minimumValue, float maximumValue)
{
this.minimumValue = minimumValue;
this.maximumValue = maximumValue;
}
private boolean isInRange(float a, float b, float c)
{
return b > a ? c >= a && c <= b : c >= b && c <= a;
}
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend)
{
try
{
int input = Integer.parseInt(dest.subSequence(0, dstart).toString() + source + dest.subSequence(dend, dest.length()));
if (isInRange(minimumValue, maximumValue, input))
return null;
}
catch (NumberFormatException nfe)
{
}
return "";
}
}
}

View File

@ -6,11 +6,16 @@ import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.TimePicker;
import android.widget.Toast;
import org.apache.commons.lang3.StringUtils;
import java.sql.Time;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
@ -18,8 +23,9 @@ public class ActivityManageTriggerTimeFrame extends Activity
{
Button bSaveTimeFrame;
TimePicker startPicker, stopPicker;
CheckBox checkMonday, checkTuesday, checkWednesday, checkThursday, checkFriday, checkSaturday, checkSunday;
CheckBox checkMonday, checkTuesday, checkWednesday, checkThursday, checkFriday, checkSaturday, checkSunday, chkRepeat;
RadioButton radioTimeFrameEntering, radioTimeFrameLeaving;
EditText etRepeatEvery;
public static Trigger editedTimeFrameTrigger = null;
@ -44,7 +50,9 @@ public class ActivityManageTriggerTimeFrame extends Activity
checkSunday = (CheckBox)findViewById(R.id.checkSunday);
radioTimeFrameEntering = (RadioButton)findViewById(R.id.radioTimeFrameEntering);
radioTimeFrameLeaving = (RadioButton)findViewById(R.id.radioTimeFrameLeaving);
chkRepeat = (CheckBox)findViewById(R.id.chkRepeat);
etRepeatEvery = (EditText)findViewById(R.id.etRepeatEvery);
bSaveTimeFrame.setOnClickListener(new OnClickListener()
{
@Override
@ -92,11 +100,43 @@ public class ActivityManageTriggerTimeFrame extends Activity
{
Toast.makeText(getBaseContext(), getResources().getString(R.string.selectOneDay), Toast.LENGTH_LONG).show();
return;
}
}
boolean goOn = false;
if(chkRepeat.isChecked())
{
if(!StringUtils.isEmpty(etRepeatEvery.getText().toString()))
{
try
{
long value = Long.parseLong(etRepeatEvery.getText().toString());
if(value > 0)
{
goOn = true;
}
}
catch(Exception e)
{
}
}
}
else
goOn = true;
if(!goOn)
{
Toast.makeText(getBaseContext(), getResources().getString(R.string.enterRepetitionTime), Toast.LENGTH_LONG).show();
return;
}
if(editedTimeFrameTrigger.getTimeFrame() == null)
{
// add new one
editedTimeFrameTrigger.setTimeFrame(new TimeFrame(startTime, stopTime, dayList));
if(chkRepeat.isChecked())
editedTimeFrameTrigger.setTimeFrame(new TimeFrame(startTime, stopTime, dayList, Long.parseLong(etRepeatEvery.getText().toString())));
else
editedTimeFrameTrigger.setTimeFrame(new TimeFrame(startTime, stopTime, dayList, 0));
}
else
{
// edit one
@ -104,6 +144,11 @@ public class ActivityManageTriggerTimeFrame extends Activity
editedTimeFrameTrigger.getTimeFrame().setTriggerTimeStop(stopTime);
editedTimeFrameTrigger.getTimeFrame().getDayList().clear();
editedTimeFrameTrigger.getTimeFrame().setDayList(dayList);
if(chkRepeat.isChecked())
editedTimeFrameTrigger.getTimeFrame().setRepetition(Long.parseLong(etRepeatEvery.getText().toString()));
else
editedTimeFrameTrigger.getTimeFrame().setRepetition(0);
}
editedTimeFrameTrigger.setTriggerParameter(radioTimeFrameEntering.isChecked());
@ -112,6 +157,15 @@ public class ActivityManageTriggerTimeFrame extends Activity
finish();
}
});
chkRepeat.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener()
{
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
{
etRepeatEvery.setEnabled(isChecked);
}
});
if(editedTimeFrameTrigger.getTimeFrame() != null)
loadVariableIntoGui();
@ -158,6 +212,12 @@ public class ActivityManageTriggerTimeFrame extends Activity
break;
}
}
if(editedTimeFrameTrigger.getTimeFrame().getRepetition() > 0)
{
chkRepeat.setChecked(true);
etRepeatEvery.setText(String.valueOf(editedTimeFrameTrigger.getTimeFrame().getRepetition()));
}
}
}

View File

@ -7,9 +7,12 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
@ -55,6 +58,7 @@ public class ActivityManageTriggerWifi extends Activity
wifiSpinnerAdapter = new ArrayAdapter<String>(this, R.layout.text_view_for_poi_listview_mediumtextsize, wifiList);
spinnerWifiList.setAdapter(wifiSpinnerAdapter);
spinnerWifiList.setEnabled(false); // bug in Android; this only works when done in code, not in xml
if (getIntent().hasExtra("edit"))
{
@ -128,12 +132,20 @@ public class ActivityManageTriggerWifi extends Activity
void reallyLoadWifiList()
{
WifiManager myWifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
if(Build.VERSION.SDK_INT >= 30)
{
Miscellaneous.messageBox(getResources().getString(R.string.hint), getResources().getString(R.string.wifiApi30), ActivityManageTriggerWifi.this).show();
loadListOfVisibleWifis();
}
else
{
WifiManager myWifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
for (WifiConfiguration wifi : myWifiManager.getConfiguredNetworks())
wifiList.add(wifi.SSID.replaceAll("\"+$", "").replaceAll("^\"+", ""));
for (WifiConfiguration wifi : myWifiManager.getConfiguredNetworks())
wifiList.add(wifi.SSID.replaceAll("\"+$", "").replaceAll("^\"+", ""));
}
if(wifiList.size() > 0)
if (wifiList.size() > 0)
{
spinnerWifiList.setEnabled(true);
Collections.sort(wifiList);
@ -147,6 +159,24 @@ public class ActivityManageTriggerWifi extends Activity
wifiSpinnerAdapter.notifyDataSetChanged();
}
void loadListOfVisibleWifis()
{
List<ScanResult> results = null;
try
{
WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE);
results = wifiManager.getScanResults();
for (ScanResult wifi : results)
wifiList.add(wifi.SSID.replaceAll("\"+$", "").replaceAll("^\"+", ""));
}
catch(Exception e)
{
Miscellaneous.logEvent("e", "loadListOfVisibleWifis()", Log.getStackTraceString(e), 1);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
{

View File

@ -3,6 +3,7 @@ package com.jens.automation2;
import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Notification;
import android.app.NotificationManager;
import android.content.ComponentName;
import android.content.Context;
@ -19,6 +20,9 @@ import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import androidx.core.app.NotificationManagerCompat;
import com.jens.automation2.receivers.NotificationListener;
@ -411,11 +415,11 @@ public class ActivityPermissions extends Activity
addToArrayListUnique(Manifest.permission.ACCESS_NETWORK_STATE, requiredPermissions);
break;
case charging:
addToArrayListUnique(Manifest.permission.READ_PHONE_STATE, requiredPermissions);
// addToArrayListUnique(Manifest.permission.READ_PHONE_STATE, requiredPermissions);
// addToArrayListUnique("android.permission.BATTERY_STATS", requiredPermissions);
break;
case headsetPlugged:
addToArrayListUnique(Manifest.permission.READ_PHONE_STATE, requiredPermissions);
// addToArrayListUnique(Manifest.permission.READ_PHONE_STATE, requiredPermissions);
break;
case nfcTag:
addToArrayListUnique(Manifest.permission.NFC, requiredPermissions);
@ -494,12 +498,13 @@ public class ActivityPermissions extends Activity
break;
case sendTextMessage:
addToArrayListUnique(Manifest.permission.SEND_SMS, requiredPermissions);
checkPermissionsInVariableUse(action.getParameter2(), requiredPermissions);
checkPermissionsInVariableUse(action.getParameter2(), requiredPermissions);
break;
case setAirplaneMode:
addToArrayListUnique(Manifest.permission.WRITE_SETTINGS, requiredPermissions);
addToArrayListUnique(Manifest.permission.ACCESS_NETWORK_STATE, requiredPermissions);
addToArrayListUnique(Manifest.permission.CHANGE_NETWORK_STATE, requiredPermissions);
// https://stackoverflow.com/questions/32185628/connectivitymanager-requestnetwork-in-android-6-0
// addToArrayListUnique(Manifest.permission.CHANGE_NETWORK_STATE, requiredPermissions);
/* Permission was not required anymore, even before Android 6: https://su.chainfire.eu/#updates-permission
addToArrayListUnique(permissionNameSuperuser, requiredPermissions);*/
break;
@ -512,7 +517,8 @@ public class ActivityPermissions extends Activity
case setDataConnection:
addToArrayListUnique(Manifest.permission.WRITE_SETTINGS, requiredPermissions);
addToArrayListUnique(Manifest.permission.ACCESS_NETWORK_STATE, requiredPermissions);
addToArrayListUnique(Manifest.permission.CHANGE_NETWORK_STATE, requiredPermissions);
// https://stackoverflow.com/questions/32185628/connectivitymanager-requestnetwork-in-android-6-0
// addToArrayListUnique(Manifest.permission.CHANGE_NETWORK_STATE, requiredPermissions);
addToArrayListUnique(Manifest.permission.READ_PHONE_STATE, requiredPermissions);
/* Permission was not required anymore, even before Android 6: https://su.chainfire.eu/#updates-permission
addToArrayListUnique(permissionNameSuperuser, requiredPermissions);*/
@ -522,16 +528,25 @@ public class ActivityPermissions extends Activity
break;
case setUsbTethering:
addToArrayListUnique(Manifest.permission.WRITE_SETTINGS, requiredPermissions);
addToArrayListUnique(Manifest.permission.CHANGE_NETWORK_STATE, requiredPermissions);
// https://stackoverflow.com/questions/32185628/connectivitymanager-requestnetwork-in-android-6-0
// addToArrayListUnique(Manifest.permission.CHANGE_NETWORK_STATE, requiredPermissions);
break;
case setBluetoothTethering:
//addToArrayListUnique(Manifest.permission.CHANGE_NETWORK_STATE, requiredPermissions);
addToArrayListUnique(Manifest.permission.BLUETOOTH, requiredPermissions);
addToArrayListUnique(Manifest.permission.BLUETOOTH_ADMIN, requiredPermissions);
addToArrayListUnique(Manifest.permission.WRITE_SETTINGS, requiredPermissions);
break;
case setWifi:
addToArrayListUnique(Manifest.permission.WRITE_SETTINGS, requiredPermissions);
addToArrayListUnique(Manifest.permission.CHANGE_NETWORK_STATE, requiredPermissions);
// https://stackoverflow.com/questions/32185628/connectivitymanager-requestnetwork-in-android-6-0
// addToArrayListUnique(Manifest.permission.CHANGE_NETWORK_STATE, requiredPermissions);
addToArrayListUnique(Manifest.permission.ACCESS_NETWORK_STATE, requiredPermissions);
break;
case setWifiTethering:
addToArrayListUnique(Manifest.permission.WRITE_SETTINGS, requiredPermissions);
addToArrayListUnique(Manifest.permission.CHANGE_NETWORK_STATE, requiredPermissions);
// https://stackoverflow.com/questions/32185628/connectivitymanager-requestnetwork-in-android-6-0
// addToArrayListUnique(Manifest.permission.CHANGE_NETWORK_STATE, requiredPermissions);
addToArrayListUnique(Manifest.permission.ACCESS_NETWORK_STATE, requiredPermissions);
/*
@ -578,30 +593,30 @@ public class ActivityPermissions extends Activity
break;
case turnUsbTetheringOff:
addToArrayListUnique(Manifest.permission.WRITE_SETTINGS, requiredPermissions);
addToArrayListUnique(Manifest.permission.CHANGE_NETWORK_STATE, requiredPermissions);
// addToArrayListUnique(Manifest.permission.CHANGE_NETWORK_STATE, requiredPermissions);
break;
case turnUsbTetheringOn:
addToArrayListUnique(Manifest.permission.WRITE_SETTINGS, requiredPermissions);
addToArrayListUnique(Manifest.permission.CHANGE_NETWORK_STATE, requiredPermissions);
// addToArrayListUnique(Manifest.permission.CHANGE_NETWORK_STATE, requiredPermissions);
break;
case turnWifiOff:
addToArrayListUnique(Manifest.permission.WRITE_SETTINGS, requiredPermissions);
addToArrayListUnique(Manifest.permission.CHANGE_NETWORK_STATE, requiredPermissions);
// addToArrayListUnique(Manifest.permission.CHANGE_NETWORK_STATE, requiredPermissions);
addToArrayListUnique(Manifest.permission.ACCESS_NETWORK_STATE, requiredPermissions);
break;
case turnWifiOn:
addToArrayListUnique(Manifest.permission.WRITE_SETTINGS, requiredPermissions);
addToArrayListUnique(Manifest.permission.CHANGE_NETWORK_STATE, requiredPermissions);
// addToArrayListUnique(Manifest.permission.CHANGE_NETWORK_STATE, requiredPermissions);
addToArrayListUnique(Manifest.permission.ACCESS_NETWORK_STATE, requiredPermissions);
break;
case turnWifiTetheringOff:
addToArrayListUnique(Manifest.permission.WRITE_SETTINGS, requiredPermissions);
addToArrayListUnique(Manifest.permission.CHANGE_NETWORK_STATE, requiredPermissions);
// addToArrayListUnique(Manifest.permission.CHANGE_NETWORK_STATE, requiredPermissions);
addToArrayListUnique(Manifest.permission.ACCESS_NETWORK_STATE, requiredPermissions);
break;
case turnWifiTetheringOn:
addToArrayListUnique(Manifest.permission.WRITE_SETTINGS, requiredPermissions);
addToArrayListUnique(Manifest.permission.CHANGE_NETWORK_STATE, requiredPermissions);
// addToArrayListUnique(Manifest.permission.CHANGE_NETWORK_STATE, requiredPermissions);
addToArrayListUnique(Manifest.permission.ACCESS_NETWORK_STATE, requiredPermissions);
break;
case waitBeforeNextAction:
@ -609,6 +624,9 @@ public class ActivityPermissions extends Activity
case wakeupDevice:
addToArrayListUnique(Manifest.permission.WAKE_LOCK, requiredPermissions);
break;
case playSound:
addToArrayListUnique(Manifest.permission.READ_EXTERNAL_STORAGE, requiredPermissions);
break;
default:
break;
}
@ -647,7 +665,7 @@ public class ActivityPermissions extends Activity
{
for (Action action : rule.getActionSet())
{
if(action.equals(actionType))
if(action.getAction().equals(actionType))
addToArrayListUnique(rule.getName(), returnList);
}
}
@ -674,17 +692,14 @@ public class ActivityPermissions extends Activity
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))
usingElements.add(String.format(getResources().getString(R.string.ruleXrequiresThis), ruleName));
break;
case Manifest.permission.ACTIVITY_RECOGNITION:
for(String ruleName : getRulesUsing(Trigger.Trigger_Enum.activityDetection))
usingElements.add(String.format(getResources().getString(R.string.ruleXrequiresThis), ruleName));
break;
case Manifest.permission.ACCESS_COARSE_LOCATION:
// usingElements.add(getResources().getString(R.string.android_permission_ACCESS_COARSE_LOCATION));
@ -821,6 +836,10 @@ public class ActivityPermissions extends Activity
case Manifest.permission.FOREGROUND_SERVICE:
usingElements.add(getResources().getString(R.string.startAutomationAsService));
break;
case Manifest.permission.READ_EXTERNAL_STORAGE:
for(String ruleName : getRulesUsing(Action.Action_Enum.playSound))
usingElements.add(String.format(getResources().getString(R.string.ruleXrequiresThis), ruleName));
break;
}
return usingElements;
@ -965,8 +984,8 @@ public class ActivityPermissions extends Activity
if(requiredPermissions.contains(Manifest.permission.SEND_SMS))
{
if(!ActivityPermissions.isPermissionDeclaratedInManifest(Miscellaneous.getAnyContext(), Manifest.permission.SEND_SMS)
&&
Miscellaneous.isGooglePlayInstalled(Miscellaneous.getAnyContext())
// &&
// Miscellaneous.isGooglePlayInstalled(Miscellaneous.getAnyContext())
)
{
requiredPermissions.remove(Manifest.permission.SEND_SMS);
@ -984,7 +1003,10 @@ public class ActivityPermissions extends Activity
Miscellaneous.logEvent("i", "Permissions", "Requesting permissions: " + permissions, 2);
// Toast.makeText(ActivityPermissions.this, "Requesting permissions. Amount: " + String.valueOf(requiredPermissions.size()), Toast.LENGTH_LONG).show();
requestPermissions(requiredPermissions.toArray(new String[requiredPermissions.size()]), requestCodeForPermissions);
if(requiredPermissions.size() > 0)
requestPermissions(requiredPermissions.toArray(new String[requiredPermissions.size()]), requestCodeForPermissions);
// else
// Miscellaneous.messageBox(getResources().getString(R.string.warning), getResources().getString(R.string.permissionsRequiredNotAvailable), ActivityPermissions.this).show();
}
else
setHaveAllPermissions();
@ -1152,10 +1174,6 @@ public class ActivityPermissions extends Activity
private void setHaveAllPermissions()
{
setResult(RESULT_OK);
// All permissions have been granted.
NotificationManager mNotificationManager = (NotificationManager) Miscellaneous.getAnyContext().getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.cancel(notificationIdPermissions);
ActivityMainScreen.updateMainScreen();
try
{
@ -1166,6 +1184,14 @@ public class ActivityPermissions extends Activity
// Activity may not have been loaded, yet.
}
// All permissions have been granted.
NotificationManager mNotificationManager = (NotificationManager) Miscellaneous.getAnyContext().getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.cancel(notificationIdPermissions);
if(AutomationService.getInstance() != null)
AutomationService.getInstance().cancelNotification();
ActivityMainScreen.updateMainScreen();
this.finish();
}
@ -1322,6 +1348,7 @@ public class ActivityPermissions extends Activity
mapActionPermissions.put("turnWifiTetheringOn", Manifest.permission.WRITE_SETTINGS);
mapActionPermissions.put("turnWifiTetheringOn", Manifest.permission.CHANGE_NETWORK_STATE);
mapActionPermissions.put("turnWifiTetheringOn", Manifest.permission.ACCESS_NETWORK_STATE);
mapActionPermissions.put("playSound", Manifest.permission.READ_EXTERNAL_STORAGE);
// mapActionPermissions.put("waitBeforeNextAction", "");
mapActionPermissions.put("wakeupDevice", Manifest.permission.WAKE_LOCK);
}

View File

@ -24,6 +24,7 @@ import android.util.Log;
import android.widget.Toast;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import com.jens.automation2.Trigger.Trigger_Enum;
import com.jens.automation2.location.LocationProvider;
@ -198,6 +199,7 @@ public class AutomationService extends Service implements OnInitListener
if (checkStartupRequirements(this, startAtBoot))
{
Miscellaneous.logEvent("i", "Service", this.getResources().getString(R.string.logServiceStarting) + " VERSION_CODE: " + BuildConfig.VERSION_CODE + ", VERSION_NAME: " + BuildConfig.VERSION_NAME + ", flavor: " + BuildConfig.FLAVOR, 1);
Miscellaneous.logEvent("i", "Service", ActivityMaintenance.getSystemInfo(), 1);
startUpRoutine();
@ -333,7 +335,7 @@ public class AutomationService extends Service implements OnInitListener
protected void startLocationProvider()
{
if(ActivityPermissions.havePermission("android.permission.ACCESS_COARSE_LOCATION", AutomationService.this))
if(ActivityPermissions.havePermission(Manifest.permission.ACCESS_COARSE_LOCATION, AutomationService.this))
myLocationProvider = new LocationProvider(this); //autostart with this (only) constructor
}
@ -407,6 +409,14 @@ public class AutomationService extends Service implements OnInitListener
}
}
public void cancelNotification()
{
// stopForeground(false);
NotificationManagerCompat.from(AutomationService.this).cancelAll();
// NotificationManagerCompat.from(AutomationService.this).cancel(ActivityPermissions.notificationIdPermissions);
// NotificationManagerCompat.from(AutomationService.this).cancel(AutomationService.notificationIdRestrictions);
}
protected void checkForMissingBackgroundLocationPermission()
{
if(Miscellaneous.googleToBlameForLocation(true))
@ -421,23 +431,6 @@ public class AutomationService extends Service implements OnInitListener
else
Miscellaneous.createDismissableNotification(getResources().getString(R.string.featuresDisabled), notificationIdLocationRestriction, pi);
}
/*
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
{
if (BuildConfig.FLAVOR.equalsIgnoreCase("googlePlayFlavor"))
{
if (Rule.isAnyRuleUsing(Trigger_Enum.pointOfInterest))
{
Intent intent = new Intent(AutomationService.this, ActivityMainTabLayout.class);
PendingIntent pi = PendingIntent.getActivity(AutomationService.this, 0, intent, 0);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1)
Miscellaneous.createDismissableNotificationWithDelay(2200, getResources().getString(R.string.featuresDisabled), notificationIdLocationRestriction, pi);
else
Miscellaneous.createDismissableNotification(getResources().getString(R.string.featuresDisabled), notificationIdLocationRestriction, pi);
}
}
}*/
}
public static void startAutomationService(Context context, boolean startAtBoot)
@ -631,7 +624,10 @@ public class AutomationService extends Service implements OnInitListener
// myNotification.setLatestEventInfo(instance, "Automation", textToDisplay, myPendingIntent);
// }
// else
// {
// {
if(notificationBuilder == null)
notificationBuilder = createDefaultNotificationBuilder();
notificationBuilder.setContentText(textToDisplay);
notificationBuilder.setStyle(new NotificationCompat.BigTextStyle().bigText(textToDisplay));

View File

@ -15,6 +15,8 @@ import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
@ -75,6 +77,8 @@ import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.sql.Time;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
@ -447,6 +451,14 @@ public class Miscellaneous extends Service
public static boolean compare(String direction, String needle, String haystack)
{
// If only one of needle or haystack is null
if(
(needle == null && haystack != null)
||
(needle != null && haystack == null)
)
return false;
switch(direction)
{
case Trigger.directionEquals:
@ -599,7 +611,10 @@ public class Miscellaneous extends Service
if(notificationTitle != null && notificationTitle.length() > 0)
source = source.replace("[notificationTitle]", notificationTitle);
else
{
source = source.replace("notificationTitle unknown", notificationTitle);
Miscellaneous.logEvent("w", "Variable replacement", "notificationTitle was empty.", 3);
}
}
if(source.contains("[notificationText]"))
@ -609,7 +624,10 @@ public class Miscellaneous extends Service
if(notificationText != null && notificationText.length() > 0)
source = source.replace("[notificationText]", notificationText);
else
{
source = source.replace("notificationText unknown", notificationText);
Miscellaneous.logEvent("w", "Variable replacement", "notificationText was empty.", 3);
}
}
// Miscellaneous.logEvent("i", "URL after replace", source);
@ -656,6 +674,24 @@ public class Miscellaneous extends Service
return alertDialog.create();
}
private boolean haveNetworkConnection()
{
boolean haveConnectedWifi = false;
boolean haveConnectedMobile = false;
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo[] netInfo = cm.getAllNetworkInfo();
for (NetworkInfo ni : netInfo) {
if (ni.getTypeName().equalsIgnoreCase("WIFI"))
if (ni.isConnected())
haveConnectedWifi = true;
if (ni.getTypeName().equalsIgnoreCase("MOBILE"))
if (ni.isConnected())
haveConnectedMobile = true;
}
return haveConnectedWifi || haveConnectedMobile;
}
/**
* Checks if the device is rooted.
@ -664,9 +700,13 @@ 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")) {
if (buildTags != null && buildTags.contains("test-keys"))
{
return true;
}
@ -873,6 +913,7 @@ public class Miscellaneous extends Service
dismissableNotificationBuilder.setContentText(textToDisplay);
dismissableNotificationBuilder.setContentIntent(pendingIntent);
dismissableNotificationBuilder.setStyle(new NotificationCompat.BigTextStyle().bigText(textToDisplay));
dismissableNotificationBuilder.setAutoCancel(true);
Notification dismissableNotification = dismissableNotificationBuilder.build();
@ -974,6 +1015,7 @@ public class Miscellaneous extends Service
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
builder.setCategory(Notification.CATEGORY_SERVICE);
builder.setAutoCancel(true);
builder.setWhen(System.currentTimeMillis());
builder.setContentIntent(myPendingIntent);
@ -1492,4 +1534,21 @@ public class Miscellaneous extends Service
else*/
return PhoneNumberUtils.compare(number1, number2);
}
public static String formatDate(Date input)
{
DateFormat sdf = null;
SimpleDateFormat fallBackFormatter = new SimpleDateFormat(Settings.dateFormat);
if(sdf == null && Settings.dateFormat != null)
sdf = new SimpleDateFormat(Settings.dateFormat);
String formattedDate;
if(sdf != null)
formattedDate = sdf.format(input);
else
formattedDate = fallBackFormatter.format(input);
return formattedDate;
}
}

View File

@ -264,7 +264,7 @@ public class PointOfInterest implements Comparable<PointOfInterest>
for(int i=0; i<ruleCandidates.size(); i++)
{
if(ruleCandidates.get(i).applies(parentService) && ruleCandidates.get(i).haveEnoughPermissions())
if(ruleCandidates.get(i).haveEnoughPermissions() && ruleCandidates.get(i).getsGreenLight(parentService))
{
Miscellaneous.logEvent("i", "POI", "Rule " + ruleCandidates.get(i).getName() + " applies for entering POI " + this.getName() + ".", 2);
ruleCandidates.get(i).activate(parentService, false);
@ -276,6 +276,7 @@ public class PointOfInterest implements Comparable<PointOfInterest>
ActivityMainScreen.updateMainScreen();
}
}
public void deactivate(AutomationService parentService)
{
if(this.isActivated())
@ -296,7 +297,7 @@ public class PointOfInterest implements Comparable<PointOfInterest>
Miscellaneous.logEvent("i", "POI", "POI " + this.getName() + " found in " + ruleCandidates.size() + " rule(s).", 2);
for(int i=0; i<ruleCandidates.size(); i++)
{
if(ruleCandidates.get(i).applies(parentService))
if(ruleCandidates.get(i).haveEnoughPermissions() && ruleCandidates.get(i).getsGreenLight(parentService))
{
Miscellaneous.logEvent("i", "POI", "Rule " + ruleCandidates.get(i).getName() + " applies for leaving POI " + this.getName() + ".", 2);
ruleCandidates.get(i).activate(parentService, false);

View File

@ -5,6 +5,7 @@ import android.content.Context;
import android.media.AudioManager;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Build;
import android.provider.MediaStore;
import android.util.Log;
import android.widget.Toast;
@ -24,6 +25,9 @@ public class Profile implements Comparable<Profile>
protected boolean changeSoundMode;
protected int soundMode;
protected boolean changeDndMode;
protected int dndMode;
boolean changeVolumeMusicVideoGameMedia;
protected int volumeMusic;
@ -81,6 +85,26 @@ public class Profile implements Comparable<Profile>
return soundMode;
}
public boolean getChangeDndMode()
{
return changeDndMode;
}
public void setChangeDndMode(boolean changeDndMode)
{
this.changeDndMode = changeDndMode;
}
public int getDndMode()
{
return dndMode;
}
public void setDndMode(int dndMode)
{
this.dndMode = dndMode;
}
public void setChangeVolumeMusicVideoGameMedia(boolean changeVolumeMusicVideoGameMedia)
{
this.changeVolumeMusicVideoGameMedia = changeVolumeMusicVideoGameMedia;
@ -449,6 +473,9 @@ public class Profile implements Comparable<Profile>
if(changeSoundMode)
Actions.setSound(context, soundMode);
if(changeDndMode)
Actions.setDND(context, dndMode);
if(changeVolumeMusicVideoGameMedia)
am.setStreamVolume(AudioManager.STREAM_MUSIC, volumeMusic, AudioManager.FLAG_PLAY_SOUND);
@ -464,10 +491,19 @@ public class Profile implements Comparable<Profile>
applyRingTone(incomingCallsRingtone, RingtoneManager.TYPE_RINGTONE, context);
if(changeVibrateWhenRinging)
if(vibrateWhenRinging)
am.setVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER, AudioManager.VIBRATE_SETTING_ON);
else
am.setVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER, AudioManager.VIBRATE_SETTING_OFF);
{
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
android.provider.Settings.System.putInt(context.getContentResolver(), "vibrate_when_ringing", vibrateWhenRinging?1:0);
}
else
{
if (vibrateWhenRinging)
am.setVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER, AudioManager.VIBRATE_SETTING_ON);
else
am.setVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER, AudioManager.VIBRATE_SETTING_OFF);
}
}
if(changeNotificationRingtone)
if(notificationRingtone != null)

View File

@ -5,11 +5,12 @@ import android.util.Log;
import com.jens.automation2.location.CellLocationChangedReceiver;
import com.jens.automation2.location.WifiBroadcastReceiver;
import com.jens.automation2.receivers.AlarmListener;
import com.jens.automation2.receivers.DateTimeListener;
import com.jens.automation2.receivers.AutomationListenerInterface;
import com.jens.automation2.receivers.BatteryReceiver;
import com.jens.automation2.receivers.BluetoothReceiver;
import com.jens.automation2.receivers.ConnectivityReceiver;
import com.jens.automation2.receivers.DevicePositionListener;
import com.jens.automation2.receivers.HeadphoneJackListener;
import com.jens.automation2.receivers.NoiseListener;
import com.jens.automation2.receivers.PhoneStatusListener;
@ -42,10 +43,11 @@ public class ReceiverCoordinator
Class adClass = Class.forName("ActivityDetectionReceiver");
allImplementers = new Class[] {
adClass,
AlarmListener.class,
DateTimeListener.class,
BatteryReceiver.class,
BluetoothReceiver.class,
ConnectivityReceiver.class,
DevicePositionListener.class,
HeadphoneJackListener.class,
//NfcReceiver.class,
NoiseListener.class,
@ -56,13 +58,12 @@ public class ReceiverCoordinator
}
catch (ClassNotFoundException e)
{
// e.printStackTrace();
allImplementers = new Class[] {
AlarmListener.class,
DateTimeListener.class,
BatteryReceiver.class,
BluetoothReceiver.class,
ConnectivityReceiver.class,
DevicePositionListener.class,
HeadphoneJackListener.class,
//NfcReceiver.class,
NoiseListener.class,
@ -144,18 +145,18 @@ public class ReceiverCoordinator
ConnectivityReceiver.startConnectivityReceiver(AutomationService.getInstance());
// startCellLocationChangedReceiver
if(!ConnectivityReceiver.isAirplaneMode(AutomationService.getInstance()) && WifiBroadcastReceiver.mayCellLocationReceiverBeActivated() && (Rule.isAnyRuleUsing(Trigger.Trigger_Enum.pointOfInterest) | Rule.isAnyRuleUsing(Trigger.Trigger_Enum.speed)))
if(!ConnectivityReceiver.isAirplaneMode(AutomationService.getInstance()) && WifiBroadcastReceiver.mayCellLocationReceiverBeActivated() && (Rule.isAnyRuleUsing(Trigger.Trigger_Enum.pointOfInterest) || Rule.isAnyRuleUsing(Trigger.Trigger_Enum.speed)))
{
if(!Miscellaneous.googleToBlameForLocation(true))
CellLocationChangedReceiver.startCellLocationChangedReceiver();
}
// startBatteryReceiver
if(Rule.isAnyRuleUsing(Trigger.Trigger_Enum.charging) | Rule.isAnyRuleUsing(Trigger.Trigger_Enum.usb_host_connection) | Rule.isAnyRuleUsing(Trigger.Trigger_Enum.batteryLevel))
if(Rule.isAnyRuleUsing(Trigger.Trigger_Enum.charging) || Rule.isAnyRuleUsing(Trigger.Trigger_Enum.usb_host_connection) || Rule.isAnyRuleUsing(Trigger.Trigger_Enum.batteryLevel))
BatteryReceiver.startBatteryReceiver(AutomationService.getInstance());
// startAlarmListener
AlarmListener.startAlarmListener(AutomationService.getInstance());
DateTimeListener.startAlarmListener(AutomationService.getInstance());
TimeZoneListener.startTimeZoneListener(AutomationService.getInstance());
// startNoiseListener
@ -166,6 +167,9 @@ public class ReceiverCoordinator
if(Rule.isAnyRuleUsing(Trigger.Trigger_Enum.process_started_stopped))
ProcessListener.startProcessListener(AutomationService.getInstance());
if(Rule.isAnyRuleUsing(Trigger.Trigger_Enum.devicePosition))
DevicePositionListener.getInstance().startListener(AutomationService.getInstance());
try
{
Class testClass = Class.forName(ActivityManageRule.activityDetectionClassPath);
@ -199,7 +203,7 @@ public class ReceiverCoordinator
WifiBroadcastReceiver.stopWifiReceiver();
BatteryReceiver.stopBatteryReceiver();
TimeZoneListener.stopTimeZoneListener();
AlarmListener.stopAlarmListener(AutomationService.getInstance());
DateTimeListener.stopAlarmListener(AutomationService.getInstance());
NoiseListener.stopNoiseListener();
ProcessListener.stopProcessListener(AutomationService.getInstance());
@ -216,6 +220,7 @@ public class ReceiverCoordinator
BluetoothReceiver.stopBluetoothReceiver();
HeadphoneJackListener.getInstance().stopListener(AutomationService.getInstance());
DevicePositionListener.getInstance().stopListener(AutomationService.getInstance());
}
catch(Exception e)
{
@ -350,6 +355,24 @@ public class ReceiverCoordinator
}
}
if(Rule.isAnyRuleUsing(Trigger.Trigger_Enum.devicePosition))
{
if(!DevicePositionListener.getInstance().isListenerRunning())
{
Miscellaneous.logEvent("i", "DevicePositionListener", "Starting DevicePositionListener because used in a new/changed rule.", 4);
// if(DevicePositionListener.getInstance().haveAllPermission())
DevicePositionListener.getInstance().startListener(AutomationService.getInstance());
}
}
else
{
if(DevicePositionListener.getInstance().isListenerRunning())
{
Miscellaneous.logEvent("i", "DevicePositionListener", "Shutting down DevicePositionListener because not used in any rule.", 4);
DevicePositionListener.getInstance().stopListener(AutomationService.getInstance());
}
}
AutomationService.updateNotification();
}
}

View File

@ -6,70 +6,90 @@ import java.util.ArrayList;
public class TimeFrame
{
// Defines a timeframe
private Time triggerTimeStart;
private Time triggerTimeStop;
protected Time triggerTimeStart;
protected Time triggerTimeStop;
protected long repetition;
private ArrayList<Integer> dayList = new ArrayList<Integer>();
public ArrayList<Integer> getDayList()
protected final static String separator = "/";
private ArrayList<Integer> dayList = new ArrayList<Integer>();
public ArrayList<Integer> getDayList()
{
return dayList;
}
public void setDayList(ArrayList<Integer> dayList)
{
this.dayList = dayList;
}
public void setDayListFromString(String dayListString)
{
// Log.i("Parsing", "Full string: " + dayListString);
char[] dayListCharArray = dayListString.toCharArray();
dayList = new ArrayList<Integer>();
for(char item : dayListCharArray)
{
return dayList;
}
public void setDayList(ArrayList<Integer> dayList)
{
this.dayList = dayList;
}
public void setDayListFromString(String dayListString)
{
// Log.i("Parsing", "Full string: " + dayListString);
char[] dayListCharArray = dayListString.toCharArray();
dayList = new ArrayList<Integer>();
for(char item : dayListCharArray)
{
// Log.i("Parsing", String.valueOf(item));
dayList.add(Integer.parseInt(String.valueOf(item)));
}
dayList.add(Integer.parseInt(String.valueOf(item)));
}
}
public Time getTriggerTimeStart()
{
return triggerTimeStart;
}
public void setTriggerTimeStart(Time triggerTimeStart)
{
this.triggerTimeStart = triggerTimeStart;
}
public Time getTriggerTimeStop()
{
return triggerTimeStop;
}
public void setTriggerTimeStop(Time triggerTimeStop)
{
this.triggerTimeStop = triggerTimeStop;
}
public TimeFrame (Time timeStart, Time timeEnd, ArrayList<Integer> dayList2)
{
this.setTriggerTimeStart(timeStart);
this.setTriggerTimeStop(timeEnd);
this.setDayList(dayList2);
}
TimeFrame (String fileContent)
{
String[] dateArray = fileContent.split("/"); // example: timestart/timestop/days[int]
this.setTriggerTimeStart(Time.valueOf(dateArray[0]));
this.setTriggerTimeStop(Time.valueOf(dateArray[1]));
this.setDayListFromString(dateArray[2]);
}
@Override
public String toString()
{
String returnString = this.getTriggerTimeStart().toString() + "/" + this.getTriggerTimeStop().toString() + "/";
for(Integer oneDay : this.getDayList())
returnString += String.valueOf(oneDay);
return returnString;
}
}
public Time getTriggerTimeStart()
{
return triggerTimeStart;
}
public void setTriggerTimeStart(Time triggerTimeStart)
{
this.triggerTimeStart = triggerTimeStart;
}
public Time getTriggerTimeStop()
{
return triggerTimeStop;
}
public void setTriggerTimeStop(Time triggerTimeStop)
{
this.triggerTimeStop = triggerTimeStop;
}
public long getRepetition()
{
return repetition;
}
public void setRepetition(long repetition)
{
this.repetition = repetition;
}
public TimeFrame (Time timeStart, Time timeEnd, ArrayList<Integer> dayList2, long repetition)
{
this.setTriggerTimeStart(timeStart);
this.setTriggerTimeStop(timeEnd);
this.setDayList(dayList2);
this.setRepetition(repetition);
}
public TimeFrame (String fileContent)
{
String[] dateArray = fileContent.split(separator); // example: timestart/timestop/days[int]/repetition
this.setTriggerTimeStart(Time.valueOf(dateArray[0]));
this.setTriggerTimeStop(Time.valueOf(dateArray[1]));
this.setDayListFromString(dateArray[2]);
if(dateArray.length > 3) // may not exist in old config files
this.setRepetition(Long.parseLong(dateArray[3]));
}
@Override
public String toString()
{
String returnString = this.getTriggerTimeStart().toString() + separator + this.getTriggerTimeStop().toString() + separator;
for(Integer oneDay : this.getDayList())
returnString += String.valueOf(oneDay);
returnString += separator + String.valueOf(repetition);
return returnString;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -170,9 +170,9 @@ public class XmlFileInterface
serializer.startTag(null, "changeVibrateWhenRinging");
serializer.text(String.valueOf(Profile.getProfileCollection().get(i).getChangeVibrateWhenRinging()));
serializer.endTag(null, "changeVibrateWhenRinging");//
serializer.startTag(null, "changeVibrateWhenRinging");
serializer.startTag(null, "vibrateWhenRinging");
serializer.text(String.valueOf(Profile.getProfileCollection().get(i).getVibrateWhenRinging()));
serializer.endTag(null, "changeVibrateWhenRinging");
serializer.endTag(null, "vibrateWhenRinging");
serializer.startTag(null, "changeNotificationRingtone");
serializer.text(String.valueOf(Profile.getProfileCollection().get(i).getChangeNotificationRingtone()));
@ -204,13 +204,19 @@ public class XmlFileInterface
serializer.endTag(null, "changeHapticFeedback");//
serializer.startTag(null, "hapticFeedback");
serializer.text(String.valueOf(Profile.getProfileCollection().get(i).getHapticFeedback()));
serializer.endTag(null, "hapticFeedback");
serializer.endTag(null, "hapticFeedback");
serializer.startTag(null, "changeDndMode");
serializer.text(String.valueOf(Profile.getProfileCollection().get(i).getChangeDndMode()));
serializer.endTag(null, "changeDndMode");//
serializer.startTag(null, "dndMode");
serializer.text(String.valueOf(Profile.getProfileCollection().get(i).getDndMode()));
serializer.endTag(null, "dndMode");
serializer.endTag(null, "Profile");
}
serializer.endTag(null, "ProfileCollection");
serializer.startTag(null, "RuleCollection");
for(int i=0; i<Rule.getRuleCollection().size(); i++)
@ -607,6 +613,10 @@ public class XmlFileInterface
newProfile.setChangeSoundMode(Boolean.parseBoolean(readTag(parser, "changeSoundMode")));
else if (name.equals("soundMode"))
newProfile.setSoundMode(Integer.parseInt(readTag(parser, "soundMode")));
else if (name.equals("changeDndMode"))
newProfile.setChangeDndMode(Boolean.parseBoolean(readTag(parser, "changeDndMode")));
else if (name.equals("dndMode"))
newProfile.setDndMode(Integer.parseInt(readTag(parser, "dndMode")));
else if (name.equals("changeVolumeMusicVideoGameMedia"))
newProfile.setChangeVolumeMusicVideoGameMedia(Boolean.parseBoolean(readTag(parser, "changeVolumeMusicVideoGameMedia")));
else if (name.equals("volumeMusic"))
@ -641,6 +651,8 @@ public class XmlFileInterface
else
newProfile.setNotificationRingtone(null);
}
else if (name.equals("vibrateWhenRinging"))
newProfile.setVibrateWhenRinging(Boolean.parseBoolean(readTag(parser, "vibrateWhenRinging")));
else if (name.equals("changeAudibleSelection"))
newProfile.setChangeAudibleSelection(Boolean.parseBoolean(readTag(parser, "changeAudibleSelection")));
else if (name.equals("audibleSelection"))
@ -752,6 +764,8 @@ public class XmlFileInterface
try
{
newRule.setTriggerSet(readTriggerCollection(parser));
for(Trigger t : newRule.getTriggerSet())
t.setParentRule(newRule);
}
catch (XmlPullParserException e)
{
@ -767,6 +781,8 @@ public class XmlFileInterface
try
{
newRule.setActionSet(readActionCollection(parser));
for(Action a : newRule.getActionSet())
a.setParentRule(newRule);
}
catch (XmlPullParserException e)
{
@ -803,7 +819,15 @@ public class XmlFileInterface
// Starts by looking for the entry tag
if (name.equals("Trigger"))
{
triggerCollection.add(readTrigger(parser));
try
{
triggerCollection.add(readTrigger(parser));
}
catch (IllegalArgumentException | NullPointerException e)
{
Miscellaneous.logEvent("e", "XMLFileInterface", "Unknown trigger found in config file. File was probably created by a newer program version. Details: " + Log.getStackTraceString(e), 1);
Miscellaneous.messageBox(context.getString(R.string.error), context.getString(R.string.elementSkipped), context).show();
}
}
else
{
@ -814,7 +838,6 @@ public class XmlFileInterface
return (triggerCollection);
}
private static Trigger readTrigger(XmlPullParser parser) throws IOException, XmlPullParserException
{
@ -1039,7 +1062,15 @@ public class XmlFileInterface
// Starts by looking for the entry tag
if (name.equals("Action"))
{
actionCollection.add(readAction(parser));
try
{
actionCollection.add(readAction(parser));
}
catch (IllegalArgumentException | NullPointerException e)
{
Miscellaneous.logEvent("e", "XMLFileInterface", "Unknown action found in config file. File was probably created by a newer program version. Details: " + Log.getStackTraceString(e), 1);
Miscellaneous.messageBox(context.getString(R.string.error), context.getString(R.string.elementSkipped), context).show();
}
}
else
{
@ -1048,7 +1079,6 @@ public class XmlFileInterface
}
return (actionCollection);
}
private static Action readAction(XmlPullParser parser) throws IOException, XmlPullParserException
{

View File

@ -130,6 +130,21 @@ public class CellLocationChangedReceiver extends PhoneStateListener
}
}
public static boolean isCellLocationChangedReceiverPossible()
{
if(telephonyManager == null)
telephonyManager = (TelephonyManager) AutomationService.getInstance().getSystemService(Context.TELEPHONY_SERVICE);
if(
ConnectivityReceiver.isAirplaneMode(AutomationService.getInstance())
||
telephonyManager.getSimState() != TelephonyManager.SIM_STATE_READY
)
return false;
else
return true;
}
public Location getLocation(String accuracy)
{
Criteria crit = new Criteria();
@ -137,7 +152,7 @@ public class CellLocationChangedReceiver extends PhoneStateListener
String myProviderName;
// If privacy mode or no data connection available
if(Settings.privacyLocationing | !ConnectivityReceiver.isDataConnectionAvailable(AutomationService.getInstance()))
if(Settings.privacyLocationing || !ConnectivityReceiver.isDataConnectionAvailable(AutomationService.getInstance()))
{
Miscellaneous.logEvent("i", "CellLocation", Miscellaneous.getAnyContext().getResources().getString(R.string.enforcingGps), 4);
myProviderName = LocationManager.GPS_PROVIDER;
@ -175,6 +190,9 @@ public class CellLocationChangedReceiver extends PhoneStateListener
}
else
{
if(myLocationManager == null)
myLocationManager = (LocationManager) AutomationService.getInstance().getSystemService(Context.LOCATION_SERVICE);
if(!myLocationManager.isProviderEnabled(myProviderName))
{
if(myProviderName.equals(LocationManager.NETWORK_PROVIDER))
@ -226,13 +244,11 @@ public class CellLocationChangedReceiver extends PhoneStateListener
return currentLocation;
}
public void setCurrentLocation(Location currentLocation)
{
this.currentLocation = currentLocation;
}
public class MyLocationListener implements LocationListener
{
@Override
@ -322,12 +338,12 @@ public class CellLocationChangedReceiver extends PhoneStateListener
{
if(telephonyManager == null)
telephonyManager = (TelephonyManager) AutomationService.getInstance().getSystemService(Context.TELEPHONY_SERVICE);
try
{
if(!cellLocationListenerActive)
{
if(!ConnectivityReceiver.isAirplaneMode(AutomationService.getInstance()))
if(!ConnectivityReceiver.isAirplaneMode(AutomationService.getInstance()) && telephonyManager.getSimState() == TelephonyManager.SIM_STATE_READY)
{
if(WifiBroadcastReceiver.mayCellLocationReceiverBeActivated())
{
@ -356,7 +372,7 @@ public class CellLocationChangedReceiver extends PhoneStateListener
Miscellaneous.logEvent("w", "cellReceiver", "Wanted to activate CellLocationChangedReceiver, but Wifi-Receiver says not to.", 4);
}
else
Miscellaneous.logEvent("i", "cellReceiver", "Not starting cellLocationListener because Airplane mode is active.", 4);
Miscellaneous.logEvent("i", "cellReceiver", "Not starting cellLocationListener because Airplane mode is active or SIM_STATE is not ready.", 4);
}
}
catch(Exception ex)
@ -409,5 +425,4 @@ public class CellLocationChangedReceiver extends PhoneStateListener
&&
ActivityPermissions.havePermission("android.permission.ACCESS_WIFI_STATE", Miscellaneous.getAnyContext());
}
}
}

View File

@ -7,6 +7,7 @@ import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.telephony.TelephonyManager;
import android.util.Log;
import com.jens.automation2.ActivityMainScreen;
@ -26,13 +27,9 @@ import java.util.Calendar;
public class LocationProvider
{
protected static boolean passiveLocationListenerActive = false;
protected static LocationListener passiveLocationListener;
protected static LocationProvider locationProviderInstance = null;
protected AutomationService parentService;
public AutomationService getParentService()
{
@ -109,123 +106,128 @@ public class LocationProvider
public void setCurrentLocation(Location newLocation, boolean skipVerification)
{
Miscellaneous.logEvent("i", "Location", "Setting location.", 4);
currentLocation = newLocation;
currentLocationStaticCopy = newLocation;
Miscellaneous.logEvent("i", "LocationListener", "Giving update to POI class", 4);
PointOfInterest.positionUpdate(newLocation, parentService, false, skipVerification);
try
if(newLocation != null)
{
if(
locationList.size() >= 1
&&
locationList.get(locationList.size()-1).getTime() == newLocation.getTime()
&&
locationList.get(locationList.size()-1).getProvider().equals(newLocation.getProvider())
Miscellaneous.logEvent("i", "Location", "Setting location.", 4);
currentLocation = newLocation;
currentLocationStaticCopy = newLocation;
Miscellaneous.logEvent("i", "LocationListener", "Giving update to POI class", 4);
PointOfInterest.positionUpdate(newLocation, parentService, false, skipVerification);
try
{
if (
locationList.size() >= 1
&&
locationList.get(locationList.size() - 1).getTime() == newLocation.getTime()
&&
locationList.get(locationList.size() - 1).getProvider().equals(newLocation.getProvider())
)
{
// This is a duplicate update, do not store it
Miscellaneous.logEvent("i", "LocationListener", "Duplicate location, ignoring.", 4);
}
else
{
Miscellaneous.logEvent("i", "Speed", "Commencing speed calculation.", 4);
// This part keeps the last two location entries to determine the current speed.
locationList.add(newLocation);
if(newLocation.hasSpeed())
{
Miscellaneous.logEvent("i", "Speed", "Location has speed, taking that: " + String.valueOf(newLocation.getSpeed()) + " km/h", 4);
setSpeed(newLocation.getSpeed()); // Take the value that came with the location, that should be more precise
// This is a duplicate update, do not store it
Miscellaneous.logEvent("i", "LocationListener", "Duplicate location, ignoring.", 4);
}
else
{
speedCalculation:
if (locationList.size() >= 2)
Miscellaneous.logEvent("i", "Speed", "Commencing speed calculation.", 4);
// This part keeps the last two location entries to determine the current speed.
locationList.add(newLocation);
if (newLocation.hasSpeed())
{
while (locationList.size() > 2)
Miscellaneous.logEvent("i", "Speed", "Location has speed, taking that: " + String.valueOf(newLocation.getSpeed()) + " km/h", 4);
setSpeed(newLocation.getSpeed()); // Take the value that came with the location, that should be more precise
}
else
{
speedCalculation:
if (locationList.size() >= 2)
{
// Remove all entries except for the last 2
Miscellaneous.logEvent("i", "Speed", "About to delete oldest position record until only 2 left. Currently have " + String.valueOf(locationList.size()) + " records.", 4);
locationList.remove(0);
}
while (locationList.size() > 2)
{
// Remove all entries except for the last 2
Miscellaneous.logEvent("i", "Speed", "About to delete oldest position record until only 2 left. Currently have " + String.valueOf(locationList.size()) + " records.", 4);
locationList.remove(0);
}
/*
The two most recent locations in the list must have a usable accuracy.
*/
for(int i = 0; i < 2; i++)
{
if
for (int i = 0; i < 2; i++)
{
if
(
(locationList.get(i).getProvider().equals(LocationManager.GPS_PROVIDER) && locationList.get(i).getAccuracy() > Settings.satisfactoryAccuracyGps)
||
(locationList.get(i).getProvider().equals(LocationManager.NETWORK_PROVIDER) && locationList.get(i).getAccuracy() > Settings.satisfactoryAccuracyNetwork)
(locationList.get(i).getProvider().equals(LocationManager.GPS_PROVIDER) && locationList.get(i).getAccuracy() > Settings.satisfactoryAccuracyGps)
||
(locationList.get(i).getProvider().equals(LocationManager.NETWORK_PROVIDER) && locationList.get(i).getAccuracy() > Settings.satisfactoryAccuracyNetwork)
)
{
Miscellaneous.logEvent("i", "Speed", "Not using 2 most recent locations for speed calculation because at least one does not have a satisfactory accuracy: " + locationList.get(i).toString(), 4);
break speedCalculation;
}
}
Miscellaneous.logEvent("i", "Speed", "Trying to calculate speed based on the last locations.", 4);
double currentSpeed;
long timeDifferenceInSeconds = (Math.abs(locationList.get(locationList.size() - 2).getTime() - locationList.get(locationList.size() - 1).getTime())) / 1000; //milliseconds
if (timeDifferenceInSeconds <= Settings.speedMaximumTimeBetweenLocations * 60)
{
double distanceTraveled = locationList.get(locationList.size() - 2).distanceTo(locationList.get(locationList.size() - 1)); //results in meters
if (timeDifferenceInSeconds == 0)
{
Miscellaneous.logEvent("w", "Speed", "No time passed since last position. Can't calculate speed here.", 4);
return;
{
Miscellaneous.logEvent("i", "Speed", "Not using 2 most recent locations for speed calculation because at least one does not have a satisfactory accuracy: " + locationList.get(i).toString(), 4);
break speedCalculation;
}
}
currentSpeed = distanceTraveled / timeDifferenceInSeconds * 3.6; // convert m/s --> km/h
Miscellaneous.logEvent("i", "Speed", "Trying to calculate speed based on the last locations.", 4);
double currentSpeed;
long timeDifferenceInSeconds = (Math.abs(locationList.get(locationList.size() - 2).getTime() - locationList.get(locationList.size() - 1).getTime())) / 1000; //milliseconds
if (timeDifferenceInSeconds <= Settings.speedMaximumTimeBetweenLocations * 60)
{
double distanceTraveled = locationList.get(locationList.size() - 2).distanceTo(locationList.get(locationList.size() - 1)); //results in meters
if (timeDifferenceInSeconds == 0)
{
Miscellaneous.logEvent("w", "Speed", "No time passed since last position. Can't calculate speed here.", 4);
return;
}
currentSpeed = distanceTraveled / timeDifferenceInSeconds * 3.6; // convert m/s --> km/h
/*
Due to strange factors the time difference might be 0 resulting in mathematical error.
*/
if (Double.isInfinite(currentSpeed) | Double.isNaN(currentSpeed))
Miscellaneous.logEvent("i", "Speed", "Error while calculating speed.", 4);
else
{
Miscellaneous.logEvent("i", "Speed", "Current speed: " + String.valueOf(currentSpeed) + " km/h", 2);
setSpeed(currentSpeed);
// execute matching rules containing speed
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesBySpeed();
for (Rule oneRule : ruleCandidates)
if (Double.isInfinite(currentSpeed) | Double.isNaN(currentSpeed))
Miscellaneous.logEvent("i", "Speed", "Error while calculating speed.", 4);
else
{
if (oneRule.applies(this.getParentService()))
oneRule.activate(getParentService(), false);
Miscellaneous.logEvent("i", "Speed", "Current speed: " + String.valueOf(currentSpeed) + " km/h", 2);
setSpeed(currentSpeed);
// execute matching rules containing speed
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesBySpeed();
for (Rule oneRule : ruleCandidates)
{
if(oneRule.getsGreenLight(this.getParentService()))
oneRule.activate(getParentService(), false);
}
}
}
else
Miscellaneous.logEvent("i", "Speed", "Last two locations are too far apart in terms of time. Cannot use them for speed calculation.", 4);
}
else
Miscellaneous.logEvent("i", "Speed", "Last two locations are too far apart in terms of time. Cannot use them for speed calculation.", 4);
}
else
{
Miscellaneous.logEvent("w", "Speed", "Don't have enough values for speed calculation, yet.", 3);
{
Miscellaneous.logEvent("w", "Speed", "Don't have enough values for speed calculation, yet.", 3);
}
}
}
}
}
catch(Exception e)
{
Miscellaneous.logEvent("e", "Speed", "Error during speed calculation: " + Log.getStackTraceString(e), 3);
}
catch (Exception e)
{
Miscellaneous.logEvent("e", "Speed", "Error during speed calculation: " + Log.getStackTraceString(e), 3);
}
AutomationService.updateNotification();
AutomationService.updateNotification();
if(AutomationService.isMainActivityRunning(parentService))
ActivityMainScreen.updateMainScreen();
if (AutomationService.isMainActivityRunning(parentService))
ActivityMainScreen.updateMainScreen();
}
else
Miscellaneous.logEvent("w", "Location", "New location given is null. Ignoring.", 5);
}
public void startLocationService()
@ -244,13 +246,37 @@ public class LocationProvider
if(Settings.positioningEngine == 0)
{
// startCellLocationChangedReceiver
if (!ConnectivityReceiver.isAirplaneMode(this.parentService) && WifiBroadcastReceiver.mayCellLocationReceiverBeActivated() && (Rule.isAnyRuleUsing(Trigger_Enum.pointOfInterest) | Rule.isAnyRuleUsing(Trigger_Enum.speed)))
CellLocationChangedReceiver.startCellLocationChangedReceiver();
// startPassiveLocationListener
if(Rule.isAnyRuleUsing(Trigger_Enum.pointOfInterest) | Rule.isAnyRuleUsing(Trigger_Enum.speed))
{
// TelephonyManager telephonyManager = (TelephonyManager) AutomationService.getInstance().getSystemService(Context.TELEPHONY_SERVICE);
// startCellLocationChangedReceiver
if (CellLocationChangedReceiver.isCellLocationChangedReceiverPossible())
{
if (WifiBroadcastReceiver.mayCellLocationReceiverBeActivated())
CellLocationChangedReceiver.startCellLocationChangedReceiver();
}
else
{
/*
Reasons why we may end up here:
- Airplane mode is active
- No phone module present (pure wifi device)
- No SIM card is inserted or it's not unlocked
We'd have to try GPS now to get an initial position.
For permanent use there is no way we could know when it
would make sense to check the position again.
*/
// Trigger a one-time-position-search
Location loc = CellLocationChangedReceiver.getInstance().getLocation("fine");
LocationProvider.getInstance().setCurrentLocation(loc, true);
}
// startPassiveLocationListener
startPassiveLocationListener();
}
}
else
{

View File

@ -147,7 +147,7 @@ public class WifiBroadcastReceiver extends BroadcastReceiver
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByWifiConnection();
for(Rule oneRule : ruleCandidates)
{
if(oneRule.applies(automationServiceInstance))
if(oneRule.getsGreenLight(automationServiceInstance))
oneRule.activate(automationServiceInstance, false);
}
}

View File

@ -1,301 +0,0 @@
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 com.jens.automation2.AutomationService;
import com.jens.automation2.Miscellaneous;
import com.jens.automation2.Rule;
import com.jens.automation2.Trigger;
import com.jens.automation2.Trigger.Trigger_Enum;
import java.sql.Time;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
public class AlarmListener extends BroadcastReceiver implements AutomationListenerInterface
{
private static AutomationService automationServiceRef;
private static AlarmManager centralAlarmManagerInstance;
// private static Intent alarmIntent;
// private static PendingIntent alarmPendingIntent;
private static boolean alarmListenerActive=false;
private static ArrayList<Long> alarmCandidates = new ArrayList<Long>();
private static ArrayList<Integer> requestCodeList = new ArrayList<Integer>();
public static void startAlarmListener(final AutomationService automationServiceRef)
{
AlarmListener.startAlarmListenerInternal(automationServiceRef);
}
public static void stopAlarmListener(Context context)
{
AlarmListener.stopAlarmListenerInternal();
}
public static boolean isAlarmListenerActive()
{
return alarmListenerActive;
}
@Override
public void onReceive(Context context, Intent intent)
{
Miscellaneous.logEvent("i", "AlarmListener", "Alarm received", 2);
Date now = new Date();
String timeString = String.valueOf(now.getHours()) + ":" + String.valueOf(now.getMinutes()) + ":" + String.valueOf(now.getSeconds());
Time passTime = Time.valueOf(timeString);
ArrayList<Rule> allRulesWithNowInTimeFrame = Rule.findRuleCandidatesByTime(passTime);
for(int i=0; i<allRulesWithNowInTimeFrame.size(); i++)
{
if(allRulesWithNowInTimeFrame.get(i).applies(context))
allRulesWithNowInTimeFrame.get(i).activate(automationServiceRef, false);
}
setAlarms();
}
public static void setAlarms()
{
alarmCandidates.clear();
SimpleDateFormat sdf = new SimpleDateFormat("E dd.MM.yyyy HH:mm");
clearAlarms();
int i=0;
// // get a Calendar object with current time
// Calendar cal = Calendar.getInstance();
// // add 5 minutes to the calendar object
// cal.add(Calendar.SECOND, 10);
// String calSetWorkingCopyString2 = null;
// SimpleDateFormat sdf2 = new SimpleDateFormat("E dd.MM.yyyy HH:mm");
// if (cal != null)
// {
// calSetWorkingCopyString2 = sdf2.format(cal.getTime());
// }
// Miscellaneous.logEvent("i", "AlarmManager", "Setting repeating alarm because of hardcoded test: beginning at " + calSetWorkingCopyString2);
// Intent alarmIntent2 = new Intent(automationServiceRef, AlarmListener.class);
// PendingIntent alarmPendingIntent2 = PendingIntent.getBroadcast(automationServiceRef, 0, alarmIntent2, 0);
// centralAlarmManagerInstance.setInexactRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 5000, alarmPendingIntent2);
// requestCodeList.add(0);
ArrayList<Rule> allRulesWithTimeFrames = new ArrayList<Rule>();
allRulesWithTimeFrames = Rule.findRuleCandidatesByTimeFrame();
for(Rule oneRule : allRulesWithTimeFrames)
{
for(Trigger oneTrigger : oneRule.getTriggerSet())
{
if(oneTrigger.getTriggerType() == Trigger_Enum.timeFrame)
{
Calendar calNow, calSet;
Time setTime;
if(oneTrigger.getTriggerParameter())
setTime = oneTrigger.getTimeFrame().getTriggerTimeStart();
else
setTime = oneTrigger.getTimeFrame().getTriggerTimeStop();
calNow = Calendar.getInstance();
calSet = (Calendar) calNow.clone();
calSet.set(Calendar.HOUR_OF_DAY, setTime.getHours());
calSet.set(Calendar.MINUTE, setTime.getMinutes());
calSet.set(Calendar.SECOND, 0);
calSet.set(Calendar.MILLISECOND, 0);
// At this point calSet would be a scheduling candidate. It's just the day the might not be right, yet.
long milliSecondsInAWeek = 1000 * 60 * 60 * 24 * 7;
for(int dayOfWeek : oneTrigger.getTimeFrame().getDayList())
{
Calendar calSetWorkingCopy = (Calendar) calSet.clone();
// calSetWorkingCopy.set(Calendar.HOUR_OF_DAY, setTime.getHours());
// calSetWorkingCopy.set(Calendar.MINUTE, setTime.getMinutes());
// calSetWorkingCopy.set(Calendar.SECOND, 0);
// calSetWorkingCopy.set(Calendar.MILLISECOND, 0);
int diff = dayOfWeek - calNow.get(Calendar.DAY_OF_WEEK);
// Log.i("AlarmManager", "Today: " + String.valueOf(calNow.get(Calendar.DAY_OF_WEEK)) + " / Sched.Day: " + String.valueOf(dayOfWeek) + " Difference to target day is: " + String.valueOf(diff));
if(diff == 0) //if we're talking about the current day, is the time still in the future?
{
if(calSetWorkingCopy.getTime().getHours() < calNow.getTime().getHours())
{
// Log.i("AlarmManager", "calSetWorkingCopy.getTime().getHours(" + String.valueOf(calSetWorkingCopy.getTime().getHours()) + ") < calNow.getTime().getHours(" + String.valueOf(calNow.getTime().getHours()) + ")");
calSetWorkingCopy.add(Calendar.DAY_OF_MONTH, 7); //add a week
}
else if(calSetWorkingCopy.getTime().getHours() == calNow.getTime().getHours())
{
// Log.i("AlarmManager", "calSetWorkingCopy.getTime().getHours() == calNow.getTime().getHours()");
if(calSetWorkingCopy.getTime().getMinutes() <= calNow.getTime().getMinutes())
{
// Log.i("AlarmManager", "calSetWorkingCopy.getTime().getMinutes() < calNow.getTime().getMinutes()");
calSetWorkingCopy.add(Calendar.DAY_OF_MONTH, 7); //add a week
}
}
}
else if(diff < 0)
{
// Miscellaneous.logEvent("i", "AlarmManager", "Adding " + String.valueOf(diff+7) + " on top of " + String.valueOf(calSetWorkingCopy.get(Calendar.DAY_OF_WEEK)));
calSetWorkingCopy.add(Calendar.DAY_OF_WEEK, diff+7); // it's a past weekday, schedule for next week
}
else
{
// Miscellaneous.logEvent("i", "AlarmManager", "Adding " + String.valueOf(diff) + " on top of " + String.valueOf(calSetWorkingCopy.get(Calendar.DAY_OF_WEEK)));
calSetWorkingCopy.add(Calendar.DAY_OF_WEEK, diff); // it's a future weekday, schedule for that day
}
i++;
i=(int)System.currentTimeMillis();
String calSetWorkingCopyString = sdf.format(calSetWorkingCopy.getTime()) + " RequestCode: " + String.valueOf(i);
// Miscellaneous.logEvent("i", "AlarmManager", "Setting repeating alarm because of rule: " + oneRule.getName() + " beginning at " + calSetWorkingCopyString);
alarmCandidates.add(calSetWorkingCopy.getTimeInMillis());
// Intent alarmIntent = new Intent(automationServiceRef, AlarmListener.class);
// alarmIntent.setData(Uri.parse("myalarms://" + i));
// PendingIntent alarmPendingIntent = PendingIntent.getBroadcast(automationServiceRef, i, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
// centralAlarmManagerInstance.setInexactRepeating(AlarmManager.RTC_WAKEUP, calSetWorkingCopy.getTimeInMillis(), milliSecondsInAWeek, alarmPendingIntent);
// requestCodeList.add(i);
}
}
}
}
// // get a Calendar object with current time
// Calendar cal = Calendar.getInstance();
// cal.add(Calendar.SECOND, 10);
// String calSetWorkingCopyString2 = sdf.format(cal.getTime());
// Miscellaneous.logEvent("i", "AlarmManager", "Setting repeating alarm because of hardcoded test: beginning at " + calSetWorkingCopyString2);
// Intent alarmIntent2 = new Intent(automationServiceRef, AlarmListener.class);
// PendingIntent alarmPendingIntent2 = PendingIntent.getBroadcast(automationServiceRef, 0, alarmIntent2, 0);
// centralAlarmManagerInstance.setInexactRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 5000, alarmPendingIntent2);
// requestCodeList.add(0);
scheduleNextAlarm();
}
private static void scheduleNextAlarm()
{
Long currentTime = System.currentTimeMillis();
Long scheduleCandidate = null;
if(alarmCandidates.size() == 0)
{
Miscellaneous.logEvent("i", "AlarmManager", "No alarms to be scheduled.", 3);
return;
}
else if(alarmCandidates.size() == 1)
{
// only one alarm, schedule that
scheduleCandidate = alarmCandidates.get(0);
}
else if(alarmCandidates.size() > 1)
{
scheduleCandidate = alarmCandidates.get(0);
for(long alarmCandidate : alarmCandidates)
{
if(Math.abs(currentTime - alarmCandidate) < Math.abs(currentTime - scheduleCandidate))
scheduleCandidate = alarmCandidate;
}
}
Intent alarmIntent = new Intent(automationServiceRef, AlarmListener.class);
PendingIntent alarmPendingIntent = PendingIntent.getBroadcast(automationServiceRef, 0, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
centralAlarmManagerInstance.set(AlarmManager.RTC_WAKEUP, scheduleCandidate, alarmPendingIntent);
SimpleDateFormat sdf = new SimpleDateFormat("E dd.MM.yyyy HH:mm");
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(scheduleCandidate);
Miscellaneous.logEvent("i", "AlarmManager", "Chose " + sdf.format(calendar.getTime()) + " as next scheduled alarm.", 4);
}
public static void clearAlarms()
{
Miscellaneous.logEvent("i", "AlarmManager", "Clearing possibly standing alarms.", 4);
for(int requestCode : requestCodeList)
{
Intent alarmIntent = new Intent(automationServiceRef, AlarmListener.class);
PendingIntent alarmPendingIntent = PendingIntent.getBroadcast(automationServiceRef, requestCode, alarmIntent, 0);
// Miscellaneous.logEvent("i", "AlarmManager", "Clearing alarm with request code: " + String.valueOf(requestCode));
centralAlarmManagerInstance.cancel(alarmPendingIntent);
}
requestCodeList.clear();
}
private static void startAlarmListenerInternal(AutomationService givenAutomationServiceRef)
{
if(!alarmListenerActive)
{
Miscellaneous.logEvent("i", "AlarmListener", "Starting alarm listener.", 4);
AlarmListener.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);
AlarmListener.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);
}
private static void stopAlarmListenerInternal()
{
if(alarmListenerActive)
{
Miscellaneous.logEvent("i", "AlarmListener", "Stopping alarm listener.", 4);
clearAlarms();
// centralAlarmManagerInstance.cancel(alarmPendingIntent);
alarmListenerActive = false;
}
else
Miscellaneous.logEvent("i", "AlarmListener", "Request to stop AlarmListener. But it's not running.", 5);
}
public static void reloadAlarms()
{
AlarmListener.setAlarms();
}
@Override
public void startListener(AutomationService automationService)
{
AlarmListener.startAlarmListener(automationService);
}
@Override
public void stopListener(AutomationService automationService)
{
AlarmListener.stopAlarmListener(automationService);
}
public static boolean haveAllPermission()
{
return true;
}
@Override
public boolean isListenerRunning()
{
return isAlarmListenerActive();
}
@Override
public Trigger_Enum[] getMonitoredTrigger()
{
return new Trigger_Enum[] { Trigger_Enum.timeFrame };
}
}

View File

@ -206,7 +206,7 @@ public class BatteryReceiver extends BroadcastReceiver implements AutomationList
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByCharging(true);
for(int i=0; i<ruleCandidates.size(); i++)
{
if(ruleCandidates.get(i).applies(context))
if(ruleCandidates.get(i).getsGreenLight(context))
ruleCandidates.get(i).activate(automationServiceRef, false);
}
}
@ -219,7 +219,7 @@ public class BatteryReceiver extends BroadcastReceiver implements AutomationList
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByBatteryLevel();
for(int i=0; i<ruleCandidates.size(); i++)
{
if(ruleCandidates.get(i).applies(context))
if(ruleCandidates.get(i).getsGreenLight(context))
ruleCandidates.get(i).activate(automationServiceRef, false);
}
}
@ -234,7 +234,7 @@ public class BatteryReceiver extends BroadcastReceiver implements AutomationList
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByCharging(false);
for(int i=0; i<ruleCandidates.size(); i++)
{
if(ruleCandidates.get(i).applies(context))
if(ruleCandidates.get(i).getsGreenLight(context))
ruleCandidates.get(i).activate(automationServiceRef, false);
}
@ -257,7 +257,7 @@ public class BatteryReceiver extends BroadcastReceiver implements AutomationList
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByUsbHost(true);
for(Rule oneRule : ruleCandidates)
{
if(oneRule.applies(context))
if(oneRule.getsGreenLight(context))
oneRule.activate(automationServiceRef, false);
}
@ -278,7 +278,7 @@ public class BatteryReceiver extends BroadcastReceiver implements AutomationList
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByUsbHost(false);
for(Rule oneRule : ruleCandidates)
{
if(oneRule.applies(context))
if(oneRule.getsGreenLight(context))
oneRule.activate(automationServiceRef, false);
}
}

View File

@ -127,7 +127,7 @@ public class BluetoothReceiver extends BroadcastReceiver implements AutomationLi
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByBluetoothConnection();
for(int i=0; i<ruleCandidates.size(); i++)
{
if(ruleCandidates.get(i).applies(AutomationService.getInstance()))
if(ruleCandidates.get(i).getsGreenLight(AutomationService.getInstance()))
ruleCandidates.get(i).activate(AutomationService.getInstance(), false);
}
}

View File

@ -112,7 +112,7 @@ public class ConnectivityReceiver extends BroadcastReceiver implements Automatio
@SuppressLint("NewApi")
public static boolean isAirplaneMode(Context context)
{
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1)
{
int value = android.provider.Settings.System.getInt(context.getContentResolver(), android.provider.Settings.System.AIRPLANE_MODE_ON, 0);
return value != 0;
@ -141,7 +141,7 @@ public class ConnectivityReceiver extends BroadcastReceiver implements Automatio
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByAirplaneMode(isAirplaneMode);
for(int i=0; i<ruleCandidates.size(); i++)
{
if(ruleCandidates.get(i).applies(automationServiceRef))
if(ruleCandidates.get(i).getsGreenLight(automationServiceRef))
ruleCandidates.get(i).activate(automationServiceRef, false);
}
}
@ -174,7 +174,7 @@ public class ConnectivityReceiver extends BroadcastReceiver implements Automatio
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByRoaming(isRoaming);
for(int i=0; i<ruleCandidates.size(); i++)
{
if(ruleCandidates.get(i).applies(automationServiceRef))
if(ruleCandidates.get(i).getsGreenLight(automationServiceRef))
ruleCandidates.get(i).activate(automationServiceRef, false);
}
}

View File

@ -0,0 +1,431 @@
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.os.Build;
import android.util.Log;
import androidx.annotation.RequiresApi;
import com.jens.automation2.AutomationService;
import com.jens.automation2.Miscellaneous;
import com.jens.automation2.Rule;
import com.jens.automation2.TimeFrame;
import com.jens.automation2.Trigger;
import com.jens.automation2.Trigger.Trigger_Enum;
import java.sql.Time;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
public class DateTimeListener extends BroadcastReceiver implements AutomationListenerInterface
{
private static AutomationService automationServiceRef;
private static AlarmManager centralAlarmManagerInstance;
// private static Intent alarmIntent;
// private static PendingIntent alarmPendingIntent;
private static boolean alarmListenerActive=false;
private static ArrayList<ScheduleElement> alarmCandidates = new ArrayList<>();
private static ArrayList<Integer> requestCodeList = new ArrayList<Integer>();
public static void startAlarmListener(final AutomationService automationServiceRef)
{
DateTimeListener.startAlarmListenerInternal(automationServiceRef);
}
public static void stopAlarmListener(Context context)
{
DateTimeListener.stopAlarmListenerInternal();
}
public static boolean isAlarmListenerActive()
{
return alarmListenerActive;
}
@Override
public void onReceive(Context context, Intent intent)
{
Miscellaneous.logEvent("i", "AlarmListener", "Alarm received", 2);
Date now = new Date();
String timeString = String.valueOf(now.getHours()) + ":" + String.valueOf(now.getMinutes()) + ":" + String.valueOf(now.getSeconds());
Time passTime = Time.valueOf(timeString);
ArrayList<Rule> allRulesWithNowInTimeFrame = Rule.findRuleCandidatesByTime(passTime);
for(int i=0; i<allRulesWithNowInTimeFrame.size(); i++)
{
if(allRulesWithNowInTimeFrame.get(i).getsGreenLight(context))
allRulesWithNowInTimeFrame.get(i).activate(automationServiceRef, false);
}
setAlarms();
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public static void setAlarms()
{
alarmCandidates.clear();
Calendar calNow = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("E dd.MM.yyyy HH:mm");
clearAlarms();
int i=0;
// // get a Calendar object with current time
// Calendar cal = Calendar.getInstance();
// // add 5 minutes to the calendar object
// cal.add(Calendar.SECOND, 10);
// String calSetWorkingCopyString2 = null;
// SimpleDateFormat sdf2 = new SimpleDateFormat("E dd.MM.yyyy HH:mm");
// if (cal != null)
// {
// calSetWorkingCopyString2 = sdf2.format(cal.getTime());
// }
// Miscellaneous.logEvent("i", "AlarmManager", "Setting repeating alarm because of hardcoded test: beginning at " + calSetWorkingCopyString2);
// Intent alarmIntent2 = new Intent(automationServiceRef, AlarmListener.class);
// PendingIntent alarmPendingIntent2 = PendingIntent.getBroadcast(automationServiceRef, 0, alarmIntent2, 0);
// centralAlarmManagerInstance.setInexactRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 5000, alarmPendingIntent2);
// requestCodeList.add(0);
ArrayList<Rule> allRulesWithTimeFrames = new ArrayList<Rule>();
allRulesWithTimeFrames = Rule.findRuleCandidatesByTimeFrame();
/*
* Take care of regular executions, no repetitions in between.
*/
Miscellaneous.logEvent("i", "DateTimeListener", "Checking rules for single run alarm candidates.", 5);
for(Rule oneRule : allRulesWithTimeFrames)
{
Miscellaneous.logEvent("i", "DateTimeListener","Checking rule " + oneRule.getName() + " for single run alarm candidates.", 5);
if(oneRule.isRuleActive())
{
try
{
for(Trigger oneTrigger : oneRule.getTriggerSet())
{
Miscellaneous.logEvent("i", "DateTimeListener","Checking trigger " + oneTrigger.toString() + " for single run alarm candidates.", 5);
if(oneTrigger.getTriggerType().equals(Trigger_Enum.timeFrame))
{
TimeFrame tf = new TimeFrame(oneTrigger.getTriggerParameter2());
Calendar calSet;
Time setTime;
if(oneTrigger.getTriggerParameter())
setTime = tf.getTriggerTimeStart();
else
setTime = tf.getTriggerTimeStop();
calSet = (Calendar) calNow.clone();
calSet.set(Calendar.HOUR_OF_DAY, setTime.getHours());
calSet.set(Calendar.MINUTE, setTime.getMinutes());
calSet.set(Calendar.SECOND, 0);
calSet.set(Calendar.MILLISECOND, 0);
// At this point calSet would be a scheduling candidate. It's just the day that might not be right, yet.
for(int dayOfWeek : tf.getDayList())
{
Calendar calSetWorkingCopy = (Calendar) calSet.clone();
int diff = dayOfWeek - calNow.get(Calendar.DAY_OF_WEEK);
if(diff == 0) // We're talking about the current weekday, but is the time still in the future?
{
if(calSetWorkingCopy.getTime().getHours() < calNow.getTime().getHours())
{
calSetWorkingCopy.add(Calendar.DAY_OF_MONTH, 7); //add a week
}
else if(calSetWorkingCopy.getTime().getHours() == calNow.getTime().getHours())
{
if(calSetWorkingCopy.getTime().getMinutes() <= calNow.getTime().getMinutes())
{
calSetWorkingCopy.add(Calendar.DAY_OF_MONTH, 7); //add a week
}
}
}
else if(diff < 0)
{
calSetWorkingCopy.add(Calendar.DAY_OF_WEEK, diff+7); // it's a past weekday, schedule for next week
}
else
{
calSetWorkingCopy.add(Calendar.DAY_OF_WEEK, diff); // it's a future weekday, schedule for that day
}
i++;
i=(int)System.currentTimeMillis();
sdf.format(calSetWorkingCopy.getTime());
String.valueOf(i);
alarmCandidates.add(new ScheduleElement(calSetWorkingCopy, "Rule " + oneRule.getName() + ", trigger " + oneTrigger.toString()));
}
}
}
}
catch(Exception e)
{
Miscellaneous.logEvent("e", "DateTimeListener","Error checking anything for rule " + oneRule.toString() + " needs to be added to candicates list: " + Log.getStackTraceString(e), 1);
}
}
}
/*
* Only take care of repeated executions.
*/
Miscellaneous.logEvent("i", "DateTimeListener","Checking rules for repeated run alarm candidates.", 5);
for(Rule oneRule : allRulesWithTimeFrames)
{
Miscellaneous.logEvent("i", "DateTimeListener","Checking rule " + oneRule.getName() + " for repeated run alarm candidates.", 5);
if(oneRule.isRuleActive())
{
try
{
Miscellaneous.logEvent("i", "DateTimeListener","Checking rule " + oneRule.toString() , 5);
for(Trigger oneTrigger : oneRule.getTriggerSet())
{
Miscellaneous.logEvent("i", "DateTimeListener","Checking trigger " + oneTrigger.toString() + " for repeated run alarm candidates.", 5);
if(oneTrigger.getTriggerType().equals(Trigger_Enum.timeFrame))
{
Miscellaneous.logEvent("i", "DateTimeListener","Checking rule trigger " + oneTrigger.toString() , 5);
/*
* Check for next repeated execution:
*
* Check if the rule currently applies....
*
* If no -> do nothing
* If yes -> Take starting time and calculate the next repeated execution
* 1. Take starting time
* 2. Take current time
* 3. Calculate difference, but include check to see if we're after that time,
* be it start or end of the timeframe.
* 4. Take div result +1 and add this on top of starting time
* 5. Is this next possible execution still inside timeframe? Also consider timeframes spanning over midnight
*/
Calendar calSet;
Time setTime;
TimeFrame tf = new TimeFrame(oneTrigger.getTriggerParameter2());
if(tf.getRepetition() > 0)
{
if(oneTrigger.applies(calNow, Miscellaneous.getAnyContext()))
{
Calendar calSchedule = getNextRepeatedExecutionAfter(oneTrigger, calNow);
alarmCandidates.add(new ScheduleElement(calSchedule, "Rule " + oneRule.getName() + ", trigger " + oneTrigger.toString()));
}
}
}
}
}
catch(Exception e)
{
Miscellaneous.logEvent("e", "DateTimeListener","Error checking anything for rule " + oneRule.toString() + " needs to be added to candicates list: " + Log.getStackTraceString(e), 1);
}
}
}
scheduleNextAlarm();
}
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)
{
// 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);
PendingIntent alarmPendingIntent = PendingIntent.getBroadcast(automationServiceRef, 0, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
centralAlarmManagerInstance.set(AlarmManager.RTC_WAKEUP, scheduleCandidate.time.getTimeInMillis(), alarmPendingIntent);
SimpleDateFormat sdf = new SimpleDateFormat("E dd.MM.yyyy HH:mm");
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(scheduleCandidate.time.getTimeInMillis());
Miscellaneous.logEvent("i", "AlarmManager", "Chose " + sdf.format(calendar.getTime()) + " as next scheduled alarm.", 4);
}
public static void clearAlarms()
{
Miscellaneous.logEvent("i", "AlarmManager", "Clearing possibly standing alarms.", 4);
for(int requestCode : requestCodeList)
{
Intent alarmIntent = new Intent(automationServiceRef, DateTimeListener.class);
PendingIntent alarmPendingIntent = PendingIntent.getBroadcast(automationServiceRef, requestCode, alarmIntent, 0);
// Miscellaneous.logEvent("i", "AlarmManager", "Clearing alarm with request code: " + String.valueOf(requestCode));
centralAlarmManagerInstance.cancel(alarmPendingIntent);
}
requestCodeList.clear();
}
private static void startAlarmListenerInternal(AutomationService givenAutomationServiceRef)
{
if(!alarmListenerActive)
{
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);
}
private static void stopAlarmListenerInternal()
{
if(alarmListenerActive)
{
Miscellaneous.logEvent("i", "AlarmListener", "Stopping alarm listener.", 4);
clearAlarms();
// centralAlarmManagerInstance.cancel(alarmPendingIntent);
alarmListenerActive = false;
}
else
Miscellaneous.logEvent("i", "AlarmListener", "Request to stop AlarmListener. But it's not running.", 5);
}
public static void reloadAlarms()
{
DateTimeListener.setAlarms();
}
@Override
public void startListener(AutomationService automationService)
{
DateTimeListener.startAlarmListener(automationService);
}
@Override
public void stopListener(AutomationService automationService)
{
DateTimeListener.stopAlarmListener(automationService);
}
public static boolean haveAllPermission()
{
return true;
}
@Override
public boolean isListenerRunning()
{
return isAlarmListenerActive();
}
@Override
public Trigger_Enum[] getMonitoredTrigger()
{
return new Trigger_Enum[] { Trigger_Enum.timeFrame };
}
static class ScheduleElement implements Comparable<ScheduleElement>
{
Calendar time;
String reason;
public ScheduleElement(Calendar timestamp, String reason)
{
super();
this.time = timestamp;
this.reason = reason;
}
@Override
public int compareTo(ScheduleElement o)
{
if(time.getTimeInMillis() == o.time.getTimeInMillis())
return 0;
if(time.getTimeInMillis() < o.time.getTimeInMillis())
return -1;
else
return 1;
}
@Override
public String toString()
{
return Miscellaneous.formatDate(time.getTime()) + ", reason : " + reason;
}
}
@RequiresApi(api = Build.VERSION_CODES.N)
public static Calendar getNextRepeatedExecutionAfter(Trigger trigger, Calendar now)
{
Calendar calSet;
Time setTime;
TimeFrame tf = new TimeFrame(trigger.getTriggerParameter2());
if(tf.getRepetition() > 0)
{
if(trigger.getTriggerParameter())
setTime = tf.getTriggerTimeStart();
else
setTime = tf.getTriggerTimeStop();
calSet = (Calendar) now.clone();
calSet.set(Calendar.HOUR_OF_DAY, setTime.getHours());
calSet.set(Calendar.MINUTE, setTime.getMinutes());
calSet.set(Calendar.SECOND, 0);
calSet.set(Calendar.MILLISECOND, 0);
// if(this.applies(null))
// {
// If the starting time is a day ahead remove 1 day.
if(calSet.getTimeInMillis() > now.getTimeInMillis())
calSet.add(Calendar.DAY_OF_MONTH, -1);
long differenceInSeconds = Math.abs(now.getTimeInMillis() - calSet.getTimeInMillis()) / 1000;
long nextExecutionMultiplier = Math.floorDiv(differenceInSeconds, tf.getRepetition()) + 1;
long nextScheduleTimestamp = (calSet.getTimeInMillis() / 1000) + (nextExecutionMultiplier * tf.getRepetition());
Calendar calSchedule = Calendar.getInstance();
calSchedule.setTimeInMillis(nextScheduleTimestamp * 1000);
/*
* 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.
*/
// if(trigger.checkDateTime(calSchedule.getTime(), false))
// {
return calSchedule;
// }
// }
}
else
Miscellaneous.logEvent("i", "DateTimeListener", "Trigger " + trigger.toString() + " is not executed repeatedly.", 5);
return null;
}
}

View File

@ -0,0 +1,229 @@
package com.jens.automation2.receivers;
import static android.content.Context.SENSOR_SERVICE;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.widget.TextView;
import com.jens.automation2.ActivityManageTriggerDevicePosition;
import com.jens.automation2.AutomationService;
import com.jens.automation2.Miscellaneous;
import com.jens.automation2.Rule;
import com.jens.automation2.Trigger;
import java.util.ArrayList;
public class DevicePositionListener implements SensorEventListener, AutomationListenerInterface
{
// https://developer.android.com/guide/topics/sensors/sensors_position#java
ActivityManageTriggerDevicePosition activityManageTriggerDevicePositionInstance = null;
//the Sensor Manager
private SensorManager sManager;
static DevicePositionListener instance = null;
boolean isRunning = false;
// Gravity rotational data
private float gravity[];
// Magnetic rotational data
private float magnetic[]; //for magnetic rotational data
private float accels[] = new float[3];
private float mags[] = new float[3];
private float[] values = new float[3];
// azimuth, pitch and roll
private float azimuth;
private float pitch;
private float roll;
boolean applies = false;
boolean flipped = false;
boolean toggable = false;
public static DevicePositionListener getInstance()
{
if (instance == null)
instance = new DevicePositionListener();
return instance;
}
public float getAzimuth()
{
return azimuth;
}
public float getPitch()
{
return pitch;
}
public float getRoll()
{
return roll;
}
public void startSensorFromConfigActivity(Context context, ActivityManageTriggerDevicePosition activityManageTriggerDevicePositionInstance)
{
this.activityManageTriggerDevicePositionInstance = activityManageTriggerDevicePositionInstance;
if(!isRunning)
{
sManager = (SensorManager) context.getSystemService(SENSOR_SERVICE);
/*
register the sensor listener to listen to the gyroscope sensor, use the
callbacks defined in this class, and gather the sensor information as quick
as possible
*/
isRunning = true;
sManager.registerListener(this, sManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
sManager.registerListener(this, sManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD), SensorManager.SENSOR_DELAY_NORMAL);
}
}
public void stopSensorFromConfigActivity()
{
activityManageTriggerDevicePositionInstance = null;
if(isRunning)
{
if(!Rule.isAnyRuleUsing(Trigger.Trigger_Enum.devicePosition))
{
//unregister the sensor listener
sManager.unregisterListener(this);
isRunning = false;
}
}
}
@Override
public void onAccuracyChanged(Sensor arg0, int arg1)
{
//Do nothing.
}
@Override
public void onSensorChanged(SensorEvent event)
{
switch (event.sensor.getType())
{
case Sensor.TYPE_MAGNETIC_FIELD:
mags = event.values.clone();
break;
case Sensor.TYPE_ACCELEROMETER:
accels = event.values.clone();
break;
}
if (mags != null && accels != null)
{
gravity = new float[9];
magnetic = new float[9];
SensorManager.getRotationMatrix(gravity, magnetic, accels, mags);
float[] outGravity = new float[9];
SensorManager.remapCoordinateSystem(gravity, SensorManager.AXIS_X, SensorManager.AXIS_Z, outGravity);
SensorManager.getOrientation(outGravity, values);
azimuth = values[0] * 57.2957795f;
pitch = values[1] * 57.2957795f;
roll = values[2] * 57.2957795f;
mags = null;
accels = null;
}
//else it will output the Roll, Pitch and Yawn values
if(activityManageTriggerDevicePositionInstance != null)
activityManageTriggerDevicePositionInstance.updateFields(azimuth, pitch, roll);
if(AutomationService.isMyServiceRunning(Miscellaneous.getAnyContext()))
{
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidates(Trigger.Trigger_Enum.devicePosition);
for (int i = 0; i < ruleCandidates.size(); i++)
{
if(ruleCandidates.get(i).getsGreenLight(Miscellaneous.getAnyContext()))
ruleCandidates.get(i).activate(AutomationService.getInstance(), false);
}
}
}
@Override
public void startListener(AutomationService automationService)
{
if(!isRunning)
{
sManager = (SensorManager) Miscellaneous.getAnyContext().getSystemService(SENSOR_SERVICE);
/*
register the sensor listener to listen to the gyroscope sensor, use the
callbacks defined in this class, and gather the sensor information as quick
as possible
*/
isRunning = true;
sManager.registerListener(this, sManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
sManager.registerListener(this, sManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD), SensorManager.SENSOR_DELAY_NORMAL);
}
}
@Override
public void stopListener(AutomationService automationService)
{
this.activityManageTriggerDevicePositionInstance = null;
if(isRunning)
{
//unregister the sensor listener
sManager.unregisterListener(this);
isRunning = false;
}
}
@Override
public boolean isListenerRunning()
{
return isRunning;
}
@Override
public Trigger.Trigger_Enum[] getMonitoredTrigger()
{
return new Trigger.Trigger_Enum[] { Trigger.Trigger_Enum.devicePosition };
}
/*
Azimuth (degrees of rotation about the -z axis).
This is the angle between the device's current compass direction and magnetic north. If the top edge of the
device faces magnetic north, the azimuth is 0 degrees; if the top edge faces south, the azimuth is 180 degrees.
Similarly, if the top edge faces east, the azimuth is 90 degrees, and if the top edge faces west, the azimuth is 270 degrees.
Pitch (degrees of rotation about the x axis).
This is the angle between a plane parallel to the device's screen and a plane parallel to the ground. If you hold the device
parallel to the ground with the bottom edge closest to you and tilt the top edge of the device toward the ground, the pitch
angle becomes positive. Tilting in the opposite direction— moving the top edge of the device away from the ground—causes
the pitch angle to become negative. The range of values is -180 degrees to 180 degrees.
Roll (degrees of rotation about the y axis).
This is the angle between a plane perpendicular to the device's screen and a plane perpendicular to the ground.
If you hold the device parallel to the ground with the bottom edge closest to you and tilt the left edge of the
device toward the ground, the roll angle becomes positive. Tilting in the opposite direction—moving the right
edge of the device toward the ground— causes the roll angle to become negative. The range of values is -90 degrees
to 90 degrees.
Computes the device's orientation based on the rotation matrix.
When it returns, the array values are as follows:
values[0]: Azimuth, angle of rotation about the -z axis. This value represents the angle between the device's y axis and the magnetic north pole. When facing north, this angle is 0, when facing south, this angle is π. Likewise, when facing east, this angle is π/2, and when facing west, this angle is -π/2. The range of values is -π to π.
values[1]: Pitch, angle of rotation about the x axis. This value represents the angle between a plane parallel to the device's screen and a plane parallel to the ground. Assuming that the bottom edge of the device faces the user and that the screen is face-up, tilting the top edge of the device toward the ground creates a positive pitch angle. The range of values is -π to π.
values[2]: Roll, angle of rotation about the y axis. This value represents the angle between a plane perpendicular to the device's screen and a plane perpendicular to the ground. Assuming that the bottom edge of the device faces the user and that the screen is face-up, tilting the left edge of the device toward the ground creates a positive roll angle. The range of values is -π/2 to π/2.
Applying these three rotations in the azimuth, pitch, roll order transforms an identity matrix to the rotation matrix passed into this method. Also, note that all three orientation angles are expressed in radians.
*/
}

View File

@ -1,5 +1,6 @@
package com.jens.automation2.receivers;
import android.Manifest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@ -77,7 +78,7 @@ public class HeadphoneJackListener extends BroadcastReceiver implements Automati
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByHeadphoneJack(isHeadsetConnected());
for(int i=0; i<ruleCandidates.size(); i++)
{
if(ruleCandidates.get(i).applies(context))
if(ruleCandidates.get(i).getsGreenLight(context))
ruleCandidates.get(i).activate(AutomationService.getInstance(), false);
}
}
@ -133,7 +134,7 @@ public class HeadphoneJackListener extends BroadcastReceiver implements Automati
public static boolean haveAllPermission()
{
return ActivityPermissions.havePermission("android.permission.READ_PHONE_STATE", Miscellaneous.getAnyContext());
return ActivityPermissions.havePermission(Manifest.permission.READ_PHONE_STATE, Miscellaneous.getAnyContext());
}

View File

@ -174,7 +174,7 @@ public class NfcReceiver
ArrayList<Rule> allRulesWithNfcTags = Rule.findRuleCandidatesByNfc();
for(int i=0; i<allRulesWithNfcTags.size(); i++)
{
if(allRulesWithNfcTags.get(i).applies(asInstance))
if(allRulesWithNfcTags.get(i).getsGreenLight(asInstance))
allRulesWithNfcTags.get(i).activate(asInstance, false);
}
}

View File

@ -33,7 +33,7 @@ public class NoiseListener implements AutomationListenerInterface
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByNoiseLevel();
for(Rule oneRule : ruleCandidates)
{
if(oneRule.applies(automationService))
if(oneRule.getsGreenLight(automationService))
oneRule.activate(automationService, false);
}
}

View File

@ -89,19 +89,12 @@ public class NotificationListener extends NotificationListenerService
lastNotification.title = title;
lastNotification.text = text;
// if(lastResponseToNotification == null || lastResponseToNotification.getTimeInMillis() < lastNotification.publishTime.getTimeInMillis())
// {
// lastResponseToNotification = Calendar.getInstance();
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidates(Trigger.Trigger_Enum.notification);
for (int i = 0; i < ruleCandidates.size(); i++)
{
if (ruleCandidates.get(i).applies(NotificationListener.this))
ruleCandidates.get(i).activate(AutomationService.getInstance(), false);
}
// }
// else
// Miscellaneous.logEvent("e", "NotificationCheck", "Ignoring notification as it is old.", 5);
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidates(Trigger.Trigger_Enum.notification);
for (int i = 0; i < ruleCandidates.size(); i++)
{
if(ruleCandidates.get(i).getsGreenLight(NotificationListener.this))
ruleCandidates.get(i).activate(AutomationService.getInstance(), false);
}
}
return false;

View File

@ -114,7 +114,7 @@ public class PhoneStatusListener implements AutomationListenerInterface
{
AutomationService asInstance = AutomationService.getInstance();
if(asInstance != null)
if(ruleCandidates.get(i).applies(asInstance))
if(ruleCandidates.get(i).getsGreenLight(asInstance))
ruleCandidates.get(i).activate(asInstance, false);
}
}
@ -146,7 +146,7 @@ public class PhoneStatusListener implements AutomationListenerInterface
{
AutomationService asInstance = AutomationService.getInstance();
if (asInstance != null)
if (ruleCandidates.get(i).applies(asInstance))
if (ruleCandidates.get(i).getsGreenLight(asInstance))
ruleCandidates.get(i).activate(asInstance, false);
}
}
@ -183,7 +183,7 @@ public class PhoneStatusListener implements AutomationListenerInterface
{
AutomationService asInstance = AutomationService.getInstance();
if(asInstance != null)
if(ruleCandidates.get(i).applies(asInstance))
if(ruleCandidates.get(i).getsGreenLight(asInstance))
ruleCandidates.get(i).activate(asInstance, false);
}
}

View File

@ -43,34 +43,27 @@ public class ProcessListener implements AutomationListenerInterface
@Override
public void handleMessage(Message msg)
{
// try
// {
Miscellaneous.logEvent("i", automationService.getResources().getString(R.string.processMonitoring), automationService.getResources().getString(R.string.messageReceivedStatingProcessMonitoringIsComplete), 5);
// This will take care of results delivered by the actual monitoring instance
for(String entry : getRunningApps())
Miscellaneous.logEvent("i", automationService.getResources().getString(R.string.runningApp), entry, 5);
// execute matching rules containing processes
if(getRecentlyStartedApps().size()>0 | getRecentlyStoppedApps().size()>0)
Miscellaneous.logEvent("i", automationService.getResources().getString(R.string.processMonitoring), automationService.getResources().getString(R.string.messageReceivedStatingProcessMonitoringIsComplete), 5);
// This will take care of results delivered by the actual monitoring instance
for(String entry : getRunningApps())
Miscellaneous.logEvent("i", automationService.getResources().getString(R.string.runningApp), entry, 5);
// execute matching rules containing processes
if(getRecentlyStartedApps().size()>0 | getRecentlyStoppedApps().size()>0)
{
for(String entry : getRecentlyStartedApps())
Miscellaneous.logEvent("i", automationService.getResources().getString(R.string.appStarted), entry, 3);
for(String entry : getRecentlyStoppedApps())
Miscellaneous.logEvent("i", automationService.getResources().getString(R.string.appStopped), entry, 3);
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByProcess();
for(int i=0; i<ruleCandidates.size(); i++)
{
for(String entry : getRecentlyStartedApps())
Miscellaneous.logEvent("i", automationService.getResources().getString(R.string.appStarted), entry, 3);
for(String entry : getRecentlyStoppedApps())
Miscellaneous.logEvent("i", automationService.getResources().getString(R.string.appStopped), entry, 3);
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByProcess();
for(int i=0; i<ruleCandidates.size(); i++)
{
if(ruleCandidates.get(i).applies(automationService))
ruleCandidates.get(i).activate(automationService, false);
}
if(ruleCandidates.get(i).getsGreenLight(automationService))
ruleCandidates.get(i).activate(automationService, false);
}
// }
// catch(Exception e)
// {
// Miscellaneous.logEvent("e", "Noise level", "Error in workHandler->handleMessage(): " + e.getMessage());
// }
}
}
};

View File

@ -77,12 +77,12 @@ public class TimeZoneListener extends BroadcastReceiver implements AutomationLis
if(action.equals(Intent.ACTION_TIMEZONE_CHANGED))
{
Miscellaneous.logEvent("i", "TimeZoneListener", "Device timezone changed. Reloading alarms.", 3);
AlarmListener.reloadAlarms();
DateTimeListener.reloadAlarms();
}
else if(action.equals(Intent.ACTION_TIME_CHANGED))
{
Miscellaneous.logEvent("i", "TimeZoneListener", "Device time changed. Reloading alarms.", 4);
AlarmListener.reloadAlarms();
DateTimeListener.reloadAlarms();
}
}
@Override

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -9,6 +9,13 @@
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/smsDialogNotice"
android:textColor="#ea131b"
android:layout_marginBottom="@dimen/default_margin" />
<Button
android:id="@+id/bImportNumberFromContacts"
android:drawableLeft="@drawable/contacts"

View File

@ -57,7 +57,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="numberDecimal" />
android:inputType="numberSigned" />
</TableRow>
@ -72,14 +72,14 @@
android:layout_height="wrap_content"
android:text="@string/longitude"
android:textAppearance="?android:attr/textAppearanceMedium" />
<EditText
android:id="@+id/etPoiLongitude"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="numberDecimal" />
</TableRow>
<EditText
android:id="@+id/etPoiLongitude"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="numberSigned" />
</TableRow>
<TableRow
android:layout_width="match_parent"

View File

@ -45,6 +45,19 @@
<requestFocus />
</EditText>
<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:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/general"
android:textAppearance="?android:attr/textAppearanceMedium" />
<CheckBox
android:id="@+id/checkBoxChangeSoundMode"
android:layout_width="wrap_content"
@ -63,13 +76,54 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="40dp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="40dp"
android:text="@string/silentTriggersDnd" />
<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:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/dnd"
android:textAppearance="?android:attr/textAppearanceMedium" />
<CheckBox
android:id="@+id/checkBoxChangeDnd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/change" />
<Spinner
android:id="@+id/spinnerDndMode"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="40dp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="40dp"
android:text="@string/dndRemarks" />
<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:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/volumes"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_marginLeft="40dp" />
android:textAppearance="?android:attr/textAppearanceMedium" />
<CheckBox
android:id="@+id/checkBoxChangeVolumeMusicVideoGameMedia"
@ -121,7 +175,20 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="40dp" />
<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:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/tones"
android:textAppearance="?android:attr/textAppearanceMedium" />
<CheckBox
android:id="@+id/checkBoxChangeIncomingCallsRingtone"
android:layout_width="wrap_content"
@ -199,7 +266,20 @@
android:text="@string/notificationRingtone"
android:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout>
<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:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/miscellaneous"
android:textAppearance="?android:attr/textAppearanceMedium" />
<CheckBox
android:id="@+id/checkBoxChangeAudibleSelection"
android:layout_width="wrap_content"
@ -240,6 +320,7 @@
<Button
android:id="@+id/bSaveProfile"
android:layout_marginTop="@dimen/default_margin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/save" />

View File

@ -0,0 +1,248 @@
<?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" >
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/devicePositionExplanation"
android:layout_marginBottom="@dimen/default_margin" />
<TableLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TableRow
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<TextView
android:text="@string/orientationAzimuth"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/tvCurrentAzimuth"
android:layout_marginLeft="@dimen/default_margin"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</TableRow>
<TableRow
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<TextView
android:text="@string/orientationPitch"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/tvCurrentOrientationPitch"
android:layout_marginLeft="@dimen/default_margin"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</TableRow>
<TableRow
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<TextView
android:text="@string/orientationRoll"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/tvCurrentRoll"
android:layout_marginLeft="@dimen/default_margin"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</TableRow>
</TableLayout>
<Button
android:id="@+id/bApplyPositionValues"
android:text="@string/apply"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginVertical="@dimen/default_margin" />
<TableLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:shrinkColumns="0"
android:stretchColumns="1">
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:text=""
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:text="@string/position"
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:text="@string/tolerance"
android:gravity="center_horizontal"
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:text="@string/wouldCurrentlyApply"
android:singleLine="false"
android:maxLines="2"
android:lines="2"
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:text="@string/orientationAzimuth"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="@dimen/default_margin" />
<EditText
android:id="@+id/etDesiredAzimuth"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="50dp"
android:enabled="false"
android:inputType="number" />
<EditText
android:id="@+id/etDesiredAzimuthTolerance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="50dp"
android:inputType="number" />
<TextView
android:id="@+id/tvAppliesAzimuth"
android:gravity="center_horizontal"
android:text="@string/unknown"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:text="@string/orientationPitch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="@dimen/default_margin" />
<EditText
android:id="@+id/etDesiredPitch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="50dp"
android:enabled="false"
android:inputType="number" />
<EditText
android:id="@+id/etDesiredPitchTolerance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="50dp"
android:inputType="number" />
<TextView
android:id="@+id/tvAppliesPitch"
android:gravity="center_horizontal"
android:text="@string/unknown"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:text="@string/orientationRoll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="@dimen/default_margin" />
<EditText
android:id="@+id/etDesiredRoll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="50dp"
android:enabled="false"
android:inputType="number" />
<EditText
android:id="@+id/etDesiredRollTolerance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="50dp"
android:inputType="number" />
<TextView
android:id="@+id/tvAppliesRoll"
android:gravity="center_horizontal"
android:text="@string/unknown"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</TableRow>
</TableLayout>
<CheckBox
android:id="@+id/chkDevicePositionApplies"
android:checked="true"
android:text="@string/mustApply"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/explanationDevicePositionDirection" />
<Button
android:id="@+id/bSavePositionValues"
android:text="@string/save"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/default_margin" />
</androidx.appcompat.widget.LinearLayoutCompat>
</ScrollView>

View File

@ -45,6 +45,18 @@
</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:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/automationNotificationsIgnored" />
<TableRow
android:layout_marginBottom="@dimen/activity_vertical_margin">
@ -78,6 +90,13 @@
</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">
@ -106,6 +125,13 @@
</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">

View File

@ -119,6 +119,34 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/sunday" />
<ImageView
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_margin="10dp"
android:background="#aa000000" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<CheckBox
android:id="@+id/chkRepeat"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/repeatEveryXseconds" />
<EditText
android:id="@+id/etRepeatEvery"
android:layout_marginLeft="@dimen/default_margin"
android:minWidth="75dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:enabled="false"
android:inputType="numberSigned" />
</LinearLayout>
<Button
android:id="@+id/bSaveTimeFrame"

View File

@ -332,6 +332,14 @@
android:layout_height="wrap_content"
android:layout_gravity="top"
android:text="@string/settings" />
<Button
android:id="@+id/bDonate"
android:visibility="gone"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:text="@string/donate" />
</LinearLayout>

View File

@ -475,14 +475,14 @@
<string name="textMessageAnnotations">Sie können direkt eine Telefonnummer eingeben. Alternativ können Sie eine aus Ihren Kontakten auswählen. Aber: Es wird immer die Nummer gespeichert, nicht der Kontakt referenziert. D.h., wenn Sie einmal die Nummer eines Kontaktes ändern, müssen Sie diese Regel aktualisieren.</string>
<string name="importNumberFromContacts">Von Kontakten importieren</string>
<string name="android9RecordAudioNotice">Falls Sie die Umgebungslautstärke als Auslöser benutzen: Leider hat sich Google entschlossen ab Android Version 9 (Pie) Hintergrundanwendungen den Zugriff auf das Mikrofon zu verweigern. Das bedeutet, dass dieser Auslöser keinen Effekt mehr hat und keine Regeln auslösen wird.</string>
<string name="android10WifiToggleNotice">Leider hat Google in Android 10 die Möglichkeit entfernt, daß normale Anwendungen WLAN an- oder ausschalten können. Diese Aktion wird also keinen Effekt auf Ihrem Gerät haben.</string>
<string name="android10WifiToggleNotice">Leider hat Google in Android 10 die Möglichkeit entfernt, daß normale Anwendungen WLAN an- oder ausschalten können. Nur, wenn Ihr Gerät gerootet ist, sollte es weiterhin funktionieren. Wenn nicht, wird diese Aktion leider keinen Effekt mehr auf Ihrem Gerät haben.</string>
<string name="messageNotShownAgain">Diese Nachricht wird nicht wieder angezeigt.</string>
<string name="chooseActivityHint">In diesem letzten Auswahlfeld müssen Sie eine bestimmte \"Activity\" auswählen. Vereinfacht ist das ein bestimmtes Fenster der ausgewählten Anwendung. Wenn Sie nicht wissen, welche Sie auswählen sollen, ist es normalerweise eine gute Idee zunächst welche auszuprobieren, die \"main\" oder \"launcher\" im Namen haben.</string>
<string name="edit">Bearbeiten</string>
<string name="clickAndHoldForOptions">Klicken und halten Sie ein Objekt für Optionen.</string>
<string name="startAutomationAsService">Automation als Dienst starten</string>
<string name="setScreenBrightness">Set screen brightness</string>
<string name="setScreenBrightnessEnterValue">Enter the desired brightness (from 0 to 100).</string>
<string name="setScreenBrightness">Bildschirmhelligkeit einstellen</string>
<string name="setScreenBrightnessEnterValue">Geben Sie den gewünschten Helligkeitswert ein (von 0 bis 100).</string>
<string name="autoBrightness">Automatische Helligkeitseinstellung verwenden</string>
<string name="apply">übernehmen</string>
<string name="brightnessAuto">automatische Helligkeit</string>
@ -537,7 +537,7 @@
<string name="notificationTriggerExplanation">Dieser Auslöser reagiert auf Benachrichtigungen anderer Anwendung im Benachrichtigungsbereich von Android (oder wenn diese geschlossen werden). Sie können eine bestimmte Anwendung festlegen, von die Nachricht stammen muß. Wenn nicht, zählt jede Benachrichtigung. Sie können auch Zeichenketten für Titel oder Nachrichteninhalt festlegen, die enthalten sein müssen. Die Groß-/Kleinschreibung wird hierbei nicht berücksichtigt.</string>
<string name="addParameters">Parameter hinzufügen</string>
<string name="errorRunningRule">Fehler beim Ausführen einer Regel.</string>
<string name="startAppChoiceNote">Hier haben Sie 2 grundsätzliche Optionen:\n\n1. Sie können ein Programm starten, indem Sie eine Activity auswählen.\nStellen Sie sich das so vor, daß Sie ein bestimmtes Fenster einer Anwendung vorauswählen, in das man direkt springt. Behalten Sie im Kopf, daß das nicht immer funktionieren wird. Das liegt daran, daß die Fenster einer Anwendung miteinander interagieren können, sich u.U. Parameter übergeben. Wenn man jetzt ganz kalt in ein bestimmtes Fenster springt, könnte dieses zum Start z.B. bestimmte Parameter erwarten - die fehlen. So könnte es passieren, daß das Fenster zwar versucht zu öffnen, das aber nicht klappt und es somit nie wirlich sichtbar wird. Versuchen Sie\'s trotzdem!\nSie können den Pfad manuell eingeben, sollten aber den Auswählen-Knopf benutzen. Wenn Sie es dennoch manuell eingeben, geben Sie den PackageName ins obere Feld ein und den vollen Pfad der Activity ins untere.\n\n2. Auswahl per Action\nIm Gegensatz zur Auswahl eines bestimmten Fensters, können Sie ein Programm auch über eine Action starten lassen. Stellen Sie sich das so vor als würden Sie in den Wald rufen \"Ich hätte gerne XYZ\" und falls eine Anwendung installiert ist, die das liefern kann, wird sie gestartet. Ein gutes Beispiel wäre zum Beispiel "Browser starten" - es könnten sogar mehrere installiert sein, die das können (aber normalerweise gibts eine, die als Standard eingestellt ist).\nDiese Action müssen Sie manuell eingeben. Der PackageName ist hier optional. Behalten Sie dabei im Auge, daß mögliche Variablen nicht aufgelöst werden. Beispielsweise werden Sie häufig im Internet finden, daß man die Kamera über die Action \"MediaStore.ACTION_IMAGE_CAPTURE\" starten kann. Das ist grundsätzlich nicht richtig, wird aber nicht direkt funktionieren, denn das ist nur eine Variable. Sie müssen dann einen Blick in die Android Dokumentation werfen, wo Sie sehen werden, daß sich hinter dieser Variable eigentlich der Wert \"android.media.action.IMAGE_CAPTURE\" verbirgt. Gibt man diesen in das Feld ein, wird\'s funktionieren.</string>
<string name="startAppChoiceNote">Hier haben Sie 2 grundsätzliche Optionen:\n\n1. Sie können ein Programm starten, indem Sie eine Activity auswählen.\nStellen Sie sich das so vor, daß Sie ein bestimmtes Fenster einer Anwendung vorauswählen, in das man direkt springt. Behalten Sie im Kopf, daß das nicht immer funktionieren wird. Das liegt daran, daß die Fenster einer Anwendung miteinander interagieren können, sich u.U. Parameter übergeben. Wenn man jetzt ganz kalt in ein bestimmtes Fenster springt, könnte dieses zum Start z.B. bestimmte Parameter erwarten - die fehlen. So könnte es passieren, daß das Fenster zwar versucht zu öffnen, das aber nicht klappt und es somit nie wirlich sichtbar wird. Versuchen Sie\'s trotzdem!\nSie können den Pfad manuell eingeben, sollten aber den Auswählen-Knopf benutzen. Wenn Sie es dennoch manuell eingeben, geben Sie den PackageName ins obere Feld ein und den vollen Pfad der Activity ins untere.\n\n2. Auswahl per Action\nIm Gegensatz zur Auswahl eines bestimmten Fensters, können Sie ein Programm auch über eine Action starten lassen. Stellen Sie sich das so vor als würden Sie in den Wald rufen \"Ich hätte gerne XYZ\" und falls eine Anwendung installiert ist, die das liefern kann, wird sie gestartet. Ein gutes Beispiel wäre zum Beispiel "Browser starten" - es könnten sogar mehrere installiert sein, die das können (aber normalerweise gibts eine, die als Standard eingestellt ist).\nDiese Action müssen Sie manuell eingeben. Der PackageName ist hier optional. Behalten Sie dabei im Auge, daß mögliche Variablen nicht aufgelöst werden. Beispielsweise werden Sie häufig im Internet finden, daß man die Kamera über die Action \"MediaStore.ACTION_IMAGE_CAPTURE\" starten kann. Das ist grundsätzlich richtig, wird aber nicht direkt funktionieren, denn das ist nur eine Variable. Sie müssen dann einen Blick in die Android Dokumentation werfen, wo Sie sehen werden, daß sich hinter dieser Variable eigentlich der Wert \"android.media.action.IMAGE_CAPTURE\" verbirgt. Gibt man diesen in das Feld ein, wird\'s funktionieren.</string>
<string name="cantFindSoundFile">Kann die Audiodatei %1$s nicht finden und daher auch nicht abspielen.</string>
<string name="startAppByActivity">per Activity</string>
<string name="startAppByAction">per Action</string>
@ -594,4 +594,22 @@
<string name="top">Oben</string>
<string name="bottom">Unten</string>
<string name="tabsPlacementSummary">Wol soll die Taskleiste angezeigt werden?</string>
<string name="tones">Klingeltöne</string>
<string name="miscellaneous">Verschiedenes</string>
<string name="dnd">Nicht stören</string>
<string name="dndOff">Nicht stören aus</string>
<string name="dndAlarms">Alarme durchlassen</string>
<string name="dndPriority">Prioritätsbenachrichtigungen durchlassen</string>
<string name="dndNothing">Nichts durchlassen</string>
<string name="repeatEveryXseconds">Alle x Sekunden wiederholen</string>
<string name="repeatEveryXsecondsWithVariable">alle %1$s Sekunden wiederholen</string>
<string name="donate">Spenden</string>
<string name="notice">Hinweis</string>
<string name="automationNotificationsIgnored">Wenn Sie keine bestimmte Anwendung auswählen, werden Benachrichtigungen von Automation selbst ignoriert, um Schleifen zu verhindern.</string>
<string name="elementSkipped">Ein Element der Konfigurationsdatei konnte nicht gelesen werden. Die Datei könnte von einer neueren Programmversion erstellt worden sein.</string>
<string name="permissionsRequiredNotAvailable">Ihre Regeln benötigen Berechtigungen, die die installierte Variante von Automation nicht unterstützt.</string>
<string name="dndRemarks">Feineinstellungen (wie Telefonanrufe erlauben, Auswählen bestimmter Telefonnummern, etc.) können nur in den Systemeinstellungen gesetzt werden.</string>
<string name="wifiApi30">Weil Google wieder einen weiteren Teil von Android kaputt gemacht hat, können ab API 30 nur noch jede WLANs angezeigt werden, die sich gegenwärtig in Reichweite befinden, nicht mehr alle, zu denen das Gerät einmal verbunden war.</string>
<string name="smsDialogNotice">Wenn Sie in diesem Programm noch keine SMS-senden Aktion benutzt haben, zeigt Android wahrscheinlich beim ersten Ausführen einen Bestätigungsdialog an. Sie müssen das Häkchen bei \"Immer erlauben\" setzen und bestätigen, wenn Sie möchten, daß diese Aktion im Hintergrund ausgeführt werden kann. Es wird daher empfohlen, diese Regel einmalig manuell auszuführen, um diesen Dialog zu provozieren.</string>
<string name="silentTriggersDnd">Hinweis: Der Stumm-Modus löst auf neuren Geräten häufig die Funktion \"Nicht stören\" aus. Wenn das auf Ihrem Gerät passiert, wird empfohlen stattdessen den Normalen Modus zu verwenden und alle Lautstärken auf 0 zu reduzieren.</string>
</resources>

View File

@ -244,7 +244,7 @@
<string name="volumeRingtoneNotifications">Sonido polifónico ý notificaciónes</string>
<string name="notificationRingtone">Sonido polifónico para notificaciónes</string>
<string name="incomingCallsRingtone">Sonido de llamadas</string>
<string name="batteryLevel">NIvel de la bateria</string>
<string name="batteryLevel">Nivel de la bateria</string>
<string name="selectBattery">Elija nivel de la bateria</string>
<string name="triggerNoiseLevel">Nivel del ruido fondo</string>
<string name="anotherAppIsRunning">Otra app esta encendida/terminada</string>
@ -556,7 +556,7 @@
<string name="logFileMaxSizeTitle">Maximo tamaño del archivo log [Mb]</string>
<string name="theseAreThePermissionsRequired">Esos son los permisos necesarios.</string>
<string name="android9RecordAudioNotice">Si usa la condición nivel del ruido fondo: Desafortunadamente iniciando con Android 9 (Pie) Google decidió prohibir aplicaciones de fondo usando el micrófono. Por eso esta condición no tendrá un efecto y no iniciará algo.</string>
<string name="android10WifiToggleNotice">Si usa la condición nivel del ruido fondo: Desafortunadamente iniciando con Android 9 (Pie) Google decidió prohibir aplicaciones de fondo usando el micrófono. Por eso esta condición no tendrá un efecto y no iniciará algo.</string>
<string name="android10WifiToggleNotice">Desafortunadamente Google dedició remover esta función en Android 10. Applicaciones regulares ya no pueden activar o desactivar wifi. Solo si su dispositivo esta rooted debe funcionar adelante. Si no este ación no va a continuar de funcionar.</string>
<string name="messageNotShownAgain">Esta nota no aparecerá otra vez.</string>
<string name="noLocationCouldBeFound">No pude encontrar una posición despues de un limite de %1$s segundos..</string>
<string name="pleaseGiveBgLocation">En la proxima pantalla por favor vaya a permisos, luego a posición. Ahi elija \"Siempre permitir\" para permitir Automation determinar la posición en el fondo.</string>
@ -593,4 +593,8 @@
<string name="intentDataComment">Si su parametro es de tipo Uri y especifica \"IntentData\" como nombre (minúscula/mayáscula no es importante), el parametro no está añadido como un parametro normal con puExtra(), pero estará añadido al intent con setData().</string>
<string name="locationEngineDisabledLong">Desafortunadamente su posición todavia no puede ser determinada. Gratitud va para Google por su sabiduria y amabilidad infinita.\n\nDejenme explicarselo mas. Comenzando con Android 10 un nuevo permiso se introdujo que es necesario para determinar la posición en el fondo (que es necesario para una app como esta). Aunque lo considero una buena idea, conlleva a una chicana para desarolladores.\n\nCuando se esta desarrollando una app se puede intentar calificar para este permiso mientras se sigue un catalogo de condiciones. Desafortunadamente nuevas versiones de mi app fueron rechazadas por un periodo de trés meses. Cumplé todas las condiciones, pero Google\'s mierda servicio para desarolladores afirmó que no. Despues de presentar pruebas, que cumplí con todo, recibí una respuesta de \"No puedo ayudarte mas.\". En algun momento me rendí.\n\nComo consecuencia la version Google Play todavia no sabe usar la locación como una condición. Mi única alternativa fue remover la applicación de Google Play.\n\nLo siento mucho, pero hicé todo lo posible para discutir con un support que no sabe aprobar la prueba de Turing repetidamente.\n\nLa noticia positiva: Usted todavia puede tener todo!\n\nAutomation ahora es open source y se puede encontrar en F-Droid. Es un app store que se preocupa por su privacidad - en vez de solo simular eso. Simplemente guarde su configuración, desinstale la app, instale la de F-Droid, restaure su configuración - terminado.\n\nCliquee aqui para averiguar más:</string>
<string name="startAppChoiceNote">Aqui tiene 2 opciones generales:\\n\\n1. Puede encender un programa seleccionando un activity. Imagine eso como preseleccionar una pantalla/ventana especifica de una aplicación. Tenga en cuenta que no siempre funcionará. Eso es porque las ventanas de una app pueden interactuar entre ellas, por ejemplo dar parametros. Si se abre una ventana especifica directamente esta interacción todavia no ha ocurrido y la ventana se podría cerrar al instante (por lo tanto nunca será presentada). Pruebe esto sin embargo! Puede introducir una trayectoria de una activity manualmente, pero es recomendable usar el boton \"Elegir\". Si decide introducir la trayectoria de la app manualmente en la casilla de arriba y la trayectoria completa de una activity en la de abajo.\\n\\n2.Elección con action\\nContrariamente a elegir una ventana especifica, tambien puede encender una app con un action. Es similar a llamar \"Queria xyz\" y si hay una app que le puede ayudar a usted sera encendida. Un ejemplo bueno seria \"abrir browser\" - podria tener multiples (una normalemente es el valor predeterminado). Usted necesita introducirlo manualmente, PackageName es opcional aqui. Tenga en cuenta las variables no seran resueltas. Si por ejemplo quiere encender la camara usando \"MediaStore.ACTION_IMAGE_CAPTURE\" no va a funcionar. Tiene que mirar en la documentación de Android y usar el valor real de esta variable que - en este ejemplo - seria \"android.media.action.IMAGE_CAPTURE\".</string>
<string name="tones">Sonidos</string>
<string name="dnd">No interrumpir</string>
<string name="donate">Donar</string>
<string name="notice">Nota</string>
</resources>

View File

@ -586,4 +586,6 @@
<string name="locationFoundInaccurate">È stato possibile solo trovare una ubicazione con una precisione limitata. Potrebbe non funzionare in maniera affidabile. Il raggio minimo per le ubicazioni è di %1$d m.</string>
<string name="noLocationCouldBeFound">Nessuna posizione è stata trovata dopo un tempo di attesa di %1$s seconds.</string>
<string name="pleaseGiveBgLocation">Nella schermata successiva vai su permessi, poi posizione. Lì seleziona \"Consenti sempre\" per permettere ad Automation di determinare la tua posizione in secondo piano.</string>
<string name="tones">Suonerias</string>
<string name="dnd">Non disturbare</string>
</resources>

View File

@ -158,6 +158,7 @@
<string name="actionSetBluetooth">Bluetooth</string>
<string name="actionSetUsbTethering">USB Tethering</string>
<string name="actionSetWifiTethering">Wifi Tethering</string>
<string name="actionSetBluetoothTethering">Bluetooth Tethering</string>
<string name="actionSetDisplayRotation">Display rotation</string>
<string name="actionTurnWifiOn">turn Wifi on</string>
<string name="actionTurnWifiOff">turn Wifi off</string>
@ -169,6 +170,8 @@
<string name="actionTurnUsbTetheringOff">turn USB Tethering off</string>
<string name="actionTurnWifiTetheringOn">turn Wifi Tethering on</string>
<string name="actionTurnWifiTetheringOff">turn Wifi Tethering off</string>
<string name="actionTurnBluetoothTetheringOn">turn Bluetooth Tethering on</string>
<string name="actionTurnBluetoothTetheringOff">turn Bluetooth Tethering off</string>
<string name="actionTurnAirplaneModeOn">turn airplane mode on</string>
<string name="actionTurnAirplaneModeOff">turn airplane mode off</string>
<string name="actionEnableScreenRotation">enable screen rotation</string>
@ -209,15 +212,15 @@
<string name="wifiName">Wifi name</string>
<string name="enterWifiName">Enter a wifi name. Leave empty for any wifi.</string>
<string name="cancel">Cancel</string>
<string name="ruleDoesntApplyWeAreSlowerThan" translatable="false">Rule doesn\'t apply. We are slower than</string>
<string name="ruleDoesntApplyWeAreFasterThan" translatable="false">Rule doesn\'t apply. We are faster than</string>
<string name="ruleDoesntApplyItsQuieterThan" translatable="false">Rule doesn\'t apply. It\'s quieter than</string>
<string name="ruleDoesntApplyItsLouderThan" translatable="false">Rule doesn\'t apply. It\'s louder than</string>
<string name="ruleDoesntApplyBatteryLowerThan" translatable="false">Rule doesn\'t apply. Battery level is lower than</string>
<string name="ruleDoesntApplyBatteryHigherThan" translatable="false">Rule doesn\'t apply. Battery level is higher than</string>
<string name="ruleDoesntApplyNotTheCorrectSsid" translatable="false">Rule doesn\'t apply. Not the correct SSID (demanded: \"%1$s\", given: \"%2$s\").</string>
<string name="ruleDoesntApplyNoTagLabel" translatable="false">Rule doesn\'t apply. There is no tag label or not tag at all.</string>
<string name="ruleDoesntApplyWrongTagLabel" translatable="false">Rule doesn\'t apply. Wrong tag label.</string>
<string name="ruleDoesntApplyWeAreSlowerThan" translatable="false">Rule %1$s doesn\'t apply. We are slower than</string>
<string name="ruleDoesntApplyWeAreFasterThan" translatable="false">Rule %1$s doesn\'t apply. We are faster than</string>
<string name="ruleDoesntApplyItsQuieterThan" translatable="false">Rule %1$s doesn\'t apply. It\'s quieter than</string>
<string name="ruleDoesntApplyItsLouderThan" translatable="false">Rule %1$s doesn\'t apply. It\'s louder than</string>
<string name="ruleDoesntApplyBatteryLowerThan" translatable="false">Rule %1$s doesn\'t apply. Battery level is lower than</string>
<string name="ruleDoesntApplyBatteryHigherThan" translatable="false">Rule %1$s doesn\'t apply. Battery level is higher than</string>
<string name="ruleDoesntApplyNotTheCorrectSsid" translatable="false">Rule %1$s doesn\'t apply. Not the correct SSID (demanded: \"%2$s\", given: \"%3$s\").</string>
<string name="ruleDoesntApplyNoTagLabel" translatable="false">Rule %1$s doesn\'t apply. There is no tag label or not tag at all.</string>
<string name="ruleDoesntApplyWrongTagLabel" translatable="false">Rule %1$s doesn\'t apply. Wrong tag label.</string>
<string name="ruleIsDeactivatedCantApply" translatable="false">Rule %1$s is deactivated, can\'t apply.</string>
<string name="starting">starting</string>
<string name="stopping">stopping</string>
@ -401,8 +404,8 @@
<string name="detectedActivityWalking">Walking</string>
<string name="detectedActivityRunning">Running</string>
<string name="detectedActivityInvalidStatus">Invalid activity</string>
<string name="ruleDoesntApplyActivityGivenButTooLowProbability" translatable="false">Rule doesn\'t apply. Detected activity %1$s given, but too low probability (%2$s %%), required %3$s %%.</string>
<string name="ruleDoesntApplyActivityNotPresent" translatable="false">Rule doesn\'t apply. Required activity %1$s not present.</string>
<string name="ruleDoesntApplyActivityGivenButTooLowProbability" translatable="false">Rule %1$s doesn\'t apply. Detected activity %2$s given, but too low probability (%3$s %%), required %4$s %%.</string>
<string name="ruleDoesntApplyActivityNotPresent" translatable="false">Rule %1$s doesn\'t apply. Required activity %2$s not present.</string>
<string name="selectTypeOfActivity">Select type of activity</string>
<string name="triggerOnlyAvailableIfPlayServicesInstalled">This trigger is only available if Google Play Services is installed.</string>
<string name="activityDetectionFrequencyTitle">Activity detection frequency [sec]</string>
@ -507,7 +510,7 @@
<string name="phoneIsNotRooted" translatable="false">Phone is not rooted.</string>
<string name="dataConWithRootSuccess" translatable="false">Data connection was successfully changed using superuser permissions.</string>
<string name="dataConWithRootFail" translatable="false">Data could not be changed using superuser permissions.</string>
<string name="rootExplanation">You need to root your phone for this function to work. Afterwards you needs to \"run the rule manually\" to show up the superuser permission question. When the superuser popups shows up you need to always allow the application to do that. Otherwise the rule cannot function when the phone is unattended.</string>
<string name="rootExplanation">You need to root your phone for this function to work. Afterwards you need to \"run the rule manually\" to show up the superuser permission question. When the superuser popups shows up you need to always allow the application to do that. Otherwise the rule cannot function when the phone is unattended.</string>
<string name="errorWritingConfig">Error writing config. Do you have a writable memory?</string>
<string name="phoneNrReplacementError">I could not insert the last phone nr in the variable. I don\'t have it.</string>
<string name="username">Username</string>
@ -570,7 +573,7 @@
<string name="textMessageAnnotations">You can directly enter a phone number. Alternatively use the contacts option to pick one. But keep in mind: The number will be stored here, not the contact. If you change the phone number of a selected contact you\'ll need to update this rule. It doesn\'t do that by itself.</string>
<string name="importNumberFromContacts">Import number from contacts</string>
<string name="android9RecordAudioNotice">If you\'re using the noise level trigger: Unfortunately beginning with Android 9 (Pie) Google decided to disallow background applications to use the microphone. So this trigger has no effect anymore and won\'t trigger anything.</string>
<string name="android10WifiToggleNotice">Unfortunately Google decided to remove this feature in Android 10. Regular apps are not allowed anymore to turn wifi on or off. This means this action will have no effect on your device.</string>
<string name="android10WifiToggleNotice">Unfortunately Google decided to remove this feature in Android 10. Regular apps are not allowed anymore to turn wifi on or off. Only if your device is rooted it should continue to work. If not, then I\'m afraid this won\'t have an effect anymore.</string>
<string name="messageNotShownAgain">This message won\'t be shown again.</string>
<string name="chooseActivityHint">In this final selection popup you need to select a specific activity. Simplified this is like a window of the desired application. If you do not know which one it is generally a good idea to pick one that has \"main\" or \"launcher\" in its name.</string>
<string name="edit">Edit</string>
@ -670,7 +673,7 @@
<string name="matching">matching</string>
<string name="urlRegex" translatable="false">https://regex101.com/</string>
<string name="loadWifiList">Load wifi list</string>
<string name="needLocationPermForWifiList">The list of wifis your device has been connected to could be used to determine which places you have been to. That\'s why the location permission is required to load the list of wifis. If you want to be able to pick one from the list you need to grant that permission. If not you can still enter your wifi name manually.</string>
<string name="needLocationPermForWifiList">The list of wifis your device has been connected to could be used to determine which places you have been to. That\'s why the location permission is required to load the list of wifis. If you want to be able to pick one from the list you need to grant that permission. If you do not want that, you can still enter your wifi name manually.</string>
<string name="noKnownWifis">There are no known wifis on your device.</string>
<string name="urlToTriggerExplanation">This feature does NOT open a browser, but triggers a URL in the background. You can use this e.g. to send commands to your home automation.</string>
<string name="automaticUpdateCheck">Check for updates</string>
@ -690,4 +693,42 @@
<string name="bottom">Bottom</string>
<string name="tabsPlacement">Position of tab bar</string>
<string name="tabsPlacementSummary">Choose where the tabs bar should be placed.</string>
<string name="wifiApi30">Because Google screwed up yet another part of Android, starting with API 30 only the currently visible wifis can be displayed, not all the ones your device has connected to anymore.</string>
<string name="smsDialogNotice">If you have not used a send-sms action in this program before, Android may show an additional confirmation dialog, asking you to allow sending messages. You need to select the \"always allow\" checkbox and confirm if you want this action to work in the background. It\'s advised to run this rule manually once to provoke this confirmation dialog.</string>
<string name="silentTriggersDnd">REMARK: The silent mode often triggers Do-Not-Disturb on newer devices. If that happens on your device, I recommend using the normal mode instead and lowering all volumes to zero.</string>
<string name="tones">Tones</string>
<string name="miscellaneous">Miscellaneous</string>
<string name="dnd">Do not disturb</string>
<string name="dndOff">DND off</string>
<string name="dndPriority">Let priority notifications through</string>
<string name="dndAlarms">Let alarms through</string>
<string name="dndNothing">Let nothing through</string>
<string name="dndRemarks">Fine tuning (like allowing phone calls, picking specific numbers, etc.) can only be done from the system\'s settings.</string>
<string name="permissionsRequiredNotAvailable">Your rules required permissions which cannot be requested from this installed flavor of Automation.</string>
<string name="automationNotificationsIgnored">If you do not choose a specific app, but choose \"Any app\", notifications from Automation will be ignored to avoid loops.</string>
<string name="repeatEveryXseconds">Repeat every x seconds</string>
<string name="repeatEveryXsecondsWithVariable">repeat every %1$s seconds</string>
<string name="enterRepetitionTime">You need to enter a positive non-decimal value for reptition time.</string>
<string name="elementSkipped">An element of the configuration file could not be read. The file may have been created by a newer program version.</string>
<string name="donate">Donate</string>
<string name="btTetheringNotice">This feature is confirmed to work up until Android 8.0. From some higher version upwards it ceases to work, but due to a lack of physical devices I cannot tell which one that is. On Android 11 it definitely ain\'t working anymore. If you have a version in between please let me know if it\'s working or not.</string>
<string name="notice">Notice</string>
<string name="devicePosition">Device position (Gyroscope)</string>
<string name="tolerance">Tolerance\n(0-180)</string>
<string name="orientationAzimuth">Azimuth:</string>
<string name="orientationPitch">Pitch:</string>
<string name="orientationRoll">Roll:</string>
<string name="enterValidNumbersIntoAllFields">Enter valid numbers in all fields.</string>
<string name="devicePositionExplanation">When you move your device the below numbers will update. What you can see there, is the current \"position\" of your device measured in degrees. If it is in the desired position, click the apply button to copy the current values to the desired fields.\nBecause reaching this exact position ever again is highly unlikely you must also enter a tolerance. The is amount of degrees to which the position can deviate in either direction. If you only care about one specific axis, specify a tolerance of 180° for the two other ones.</string>
<string name="wouldCurrentlyApply">Would currently apply?</string>
<string name="deviceIsInCertainPosition">the device is in a certain position</string>
<string name="toleranceOf180OnlyAllowedIn2Fields">A tolerance of 180 is allowed for 2 tolerance fields only, not all 3. Otherwise the trigger would ALWAYS apply.</string>
<string name="unknown">unknown</string>
<string name="position">Position</string>
<string name="triggerWrong">" There's something wrong with this trigger. It could not be loaded correctly."</string>
<string name="turnScreenOnOrOff">Turn screen on or off</string>
<string name="turnScreenOn">turn screen on</string>
<string name="turnScreenOff">turn screen off</string>
<string name="mustApply">Must apply</string>
<string name="explanationDevicePositionDirection">If the checkbox is checked that means the device has to be in the position you specify. If it\'s not checked, any position that does NOT match your criteria will do.</string>
</resources>

View File

@ -1,5 +1,6 @@
<network-security-config>
<base-config>
<base-config
cleartextTrafficPermitted="true">
<trust-anchors>
<!-- Trust preinstalled CAs -->
<certificates src="system" />

View File

@ -5,7 +5,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.2.2'
classpath 'com.android.tools.build:gradle:7.0.4'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files

View File

@ -0,0 +1 @@
* Klartext HTTP Datenverkehr für URL-Auslösen-Aktionen ermöglicht.

View File

@ -0,0 +1 @@
* HTTP Klartext wieder entfernt, hat nicht kompiliert.

View File

@ -0,0 +1 @@
* Klartext HTTP Datenverkehr für URL-Auslösen-Aktionen ermöglicht.

View File

@ -0,0 +1,4 @@
* Fehler im Benachrichtigungsauslöser behoben
* WLAN Liste laden für API > 30 (soweit möglich)
* Fehler behoben beim Hinzufügen/Ändern der SMS-senden Aktion
* Fehler behoben beim Ändern der Text-sprechen Aktion

View File

@ -0,0 +1,6 @@
* Fehler beim Erstellen einer Text-sprechen-Aktion behoben
* Fehler beim Hinzufügen eines Benachrichtigungs-Auslösers behoben
* Behoben: "beim Anrufen vibrieren" in Profilen hatte nicht funktioniert
* Hinzugefügt: "Nicht stören" kann nun in Profilen gesteuert werden.
* USB Router für Android 9 und höher unterstützt (benötigt root)
* Berechtigung READ_EXTERNAL_STORAGE für Regeln hinzugefügt, die Tondateien abspielen.

View File

@ -19,12 +19,14 @@ Mögliche Auslöser:
* Headset verbunden
* Telefongespräch im Gange
* Benachrichtigungen anderer Anwendungen
* Geräteposition (Gyroskop)
Mögliche Aktionen:
* WLAN ein-/ausschalten
* Bluetooth ein-/ausschalten
* USB Router ein-/ausschalten
* WLAN Router ein-/ausschalten
* Bluetooth Router ein-/ausschalten
* Bildschirmdrehung ein-/ausschalten
* HTTP Request im Hintergrund auslösen
* Klingelton und Toneinstellungen ändern
@ -39,13 +41,15 @@ Mögliche Aktionen:
* SMS verschicken
* Sounddatei abspielen.
Es ist ziemlich schwierig diese Anwendung über die vielen verschiedenen Geräte sowie die vielen Änderungen an Android Versionen am Laufen zu halten. Ich kann vieles im Emulator testen, aber eben nicht alles.
Es ist ziemlich schwierig diese Anwendung über die vielen verschiedenen Geräte und Android Versionen am Laufen zu halten. Ich kann vieles im Emulator testen, aber eben nicht alles.
Wenn also eine bestimmte Funktion nicht so tut wie sie sollte - lassen Sie es mich wissen. Über die Jahre habe ich noch alle Fehler behoben, die mir vernünftig gemeldet wurden. Aber dafür bin ich auf Ihre Mithilfe angewiesen.
Wenn Sie ein Problem mit der Anwendung haben und mich dazu kontaktieren möchten, updaten Sie bitte vorher auf die neueste Version und schauen Sie, ob Ihr Problem darin auch besteht.
Wenn Sie ein Problem mit der Anwendung haben und mich dazu kontaktieren möchten
- updaten Sie bitte vorher auf die neueste Version und schauen Sie, ob Ihr Problem darin auch besteht.
- prüfen Sie, ob Ihr Problem schon bekannt ist: https://server47.de/automation/index.php#knownProblems
Spenden sind sicher eine gute, aber nicht die einzige Möglichkeit mich zu motivieren :-)
* Wer mir etwas Gutes tun will, kann die Anwendung auch im Play Store bewerten.
* Wer mir etwas Gutes tun will, kann die Anwendung auch im Play Store bewerten (https://play.google.com/store/apps/details?id=com.jens.automation2).
* Außerdem ist Hilfe bei der Übersetzung willkommen. Englisch, Spanisch und Deutsch kann ich selbst. Aber sonst ist alles gern gesehen.
Erklärungen zu den vielen Berechtigungen können hier abgerufen werden: https://server47.de/automation/permissions_de.html

View File

@ -1 +1 @@
Automatisieren Sie Dinge auf Ihrem Ger<EFBFBD>t, indem Sie Regeln anlegen.
Automatisieren Sie Dinge auf Ihrem Gerät, indem Sie Regeln anlegen.

View File

@ -0,0 +1,4 @@
* Translations updated.
* New action: Vibrate
* Improved speed calculation
* Position of tab-bar can be chosen (top/bottom)

View File

@ -0,0 +1 @@
* Allowed cleartext HTTP traffic for rules using triggerUrl action

View File

@ -0,0 +1 @@
* Removed again, wouldn't compile.

View File

@ -0,0 +1 @@
* Allowed cleartext HTTP traffic for rules using triggerUrl action

View File

@ -0,0 +1,4 @@
* Fixed bug in notification trigger.
* Load wifi list for API > 30 (as far as possible)
* Fixed a bug when adding/editing sendTextMessage action
* Fixed a bug when editing speakText action

View File

@ -0,0 +1,6 @@
* Fixed bug in adding speakText action
* Fixed bug in adding notification trigger
* Fixed: vibrateWhenRinging setting in profiles didn't save nor activate
* Added: Do not disturb can be controlled in a profile
* Enabled USB Tethering for Android 9 and above (requires root)
* Added permission READ_EXTERNAL_STORAGE for rules that play sound files.

View File

@ -19,12 +19,14 @@ Supported triggers:
* Headset connected
* Phone call running
* Notifications of other apps
* Device position (gyroscope)
Supported actions:
* Change wifi state
* Change bluetooth state
* Toggle USB tethering
* Toggle wifi tethering
* Toggle Bluetooth tethering
* Toggle automatic screen rotation
* Make an HTTP request
* Change ringtone/sound setting
@ -42,10 +44,12 @@ Supported actions:
It's quite hard to keep this app working across the many different hardwares as well as the many changes Android undergoes over the versions. I can test it in the emulator, but that cannot show all bugs.
So if a certain feature is not working on your device - let me know. Over the years I have fixed almost all bugs that have been reasonably reported to me. But for that I'm dependend on your input.
If you have a problem and think about contacting me please update to the latest version first and see if your problem persists there, too.
If you have a problem and think about contacting me please
- update to the latest version first and see if your problem persists there, too.
- check this list of known problems first: https://server47.de/automation/index.php#knownProblems
Donations are certainly a good, but not the only way to motivate me :-)
* If you'd like to support me, you can also leave a positive review for the app on Google Play.
* If you'd like to support me, you can also leave a positive review for the app on Google Play (https://play.google.com/store/apps/details?id=com.jens.automation2).
* Furthermore I can always use help in translating the app. English, German and some Spanish are among my own skills. But everything else is more than welcome.
Explanation of the many permissions can be found here: https://server47.de/automation/permissions_en.html

View File

@ -0,0 +1 @@
* Permitido texto claro HTTP tráfico para reglas usando el gatillo Acción urgente

View File

@ -0,0 +1,4 @@
* Error fijo en el gatillo de notificación.
* Lista de wifi de carga para API > 30 (en la medida de lo posible)
* Arregló un error al añadir/editar sendTextMessage acción
* Arregló un error al editar la acción de TalkText

View File

@ -0,0 +1,6 @@
* Se ha corregido un error al agregar la acción speakText
* Se ha corregido un error en la adición de un disparador de notificación
* Corregido: vibrarCuando la configuración deRinging en los perfiles no se guardó ni se activó
* Añadido: No molestar se puede controlar en un perfil
* Conexión USB habilitada para Android 9 y superior (requiere root)
* Se agregó permiso READ_EXTERNAL_STORAGE para las reglas que reproducen archivos de sonido.

View File

@ -19,12 +19,14 @@ Disparadores:
* Headset conectado
* Llamado de teléfono activo
* Notificaciónes de otras apps
* Posición del dispositivo (giroscopio)
Supported actions:
* Pasar de wifi
* Pasar de bluetooth
* Pasar USB rúter
* Pasar wifi rúter
* Pasar Bluetooth rúter
* Pasar rotación automatica del monitor
* Hacer un solicitud HTTP
* Cambiar el tono de llamada / ajustes de sonido
@ -42,10 +44,12 @@ Supported actions:
Es muy dificil mantener esta applicación functionando en todos los hardwares y versiónes de Android. Puedo probrar mucho en el emulator, pero no puedo enviar todos los errores.
Si una función no funcióna - digame. En muchos años resolvaba la mayoria de los errores que los halladores me informaron bien. Pero dependo en su ayuda.
Si tiene un problema y considera contactarme update a la ultima version al primero y probar si su problam persiste.
Si tiene un problema y considera contactarme
- update a la ultima version al primero y probar si su problam persiste.
- al primero compruebe esta lista de problemas conocidos: https://server47.de/automation/index.php#knownProblems
Donaciónes seguramente son una buena, pero no la unica posibilidad de apoyarme :-)
* Si quiere apoyarme puedes escribir un buena revisión en Google Play
* Si quiere apoyarme puedes escribir un buena revisión en Google Play (https://play.google.com/store/apps/details?id=com.jens.automation2).
* Además siempre necesito ayuda en traduciendo la app. Ingles, Aleman y Español estan en mis habilidades. Per todo lo demás es bienvenido.
Puedes leer una explicación de los permisos aqui: https://server47.de/automation/permissions_en.html

View File

@ -0,0 +1 @@
* Cleartext http traffico dati per le azioni di trigger URL abilitate.

View File

@ -0,0 +1,4 @@
* Corretto bug nel trigger di notifica.
* Carica elenco wifi per API > 30 (per quanto possibile)
* Corretto un bug quando si aggiunge / modifica l'azione di sendTextMessage
* Corretto un bug quando si modifica l'azione del testo

View File

@ -0,0 +1,6 @@
* Corretto bug nell'aggiunta dell'azione speakText
* Risolto bug nell'aggiunta del trigger di notifica
* Risolto: vibrazioneQuando l'impostazioneringing nei profili non è stata salvata né attivata
* Aggiunto: Non disturbare può essere controllato in un profilo
* Tethering USB abilitato per Android 9 e versioni successive (richiede root)
* Aggiunta la READ_EXTERNAL_STORAGE delle autorizzazioni per le regole che riproduceno file audio.

View File

@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip