Compare commits

...

24 Commits

Author SHA1 Message Date
e0c3b9d450 Changelog updated and translated to German. 2021-04-27 15:51:02 +02:00
c134b15ab1 Changelog updated and translated to German. 2021-04-27 15:43:52 +02:00
6ef6277976 Changelog updated and translated to German. 2021-04-27 15:30:46 +02:00
10e6c74ba8 Cleanups. 2021-04-27 14:49:34 +02:00
b6f3d928ae Cleanups. 2021-04-27 14:42:29 +02:00
e898264178 StartAppChanges 2021-04-20 19:49:19 +02:00
0891dca98d StartAppChanges 2021-04-17 14:52:58 +02:00
8843a97b79 StartAppChanges 2021-04-13 20:00:36 +02:00
1c24af7bcb StartAppChanges 2021-04-11 19:37:50 +02:00
ee43e109da StartAppChanges 2021-04-09 17:39:59 +02:00
13bcb02ffc Notification trigger. 2021-03-30 23:06:07 +02:00
864ed2111e Notification listener finished. 2021-03-30 19:52:31 +02:00
67e6a38ddc Notification listener finished. 2021-03-29 16:36:21 +02:00
fb44196a0d Notification trigger. 2021-03-28 23:23:29 +02:00
7894504791 Notification listener started. 2021-03-28 20:33:44 +02:00
0df5342036 Notification trigger. 2021-03-27 22:52:42 +01:00
712a374adb Notification listener started. 2021-03-27 19:57:39 +01:00
80f8f9cfe2 Notification listener started. 2021-03-27 14:11:39 +01:00
1d9ed8b3ff Notification trigger. 2021-03-26 23:11:36 +01:00
5d6221888a Notification listener started. 2021-03-26 19:58:27 +01:00
56806f0349 Merge remote-tracking branch 'origin/master' into development
# Conflicts:
#	app/googlePlayFlavor/release/output-metadata.json
2021-03-21 22:45:34 +01:00
8a43741b21 Merge remote-tracking branch 'origin/master' into development 2021-03-21 22:30:20 +01:00
054ab6d84b Background location notifications in googlePlayFlavor 2021-03-20 22:49:05 +01:00
47b56d4978 Google shit again. 2021-03-20 13:37:18 +01:00
62 changed files with 3126 additions and 972 deletions

View File

@ -11,8 +11,8 @@ android {
compileSdkVersion 29 compileSdkVersion 29
buildToolsVersion '29.0.2' buildToolsVersion '29.0.2'
useLibrary 'org.apache.http.legacy' useLibrary 'org.apache.http.legacy'
versionCode 101 versionCode 102
versionName "1.6.25" versionName "1.6.30"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} }
@ -42,7 +42,7 @@ android {
dimension "version" dimension "version"
// applicationIdSuffix ".googlePlay" // applicationIdSuffix ".googlePlay"
versionNameSuffix "-googlePlay" versionNameSuffix "-googlePlay"
targetSdkVersion 30 targetSdkVersion 29
} }
fdroidFlavor fdroidFlavor

View File

@ -10,8 +10,8 @@
{ {
"type": "SINGLE", "type": "SINGLE",
"filters": [], "filters": [],
"versionCode": 101, "versionCode": 102,
"versionName": "1.6.25-googlePlay", "versionName": "1.6.30-googlePlay",
"outputFile": "app-googlePlayFlavor-release.apk" "outputFile": "app-googlePlayFlavor-release.apk"
} }
] ]

View File

@ -62,6 +62,7 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_CONTACTS"/> <uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"/>
<!-- Commented out because of Google Play policy --> <!-- Commented out because of Google Play policy -->
@ -136,11 +137,12 @@
<receiver android:name=".receivers.TimeZoneListener" /> <receiver android:name=".receivers.TimeZoneListener" />
<activity android:name=".ActivityManageRule" /> <activity android:name=".ActivityManageRule" />
<activity android:name=".ActivityEditTriggerUrl" /> <activity android:name=".ActivityManageActionTriggerUrl" />
<activity android:name=".ActivityDisplayLongMessage" /> <activity android:name=".ActivityDisplayLongMessage" />
<activity android:name=".ActivityEditSendTextMessage" /> <activity android:name=".ActivityManageActionSendTextMessage" />
<activity android:name=".ActivityManageTimeFrame" /> <activity android:name=".ActivityManageActionPlaySound" />
<activity android:name=".ActivityManageBrightnessSetting" /> <activity android:name=".ActivityManageTriggerTimeFrame" />
<activity android:name=".ActivityManageActionBrightnessSetting" />
<activity android:name=".ActivityHelp" /> <activity android:name=".ActivityHelp" />
<activity <activity
android:name=".ActivityMainTabLayout" android:name=".ActivityMainTabLayout"
@ -178,10 +180,10 @@
<activity android:name=".ActivityMainPoi" /> <activity android:name=".ActivityMainPoi" />
<activity android:name=".ActivityMainRules" /> <activity android:name=".ActivityMainRules" />
<activity android:name=".ActivityGeneric" /> <activity android:name=".ActivityGeneric" />
<activity android:name=".ActivityManageStartActivity" /> <activity android:name=".ActivityManageActionStartActivity" />
<activity android:name=".ActivityManageNfc" /> <activity android:name=".ActivityManageTriggerNfc" />
<activity android:name=".ActivityEditSpeakText" /> <activity android:name=".ActivityManageActionSpeakText" />
<activity android:name=".ActivityManageBluetoothTrigger" /> <activity android:name=".ActivityManageTriggerBluetooth" />
<activity android:name=".ActivityMainProfiles" /> <activity android:name=".ActivityMainProfiles" />
<activity android:name=".ActivityManageProfile" /> <activity android:name=".ActivityManageProfile" />
<activity android:name=".ActivityVolumeTest" /> <activity android:name=".ActivityVolumeTest" />
@ -203,6 +205,25 @@
<service android:name=".location.GeofenceIntentService"/> <service android:name=".location.GeofenceIntentService"/>
<activity android:name=".ActivityManageTriggerNotification"></activity>
<service
android:name=".receivers.NotificationListener"
android:label="@string/app_name"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE" >
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService" />
</intent-filter>
</service>
<provider
android:name=".FileShareProvider"
android:authorities="com.jens.automation2"
android:exported="true"
/>
</application> </application>
</manifest> </manifest>

View File

@ -1,13 +1,17 @@
package com.jens.automation2; package com.jens.automation2;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice;
import android.content.Context; import android.content.Context;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Build;
import android.os.Looper; import android.os.Looper;
import android.service.notification.StatusBarNotification;
import android.util.Log; import android.util.Log;
import android.widget.Toast; import android.widget.Toast;
import com.google.android.gms.location.DetectedActivity; import com.google.android.gms.location.DetectedActivity;
import com.jens.automation2.location.LocationProvider;
import com.jens.automation2.location.WifiBroadcastReceiver; import com.jens.automation2.location.WifiBroadcastReceiver;
import com.jens.automation2.receivers.ActivityDetectionReceiver; import com.jens.automation2.receivers.ActivityDetectionReceiver;
import com.jens.automation2.receivers.BatteryReceiver; import com.jens.automation2.receivers.BatteryReceiver;
@ -16,6 +20,7 @@ import com.jens.automation2.receivers.ConnectivityReceiver;
import com.jens.automation2.receivers.HeadphoneJackListener; import com.jens.automation2.receivers.HeadphoneJackListener;
import com.jens.automation2.receivers.NfcReceiver; import com.jens.automation2.receivers.NfcReceiver;
import com.jens.automation2.receivers.NoiseListener; import com.jens.automation2.receivers.NoiseListener;
import com.jens.automation2.receivers.NotificationListener;
import com.jens.automation2.receivers.PhoneStatusListener; import com.jens.automation2.receivers.PhoneStatusListener;
import com.jens.automation2.receivers.ProcessListener; import com.jens.automation2.receivers.ProcessListener;
@ -24,6 +29,10 @@ import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; 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> public class Rule implements Comparable<Rule>
{ {
@ -42,9 +51,20 @@ public class Rule implements Comparable<Rule>
private String name; private String name;
private boolean ruleActive = true; // rules can be deactivated, so they won't fire if you don't want them temporarily private boolean ruleActive = true; // rules can be deactivated, so they won't fire if you don't want them temporarily
private boolean ruleToggle = false; // rule will run again and do the opposite of its actions if applicable private boolean ruleToggle = false; // rule will run again and do the opposite of its actions if applicable
private Calendar lastExecution;
private static Date lastActivatedRuleActivationTime; private static Date lastActivatedRuleActivationTime;
public Calendar getLastExecution()
{
return lastExecution;
}
public void setLastExecution(Calendar lastExecution)
{
this.lastExecution = lastExecution;
}
public boolean isRuleToggle() public boolean isRuleToggle()
{ {
return ruleToggle; return ruleToggle;
@ -114,6 +134,7 @@ public class Rule implements Comparable<Rule>
{ {
return this.getName(); return this.getName();
} }
@SuppressLint("NewApi")
public String toStringLong() public String toStringLong()
{ {
String returnString = ""; String returnString = "";
@ -469,7 +490,7 @@ public class Rule implements Comparable<Rule>
{ {
if(oneTrigger.getTriggerParameter()) if(oneTrigger.getTriggerParameter())
{ {
if(BatteryReceiver.getBatteryLevel() < oneTrigger.getBatteryLevel()) 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); 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; return false;
@ -477,7 +498,7 @@ public class Rule implements Comparable<Rule>
} }
else else
{ {
if(BatteryReceiver.getBatteryLevel() > oneTrigger.getBatteryLevel()) 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); 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; return false;
@ -488,7 +509,7 @@ public class Rule implements Comparable<Rule>
{ {
if(oneTrigger.getTriggerParameter()) if(oneTrigger.getTriggerParameter())
{ {
if(com.jens.automation2.location.LocationProvider.getSpeed() < oneTrigger.getSpeed()) 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); 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; return false;
@ -496,7 +517,7 @@ public class Rule implements Comparable<Rule>
} }
else else
{ {
if(com.jens.automation2.location.LocationProvider.getSpeed() > oneTrigger.getSpeed()) 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); 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; return false;
@ -649,45 +670,6 @@ public class Rule implements Comparable<Rule>
{ {
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Checking for bluetooth...", 4); Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Checking for bluetooth...", 4);
// if( // connected / disconnected
// (oneTrigger.getTriggerParameter() && (BluetoothReceiver.getLastAction().equals(android.bluetooth.BluetoothDevice.ACTION_ACL_CONNECTED) | BluetoothReceiver.getLastAction().equals("android.bluetooth.device.action.ACL_CONNECTED")))
// |
// (!oneTrigger.getTriggerParameter() && (BluetoothReceiver.getLastAction().equals(android.bluetooth.BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED) | BluetoothReceiver.getLastAction().equals(android.bluetooth.BluetoothDevice.ACTION_ACL_DISCONNECTED) | BluetoothReceiver.getLastAction().equals("android.bluetooth.device.action.ACTION_ACL_DISCONNECT_REQUESTED") | BluetoothReceiver.getLastAction().equals("android.bluetooth.device.action.ACTION_ACL_DISCONNECTED")))
// )
// {
// if(oneTrigger.getBluetoothDeviceAddress() != null)
// {
// if(oneTrigger.getBluetoothDeviceAddress().equals("<any>"))
// {
// Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "No bluetooth address specified, any will do.", 4);
// }
// else if(oneTrigger.getBluetoothDeviceAddress().equals("<none>"))
// {
// // ???
// }
// else
// {
// Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Bluetooth address specified, checking that.", 4);
// if(!BluetoothReceiver.getLastAffectedDevice().getAddress().equals(oneTrigger.getBluetoothDeviceAddress()))
// {
// Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyNotTheCorrectDeviceAddress), 3);
// return false;
// }
// else
// Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Bluetooth address matches. Rule will apply.", 4);
// }
// }
// }
// else if(BluetoothReceiver.getLastAction().equals(android.bluetooth.BluetoothDevice.ACTION_FOUND) | BluetoothReceiver.getLastAction().equals(android.bluetooth.BluetoothDevice.ACTION_FOUND))
// {
// if(!oneTrigger.getTriggerParameter())
// {
// Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyDeviceInRangeButShouldNotBe), 3);
// return false;
// }
// }
// else // above only checks for last action, this checks for things in the past
{
if(oneTrigger.getBluetoothDeviceAddress().equals("<any>")) if(oneTrigger.getBluetoothDeviceAddress().equals("<any>"))
{ {
if(oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED)) if(oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED))
@ -751,7 +733,6 @@ public class Rule implements Comparable<Rule>
return false; return false;
} }
} }
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.headsetPlugged)) else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.headsetPlugged))
{ {
if(HeadphoneJackListener.isHeadsetConnected() != oneTrigger.getTriggerParameter()) if(HeadphoneJackListener.isHeadsetConnected() != oneTrigger.getTriggerParameter())
@ -763,6 +744,109 @@ public class Rule implements Comparable<Rule>
return false; 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;
}
}
}
}
} }
return true; return true;
@ -774,6 +858,8 @@ public class Rule implements Comparable<Rule>
private class ActivateRuleTask extends AsyncTask<Object, String, Void> private class ActivateRuleTask extends AsyncTask<Object, String, Void>
{ {
boolean wasActivated = false;
@Override @Override
protected Void doInBackground(Object... params) protected Void doInBackground(Object... params)
{ {
@ -788,7 +874,7 @@ public class Rule implements Comparable<Rule>
if (Looper.myLooper() == null) if (Looper.myLooper() == null)
Looper.prepare(); Looper.prepare();
activateInternally((AutomationService)params[0], (Boolean)params[1]); wasActivated = activateInternally((AutomationService)params[0], (Boolean)params[1]);
return null; return null;
} }
@ -806,16 +892,24 @@ public class Rule implements Comparable<Rule>
@Override @Override
protected void onPostExecute(Void result) protected void onPostExecute(Void result)
{ {
/*
Only update if the rules was actually executed. Became necessary for the notification trigger. If a user created a rule
with a notification trigger and this app creates a notification itself this will otherwise end in an infinite loop.
*/
if(wasActivated)
{
setLastExecution(Calendar.getInstance());
AutomationService.updateNotification(); AutomationService.updateNotification();
ActivityMainScreen.updateMainScreen(); ActivityMainScreen.updateMainScreen();
super.onPostExecute(result); super.onPostExecute(result);
} }
}
/** /**
* Will activate the rule. Should be called by a separate execution thread * Will activate the rule. Should be called by a separate execution thread
* @param automationService * @param automationService
*/ */
protected void activateInternally(AutomationService automationService, boolean force) protected boolean activateInternally(AutomationService automationService, boolean force)
{ {
boolean isActuallyToggable = isActuallyToggable(); boolean isActuallyToggable = isActuallyToggable();
@ -836,7 +930,16 @@ public class Rule implements Comparable<Rule>
publishProgress(message); publishProgress(message);
for(int i = 0; i< Rule.this.getActionSet().size(); i++) for(int i = 0; i< Rule.this.getActionSet().size(); i++)
{
try
{
Rule.this.getActionSet().get(i).run(automationService, doToggle); Rule.this.getActionSet().get(i).run(automationService, doToggle);
}
catch(Exception e)
{
Miscellaneous.logEvent("e", "RuleExecution", "Error running action of rule " + Rule.this.getName() + ": " + Log.getStackTraceString(e), 1);
}
}
// Keep log of last x rule activations (Settings) // Keep log of last x rule activations (Settings)
try try
@ -862,7 +965,10 @@ public class Rule implements Comparable<Rule>
else 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); 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;
} }
} }
@ -1280,6 +1386,26 @@ public class Rule implements Comparable<Rule>
return ruleCandidates; return ruleCandidates;
} }
public static ArrayList<Rule> findRuleCandidates(Trigger.Trigger_Enum triggerType)
{
ArrayList<Rule> ruleCandidates = new ArrayList<Rule>();
for(Rule oneRule : ruleCollection)
{
innerloop:
for(Trigger oneTrigger : oneRule.getTriggerSet())
{
if(oneTrigger.getTriggerType() == triggerType)
{
ruleCandidates.add(oneRule);
break innerloop; //we don't need to search the other triggers in the same rule
}
}
}
return ruleCandidates;
}
public static ArrayList<Rule> findRuleCandidatesByActivityDetection() public static ArrayList<Rule> findRuleCandidatesByActivityDetection()
{ {
ArrayList<Rule> ruleCandidates = new ArrayList<Rule>(); ArrayList<Rule> ruleCandidates = new ArrayList<Rule>();

View File

@ -132,11 +132,11 @@
<receiver android:name=".receivers.TimeZoneListener" /> <receiver android:name=".receivers.TimeZoneListener" />
<activity android:name=".ActivityManageRule" /> <activity android:name=".ActivityManageRule" />
<activity android:name=".ActivityEditTriggerUrl" /> <activity android:name=".ActivityManageActionTriggerUrl" />
<activity android:name=".ActivityDisplayLongMessage" /> <activity android:name=".ActivityDisplayLongMessage" />
<activity android:name=".ActivityEditSendTextMessage" /> <activity android:name=".ActivityManageActionSendTextMessage" />
<activity android:name=".ActivityManageTimeFrame" /> <activity android:name=".ActivityManageTriggerTimeFrame" />
<activity android:name=".ActivityManageBrightnessSetting" /> <activity android:name=".ActivityManageActionBrightnessSetting" />
<activity android:name=".ActivityHelp" /> <activity android:name=".ActivityHelp" />
<activity <activity
android:name=".ActivityMainTabLayout" android:name=".ActivityMainTabLayout"
@ -173,18 +173,35 @@
<activity android:name=".ActivityMainPoi" /> <activity android:name=".ActivityMainPoi" />
<activity android:name=".ActivityMainRules" /> <activity android:name=".ActivityMainRules" />
<activity android:name=".ActivityGeneric" /> <activity android:name=".ActivityGeneric" />
<activity android:name=".ActivityManageStartActivity" /> <activity android:name=".ActivityManageActionStartActivity" />
<activity android:name=".ActivityManageNfc" /> <activity android:name=".ActivityManageTriggerNfc" />
<activity android:name=".ActivityEditSpeakText" /> <activity android:name=".ActivityManageActionSpeakText" />
<activity android:name=".ActivityManageBluetoothTrigger" /> <activity android:name=".ActivityManageActionPlaySound" />
<activity android:name=".ActivityManageTriggerBluetooth" />
<activity android:name=".ActivityMainProfiles" /> <activity android:name=".ActivityMainProfiles" />
<activity android:name=".ActivityManageProfile" /> <activity android:name=".ActivityManageProfile" />
<activity android:name=".ActivityVolumeTest" /> <activity android:name=".ActivityVolumeTest" />
<activity android:name=".ActivityPermissions"></activity> <activity android:name=".ActivityPermissions"></activity>
<activity android:name=".ActivityManageTriggerNotification" />
<service
android:name=".receivers.NotificationListener"
android:label="@string/app_name"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE" >
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService" />
</intent-filter>
</service>
<uses-library android:name="org.apache.http.legacy" android:required="false"/> <uses-library android:name="org.apache.http.legacy" android:required="false"/>
<provider
android:name=".FileShareProvider"
android:authorities="com.jens.automation2"
android:exported="true"
/>
</application> </application>
</manifest> </manifest>

View File

@ -1,12 +1,16 @@
package com.jens.automation2; package com.jens.automation2;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice;
import android.content.Context; import android.content.Context;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Build;
import android.os.Looper; import android.os.Looper;
import android.service.notification.StatusBarNotification;
import android.util.Log; import android.util.Log;
import android.widget.Toast; import android.widget.Toast;
import com.jens.automation2.location.LocationProvider;
import com.jens.automation2.location.WifiBroadcastReceiver; import com.jens.automation2.location.WifiBroadcastReceiver;
import com.jens.automation2.receivers.BatteryReceiver; import com.jens.automation2.receivers.BatteryReceiver;
import com.jens.automation2.receivers.BluetoothReceiver; import com.jens.automation2.receivers.BluetoothReceiver;
@ -14,6 +18,7 @@ import com.jens.automation2.receivers.ConnectivityReceiver;
import com.jens.automation2.receivers.HeadphoneJackListener; import com.jens.automation2.receivers.HeadphoneJackListener;
import com.jens.automation2.receivers.NfcReceiver; import com.jens.automation2.receivers.NfcReceiver;
import com.jens.automation2.receivers.NoiseListener; import com.jens.automation2.receivers.NoiseListener;
import com.jens.automation2.receivers.NotificationListener;
import com.jens.automation2.receivers.PhoneStatusListener; import com.jens.automation2.receivers.PhoneStatusListener;
import com.jens.automation2.receivers.ProcessListener; import com.jens.automation2.receivers.ProcessListener;
@ -22,6 +27,9 @@ import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; 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> public class Rule implements Comparable<Rule>
{ {
@ -40,9 +48,20 @@ public class Rule implements Comparable<Rule>
private String name; private String name;
private boolean ruleActive = true; // rules can be deactivated, so they won't fire if you don't want them temporarily private boolean ruleActive = true; // rules can be deactivated, so they won't fire if you don't want them temporarily
private boolean ruleToggle = false; // rule will run again and do the opposite of its actions if applicable private boolean ruleToggle = false; // rule will run again and do the opposite of its actions if applicable
private Calendar lastExecution;
private static Date lastActivatedRuleActivationTime; private static Date lastActivatedRuleActivationTime;
public Calendar getLastExecution()
{
return lastExecution;
}
public void setLastExecution(Calendar lastExecution)
{
this.lastExecution = lastExecution;
}
public boolean isRuleToggle() public boolean isRuleToggle()
{ {
return ruleToggle; return ruleToggle;
@ -112,6 +131,7 @@ public class Rule implements Comparable<Rule>
{ {
return this.getName(); return this.getName();
} }
@SuppressLint("NewApi")
public String toStringLong() public String toStringLong()
{ {
String returnString = ""; String returnString = "";
@ -467,7 +487,7 @@ public class Rule implements Comparable<Rule>
{ {
if(oneTrigger.getTriggerParameter()) if(oneTrigger.getTriggerParameter())
{ {
if(BatteryReceiver.getBatteryLevel() < oneTrigger.getBatteryLevel()) 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); 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; return false;
@ -475,7 +495,7 @@ public class Rule implements Comparable<Rule>
} }
else else
{ {
if(BatteryReceiver.getBatteryLevel() > oneTrigger.getBatteryLevel()) 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); 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; return false;
@ -486,7 +506,7 @@ public class Rule implements Comparable<Rule>
{ {
if(oneTrigger.getTriggerParameter()) if(oneTrigger.getTriggerParameter())
{ {
if(com.jens.automation2.location.LocationProvider.getSpeed() < oneTrigger.getSpeed()) 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); 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; return false;
@ -494,7 +514,7 @@ public class Rule implements Comparable<Rule>
} }
else else
{ {
if(com.jens.automation2.location.LocationProvider.getSpeed() > oneTrigger.getSpeed()) 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); 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; return false;
@ -618,45 +638,6 @@ public class Rule implements Comparable<Rule>
{ {
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Checking for bluetooth...", 4); Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Checking for bluetooth...", 4);
// if( // connected / disconnected
// (oneTrigger.getTriggerParameter() && (BluetoothReceiver.getLastAction().equals(android.bluetooth.BluetoothDevice.ACTION_ACL_CONNECTED) | BluetoothReceiver.getLastAction().equals("android.bluetooth.device.action.ACL_CONNECTED")))
// |
// (!oneTrigger.getTriggerParameter() && (BluetoothReceiver.getLastAction().equals(android.bluetooth.BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED) | BluetoothReceiver.getLastAction().equals(android.bluetooth.BluetoothDevice.ACTION_ACL_DISCONNECTED) | BluetoothReceiver.getLastAction().equals("android.bluetooth.device.action.ACTION_ACL_DISCONNECT_REQUESTED") | BluetoothReceiver.getLastAction().equals("android.bluetooth.device.action.ACTION_ACL_DISCONNECTED")))
// )
// {
// if(oneTrigger.getBluetoothDeviceAddress() != null)
// {
// if(oneTrigger.getBluetoothDeviceAddress().equals("<any>"))
// {
// Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "No bluetooth address specified, any will do.", 4);
// }
// else if(oneTrigger.getBluetoothDeviceAddress().equals("<none>"))
// {
// // ???
// }
// else
// {
// Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Bluetooth address specified, checking that.", 4);
// if(!BluetoothReceiver.getLastAffectedDevice().getAddress().equals(oneTrigger.getBluetoothDeviceAddress()))
// {
// Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyNotTheCorrectDeviceAddress), 3);
// return false;
// }
// else
// Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Bluetooth address matches. Rule will apply.", 4);
// }
// }
// }
// else if(BluetoothReceiver.getLastAction().equals(android.bluetooth.BluetoothDevice.ACTION_FOUND) | BluetoothReceiver.getLastAction().equals(android.bluetooth.BluetoothDevice.ACTION_FOUND))
// {
// if(!oneTrigger.getTriggerParameter())
// {
// Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyDeviceInRangeButShouldNotBe), 3);
// return false;
// }
// }
// else // above only checks for last action, this checks for things in the past
{
if(oneTrigger.getBluetoothDeviceAddress().equals("<any>")) if(oneTrigger.getBluetoothDeviceAddress().equals("<any>"))
{ {
if(oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED)) if(oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED))
@ -720,7 +701,6 @@ public class Rule implements Comparable<Rule>
return false; return false;
} }
} }
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.headsetPlugged)) else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.headsetPlugged))
{ {
if(HeadphoneJackListener.isHeadsetConnected() != oneTrigger.getTriggerParameter()) if(HeadphoneJackListener.isHeadsetConnected() != oneTrigger.getTriggerParameter())
@ -732,6 +712,108 @@ public class Rule implements Comparable<Rule>
return false; 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;
}
}
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;
}
}
}
}
} }
return true; return true;
@ -743,6 +825,8 @@ public class Rule implements Comparable<Rule>
private class ActivateRuleTask extends AsyncTask<Object, String, Void> private class ActivateRuleTask extends AsyncTask<Object, String, Void>
{ {
boolean wasActivated = false;
@Override @Override
protected Void doInBackground(Object... params) protected Void doInBackground(Object... params)
{ {
@ -757,7 +841,7 @@ public class Rule implements Comparable<Rule>
if (Looper.myLooper() == null) if (Looper.myLooper() == null)
Looper.prepare(); Looper.prepare();
activateInternally((AutomationService)params[0], (Boolean)params[1]); wasActivated = activateInternally((AutomationService)params[0], (Boolean)params[1]);
return null; return null;
} }
@ -775,16 +859,24 @@ public class Rule implements Comparable<Rule>
@Override @Override
protected void onPostExecute(Void result) protected void onPostExecute(Void result)
{ {
/*
Only update if the rules was actually executed. Became necessary for the notification trigger. If a user created a rule
with a notification trigger and this app creates a notification itself this will otherwise end in an infinite loop.
*/
if(wasActivated)
{
setLastExecution(Calendar.getInstance());
AutomationService.updateNotification(); AutomationService.updateNotification();
ActivityMainScreen.updateMainScreen(); ActivityMainScreen.updateMainScreen();
super.onPostExecute(result); super.onPostExecute(result);
} }
}
/** /**
* Will activate the rule. Should be called by a separate execution thread * Will activate the rule. Should be called by a separate execution thread
* @param automationService * @param automationService
*/ */
protected void activateInternally(AutomationService automationService, boolean force) protected boolean activateInternally(AutomationService automationService, boolean force)
{ {
boolean isActuallyToggable = isActuallyToggable(); boolean isActuallyToggable = isActuallyToggable();
@ -805,7 +897,16 @@ public class Rule implements Comparable<Rule>
publishProgress(message); publishProgress(message);
for(int i = 0; i< Rule.this.getActionSet().size(); i++) for(int i = 0; i< Rule.this.getActionSet().size(); i++)
{
try
{
Rule.this.getActionSet().get(i).run(automationService, doToggle); Rule.this.getActionSet().get(i).run(automationService, doToggle);
}
catch(Exception e)
{
Miscellaneous.logEvent("e", "RuleExecution", "Error running action of rule " + Rule.this.getName() + ": " + Log.getStackTraceString(e), 1);
}
}
// Keep log of last x rule activations (Settings) // Keep log of last x rule activations (Settings)
try try
@ -831,7 +932,10 @@ public class Rule implements Comparable<Rule>
else 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); 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;
} }
} }
@ -1249,6 +1353,26 @@ public class Rule implements Comparable<Rule>
return ruleCandidates; return ruleCandidates;
} }
public static ArrayList<Rule> findRuleCandidates(Trigger.Trigger_Enum triggerType)
{
ArrayList<Rule> ruleCandidates = new ArrayList<Rule>();
for(Rule oneRule : ruleCollection)
{
innerloop:
for(Trigger oneTrigger : oneRule.getTriggerSet())
{
if(oneTrigger.getTriggerType() == triggerType)
{
ruleCandidates.add(oneRule);
break innerloop; //we don't need to search the other triggers in the same rule
}
}
}
return ruleCandidates;
}
public static ArrayList<Rule> findRuleCandidatesByActivityDetection() public static ArrayList<Rule> findRuleCandidatesByActivityDetection()
{ {
ArrayList<Rule> ruleCandidates = new ArrayList<Rule>(); ArrayList<Rule> ruleCandidates = new ArrayList<Rule>();

View File

@ -126,11 +126,12 @@
<receiver android:name=".receivers.TimeZoneListener" /> <receiver android:name=".receivers.TimeZoneListener" />
<activity android:name=".ActivityManageRule" /> <activity android:name=".ActivityManageRule" />
<activity android:name=".ActivityEditTriggerUrl" /> <activity android:name=".ActivityManageActionTriggerUrl" />
<activity android:name=".ActivityDisplayLongMessage" /> <activity android:name=".ActivityDisplayLongMessage" />
<activity android:name=".ActivityEditSendTextMessage" /> <activity android:name=".ActivityManageActionSendTextMessage" />
<activity android:name=".ActivityManageTimeFrame" /> <activity android:name=".ActivityManageActionPlaySound" />
<activity android:name=".ActivityManageBrightnessSetting" /> <activity android:name=".ActivityManageTriggerTimeFrame" />
<activity android:name=".ActivityManageActionBrightnessSetting" />
<activity android:name=".ActivityHelp" /> <activity android:name=".ActivityHelp" />
<activity <activity
android:name=".ActivityMainTabLayout" android:name=".ActivityMainTabLayout"
@ -168,13 +169,25 @@
<activity android:name=".ActivityMainPoi" /> <activity android:name=".ActivityMainPoi" />
<activity android:name=".ActivityMainRules" /> <activity android:name=".ActivityMainRules" />
<activity android:name=".ActivityGeneric" /> <activity android:name=".ActivityGeneric" />
<activity android:name=".ActivityManageStartActivity" /> <activity android:name=".ActivityManageActionStartActivity" />
<activity android:name=".ActivityManageNfc" /> <activity android:name=".ActivityManageTriggerNfc" />
<activity android:name=".ActivityEditSpeakText" /> <activity android:name=".ActivityManageActionSpeakText" />
<activity android:name=".ActivityManageBluetoothTrigger" /> <activity android:name=".ActivityManageTriggerBluetooth" />
<activity android:name=".ActivityMainProfiles" /> <activity android:name=".ActivityMainProfiles" />
<activity android:name=".ActivityManageProfile" /> <activity android:name=".ActivityManageProfile" />
<activity android:name=".ActivityVolumeTest" /> <activity android:name=".ActivityVolumeTest" />
<activity android:name=".ActivityPermissions"></activity>
<activity android:name=".ActivityManageTriggerNotification"></activity>
<service
android:name=".receivers.NotificationListener"
android:label="@string/app_name"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE" >
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService" />
</intent-filter>
</service>
<service <service
android:name=".receivers.ActivityDetectionReceiver" android:name=".receivers.ActivityDetectionReceiver"
@ -191,6 +204,12 @@
<uses-library android:name="org.apache.http.legacy" android:required="false"/> <uses-library android:name="org.apache.http.legacy" android:required="false"/>
<provider
android:name=".FileShareProvider"
android:authorities="com.jens.automation2"
android:exported="true"
/>
</application> </application>
</manifest> </manifest>

View File

@ -1,13 +1,17 @@
package com.jens.automation2; package com.jens.automation2;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice;
import android.content.Context; import android.content.Context;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Build;
import android.os.Looper; import android.os.Looper;
import android.service.notification.StatusBarNotification;
import android.util.Log; import android.util.Log;
import android.widget.Toast; import android.widget.Toast;
import com.google.android.gms.location.DetectedActivity; import com.google.android.gms.location.DetectedActivity;
import com.jens.automation2.location.LocationProvider;
import com.jens.automation2.location.WifiBroadcastReceiver; import com.jens.automation2.location.WifiBroadcastReceiver;
import com.jens.automation2.receivers.ActivityDetectionReceiver; import com.jens.automation2.receivers.ActivityDetectionReceiver;
import com.jens.automation2.receivers.BatteryReceiver; import com.jens.automation2.receivers.BatteryReceiver;
@ -16,6 +20,7 @@ import com.jens.automation2.receivers.ConnectivityReceiver;
import com.jens.automation2.receivers.HeadphoneJackListener; import com.jens.automation2.receivers.HeadphoneJackListener;
import com.jens.automation2.receivers.NfcReceiver; import com.jens.automation2.receivers.NfcReceiver;
import com.jens.automation2.receivers.NoiseListener; import com.jens.automation2.receivers.NoiseListener;
import com.jens.automation2.receivers.NotificationListener;
import com.jens.automation2.receivers.PhoneStatusListener; import com.jens.automation2.receivers.PhoneStatusListener;
import com.jens.automation2.receivers.ProcessListener; import com.jens.automation2.receivers.ProcessListener;
@ -24,6 +29,9 @@ import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; 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> public class Rule implements Comparable<Rule>
{ {
@ -42,9 +50,20 @@ public class Rule implements Comparable<Rule>
private String name; private String name;
private boolean ruleActive = true; // rules can be deactivated, so they won't fire if you don't want them temporarily private boolean ruleActive = true; // rules can be deactivated, so they won't fire if you don't want them temporarily
private boolean ruleToggle = false; // rule will run again and do the opposite of its actions if applicable private boolean ruleToggle = false; // rule will run again and do the opposite of its actions if applicable
private Calendar lastExecution;
private static Date lastActivatedRuleActivationTime; private static Date lastActivatedRuleActivationTime;
public Calendar getLastExecution()
{
return lastExecution;
}
public void setLastExecution(Calendar lastExecution)
{
this.lastExecution = lastExecution;
}
public boolean isRuleToggle() public boolean isRuleToggle()
{ {
return ruleToggle; return ruleToggle;
@ -114,6 +133,7 @@ public class Rule implements Comparable<Rule>
{ {
return this.getName(); return this.getName();
} }
@SuppressLint("NewApi")
public String toStringLong() public String toStringLong()
{ {
String returnString = ""; String returnString = "";
@ -469,7 +489,7 @@ public class Rule implements Comparable<Rule>
{ {
if(oneTrigger.getTriggerParameter()) if(oneTrigger.getTriggerParameter())
{ {
if(BatteryReceiver.getBatteryLevel() < oneTrigger.getBatteryLevel()) 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); 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; return false;
@ -477,7 +497,7 @@ public class Rule implements Comparable<Rule>
} }
else else
{ {
if(BatteryReceiver.getBatteryLevel() > oneTrigger.getBatteryLevel()) 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); 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; return false;
@ -488,7 +508,7 @@ public class Rule implements Comparable<Rule>
{ {
if(oneTrigger.getTriggerParameter()) if(oneTrigger.getTriggerParameter())
{ {
if(com.jens.automation2.location.LocationProvider.getSpeed() < oneTrigger.getSpeed()) 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); 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; return false;
@ -496,7 +516,7 @@ public class Rule implements Comparable<Rule>
} }
else else
{ {
if(com.jens.automation2.location.LocationProvider.getSpeed() > oneTrigger.getSpeed()) 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); 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; return false;
@ -649,45 +669,6 @@ public class Rule implements Comparable<Rule>
{ {
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Checking for bluetooth...", 4); Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Checking for bluetooth...", 4);
// if( // connected / disconnected
// (oneTrigger.getTriggerParameter() && (BluetoothReceiver.getLastAction().equals(android.bluetooth.BluetoothDevice.ACTION_ACL_CONNECTED) | BluetoothReceiver.getLastAction().equals("android.bluetooth.device.action.ACL_CONNECTED")))
// |
// (!oneTrigger.getTriggerParameter() && (BluetoothReceiver.getLastAction().equals(android.bluetooth.BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED) | BluetoothReceiver.getLastAction().equals(android.bluetooth.BluetoothDevice.ACTION_ACL_DISCONNECTED) | BluetoothReceiver.getLastAction().equals("android.bluetooth.device.action.ACTION_ACL_DISCONNECT_REQUESTED") | BluetoothReceiver.getLastAction().equals("android.bluetooth.device.action.ACTION_ACL_DISCONNECTED")))
// )
// {
// if(oneTrigger.getBluetoothDeviceAddress() != null)
// {
// if(oneTrigger.getBluetoothDeviceAddress().equals("<any>"))
// {
// Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "No bluetooth address specified, any will do.", 4);
// }
// else if(oneTrigger.getBluetoothDeviceAddress().equals("<none>"))
// {
// // ???
// }
// else
// {
// Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Bluetooth address specified, checking that.", 4);
// if(!BluetoothReceiver.getLastAffectedDevice().getAddress().equals(oneTrigger.getBluetoothDeviceAddress()))
// {
// Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyNotTheCorrectDeviceAddress), 3);
// return false;
// }
// else
// Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Bluetooth address matches. Rule will apply.", 4);
// }
// }
// }
// else if(BluetoothReceiver.getLastAction().equals(android.bluetooth.BluetoothDevice.ACTION_FOUND) | BluetoothReceiver.getLastAction().equals(android.bluetooth.BluetoothDevice.ACTION_FOUND))
// {
// if(!oneTrigger.getTriggerParameter())
// {
// Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyDeviceInRangeButShouldNotBe), 3);
// return false;
// }
// }
// else // above only checks for last action, this checks for things in the past
{
if(oneTrigger.getBluetoothDeviceAddress().equals("<any>")) if(oneTrigger.getBluetoothDeviceAddress().equals("<any>"))
{ {
if(oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED)) if(oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED))
@ -751,7 +732,6 @@ public class Rule implements Comparable<Rule>
return false; return false;
} }
} }
}
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.headsetPlugged)) else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.headsetPlugged))
{ {
if(HeadphoneJackListener.isHeadsetConnected() != oneTrigger.getTriggerParameter()) if(HeadphoneJackListener.isHeadsetConnected() != oneTrigger.getTriggerParameter())
@ -763,6 +743,109 @@ public class Rule implements Comparable<Rule>
return false; 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;
}
}
}
}
} }
return true; return true;
@ -774,6 +857,8 @@ public class Rule implements Comparable<Rule>
private class ActivateRuleTask extends AsyncTask<Object, String, Void> private class ActivateRuleTask extends AsyncTask<Object, String, Void>
{ {
boolean wasActivated = false;
@Override @Override
protected Void doInBackground(Object... params) protected Void doInBackground(Object... params)
{ {
@ -788,7 +873,7 @@ public class Rule implements Comparable<Rule>
if (Looper.myLooper() == null) if (Looper.myLooper() == null)
Looper.prepare(); Looper.prepare();
activateInternally((AutomationService)params[0], (Boolean)params[1]); wasActivated = activateInternally((AutomationService)params[0], (Boolean)params[1]);
return null; return null;
} }
@ -806,16 +891,24 @@ public class Rule implements Comparable<Rule>
@Override @Override
protected void onPostExecute(Void result) protected void onPostExecute(Void result)
{ {
/*
Only update if the rules was actually executed. Became necessary for the notification trigger. If a user created a rule
with a notification trigger and this app creates a notification itself this will otherwise end in an infinite loop.
*/
if(wasActivated)
{
setLastExecution(Calendar.getInstance());
AutomationService.updateNotification(); AutomationService.updateNotification();
ActivityMainScreen.updateMainScreen(); ActivityMainScreen.updateMainScreen();
super.onPostExecute(result); super.onPostExecute(result);
} }
}
/** /**
* Will activate the rule. Should be called by a separate execution thread * Will activate the rule. Should be called by a separate execution thread
* @param automationService * @param automationService
*/ */
protected void activateInternally(AutomationService automationService, boolean force) protected boolean activateInternally(AutomationService automationService, boolean force)
{ {
boolean isActuallyToggable = isActuallyToggable(); boolean isActuallyToggable = isActuallyToggable();
@ -836,7 +929,16 @@ public class Rule implements Comparable<Rule>
publishProgress(message); publishProgress(message);
for(int i = 0; i< Rule.this.getActionSet().size(); i++) for(int i = 0; i< Rule.this.getActionSet().size(); i++)
{
try
{
Rule.this.getActionSet().get(i).run(automationService, doToggle); Rule.this.getActionSet().get(i).run(automationService, doToggle);
}
catch(Exception e)
{
Miscellaneous.logEvent("e", "RuleExecution", "Error running action of rule " + Rule.this.getName() + ": " + Log.getStackTraceString(e), 1);
}
}
// Keep log of last x rule activations (Settings) // Keep log of last x rule activations (Settings)
try try
@ -862,7 +964,10 @@ public class Rule implements Comparable<Rule>
else 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); 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;
} }
} }
@ -1280,6 +1385,26 @@ public class Rule implements Comparable<Rule>
return ruleCandidates; return ruleCandidates;
} }
public static ArrayList<Rule> findRuleCandidates(Trigger.Trigger_Enum triggerType)
{
ArrayList<Rule> ruleCandidates = new ArrayList<Rule>();
for(Rule oneRule : ruleCollection)
{
innerloop:
for(Trigger oneTrigger : oneRule.getTriggerSet())
{
if(oneTrigger.getTriggerType() == triggerType)
{
ruleCandidates.add(oneRule);
break innerloop; //we don't need to search the other triggers in the same rule
}
}
}
return ruleCandidates;
}
public static ArrayList<Rule> findRuleCandidatesByActivityDetection() public static ArrayList<Rule> findRuleCandidatesByActivityDetection()
{ {
ArrayList<Rule> ruleCandidates = new ArrayList<Rule>(); ArrayList<Rule> ruleCandidates = new ArrayList<Rule>();

View File

@ -2,7 +2,9 @@ package com.jens.automation2;
import android.content.Context; import android.content.Context;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.text.style.TabStopSpan;
import android.util.Log; import android.util.Log;
import android.widget.Toast;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
@ -12,6 +14,8 @@ import java.util.Locale;
public class Action public class Action
{ {
public static final String actionParameter2Split = "ap2split";
public enum Action_Enum { public enum Action_Enum {
setWifi, setWifi,
setBluetooth, setBluetooth,
@ -33,6 +37,7 @@ public class Action
speakText, speakText,
playMusic, playMusic,
setScreenBrightness, setScreenBrightness,
playSound,
sendTextMessage; sendTextMessage;
public String getFullName(Context context) public String getFullName(Context context)
@ -87,6 +92,8 @@ public class Action
return context.getResources().getString(R.string.actionSpeakText); return context.getResources().getString(R.string.actionSpeakText);
case playMusic: case playMusic:
return context.getResources().getString(R.string.actionPlayMusic); return context.getResources().getString(R.string.actionPlayMusic);
case playSound:
return context.getResources().getString(R.string.playSound);
case sendTextMessage: case sendTextMessage:
return context.getResources().getString(R.string.sendTextMessage); return context.getResources().getString(R.string.sendTextMessage);
case setScreenBrightness: case setScreenBrightness:
@ -210,6 +217,10 @@ public class Action
{ {
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.wakeupDevice)); returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.wakeupDevice));
} }
else if(this.getAction().equals(Action_Enum.playSound))
{
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.playSound));
}
else else
returnString.append(action.toString()); returnString.append(action.toString());
@ -320,6 +331,8 @@ public class Action
} }
public void run(Context context, boolean toggleActionIfPossible) public void run(Context context, boolean toggleActionIfPossible)
{
try
{ {
switch(this.getAction()) switch(this.getAction())
{ {
@ -337,7 +350,7 @@ public class Action
// else // else
// { // {
Profile p = Profile.getByName(this.getParameter2()); Profile p = Profile.getByName(this.getParameter2());
if(p != null) if (p != null)
p.activate(context); p.activate(context);
// } // }
break; break;
@ -395,11 +408,20 @@ public class Action
case setScreenBrightness: case setScreenBrightness:
Actions.setScreenBrightness(getParameter1(), Integer.parseInt(getParameter2())); Actions.setScreenBrightness(getParameter1(), Integer.parseInt(getParameter2()));
break; break;
case playSound:
Actions.playSound(getParameter1(), getParameter2());
break;
default: default:
Miscellaneous.logEvent("w", "Action", context.getResources().getString(R.string.unknownActionSpecified), 3); Miscellaneous.logEvent("w", "Action", context.getResources().getString(R.string.unknownActionSpecified), 3);
break; break;
} }
} }
catch(Exception e)
{
Miscellaneous.logEvent("e", "ActionExecution", Log.getStackTraceString(e), 1);
Toast.makeText(context, context.getResources().getString(R.string.errorRunningRule), Toast.LENGTH_LONG).show();
}
}
private void triggerUrl(Context context) private void triggerUrl(Context context)
{ {

View File

@ -8,7 +8,9 @@ import android.content.ActivityNotFoundException;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.media.AudioManager; import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.Uri;
import android.net.wifi.WifiManager; import android.net.wifi.WifiManager;
import android.os.Build; import android.os.Build;
import android.os.PowerManager; import android.os.PowerManager;
@ -32,6 +34,7 @@ import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.util.InetAddressUtils; import org.apache.http.conn.util.InetAddressUtils;
import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.client.DefaultHttpClient;
import java.io.File;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.InetAddress; import java.net.InetAddress;
@ -465,6 +468,45 @@ public class Actions
return ""; return "";
} }
public static void playSound(boolean alwaysPlay, String soundFileLocation)
{
if(alwaysPlay || ((AudioManager) Miscellaneous.getAnyContext().getSystemService(Context.AUDIO_SERVICE)).getRingerMode() == AudioManager.RINGER_MODE_NORMAL)
{
MediaPlayer mp = new MediaPlayer();
try
{
File file = new File(soundFileLocation);
if(file.exists())
{
Uri fileUri = Uri.parse(soundFileLocation);
mp.setLooping(false);
mp.setDataSource(Miscellaneous.getAnyContext(), fileUri);
mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener()
{
@Override
public void onCompletion(MediaPlayer mp)
{
mp.release();
}
});
mp.prepare();
mp.start();
}
else
{
Miscellaneous.logEvent("w", "Play sound file", "Sound file " + soundFileLocation + " does not exist. Can't play it.", 2);
Toast.makeText(context, String.format(context.getResources().getString(R.string.cantFindSoundFile), soundFileLocation), Toast.LENGTH_SHORT).show();
}
}
catch (Exception e)
{
Miscellaneous.logEvent("e", "Play sound file", "Error playing sound: " + Log.getStackTraceString(e), 2);
}
}
else
Miscellaneous.logEvent("i", "Play sound file", "Not playing sound file because phone is on some kind of mute state.", 2);
}
public void useDownloadedWebpage(String result) public void useDownloadedWebpage(String result)
{ {
// Toast.makeText(context, "Result: " + result, Toast.LENGTH_LONG).show(); // Toast.makeText(context, "Result: " + result, Toast.LENGTH_LONG).show();
@ -527,7 +569,9 @@ public class Actions
Miscellaneous.logEvent("i", "StartOtherActivity", "Starting other Activity...", 4); Miscellaneous.logEvent("i", "StartOtherActivity", "Starting other Activity...", 4);
String packageName, className; String packageName, className;
String params[] = param.split(";"); String params[] = param.split(";");
packageName = params[0]; packageName = params[0];
className = params[1]; className = params[1];
@ -537,10 +581,16 @@ public class Actions
Intent externalActivityIntent = new Intent(Intent.ACTION_MAIN); Intent externalActivityIntent = new Intent(Intent.ACTION_MAIN);
externalActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); externalActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
externalActivityIntent.addCategory(Intent.CATEGORY_LAUNCHER); externalActivityIntent.addCategory(Intent.CATEGORY_LAUNCHER);
if(packageName.equals("dummyPkg"))
externalActivityIntent.setAction(className);
else
externalActivityIntent.setClassName(packageName, className); externalActivityIntent.setClassName(packageName, className);
if(Miscellaneous.doesActivityExist(externalActivityIntent, Miscellaneous.getAnyContext()))
{
// has intent values to deliver // has intent values to deliver
for(int i=2; i<params.length; i++) for (int i = 2; i < params.length; i++)
{ {
String[] singleParam = params[i].split("/"); String[] singleParam = params[i].split("/");
@ -554,62 +604,67 @@ public class Actions
} }
}*/ }*/
if(singleParam[0].equals("boolean")) if (singleParam[0].equals("boolean"))
{ {
Miscellaneous.logEvent("i", "StartOtherApp" , "Adding parameter of type " + singleParam[0] + " with name " + singleParam[1] + " and value " + singleParam[2], 3); Miscellaneous.logEvent("i", "StartOtherApp", "Adding parameter of type " + singleParam[0] + " with name " + singleParam[1] + " and value " + singleParam[2], 3);
externalActivityIntent.putExtra(singleParam[1], Boolean.parseBoolean(singleParam[2])); externalActivityIntent.putExtra(singleParam[1], Boolean.parseBoolean(singleParam[2]));
} }
else if(singleParam[0].equals("byte")) else if (singleParam[0].equals("byte"))
{ {
Miscellaneous.logEvent("i", "StartOtherApp" , "Adding parameter of type " + singleParam[0] + " with name " + singleParam[1] + " and value " + singleParam[2], 3); Miscellaneous.logEvent("i", "StartOtherApp", "Adding parameter of type " + singleParam[0] + " with name " + singleParam[1] + " and value " + singleParam[2], 3);
externalActivityIntent.putExtra(singleParam[1], Byte.parseByte(singleParam[2])); externalActivityIntent.putExtra(singleParam[1], Byte.parseByte(singleParam[2]));
} }
else if(singleParam[0].equals("char")) else if (singleParam[0].equals("char"))
{ {
Miscellaneous.logEvent("i", "StartOtherApp" , "Adding parameter of type " + singleParam[0] + " with name " + singleParam[1] + " and value " + singleParam[2], 3); Miscellaneous.logEvent("i", "StartOtherApp", "Adding parameter of type " + singleParam[0] + " with name " + singleParam[1] + " and value " + singleParam[2], 3);
externalActivityIntent.putExtra(singleParam[1], singleParam[2].charAt(0)); externalActivityIntent.putExtra(singleParam[1], singleParam[2].charAt(0));
} }
else if(singleParam[0].equals("CharSequence")) else if (singleParam[0].equals("CharSequence"))
{ {
Miscellaneous.logEvent("i", "StartOtherApp" , "Adding parameter of type " + singleParam[0] + " with name " + singleParam[1] + " and value " + singleParam[2], 3); Miscellaneous.logEvent("i", "StartOtherApp", "Adding parameter of type " + singleParam[0] + " with name " + singleParam[1] + " and value " + singleParam[2], 3);
externalActivityIntent.putExtra(singleParam[1], (CharSequence)singleParam[2]); externalActivityIntent.putExtra(singleParam[1], (CharSequence) singleParam[2]);
} }
else if(singleParam[0].equals("double")) else if (singleParam[0].equals("double"))
{ {
Miscellaneous.logEvent("i", "StartOtherApp" , "Adding parameter of type " + singleParam[0] + " with name " + singleParam[1] + " and value " + singleParam[2], 3); Miscellaneous.logEvent("i", "StartOtherApp", "Adding parameter of type " + singleParam[0] + " with name " + singleParam[1] + " and value " + singleParam[2], 3);
externalActivityIntent.putExtra(singleParam[1], Double.parseDouble(singleParam[2])); externalActivityIntent.putExtra(singleParam[1], Double.parseDouble(singleParam[2]));
} }
else if(singleParam[0].equals("float")) else if (singleParam[0].equals("float"))
{ {
Miscellaneous.logEvent("i", "StartOtherApp" , "Adding parameter of type " + singleParam[0] + " with name " + singleParam[1] + " and value " + singleParam[2], 3); Miscellaneous.logEvent("i", "StartOtherApp", "Adding parameter of type " + singleParam[0] + " with name " + singleParam[1] + " and value " + singleParam[2], 3);
externalActivityIntent.putExtra(singleParam[1], Float.parseFloat(singleParam[2])); externalActivityIntent.putExtra(singleParam[1], Float.parseFloat(singleParam[2]));
} }
else if(singleParam[0].equals("int")) else if (singleParam[0].equals("int"))
{ {
Miscellaneous.logEvent("i", "StartOtherApp" , "Adding parameter of type " + singleParam[0] + " with name " + singleParam[1] + " and value " + singleParam[2], 3); Miscellaneous.logEvent("i", "StartOtherApp", "Adding parameter of type " + singleParam[0] + " with name " + singleParam[1] + " and value " + singleParam[2], 3);
externalActivityIntent.putExtra(singleParam[1], Integer.parseInt(singleParam[2])); externalActivityIntent.putExtra(singleParam[1], Integer.parseInt(singleParam[2]));
} }
else if(singleParam[0].equals("long")) else if (singleParam[0].equals("long"))
{ {
Miscellaneous.logEvent("i", "StartOtherApp" , "Adding parameter of type " + singleParam[0] + " with name " + singleParam[1] + " and value " + singleParam[2], 3); Miscellaneous.logEvent("i", "StartOtherApp", "Adding parameter of type " + singleParam[0] + " with name " + singleParam[1] + " and value " + singleParam[2], 3);
externalActivityIntent.putExtra(singleParam[1], Long.parseLong(singleParam[2])); externalActivityIntent.putExtra(singleParam[1], Long.parseLong(singleParam[2]));
} }
else if(singleParam[0].equals("short")) else if (singleParam[0].equals("short"))
{ {
Miscellaneous.logEvent("i", "StartOtherApp" , "Adding parameter of type " + singleParam[0] + " with name " + singleParam[1] + " and value " + singleParam[2], 3); Miscellaneous.logEvent("i", "StartOtherApp", "Adding parameter of type " + singleParam[0] + " with name " + singleParam[1] + " and value " + singleParam[2], 3);
externalActivityIntent.putExtra(singleParam[1], Short.parseShort(singleParam[2])); externalActivityIntent.putExtra(singleParam[1], Short.parseShort(singleParam[2]));
} }
else if(singleParam[0].equals("String")) else if (singleParam[0].equals("String"))
{ {
Miscellaneous.logEvent("i", "StartOtherApp" , "Adding parameter of type " + singleParam[0] + " with name " + singleParam[1] + " and value " + singleParam[2], 3); Miscellaneous.logEvent("i", "StartOtherApp", "Adding parameter of type " + singleParam[0] + " with name " + singleParam[1] + " and value " + singleParam[2], 3);
externalActivityIntent.putExtra(singleParam[1], singleParam[2]); externalActivityIntent.putExtra(singleParam[1], singleParam[2]);
} }
else else
Miscellaneous.logEvent("w", "StartOtherApp" , "Unknown type of parameter " + singleParam[0] + " found. Name " + singleParam[1] + " and value " + singleParam[2], 3); Miscellaneous.logEvent("w", "StartOtherApp", "Unknown type of parameter " + singleParam[0] + " found. Name " + singleParam[1] + " and value " + singleParam[2], 3);
} }
autoMationServerRef.startActivity(externalActivityIntent); autoMationServerRef.startActivity(externalActivityIntent);
} }
else
{
Miscellaneous.logEvent("w", "StartOtherApp", "Activity not found: " + className, 2);
}
}
catch(ActivityNotFoundException | SecurityException e) catch(ActivityNotFoundException | SecurityException e)
{ {
Miscellaneous.logEvent("e", "StartOtherApp", autoMationServerRef.getResources().getString(R.string.errorStartingOtherActivity) + ": " + Log.getStackTraceString(e), 2); Miscellaneous.logEvent("e", "StartOtherApp", autoMationServerRef.getResources().getString(R.string.errorStartingOtherActivity) + ": " + Log.getStackTraceString(e), 2);

View File

@ -10,6 +10,7 @@ import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.util.Xml;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
@ -29,6 +30,8 @@ import com.jens.automation2.AutomationService.serviceCommands;
import com.jens.automation2.Trigger.Trigger_Enum; import com.jens.automation2.Trigger.Trigger_Enum;
import com.jens.automation2.location.LocationProvider; import com.jens.automation2.location.LocationProvider;
import java.io.File;
import java.lang.reflect.Array;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
@ -39,7 +42,7 @@ public class ActivityMainScreen extends ActivityGeneric
private static ActivityMainScreen activityMainScreenInstance = null; private static ActivityMainScreen activityMainScreenInstance = null;
private ToggleButton toggleService, tbLockSound; private ToggleButton toggleService, tbLockSound;
private Button bShowHelp, bPrivacy, bSettingsErase, bSettingsSetToDefault, bVolumeTest, bAddSoundLockTIme; private Button bShowHelp, bPrivacy, bSettingsErase, bSettingsSetToDefault, bVolumeTest, bAddSoundLockTIme, bShareConfigAndLog;
private TextView tvActivePoi, tvClosestPoi, tvLastRule, tvMainScreenNotePermissions, tvMainScreenNoteFeaturesFromOtherFlavor, tvMainScreenNoteLocationImpossibleBlameGoogle, tvMainScreenNoteNews, tvlockSoundDuration, tvFileStoreLocation; private TextView tvActivePoi, tvClosestPoi, tvLastRule, tvMainScreenNotePermissions, tvMainScreenNoteFeaturesFromOtherFlavor, tvMainScreenNoteLocationImpossibleBlameGoogle, tvMainScreenNoteNews, tvlockSoundDuration, tvFileStoreLocation;
private ListView lvRuleHistory; private ListView lvRuleHistory;
@ -76,6 +79,9 @@ public class ActivityMainScreen extends ActivityGeneric
tvlockSoundDuration = (TextView)findViewById(R.id.tvlockSoundDuration); tvlockSoundDuration = (TextView)findViewById(R.id.tvlockSoundDuration);
tvFileStoreLocation = (TextView)findViewById(R.id.tvFileStoreLocation); tvFileStoreLocation = (TextView)findViewById(R.id.tvFileStoreLocation);
tbLockSound = (ToggleButton) findViewById(R.id.tbLockSound); tbLockSound = (ToggleButton) findViewById(R.id.tbLockSound);
bVolumeTest = (Button) findViewById(R.id.bVolumeTest);
bSettingsSetToDefault = (Button) findViewById(R.id.bSettingsSetToDefault);
bShareConfigAndLog = (Button) findViewById(R.id.bShareConfigAndLog);
toggleService = (ToggleButton) findViewById(R.id.tbArmMastListener); toggleService = (ToggleButton) findViewById(R.id.tbArmMastListener);
toggleService.setChecked(AutomationService.isMyServiceRunning(this)); toggleService.setChecked(AutomationService.isMyServiceRunning(this));
toggleService.setOnCheckedChangeListener(new OnCheckedChangeListener() toggleService.setOnCheckedChangeListener(new OnCheckedChangeListener()
@ -135,7 +141,6 @@ public class ActivityMainScreen extends ActivityGeneric
} }
}); });
Button bVolumeTest = (Button) findViewById(R.id.bVolumeTest);
bVolumeTest.setOnClickListener(new OnClickListener() bVolumeTest.setOnClickListener(new OnClickListener()
{ {
@Override @Override
@ -179,16 +184,6 @@ public class ActivityMainScreen extends ActivityGeneric
} }
}); });
/*bSettingsErase = (Button)findViewById(R.id.bSettingsErase);
bSettingsErase.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
getEraseSettingsDialog(ActivityMainScreen.this).show();
}
});*/
bSettingsSetToDefault = (Button) findViewById(R.id.bSettingsSetToDefault);
bSettingsSetToDefault.setOnClickListener(new OnClickListener() bSettingsSetToDefault.setOnClickListener(new OnClickListener()
{ {
@Override @Override
@ -198,6 +193,15 @@ public class ActivityMainScreen extends ActivityGeneric
} }
}); });
bShareConfigAndLog.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
getShareConfigAndLogDialogue(ActivityMainScreen.this).show();
}
});
lvRuleHistory.setOnTouchListener(new OnTouchListener() lvRuleHistory.setOnTouchListener(new OnTouchListener()
{ {
@Override @Override
@ -279,6 +283,62 @@ public class ActivityMainScreen extends ActivityGeneric
return alertDialog; return alertDialog;
} }
AlertDialog getShareConfigAndLogDialogue(final Context context)
{
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(context);
alertDialogBuilder.setTitle(context.getResources().getString(R.string.shareConfigAndLogFilesWithDev));
alertDialogBuilder.setMessage(context.getResources().getString(R.string.shareConfigAndLogExplanation));
alertDialogBuilder.setPositiveButton(context.getResources().getString(R.string.yes), new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
File dstZipFile = new File(Miscellaneous.getAnyContext().getCacheDir() + "/" + Settings.zipFileName);
ArrayList<String> srcFilesList = new ArrayList<>();
srcFilesList.add(Miscellaneous.getWriteableFolder() + "/" + XmlFileInterface.settingsFileName);
String logFilePath = Miscellaneous.getWriteableFolder() + "/" + Miscellaneous.logFileName;
if((new File(logFilePath)).exists())
srcFilesList.add(logFilePath);
String logFilePathArchive = Miscellaneous.getWriteableFolder() + "/" + Miscellaneous.logFileName + "-old";
if((new File(logFilePathArchive)).exists())
srcFilesList.add(logFilePathArchive);
String[] srcFiles = srcFilesList.toArray(new String[srcFilesList.size()]);
if(dstZipFile.exists())
dstZipFile.delete();
Miscellaneous.zip(srcFiles, dstZipFile.getAbsolutePath());
/*
Without root the zip file in the cache directory is not directly accessible.
But have to route it through this content provider crap.
*/
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);
Uri uri = Uri.parse("content://com.jens.automation2/" + Settings.zipFileName);
Miscellaneous.sendEmail(ActivityMainScreen.this, "android-development@gmx.de", "Automation logs", emailBody.toString(), uri);
}
});
alertDialogBuilder.setNegativeButton(context.getResources().getString(R.string.no), null);
AlertDialog alertDialog = alertDialogBuilder.create();
return alertDialog;
}
public static ActivityMainScreen getActivityMainScreenInstance() public static ActivityMainScreen getActivityMainScreenInstance()
{ {
return activityMainScreenInstance; return activityMainScreenInstance;
@ -370,9 +430,9 @@ public class ActivityMainScreen extends ActivityGeneric
if( if(
Rule.isAnyRuleUsing(Trigger_Enum.pointOfInterest) Rule.isAnyRuleUsing(Trigger_Enum.pointOfInterest)
&& &&
ActivityPermissions.havePermission(ActivityPermissions.permissionNameLocationCoarse, AutomationService.getInstance()) ActivityPermissions.havePermission(ActivityPermissions.permissionNameLocationCoarse, Miscellaneous.getAnyContext())
&& &&
ActivityPermissions.havePermission(ActivityPermissions.permissionNameLocationFine, AutomationService.getInstance()) ActivityPermissions.havePermission(ActivityPermissions.permissionNameLocationFine, Miscellaneous.getAnyContext())
) )
activityMainScreenInstance.tvActivePoi.setText(activityMainScreenInstance.getResources().getString(R.string.stillGettingPosition)); activityMainScreenInstance.tvActivePoi.setText(activityMainScreenInstance.getResources().getString(R.string.stillGettingPosition));
else else
@ -458,7 +518,31 @@ public class ActivityMainScreen extends ActivityGeneric
String folder = Miscellaneous.getWriteableFolder(); String folder = Miscellaneous.getWriteableFolder();
if(folder != null && folder.length() > 0) if(folder != null && folder.length() > 0)
{
activityMainScreenInstance.tvFileStoreLocation.setText(String.format(activityMainScreenInstance.getResources().getString(R.string.filesStoredAt), folder)); activityMainScreenInstance.tvFileStoreLocation.setText(String.format(activityMainScreenInstance.getResources().getString(R.string.filesStoredAt), folder));
activityMainScreenInstance.tvFileStoreLocation.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
Uri selectedUri = Uri.parse(folder);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(selectedUri, "resource/folder");
if (intent.resolveActivityInfo(activityMainScreenInstance.getPackageManager(), 0) != null)
{
activityMainScreenInstance.startActivity(intent);
}
else
{
// if you reach this place, it means there is no any file
// explorer app installed on your device
Toast.makeText(activityMainScreenInstance, activityMainScreenInstance.getResources().getString(R.string.noFileManageInstalled), Toast.LENGTH_LONG).show();
}
}
});
}
} }
} }

View File

@ -12,7 +12,7 @@ import android.widget.TextView;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
public class ActivityManageBrightnessSetting extends Activity public class ActivityManageActionBrightnessSetting extends Activity
{ {
CheckBox chkAutoBrightness; CheckBox chkAutoBrightness;
SeekBar sbBrightness; SeekBar sbBrightness;

View File

@ -0,0 +1,110 @@
package com.jens.automation2;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
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 java.io.File;
public class ActivityManageActionPlaySound extends Activity
{
final static int PICKFILE_RESULT_CODE = 4711;
CheckBox chkPlaySoundAlwaysPlay;
EditText etSelectedSoundFile;
Button bSelectSoundFile, bSavePlaySound;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_manage_play_sound);
chkPlaySoundAlwaysPlay = (CheckBox)findViewById(R.id.chkPlaySoundAlwaysPlay);
etSelectedSoundFile = (EditText)findViewById(R.id.etSelectedSoundFile);
bSelectSoundFile = (Button)findViewById(R.id.bSelectSoundFile);
bSavePlaySound = (Button)findViewById(R.id.bSavePlaySound);
boolean edit = getIntent().getBooleanExtra("edit", false);
if(edit)
{
boolean param1 = getIntent().getBooleanExtra("actionParameter1", false);
String param2 = getIntent().getStringExtra("actionParameter2");
chkPlaySoundAlwaysPlay.setChecked(param1);
etSelectedSoundFile.setText(param2);
}
bSelectSoundFile.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
//Need to check for storage permissions
Intent chooseFile = new Intent(Intent.ACTION_GET_CONTENT);
chooseFile.setType("*/*");
chooseFile = Intent.createChooser(chooseFile, getResources().getString(R.string.selectSoundFile));
startActivityForResult(chooseFile, PICKFILE_RESULT_CODE);
}
});
bSavePlaySound.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
savePlaySoundSettings();
}
});
}
void savePlaySoundSettings()
{
if(etSelectedSoundFile.getText().toString() == null || etSelectedSoundFile.getText().toString().length() == 0)
{
Toast.makeText(ActivityManageActionPlaySound.this, getResources().getString(R.string.selectSoundFile), Toast.LENGTH_LONG).show();
return;
}
else
{
File soundFile = new File(etSelectedSoundFile.getText().toString());
if(!soundFile.exists())
{
Toast.makeText(ActivityManageActionPlaySound.this, getResources().getString(R.string.fileDoesNotExist), Toast.LENGTH_LONG).show();
return;
}
}
Intent returnData = new Intent();
returnData.putExtra("actionParameter1", chkPlaySoundAlwaysPlay.isChecked());
returnData.putExtra("actionParameter2", etSelectedSoundFile.getText().toString());
setResult(RESULT_OK, returnData);
finish();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_OK)
{
if(requestCode == PICKFILE_RESULT_CODE)
{
Uri fileUri = data.getData();
String filePath = CompensateCrappyAndroidPaths.getPath(ActivityManageActionPlaySound.this, fileUri);
etSelectedSoundFile.setText(filePath);
}
}
}
}

View File

@ -19,7 +19,7 @@ import androidx.annotation.NonNull;
import com.jens.automation2.Action.Action_Enum; import com.jens.automation2.Action.Action_Enum;
public class ActivityEditSendTextMessage extends Activity public class ActivityManageActionSendTextMessage extends Activity
{ {
Button bSaveSendTextMessage, bImportNumberFromContacts; Button bSaveSendTextMessage, bImportNumberFromContacts;
EditText etPhoneNumber, etSendTextMessage; EditText etPhoneNumber, etSendTextMessage;
@ -67,7 +67,7 @@ public class ActivityEditSendTextMessage extends Activity
@Override @Override
public void onClick(View view) public void onClick(View view)
{ {
if(!ActivityPermissions.havePermission("android.permission.READ_CONTACTS", ActivityEditSendTextMessage.this)) if(!ActivityPermissions.havePermission("android.permission.READ_CONTACTS", ActivityManageActionSendTextMessage.this))
{ {
requestPermissions("android.permission.READ_CONTACTS"); requestPermissions("android.permission.READ_CONTACTS");
} }
@ -76,10 +76,10 @@ public class ActivityEditSendTextMessage extends Activity
} }
}); });
ActivityEditSendTextMessage.edit = getIntent().getBooleanExtra("edit", false); ActivityManageActionSendTextMessage.edit = getIntent().getBooleanExtra("edit", false);
if(edit) if(edit)
{ {
String[] parameters = ActivityEditSendTextMessage.resultingAction.getParameter2().split(Actions.smsSeparator); String[] parameters = ActivityManageActionSendTextMessage.resultingAction.getParameter2().split(Actions.smsSeparator);
etPhoneNumber.setText(parameters[0]); etPhoneNumber.setText(parameters[0]);
etSendTextMessage.setText(parameters[1]); etSendTextMessage.setText(parameters[1]);
} }
@ -99,7 +99,7 @@ public class ActivityEditSendTextMessage extends Activity
if(edit && resultingAction != null) if(edit && resultingAction != null)
{ {
ActivityEditSendTextMessage.resultingAction.setParameter2(etPhoneNumber.getText().toString() + Actions.smsSeparator + etSendTextMessage.getText().toString()); ActivityManageActionSendTextMessage.resultingAction.setParameter2(etPhoneNumber.getText().toString() + Actions.smsSeparator + etSendTextMessage.getText().toString());
} }
setResult(RESULT_OK); setResult(RESULT_OK);
@ -162,7 +162,7 @@ public class ActivityEditSendTextMessage extends Activity
String name = null; String name = null;
Uri uri = data.getData(); Uri uri = data.getData();
Cursor cursor = ActivityEditSendTextMessage.this.getContentResolver().query(uri, null, null, null, null); Cursor cursor = ActivityManageActionSendTextMessage.this.getContentResolver().query(uri, null, null, null, null);
if (cursor.moveToFirst()) if (cursor.moveToFirst())
{ {

View File

@ -10,7 +10,7 @@ import android.widget.Toast;
import com.jens.automation2.Action.Action_Enum; import com.jens.automation2.Action.Action_Enum;
public class ActivityEditSpeakText extends Activity public class ActivityManageActionSpeakText extends Activity
{ {
private Button bSaveSpeakText; private Button bSaveSpeakText;
private EditText etSpeakText; private EditText etSpeakText;
@ -48,9 +48,9 @@ public class ActivityEditSpeakText extends Activity
} }
}); });
ActivityEditSpeakText.edit = getIntent().getBooleanExtra("edit", false); ActivityManageActionSpeakText.edit = getIntent().getBooleanExtra("edit", false);
if(edit) if(edit)
etSpeakText.setText(ActivityEditSpeakText.resultingAction.getParameter2()); etSpeakText.setText(ActivityManageActionSpeakText.resultingAction.getParameter2());
// String url = getIntent().getStringExtra("urlToTrigger"); // String url = getIntent().getStringExtra("urlToTrigger");
@ -66,7 +66,7 @@ public class ActivityEditSpeakText extends Activity
// setResult(RESULT_OK, returnIntent); // setResult(RESULT_OK, returnIntent);
if(edit && resultingAction != null) if(edit && resultingAction != null)
ActivityEditSpeakText.resultingAction.setParameter2(etSpeakText.getText().toString()); ActivityManageActionSpeakText.resultingAction.setParameter2(etSpeakText.getText().toString());
setResult(RESULT_OK); setResult(RESULT_OK);

View File

@ -35,13 +35,12 @@ import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
public class ActivityManageStartActivity extends Activity public class ActivityManageActionStartActivity extends Activity
{ {
ListView lvIntentPairs; ListView lvIntentPairs;
EditText etParameterName, etParameterValue; EditText etParameterName, etParameterValue, etSelectedActivity;
Button bSelectApp, bAddIntentPair, bSaveActionStartOtherActivity; Button bSelectApp, bAddIntentPair, bSaveActionStartOtherActivity;
Spinner spinnerParameterType; Spinner spinnerParameterType;
TextView tvSelectedActivity;
boolean edit = false; boolean edit = false;
ProgressDialog progressDialog = null; ProgressDialog progressDialog = null;
@ -56,12 +55,12 @@ public class ActivityManageStartActivity extends Activity
ApplicationInfo aInfo1 = this.applicationInfo; ApplicationInfo aInfo1 = this.applicationInfo;
if (aInfo1 != null) if (aInfo1 != null)
{ {
name1 = (String) ActivityManageStartActivity.this.getPackageManager().getApplicationLabel(aInfo1); name1 = (String) ActivityManageActionStartActivity.this.getPackageManager().getApplicationLabel(aInfo1);
} }
ApplicationInfo aInfo2 = another.applicationInfo; ApplicationInfo aInfo2 = another.applicationInfo;
if (aInfo2 != null) if (aInfo2 != null)
{ {
name2 = (String) ActivityManageStartActivity.this.getPackageManager().getApplicationLabel(aInfo2); name2 = (String) ActivityManageActionStartActivity.this.getPackageManager().getApplicationLabel(aInfo2);
} }
return name1.compareTo(name2); return name1.compareTo(name2);
@ -224,7 +223,7 @@ public class ActivityManageStartActivity extends Activity
{ {
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this); AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
alertDialogBuilder.setTitle(getResources().getString(R.string.selectApplication)); alertDialogBuilder.setTitle(getResources().getString(R.string.selectApplication));
final String[] applicationArray = ActivityManageStartActivity.getApplicationNameListString(this); final String[] applicationArray = ActivityManageActionStartActivity.getApplicationNameListString(this);
alertDialogBuilder.setItems(applicationArray, new DialogInterface.OnClickListener() alertDialogBuilder.setItems(applicationArray, new DialogInterface.OnClickListener()
{ {
@Override @Override
@ -242,14 +241,14 @@ public class ActivityManageStartActivity extends Activity
{ {
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this); AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
alertDialogBuilder.setTitle(getResources().getString(R.string.selectPackageOfApplication)); alertDialogBuilder.setTitle(getResources().getString(R.string.selectPackageOfApplication));
final String[] packageArray = ActivityManageStartActivity.getPackageListString(this, applicationName); final String[] packageArray = ActivityManageActionStartActivity.getPackageListString(this, applicationName);
alertDialogBuilder.setItems(packageArray, new DialogInterface.OnClickListener() alertDialogBuilder.setItems(packageArray, new DialogInterface.OnClickListener()
{ {
@Override @Override
public void onClick(DialogInterface dialog, int which) public void onClick(DialogInterface dialog, int which)
{ {
getActionStartActivityDialog3(packageArray[which]).show(); getActionStartActivityDialog3(packageArray[which]).show();
Miscellaneous.messageBox(getResources().getString(R.string.hint), getResources().getString(R.string.chooseActivityHint), ActivityManageStartActivity.this).show(); Miscellaneous.messageBox(getResources().getString(R.string.hint), getResources().getString(R.string.chooseActivityHint), ActivityManageActionStartActivity.this).show();
} }
}); });
@ -261,14 +260,14 @@ public class ActivityManageStartActivity extends Activity
{ {
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this); AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
alertDialogBuilder.setTitle(getResources().getString(R.string.selectActivityToBeStarted)); alertDialogBuilder.setTitle(getResources().getString(R.string.selectActivityToBeStarted));
final String activityArray[] = ActivityManageStartActivity.getActivityListForPackageName(packageName); final String activityArray[] = ActivityManageActionStartActivity.getActivityListForPackageName(packageName);
alertDialogBuilder.setItems(activityArray, new DialogInterface.OnClickListener() alertDialogBuilder.setItems(activityArray, new DialogInterface.OnClickListener()
{ {
@Override @Override
public void onClick(DialogInterface dialog, int which) public void onClick(DialogInterface dialog, int which)
{ {
ActivityInfo ai = ActivityManageStartActivity.getActivityInfoForPackageNameAndActivityName(packageName, activityArray[which]); ActivityInfo ai = ActivityManageActionStartActivity.getActivityInfoForPackageNameAndActivityName(packageName, activityArray[which]);
tvSelectedActivity.setText(ai.packageName + ";" + ai.name); etSelectedActivity.setText(ai.packageName + ";" + ai.name);
} }
}); });
AlertDialog alertDialog = alertDialogBuilder.create(); AlertDialog alertDialog = alertDialogBuilder.create();
@ -289,13 +288,13 @@ public class ActivityManageStartActivity extends Activity
bAddIntentPair = (Button)findViewById(R.id.bAddIntentPair); bAddIntentPair = (Button)findViewById(R.id.bAddIntentPair);
bSaveActionStartOtherActivity = (Button)findViewById(R.id.bSaveActionStartOtherActivity); bSaveActionStartOtherActivity = (Button)findViewById(R.id.bSaveActionStartOtherActivity);
spinnerParameterType = (Spinner)findViewById(R.id.spinnerParameterType); spinnerParameterType = (Spinner)findViewById(R.id.spinnerParameterType);
tvSelectedActivity = (TextView)findViewById(R.id.tvSelectedActivity); etSelectedActivity = (EditText) findViewById(R.id.etSelectedApplication);
intentTypeSpinnerAdapter = new ArrayAdapter<String>(this, R.layout.text_view_for_poi_listview_mediumtextsize, ActivityManageStartActivity.supportedIntentTypes); intentTypeSpinnerAdapter = new ArrayAdapter<String>(this, R.layout.text_view_for_poi_listview_mediumtextsize, ActivityManageActionStartActivity.supportedIntentTypes);
spinnerParameterType.setAdapter(intentTypeSpinnerAdapter); spinnerParameterType.setAdapter(intentTypeSpinnerAdapter);
intentTypeSpinnerAdapter.notifyDataSetChanged(); intentTypeSpinnerAdapter.notifyDataSetChanged();
intentPairAdapter = new ArrayAdapter<String>(this, R.layout.text_view_for_poi_listview_smalltextsize, intentPairList); intentPairAdapter = new ArrayAdapter<String>(this, R.layout.text_view_for_poi_listview_mediumtextsize, intentPairList);
bSelectApp.setOnClickListener(new OnClickListener() bSelectApp.setOnClickListener(new OnClickListener()
{ {
@ -304,7 +303,7 @@ public class ActivityManageStartActivity extends Activity
{ {
GetActivityListTask getActivityListTask = new GetActivityListTask(); GetActivityListTask getActivityListTask = new GetActivityListTask();
getActivityListTask.execute(); getActivityListTask.execute();
progressDialog = ProgressDialog.show(ActivityManageStartActivity.this, "", ActivityManageStartActivity.this.getResources().getString(R.string.gettingListOfInstalledApplications)); progressDialog = ProgressDialog.show(ActivityManageActionStartActivity.this, "", ActivityManageActionStartActivity.this.getResources().getString(R.string.gettingListOfInstalledApplications));
} }
}); });
@ -316,19 +315,19 @@ public class ActivityManageStartActivity extends Activity
// type;name;value // type;name;value
if(spinnerParameterType.getSelectedItem().toString().length() == 0) if(spinnerParameterType.getSelectedItem().toString().length() == 0)
{ {
Toast.makeText(ActivityManageStartActivity.this, getResources().getString(R.string.selectTypeOfIntentPair), Toast.LENGTH_LONG).show(); Toast.makeText(ActivityManageActionStartActivity.this, getResources().getString(R.string.selectTypeOfIntentPair), Toast.LENGTH_LONG).show();
return; return;
} }
if(etParameterName.getText().toString().length() == 0) if(etParameterName.getText().toString().length() == 0)
{ {
Toast.makeText(ActivityManageStartActivity.this, getResources().getString(R.string.enterNameForIntentPair), Toast.LENGTH_LONG).show(); Toast.makeText(ActivityManageActionStartActivity.this, getResources().getString(R.string.enterNameForIntentPair), Toast.LENGTH_LONG).show();
return; return;
} }
if(etParameterValue.getText().toString().length() == 0) if(etParameterValue.getText().toString().length() == 0)
{ {
Toast.makeText(ActivityManageStartActivity.this, getResources().getString(R.string.enterValueForIntentPair), Toast.LENGTH_LONG).show(); Toast.makeText(ActivityManageActionStartActivity.this, getResources().getString(R.string.enterValueForIntentPair), Toast.LENGTH_LONG).show();
return; return;
} }
@ -360,7 +359,7 @@ public class ActivityManageStartActivity extends Activity
{ {
if(saveAction()) if(saveAction())
{ {
ActivityManageStartActivity.this.setResult(RESULT_OK); ActivityManageActionStartActivity.this.setResult(RESULT_OK);
finish(); finish();
} }
} }
@ -382,9 +381,9 @@ public class ActivityManageStartActivity extends Activity
public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3)
{ {
if(supportedIntentTypes[arg2].equals("double") | supportedIntentTypes[arg2].equals("float") | supportedIntentTypes[arg2].equals("int") | supportedIntentTypes[arg2].equals("long") | supportedIntentTypes[arg2].equals("short")) if(supportedIntentTypes[arg2].equals("double") | supportedIntentTypes[arg2].equals("float") | supportedIntentTypes[arg2].equals("int") | supportedIntentTypes[arg2].equals("long") | supportedIntentTypes[arg2].equals("short"))
ActivityManageStartActivity.this.etParameterValue.setInputType(InputType.TYPE_CLASS_NUMBER); ActivityManageActionStartActivity.this.etParameterValue.setInputType(InputType.TYPE_CLASS_NUMBER);
else else
ActivityManageStartActivity.this.etParameterValue.setInputType(InputType.TYPE_CLASS_TEXT); ActivityManageActionStartActivity.this.etParameterValue.setInputType(InputType.TYPE_CLASS_TEXT);
} }
@Override @Override
@ -408,7 +407,7 @@ public class ActivityManageStartActivity extends Activity
String[] params = resultingAction.getParameter2().split(";"); String[] params = resultingAction.getParameter2().split(";");
if(params.length >= 2) if(params.length >= 2)
{ {
tvSelectedActivity.setText(params[0] + ";" + params[1]); etSelectedActivity.setText(params[0] + ";" + params[1]);
if(params.length > 2) if(params.length > 2)
{ {
@ -434,13 +433,23 @@ public class ActivityManageStartActivity extends Activity
private boolean saveAction() private boolean saveAction()
{ {
if(tvSelectedActivity.getText().toString().length() == 0) if(etSelectedActivity.getText().toString().length() == 0)
{ {
Toast.makeText(ActivityManageStartActivity.this, getResources().getString(R.string.selectApplication), Toast.LENGTH_LONG).show(); Toast.makeText(ActivityManageActionStartActivity.this, getResources().getString(R.string.selectApplication), Toast.LENGTH_LONG).show();
return false; return false;
} }
// else
// {
// Intent testIntent = new Intent(ActivityManageActionStartActivity.this, etSelectedActivity);
// Intent externalActivityIntent = new Intent(Intent.ACTION_MAIN);
// externalActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// externalActivityIntent.addCategory(Intent.CATEGORY_LAUNCHER);
// externalActivityIntent.setClassName(packageName, className);
//
// boolean activityExists = externalActivityIntent.resolveActivityInfo(getPackageManager(), 0) != null;
// }
if(tvSelectedActivity.getText().toString().equals(getResources().getString(R.string.selectApplication))) if(etSelectedActivity.getText().toString().equals(getResources().getString(R.string.selectApplication)))
{ {
Toast.makeText(this, getResources().getString(R.string.selectApplication), Toast.LENGTH_LONG).show(); Toast.makeText(this, getResources().getString(R.string.selectApplication), Toast.LENGTH_LONG).show();
return false; return false;
@ -451,7 +460,13 @@ public class ActivityManageStartActivity extends Activity
resultingAction.setAction(Action_Enum.startOtherActivity); resultingAction.setAction(Action_Enum.startOtherActivity);
String parameter2 = tvSelectedActivity.getText().toString(); String parameter2;
if(etSelectedActivity.getText().toString().contains(";"))
parameter2 = etSelectedActivity.getText().toString();
else
parameter2 = "dummyPkg;" + etSelectedActivity.getText().toString();
for(String s : intentPairList) for(String s : intentPairList)
parameter2 += ";" + s; parameter2 += ";" + s;
@ -462,7 +477,7 @@ public class ActivityManageStartActivity extends Activity
private AlertDialog getIntentPairDialog(final int itemPosition) private AlertDialog getIntentPairDialog(final int itemPosition)
{ {
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(ActivityManageStartActivity.this); AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(ActivityManageActionStartActivity.this);
alertDialogBuilder.setTitle(getResources().getString(R.string.whatToDoWithIntentPair)); alertDialogBuilder.setTitle(getResources().getString(R.string.whatToDoWithIntentPair));
alertDialogBuilder.setItems(new String[]{getResources().getString(R.string.delete)}, new DialogInterface.OnClickListener() alertDialogBuilder.setItems(new String[]{getResources().getString(R.string.delete)}, new DialogInterface.OnClickListener()
{ {
@ -470,7 +485,7 @@ public class ActivityManageStartActivity extends Activity
public void onClick(DialogInterface dialog, int which) public void onClick(DialogInterface dialog, int which)
{ {
// Only 1 choice at the moment, no need to check // Only 1 choice at the moment, no need to check
ActivityManageStartActivity.this.intentPairList.remove(itemPosition); ActivityManageActionStartActivity.this.intentPairList.remove(itemPosition);
updateIntentPairList(); updateIntentPairList();
} }
}); });
@ -484,7 +499,7 @@ public class ActivityManageStartActivity extends Activity
@Override @Override
protected Void doInBackground(Void... params) protected Void doInBackground(Void... params)
{ {
getActivityList(ActivityManageStartActivity.this); getActivityList(ActivityManageActionStartActivity.this);
return null; return null;
} }

View File

@ -20,7 +20,7 @@ import com.jens.automation2.Action.Action_Enum;
import java.util.Map; import java.util.Map;
public class ActivityEditTriggerUrl extends Activity public class ActivityManageActionTriggerUrl extends Activity
{ {
Button bSaveTriggerUrl; Button bSaveTriggerUrl;
EditText etTriggerUrl, etTriggerUrlUsername, etTriggerUrlPassword; EditText etTriggerUrl, etTriggerUrlUsername, etTriggerUrlPassword;
@ -70,7 +70,7 @@ public class ActivityEditTriggerUrl extends Activity
if(password == null) if(password == null)
password = ""; password = "";
ActivityEditTriggerUrl.resultingAction.setParameter2( ActivityManageActionTriggerUrl.resultingAction.setParameter2(
username + ";" + username + ";" +
password + ";" + password + ";" +
etTriggerUrl.getText().toString().trim() etTriggerUrl.getText().toString().trim()
@ -110,16 +110,16 @@ public class ActivityEditTriggerUrl extends Activity
updateListView(); updateListView();
ActivityEditTriggerUrl.edit = getIntent().getBooleanExtra("edit", false); ActivityManageActionTriggerUrl.edit = getIntent().getBooleanExtra("edit", false);
if(edit) if(edit)
{ {
// username,password,URL // username,password,URL
String[] components = ActivityEditTriggerUrl.resultingAction.getParameter2().split(";"); String[] components = ActivityManageActionTriggerUrl.resultingAction.getParameter2().split(";");
if(components.length >= 3) if(components.length >= 3)
{ {
etTriggerUrl.setText(components[2]); etTriggerUrl.setText(components[2]);
chkTriggerUrlUseAuthentication.setChecked(ActivityEditTriggerUrl.resultingAction.getParameter1()); chkTriggerUrlUseAuthentication.setChecked(ActivityManageActionTriggerUrl.resultingAction.getParameter1());
etTriggerUrlUsername.setText(components[0]); etTriggerUrlUsername.setText(components[0]);
etTriggerUrlPassword.setText(components[1]); etTriggerUrlPassword.setText(components[1]);
} }
@ -141,9 +141,9 @@ public class ActivityEditTriggerUrl extends Activity
if(password == null) if(password == null)
password = ""; password = "";
ActivityEditTriggerUrl.resultingAction.setParameter1(chkTriggerUrlUseAuthentication.isChecked()); ActivityManageActionTriggerUrl.resultingAction.setParameter1(chkTriggerUrlUseAuthentication.isChecked());
ActivityEditTriggerUrl.resultingAction.setParameter2( ActivityManageActionTriggerUrl.resultingAction.setParameter2(
username + ";" + username + ";" +
password + ";" + password + ";" +
etTriggerUrl.getText().toString() etTriggerUrl.getText().toString()

View File

@ -95,6 +95,10 @@ public class ActivityManageRule extends Activity
final static int requestCodeActionScreenBrightnessAdd = 401; final static int requestCodeActionScreenBrightnessAdd = 401;
final static int requestCodeActionScreenBrightnessEdit = 402; final static int requestCodeActionScreenBrightnessEdit = 402;
final static int requestCodeActionSendTextMessage = 7001; final static int requestCodeActionSendTextMessage = 7001;
final static int requestCodeTriggerNotificationAdd = 8000;
final static int requestCodeTriggerNfcNotificationEdit = 8001;
final static int requestCodeActionPlaySoundAdd = 501;
final static int requestCodeActionPlaySoundEdit = 502;
public static ActivityManageRule getInstance() public static ActivityManageRule getInstance()
{ {
@ -233,8 +237,8 @@ public class ActivityManageRule extends Activity
// case speed: // case speed:
// break; // break;
case timeFrame: case timeFrame:
ActivityManageTimeFrame.editedTimeFrameTrigger = selectedTrigger; ActivityManageTriggerTimeFrame.editedTimeFrameTrigger = selectedTrigger;
Intent timeFrameEditor = new Intent(ActivityManageRule.this, ActivityManageTimeFrame.class); Intent timeFrameEditor = new Intent(ActivityManageRule.this, ActivityManageTriggerTimeFrame.class);
startActivityForResult(timeFrameEditor, requestCodeTriggerTimeframeEdit); startActivityForResult(timeFrameEditor, requestCodeTriggerTimeframeEdit);
break; break;
// case usb_host_connection: // case usb_host_connection:
@ -242,10 +246,16 @@ public class ActivityManageRule extends Activity
// case wifiConnection: // case wifiConnection:
// break; // break;
case bluetoothConnection: case bluetoothConnection:
ActivityManageBluetoothTrigger.editedBluetoothTrigger = selectedTrigger; ActivityManageTriggerBluetooth.editedBluetoothTrigger = selectedTrigger;
Intent bluetoothEditor = new Intent(ActivityManageRule.this, ActivityManageBluetoothTrigger.class); Intent bluetoothEditor = new Intent(ActivityManageRule.this, ActivityManageTriggerBluetooth.class);
startActivityForResult(bluetoothEditor, requestCodeTriggerBluetoothEdit); startActivityForResult(bluetoothEditor, requestCodeTriggerBluetoothEdit);
break; break;
case notification:
ActivityManageTriggerNotification.editedNotificationTrigger = selectedTrigger;
Intent notificationEditor = new Intent(ActivityManageRule.this, ActivityManageTriggerNotification.class);
notificationEditor.putExtra("edit", true);
startActivityForResult(notificationEditor, requestCodeTriggerNfcNotificationEdit);
break;
default: default:
break; break;
} }
@ -288,15 +298,15 @@ public class ActivityManageRule extends Activity
// case setAirplaneMode: // case setAirplaneMode:
// break; // break;
case startOtherActivity: case startOtherActivity:
Intent intent = new Intent(ActivityManageRule.this, ActivityManageStartActivity.class); Intent intent = new Intent(ActivityManageRule.this, ActivityManageActionStartActivity.class);
ActivityManageStartActivity.resultingAction = a; ActivityManageActionStartActivity.resultingAction = a;
intent.putExtra("edit", true); intent.putExtra("edit", true);
startActivityForResult(intent, requestCodeActionStartActivityEdit); startActivityForResult(intent, requestCodeActionStartActivityEdit);
break; break;
case triggerUrl: case triggerUrl:
Intent activityEditTriggerUrlIntent = new Intent(ActivityManageRule.this, ActivityEditTriggerUrl.class); Intent activityEditTriggerUrlIntent = new Intent(ActivityManageRule.this, ActivityManageActionTriggerUrl.class);
// activityEditTriggerUrlIntent.putExtra("urlToTrigger", a.getParameter2()); // activityEditTriggerUrlIntent.putExtra("urlToTrigger", a.getParameter2());
ActivityEditTriggerUrl.resultingAction = a; ActivityManageActionTriggerUrl.resultingAction = a;
activityEditTriggerUrlIntent.putExtra("edit", true); activityEditTriggerUrlIntent.putExtra("edit", true);
startActivityForResult(activityEditTriggerUrlIntent, requestCodeActionTriggerUrlEdit); startActivityForResult(activityEditTriggerUrlIntent, requestCodeActionTriggerUrlEdit);
break; break;
@ -321,24 +331,31 @@ public class ActivityManageRule extends Activity
// case wakeupDevice: // case wakeupDevice:
// break; // break;
case speakText: case speakText:
Intent activitySpeakTextIntent = new Intent(ActivityManageRule.this, ActivityEditSpeakText.class); Intent activitySpeakTextIntent = new Intent(ActivityManageRule.this, ActivityManageActionSpeakText.class);
ActivityEditSpeakText.resultingAction = a; ActivityManageActionSpeakText.resultingAction = a;
activitySpeakTextIntent.putExtra("edit", true); activitySpeakTextIntent.putExtra("edit", true);
startActivityForResult(activitySpeakTextIntent, requestCodeActionSpeakTextEdit); startActivityForResult(activitySpeakTextIntent, requestCodeActionSpeakTextEdit);
break; break;
case sendTextMessage: case sendTextMessage:
Intent activitySendTextMessageIntent = new Intent(ActivityManageRule.this, ActivityEditSendTextMessage.class); Intent activitySendTextMessageIntent = new Intent(ActivityManageRule.this, ActivityManageActionSendTextMessage.class);
ActivityEditSendTextMessage.resultingAction = a; ActivityManageActionSendTextMessage.resultingAction = a;
activitySendTextMessageIntent.putExtra("edit", true); activitySendTextMessageIntent.putExtra("edit", true);
startActivityForResult(activitySendTextMessageIntent, requestCodeActionSendTextMessage); startActivityForResult(activitySendTextMessageIntent, requestCodeActionSendTextMessage);
break; break;
case setScreenBrightness: case setScreenBrightness:
Intent activityEditScreenBrightnessIntent = new Intent(ActivityManageRule.this, ActivityManageBrightnessSetting.class); Intent activityEditScreenBrightnessIntent = new Intent(ActivityManageRule.this, ActivityManageActionBrightnessSetting.class);
// ActivityEditTriggerUrl.resultingAction = a; // ActivityEditTriggerUrl.resultingAction = a;
activityEditScreenBrightnessIntent.putExtra("autoBrightness", a.getParameter1()); activityEditScreenBrightnessIntent.putExtra("autoBrightness", a.getParameter1());
activityEditScreenBrightnessIntent.putExtra("brightnessValue", Integer.parseInt(a.getParameter2())); activityEditScreenBrightnessIntent.putExtra("brightnessValue", Integer.parseInt(a.getParameter2()));
startActivityForResult(activityEditScreenBrightnessIntent, requestCodeActionScreenBrightnessEdit); startActivityForResult(activityEditScreenBrightnessIntent, requestCodeActionScreenBrightnessEdit);
break; break;
case playSound:
Intent actionPlaySoundIntent = new Intent(context, ActivityManageActionPlaySound.class);
actionPlaySoundIntent.putExtra("edit", true);
actionPlaySoundIntent.putExtra("actionParameter1", a.getParameter1());
actionPlaySoundIntent.putExtra("actionParameter2", a.getParameter2());
startActivityForResult(actionPlaySoundIntent, requestCodeActionPlaySoundEdit);
break;
default: default:
Miscellaneous.logEvent("w", "Edit action", "Editing of action type " + a.getAction().toString() + " not implemented, yet.", 4); Miscellaneous.logEvent("w", "Edit action", "Editing of action type " + a.getAction().toString() + " not implemented, yet.", 4);
break; break;
@ -466,6 +483,8 @@ public class ActivityManageRule extends Activity
items.add(new Item(typesLong[i].toString(), R.drawable.bluetooth)); items.add(new Item(typesLong[i].toString(), R.drawable.bluetooth));
else if(types[i].toString().equals(Trigger_Enum.headsetPlugged.toString())) else if(types[i].toString().equals(Trigger_Enum.headsetPlugged.toString()))
items.add(new Item(typesLong[i].toString(), R.drawable.headphone)); 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 else
items.add(new Item(typesLong[i].toString(), R.drawable.placeholder)); items.add(new Item(typesLong[i].toString(), R.drawable.placeholder));
} }
@ -521,8 +540,8 @@ public class ActivityManageRule extends Activity
else if(triggerType == Trigger_Enum.timeFrame) else if(triggerType == Trigger_Enum.timeFrame)
{ {
newTrigger.setTriggerType(Trigger_Enum.timeFrame); newTrigger.setTriggerType(Trigger_Enum.timeFrame);
ActivityManageTimeFrame.editedTimeFrameTrigger = newTrigger; ActivityManageTriggerTimeFrame.editedTimeFrameTrigger = newTrigger;
Intent timeFrameEditor = new Intent(myContext, ActivityManageTimeFrame.class); Intent timeFrameEditor = new Intent(myContext, ActivityManageTriggerTimeFrame.class);
startActivityForResult(timeFrameEditor, requestCodeTriggerTimeframeAdd); startActivityForResult(timeFrameEditor, requestCodeTriggerTimeframeAdd);
return; return;
} }
@ -536,6 +555,13 @@ public class ActivityManageRule extends Activity
booleanChoices = new String[]{getResources().getString(R.string.connected), getResources().getString(R.string.disconnected)}; booleanChoices = new String[]{getResources().getString(R.string.connected), getResources().getString(R.string.disconnected)};
else if(triggerType == Trigger_Enum.process_started_stopped) else if(triggerType == Trigger_Enum.process_started_stopped)
booleanChoices = new String[]{getResources().getString(R.string.started), getResources().getString(R.string.stopped)}; booleanChoices = new String[]{getResources().getString(R.string.started), getResources().getString(R.string.stopped)};
else if(triggerType == Trigger_Enum.notification)
{
newTrigger.setTriggerType(Trigger_Enum.notification);
Intent nfcEditor = new Intent(myContext, ActivityManageTriggerNotification.class);
startActivityForResult(nfcEditor, requestCodeTriggerNotificationAdd);
return;
}
else if(triggerType == Trigger_Enum.airplaneMode) else if(triggerType == Trigger_Enum.airplaneMode)
booleanChoices = new String[]{getResources().getString(R.string.activated), getResources().getString(R.string.deactivated)}; booleanChoices = new String[]{getResources().getString(R.string.activated), getResources().getString(R.string.deactivated)};
else if(triggerType == Trigger_Enum.roaming) else if(triggerType == Trigger_Enum.roaming)
@ -572,7 +598,7 @@ public class ActivityManageRule extends Activity
if(NfcReceiver.checkNfcRequirements(ActivityManageRule.this, true)) if(NfcReceiver.checkNfcRequirements(ActivityManageRule.this, true))
{ {
newTrigger.setTriggerType(Trigger_Enum.nfcTag); newTrigger.setTriggerType(Trigger_Enum.nfcTag);
Intent nfcEditor = new Intent(myContext, ActivityManageNfc.class); Intent nfcEditor = new Intent(myContext, ActivityManageTriggerNfc.class);
startActivityForResult(nfcEditor, requestCodeTriggerNfcTagAdd); startActivityForResult(nfcEditor, requestCodeTriggerNfcTagAdd);
return; return;
} }
@ -583,8 +609,8 @@ public class ActivityManageRule extends Activity
Miscellaneous.messageBox("Bluetooth", getResources().getString(R.string.deviceDoesNotHaveBluetooth), ActivityManageRule.this).show();; Miscellaneous.messageBox("Bluetooth", getResources().getString(R.string.deviceDoesNotHaveBluetooth), ActivityManageRule.this).show();;
newTrigger.setTriggerType(Trigger_Enum.bluetoothConnection); newTrigger.setTriggerType(Trigger_Enum.bluetoothConnection);
ActivityManageBluetoothTrigger.editedBluetoothTrigger = newTrigger; ActivityManageTriggerBluetooth.editedBluetoothTrigger = newTrigger;
Intent bluetoothEditor = new Intent(myContext, ActivityManageBluetoothTrigger.class); Intent bluetoothEditor = new Intent(myContext, ActivityManageTriggerBluetooth.class);
startActivityForResult(bluetoothEditor, requestCodeTriggerBluetoothAdd); startActivityForResult(bluetoothEditor, requestCodeTriggerBluetoothAdd);
return; return;
} }
@ -979,7 +1005,7 @@ public class ActivityManageRule extends Activity
protected String[] doInBackground(ActivityManageRule... params) protected String[] doInBackground(ActivityManageRule... params)
{ {
// Looper.prepare(); // Looper.prepare();
final String[] applicationArray = ActivityManageStartActivity.getApplicationNameListString(params[0]); final String[] applicationArray = ActivityManageActionStartActivity.getApplicationNameListString(params[0]);
return applicationArray; return applicationArray;
} }
@ -1026,7 +1052,7 @@ public class ActivityManageRule extends Activity
{ {
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(myContext); AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(myContext);
alertDialogBuilder.setTitle(myContext.getResources().getString(R.string.selectPackageOfApplication)); alertDialogBuilder.setTitle(myContext.getResources().getString(R.string.selectPackageOfApplication));
final String[] packageArray = ActivityManageStartActivity.getPackageListString(myContext, applicationName); final String[] packageArray = ActivityManageActionStartActivity.getPackageListString(myContext, applicationName);
alertDialogBuilder.setItems(packageArray, new DialogInterface.OnClickListener() alertDialogBuilder.setItems(packageArray, new DialogInterface.OnClickListener()
{ {
@Override @Override
@ -1046,7 +1072,7 @@ public class ActivityManageRule extends Activity
{ {
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(myContext); AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(myContext);
alertDialogBuilder.setTitle(myContext.getResources().getString(R.string.selectActivityToBeStarted)); alertDialogBuilder.setTitle(myContext.getResources().getString(R.string.selectActivityToBeStarted));
final String activityArray[] = ActivityManageStartActivity.getActivityListForPackageName(packageName); final String activityArray[] = ActivityManageActionStartActivity.getActivityListForPackageName(packageName);
alertDialogBuilder.setItems(activityArray, new DialogInterface.OnClickListener() alertDialogBuilder.setItems(activityArray, new DialogInterface.OnClickListener()
{ {
@Override @Override
@ -1074,7 +1100,7 @@ public class ActivityManageRule extends Activity
if(resultCode == RESULT_OK) if(resultCode == RESULT_OK)
{ {
//add TriggerUrl //add TriggerUrl
ruleToEdit.getActionSet().add(ActivityEditTriggerUrl.resultingAction); ruleToEdit.getActionSet().add(ActivityManageActionTriggerUrl.resultingAction);
this.refreshActionList(); this.refreshActionList();
} }
} }
@ -1089,7 +1115,7 @@ public class ActivityManageRule extends Activity
else if(requestCode == requestCodeTriggerTimeframeAdd) else if(requestCode == requestCodeTriggerTimeframeAdd)
{ {
//add TimeFrame //add TimeFrame
if(resultCode == RESULT_OK && ActivityManageTimeFrame.editedTimeFrameTrigger != null) if(resultCode == RESULT_OK && ActivityManageTriggerTimeFrame.editedTimeFrameTrigger != null)
{ {
ruleToEdit.getTriggerSet().add(newTrigger); ruleToEdit.getTriggerSet().add(newTrigger);
this.refreshTriggerList(); this.refreshTriggerList();
@ -1100,7 +1126,7 @@ public class ActivityManageRule extends Activity
else if(requestCode == requestCodeTriggerTimeframeEdit) else if(requestCode == requestCodeTriggerTimeframeEdit)
{ {
//edit TimeFrame //edit TimeFrame
if(resultCode == RESULT_OK && ActivityManageTimeFrame.editedTimeFrameTrigger != null) if(resultCode == RESULT_OK && ActivityManageTriggerTimeFrame.editedTimeFrameTrigger != null)
{ {
this.refreshTriggerList(); this.refreshTriggerList();
} }
@ -1112,7 +1138,7 @@ public class ActivityManageRule extends Activity
// manage start of other activity // manage start of other activity
if(resultCode == RESULT_OK) if(resultCode == RESULT_OK)
{ {
newAction = ActivityManageStartActivity.resultingAction; newAction = ActivityManageActionStartActivity.resultingAction;
ruleToEdit.getActionSet().add(newAction); ruleToEdit.getActionSet().add(newAction);
this.refreshActionList(); this.refreshActionList();
} }
@ -1122,7 +1148,7 @@ public class ActivityManageRule extends Activity
// manage start of other activity // manage start of other activity
if(resultCode == RESULT_OK) if(resultCode == RESULT_OK)
{ {
newAction = ActivityManageStartActivity.resultingAction; newAction = ActivityManageActionStartActivity.resultingAction;
// ruleToEdit.getActionSet().add(newAction); // ruleToEdit.getActionSet().add(newAction);
this.refreshActionList(); this.refreshActionList();
} }
@ -1130,21 +1156,49 @@ public class ActivityManageRule extends Activity
else if(requestCode == requestCodeTriggerNfcTagAdd) else if(requestCode == requestCodeTriggerNfcTagAdd)
{ {
//add TimeFrame //add TimeFrame
if(resultCode == RESULT_OK && ActivityManageNfc.generatedId != null) if(resultCode == RESULT_OK && ActivityManageTriggerNfc.generatedId != null)
{ {
newTrigger.setNfcTagId(ActivityManageNfc.generatedId); newTrigger.setNfcTagId(ActivityManageTriggerNfc.generatedId);
ruleToEdit.getTriggerSet().add(newTrigger); ruleToEdit.getTriggerSet().add(newTrigger);
this.refreshTriggerList(); this.refreshTriggerList();
} }
else else
Miscellaneous.logEvent("w", "ActivityManageNfc", "No nfc id returned. Assuming abort.", 5); Miscellaneous.logEvent("w", "ActivityManageNfc", "No nfc id returned. Assuming abort.", 5);
} }
else if(requestCode == requestCodeTriggerNotificationAdd)
{
//add notification
if(resultCode == RESULT_OK)
{
//newTrigger.setNfcTagId(ActivityManageNfc.generatedId);
ruleToEdit.getTriggerSet().add(newTrigger);
newTrigger.setTriggerParameter2(
data.getStringExtra("app") + Trigger.triggerParameter2Split +
data.getStringExtra("titleDir") + Trigger.triggerParameter2Split +
data.getStringExtra("title") + Trigger.triggerParameter2Split +
data.getStringExtra("textDir") + Trigger.triggerParameter2Split +
data.getStringExtra("text")
);
this.refreshTriggerList();
}
else
Miscellaneous.logEvent("w", "ActivityManageNfc", "No nfc id returned. Assuming abort.", 5);
}
else if(requestCode == requestCodeTriggerNfcNotificationEdit)
{
if(resultCode == RESULT_OK)
{
newTrigger = ActivityManageTriggerNotification.resultingTrigger;
this.refreshTriggerList();
}
}
else if(requestCode == requestCodeActionSpeakTextAdd) else if(requestCode == requestCodeActionSpeakTextAdd)
{ {
if(resultCode == RESULT_OK) if(resultCode == RESULT_OK)
{ {
//add SpeakText //add SpeakText
ruleToEdit.getActionSet().add(ActivityEditSpeakText.resultingAction); ruleToEdit.getActionSet().add(ActivityManageActionSpeakText.resultingAction);
this.refreshActionList(); this.refreshActionList();
} }
} }
@ -1153,14 +1207,14 @@ public class ActivityManageRule extends Activity
if(resultCode == RESULT_OK) if(resultCode == RESULT_OK)
{ {
//add SpeakText //add SpeakText
ruleToEdit.getActionSet().add(ActivityEditSendTextMessage.resultingAction); ruleToEdit.getActionSet().add(ActivityManageActionSendTextMessage.resultingAction);
this.refreshActionList(); this.refreshActionList();
} }
} }
else if(requestCode == requestCodeTriggerBluetoothAdd) else if(requestCode == requestCodeTriggerBluetoothAdd)
{ {
//add bluetooth trigger //add bluetooth trigger
if(resultCode == RESULT_OK && ActivityManageBluetoothTrigger.editedBluetoothTrigger != null) if(resultCode == RESULT_OK && ActivityManageTriggerBluetooth.editedBluetoothTrigger != null)
{ {
ruleToEdit.getTriggerSet().add(newTrigger); ruleToEdit.getTriggerSet().add(newTrigger);
this.refreshTriggerList(); this.refreshTriggerList();
@ -1171,7 +1225,7 @@ public class ActivityManageRule extends Activity
else if(requestCode == requestCodeTriggerBluetoothEdit) else if(requestCode == requestCodeTriggerBluetoothEdit)
{ {
//edit bluetooth trigger //edit bluetooth trigger
if(resultCode == RESULT_OK && ActivityManageBluetoothTrigger.editedBluetoothTrigger != null) if(resultCode == RESULT_OK && ActivityManageTriggerBluetooth.editedBluetoothTrigger != null)
{ {
this.refreshTriggerList(); this.refreshTriggerList();
} }
@ -1201,6 +1255,29 @@ public class ActivityManageRule extends Activity
this.refreshActionList(); this.refreshActionList();
} }
} }
else if(requestCode == requestCodeActionPlaySoundAdd)
{
if(resultCode == RESULT_OK)
{
newAction.setParameter1(data.getBooleanExtra("actionParameter1", false));
newAction.setParameter2(data.getStringExtra("actionParameter2"));
ruleToEdit.getActionSet().add(newAction);
this.refreshActionList();
}
}
else if(requestCode == requestCodeActionPlaySoundEdit)
{
if(resultCode == RESULT_OK)
{
if(data.hasExtra("actionParameter1"))
ruleToEdit.getActionSet().get(editIndex).setParameter1(data.getBooleanExtra("actionParameter1", false));
if(data.hasExtra("actionParameter2"))
ruleToEdit.getActionSet().get(editIndex).setParameter2(data.getStringExtra("actionParameter2"));
this.refreshActionList();
}
}
//TODO: Check with has data been changed or something like that. //TODO: Check with has data been changed or something like that.
/*try /*try
@ -1253,6 +1330,8 @@ public class ActivityManageRule extends Activity
items.add(new Item(typesLong[i].toString(), R.drawable.tune)); items.add(new Item(typesLong[i].toString(), R.drawable.tune));
else if(types[i].toString().equals(Action_Enum.setScreenBrightness.toString())) else if(types[i].toString().equals(Action_Enum.setScreenBrightness.toString()))
items.add(new Item(typesLong[i].toString(), R.drawable.brightness)); items.add(new Item(typesLong[i].toString(), R.drawable.brightness));
else if(types[i].toString().equals(Action_Enum.playSound.toString()))
items.add(new Item(typesLong[i].toString(), R.drawable.sound));
else if(types[i].toString().equals(Action_Enum.sendTextMessage.toString())) 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(ActivityManageSpecificRule.this, "android.permission.SEND_SMS") && !Miscellaneous.isGooglePlayInstalled(ActivityManageSpecificRule.this))
@ -1263,13 +1342,6 @@ public class ActivityManageRule extends Activity
items.add(new Item(typesLong[i].toString(), R.drawable.placeholder)); items.add(new Item(typesLong[i].toString(), R.drawable.placeholder));
} }
// = {
// new Item("Bluetooth", R.drawable.bluetooth),
// new Item("Wifi", R.drawable.wifi),
// new Item("...", 0), //no icon for this one
// };
// ListAdapter adapter = new ArrayAdapter<Item>(this, android.R.layout.select_dialog_item, android.R.id.text1, items)
ListAdapter adapter = new ArrayAdapter<Item>(this, android.R.layout.select_dialog_item, android.R.id.text1, items) ListAdapter adapter = new ArrayAdapter<Item>(this, android.R.layout.select_dialog_item, android.R.id.text1, items)
{ {
public View getView(int position, View convertView, ViewGroup parent) public View getView(int position, View convertView, ViewGroup parent)
@ -1302,8 +1374,8 @@ public class ActivityManageRule extends Activity
{ {
//launch other activity to enter a url and parameters; //launch other activity to enter a url and parameters;
newAction.setAction(Action_Enum.triggerUrl); newAction.setAction(Action_Enum.triggerUrl);
ActivityEditTriggerUrl.resultingAction = null; ActivityManageActionTriggerUrl.resultingAction = null;
Intent editTriggerIntent = new Intent(context, ActivityEditTriggerUrl.class); Intent editTriggerIntent = new Intent(context, ActivityManageActionTriggerUrl.class);
startActivityForResult(editTriggerIntent, 1000); startActivityForResult(editTriggerIntent, 1000);
} }
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.setWifi.toString())) else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.setWifi.toString()))
@ -1350,7 +1422,7 @@ public class ActivityManageRule extends Activity
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.startOtherActivity.toString())) else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.startOtherActivity.toString()))
{ {
newAction.setAction(Action_Enum.startOtherActivity); newAction.setAction(Action_Enum.startOtherActivity);
Intent intent = new Intent(ActivityManageRule.this, ActivityManageStartActivity.class); Intent intent = new Intent(ActivityManageRule.this, ActivityManageActionStartActivity.class);
startActivityForResult(intent, 3000); startActivityForResult(intent, 3000);
} }
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.waitBeforeNextAction.toString())) else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.waitBeforeNextAction.toString()))
@ -1383,8 +1455,8 @@ public class ActivityManageRule extends Activity
{ {
//launch other activity to enter a url and parameters; //launch other activity to enter a url and parameters;
newAction.setAction(Action_Enum.speakText); newAction.setAction(Action_Enum.speakText);
ActivityEditSpeakText.resultingAction = null; ActivityManageActionSpeakText.resultingAction = null;
Intent editTriggerIntent = new Intent(context, ActivityEditSpeakText.class); Intent editTriggerIntent = new Intent(context, ActivityManageActionSpeakText.class);
startActivityForResult(editTriggerIntent, 5000); startActivityForResult(editTriggerIntent, 5000);
} }
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.sendTextMessage.toString())) else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.sendTextMessage.toString()))
@ -1394,8 +1466,8 @@ public class ActivityManageRule extends Activity
{ {
//launch other activity to enter parameters; //launch other activity to enter parameters;
newAction.setAction(Action_Enum.sendTextMessage); newAction.setAction(Action_Enum.sendTextMessage);
ActivityEditSendTextMessage.resultingAction = null; ActivityManageActionSendTextMessage.resultingAction = null;
Intent editTriggerIntent = new Intent(context, ActivityEditSendTextMessage.class); Intent editTriggerIntent = new Intent(context, ActivityManageActionSendTextMessage.class);
startActivityForResult(editTriggerIntent, 5001); startActivityForResult(editTriggerIntent, 5001);
} }
} }
@ -1408,9 +1480,15 @@ public class ActivityManageRule extends Activity
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.setScreenBrightness.toString())) else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.setScreenBrightness.toString()))
{ {
newAction.setAction(Action_Enum.setScreenBrightness); newAction.setAction(Action_Enum.setScreenBrightness);
Intent actionScreenBrightnessIntent = new Intent(context, ActivityManageBrightnessSetting.class); Intent actionScreenBrightnessIntent = new Intent(context, ActivityManageActionBrightnessSetting.class);
startActivityForResult(actionScreenBrightnessIntent, requestCodeActionScreenBrightnessAdd); startActivityForResult(actionScreenBrightnessIntent, requestCodeActionScreenBrightnessAdd);
} }
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.playSound.toString()))
{
newAction.setAction(Action_Enum.playSound);
Intent actionPlaySoundIntent = new Intent(context, ActivityManageActionPlaySound.class);
startActivityForResult(actionPlaySoundIntent, requestCodeActionPlaySoundAdd);
}
} }
}); });

View File

@ -16,7 +16,7 @@ import android.widget.Toast;
import com.jens.automation2.receivers.BluetoothReceiver; import com.jens.automation2.receivers.BluetoothReceiver;
public class ActivityManageBluetoothTrigger extends Activity public class ActivityManageTriggerBluetooth extends Activity
{ {
protected static Trigger editedBluetoothTrigger; protected static Trigger editedBluetoothTrigger;
RadioButton radioAnyBluetoothDevice, radioNoDevice, radioDeviceFromList, radioBluetoothConnected, radioBluetoothDisconnected, radioBluetoothInRange, radioBluetoothOutRange; RadioButton radioAnyBluetoothDevice, radioNoDevice, radioDeviceFromList, radioBluetoothConnected, radioBluetoothDisconnected, radioBluetoothInRange, radioBluetoothOutRange;
@ -109,7 +109,7 @@ public class ActivityManageBluetoothTrigger extends Activity
} }
else else
{ {
Toast.makeText(ActivityManageBluetoothTrigger.this, getResources().getString(R.string.selectDeviceOption), Toast.LENGTH_LONG).show(); Toast.makeText(ActivityManageTriggerBluetooth.this, getResources().getString(R.string.selectDeviceOption), Toast.LENGTH_LONG).show();
return false; return false;
} }
@ -138,7 +138,7 @@ public class ActivityManageBluetoothTrigger extends Activity
} }
else else
{ {
Toast.makeText(ActivityManageBluetoothTrigger.this, getResources().getString(R.string.selectConnectionOption), Toast.LENGTH_LONG).show(); Toast.makeText(ActivityManageTriggerBluetooth.this, getResources().getString(R.string.selectConnectionOption), Toast.LENGTH_LONG).show();
return false; return false;
} }

View File

@ -21,7 +21,7 @@ import android.widget.Toast;
import com.jens.automation2.receivers.NfcReceiver; import com.jens.automation2.receivers.NfcReceiver;
@SuppressLint("NewApi") @SuppressLint("NewApi")
public class ActivityManageNfc extends Activity public class ActivityManageTriggerNfc extends Activity
{ {
public static String generatedId = null; public static String generatedId = null;
private static Tag discoveredTag = null; private static Tag discoveredTag = null;
@ -39,7 +39,7 @@ public class ActivityManageNfc extends Activity
protected void onCreate(Bundle savedInstanceState) protected void onCreate(Bundle savedInstanceState)
{ {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.manage_nfc); setContentView(R.layout.activity_manage_trigger_nfc);
etNewNfcIdValue = (EditText)findViewById(R.id.etNewNfcIdValue); etNewNfcIdValue = (EditText)findViewById(R.id.etNewNfcIdValue);
bReadNfcTag = (Button)findViewById(R.id.bReadNfcTag); bReadNfcTag = (Button)findViewById(R.id.bReadNfcTag);
@ -59,7 +59,7 @@ public class ActivityManageNfc extends Activity
} }
else else
{ {
progressDialog = ProgressDialog.show(ActivityManageNfc.this, null, getResources().getString(R.string.nfcBringTagIntoRange), false, true, new OnCancelListener() progressDialog = ProgressDialog.show(ActivityManageTriggerNfc.this, null, getResources().getString(R.string.nfcBringTagIntoRange), false, true, new OnCancelListener()
{ {
@Override @Override
public void onCancel(DialogInterface dialog) public void onCancel(DialogInterface dialog)
@ -88,7 +88,7 @@ public class ActivityManageNfc extends Activity
} }
else else
{ {
progressDialog = ProgressDialog.show(ActivityManageNfc.this, null, getResources().getString(R.string.nfcBringTagIntoRange), false, true, new OnCancelListener() progressDialog = ProgressDialog.show(ActivityManageTriggerNfc.this, null, getResources().getString(R.string.nfcBringTagIntoRange), false, true, new OnCancelListener()
{ {
@Override @Override
public void onCancel(DialogInterface dialog) public void onCancel(DialogInterface dialog)
@ -118,7 +118,7 @@ public class ActivityManageNfc extends Activity
} }
else else
{ {
progressDialog = ProgressDialog.show(ActivityManageNfc.this, null, getResources().getString(R.string.nfcBringTagIntoRange), false, true, new OnCancelListener() progressDialog = ProgressDialog.show(ActivityManageTriggerNfc.this, null, getResources().getString(R.string.nfcBringTagIntoRange), false, true, new OnCancelListener()
{ {
@Override @Override
public void onCancel(DialogInterface dialog) public void onCancel(DialogInterface dialog)
@ -255,7 +255,7 @@ public class ActivityManageNfc extends Activity
if(generatedId.length() == 0) if(generatedId.length() == 0)
{ {
generatedId = null; generatedId = null;
Toast.makeText(ActivityManageNfc.this, getResources().getString(R.string.nfcEnterValidIdentifier), Toast.LENGTH_LONG).show(); Toast.makeText(ActivityManageTriggerNfc.this, getResources().getString(R.string.nfcEnterValidIdentifier), Toast.LENGTH_LONG).show();
return false; return false;
} }
else else
@ -267,14 +267,14 @@ public class ActivityManageNfc extends Activity
if(NfcReceiver.writeTag(generatedId, discoveredTag)) if(NfcReceiver.writeTag(generatedId, discoveredTag))
{ {
currentStatus = 0; currentStatus = 0;
Toast.makeText(ActivityManageNfc.this, getResources().getString(R.string.nfcTagWrittenSuccessfully), Toast.LENGTH_LONG).show(); Toast.makeText(ActivityManageTriggerNfc.this, getResources().getString(R.string.nfcTagWrittenSuccessfully), Toast.LENGTH_LONG).show();
setResult(RESULT_OK); setResult(RESULT_OK);
finish(); finish();
} }
else else
{ {
currentStatus = 0; currentStatus = 0;
Toast.makeText(ActivityManageNfc.this, getResources().getString(R.string.nfcTagWriteError), Toast.LENGTH_LONG).show(); Toast.makeText(ActivityManageTriggerNfc.this, getResources().getString(R.string.nfcTagWriteError), Toast.LENGTH_LONG).show();
Miscellaneous.logEvent("e", "NFC", getResources().getString(R.string.nfcTagWriteError), 2); Miscellaneous.logEvent("e", "NFC", getResources().getString(R.string.nfcTagWriteError), 2);
} }
} }
@ -285,14 +285,14 @@ public class ActivityManageNfc extends Activity
if(checkEnteredText(false)) if(checkEnteredText(false))
{ {
currentStatus = 0; currentStatus = 0;
Toast.makeText(ActivityManageNfc.this, getResources().getString(R.string.nfcTagReadSuccessfully), Toast.LENGTH_LONG).show(); Toast.makeText(ActivityManageTriggerNfc.this, getResources().getString(R.string.nfcTagReadSuccessfully), Toast.LENGTH_LONG).show();
setResult(RESULT_OK); setResult(RESULT_OK);
finish(); finish();
} }
else else
{ {
currentStatus = 0; currentStatus = 0;
Toast.makeText(ActivityManageNfc.this, getResources().getString(R.string.nfcValueNotSuitable), Toast.LENGTH_LONG).show(); Toast.makeText(ActivityManageTriggerNfc.this, getResources().getString(R.string.nfcValueNotSuitable), Toast.LENGTH_LONG).show();
generatedId = null; generatedId = null;
} }
} }

View File

@ -0,0 +1,399 @@
package com.jens.automation2;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import static com.jens.automation2.Trigger.triggerParameter2Split;
public class ActivityManageTriggerNotification extends Activity
{
public static Trigger editedNotificationTrigger;
EditText etNotificationTitle, etNotificationText;
Button bSelectApp, bSaveTriggerNotification;
Spinner spinnerTitleDirection, spinnerTextDirection;
TextView tvSelectedApplication;
CheckBox chkNotificationDirection;
boolean edit = false;
ProgressDialog progressDialog = null;
private static List<PackageInfo> pInfos = null;
public static Trigger resultingTrigger;
private static String[] directions;
ArrayAdapter<String> directionSpinnerAdapter;
public static void getActivityList(final Context context)
{
if(pInfos == null)
{
pInfos = context.getPackageManager().getInstalledPackages(PackageManager.GET_ACTIVITIES);
Collections.sort(pInfos, new Comparator<PackageInfo>()
{
public int compare(PackageInfo obj1, PackageInfo obj2)
{
String name1 = "";
String name2 = "";
ApplicationInfo aInfo1 = obj1.applicationInfo;
if (aInfo1 != null)
{
name1 = (String) context.getPackageManager().getApplicationLabel(aInfo1);
}
ApplicationInfo aInfo2 = obj2.applicationInfo;
if (aInfo2 != null)
{
name2 = (String) context.getPackageManager().getApplicationLabel(aInfo2);
}
return name1.compareTo(name2);
}
});
}
}
public static String[] getApplicationNameListString(Context myContext)
{
// Generate the actual list
getActivityList(myContext);
ArrayList<String> returnList = new ArrayList<String>();
for (PackageInfo pInfo : pInfos)
{
ApplicationInfo aInfo = pInfo.applicationInfo;
if (aInfo != null)
{
String aLabel;
aLabel = (String) myContext.getPackageManager().getApplicationLabel(aInfo);
ActivityInfo[] aInfos = pInfo.activities;
if (aInfos != null && aInfos.length > 0) // Only put Applications into the list that have packages.
{
if(!returnList.contains(aLabel))
returnList.add(aLabel);
}
}
}
return returnList.toArray(new String[returnList.size()]);
}
public static String[] getPackageListString(Context myContext, String applicationLabel)
{
// Generate the actual list
getActivityList(myContext);
ArrayList<String> returnList = new ArrayList<String>();
for (PackageInfo pInfo : pInfos)
{
if(myContext.getPackageManager().getApplicationLabel(pInfo.applicationInfo).equals(applicationLabel))
{
ActivityInfo[] aInfos = pInfo.activities;
if (aInfos != null && aInfos.length > 0)
{
returnList.add(pInfo.packageName);
}
}
}
return returnList.toArray(new String[returnList.size()]);
}
public static String[] getPackageListString(Context myContext)
{
// Generate the actual list
getActivityList(myContext);
ArrayList<String> returnList = new ArrayList<String>();
for (PackageInfo pInfo : pInfos)
{
ActivityInfo[] aInfos = pInfo.activities;
if (aInfos != null && aInfos.length > 0)
{
returnList.add(pInfo.packageName);
}
else
Miscellaneous.logEvent("w", "Empty Application", "Application " + myContext.getPackageManager().getApplicationLabel(pInfo.applicationInfo) + " doesn\'t have packages.", 5);
}
return returnList.toArray(new String[returnList.size()]);
}
public static String[] getActivityListForPackageName(String packageName)
{
ArrayList<String> returnList = new ArrayList<String>();
for (PackageInfo pInfo : pInfos)
{
if(pInfo.packageName.equals(packageName))
{
ActivityInfo[] aInfos = pInfo.activities;
if (aInfos != null)
{
for (ActivityInfo activityInfo : aInfos)
{
returnList.add(activityInfo.name);
}
}
}
}
return returnList.toArray(new String[returnList.size()]);
}
public static ActivityInfo getActivityInfoForPackageNameAndActivityName(String packageName, String activityName)
{
for (PackageInfo pInfo : pInfos)
{
if(pInfo.packageName.equals(packageName))
{
ActivityInfo[] aInfos = pInfo.activities;
if (aInfos != null)
{
for (ActivityInfo activityInfo : aInfos)
{
if(activityInfo.name.equals(activityName))
return activityInfo;
}
}
}
}
return null;
}
private AlertDialog getActionStartActivityDialog1()
{
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
alertDialogBuilder.setTitle(getResources().getString(R.string.selectApplication));
final String[] applicationArray = ActivityManageTriggerNotification.getApplicationNameListString(this);
alertDialogBuilder.setItems(applicationArray, new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
dialog.dismiss();
getActionStartActivityDialog2(applicationArray[which]).show();
}
});
AlertDialog alertDialog = alertDialogBuilder.create();
return alertDialog;
}
private AlertDialog getActionStartActivityDialog2(String applicationName)
{
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
alertDialogBuilder.setTitle(getResources().getString(R.string.selectPackageOfApplication));
final String[] packageArray = ActivityManageTriggerNotification.getPackageListString(this, applicationName);
alertDialogBuilder.setItems(packageArray, new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
//getActionStartActivityDialog3(packageArray[which]).show();
//Miscellaneous.messageBox(getResources().getString(R.string.hint), getResources().getString(R.string.chooseActivityHint), ActivityManageNotificationTrigger.this).show();
tvSelectedApplication.setText(packageArray[which]);
}
});
AlertDialog alertDialog = alertDialogBuilder.create();
return alertDialog;
}
private AlertDialog getActionStartActivityDialog3(final String packageName)
{
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
alertDialogBuilder.setTitle(getResources().getString(R.string.selectActivityToBeStarted));
final String activityArray[] = ActivityManageTriggerNotification.getActivityListForPackageName(packageName);
alertDialogBuilder.setItems(activityArray, new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
ActivityInfo ai = ActivityManageTriggerNotification.getActivityInfoForPackageNameAndActivityName(packageName, activityArray[which]);
tvSelectedApplication.setText(ai.packageName + ";" + ai.name);
}
});
AlertDialog alertDialog = alertDialogBuilder.create();
return alertDialog;
}
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.manage_trigger_notification);
etNotificationTitle = (EditText)findViewById(R.id.etNotificationTitle);
etNotificationText = (EditText)findViewById(R.id.etNotificationText);
bSelectApp = (Button)findViewById(R.id.bSelectApp);
bSaveTriggerNotification = (Button)findViewById(R.id.bSaveTriggerNotification);
spinnerTitleDirection = (Spinner)findViewById(R.id.spinnerTitleDirection);
spinnerTextDirection = (Spinner)findViewById(R.id.spinnerTextDirection);
tvSelectedApplication = (TextView)findViewById(R.id.etSelectedApplication);
chkNotificationDirection = (CheckBox)findViewById(R.id.chkNotificationDirection);
directions = new String[] {
getResources().getString(R.string.directionStringEquals),
getResources().getString(R.string.directionStringContains),
getResources().getString(R.string.directionStringStartsWith),
getResources().getString(R.string.directionStringEndsWith),
getResources().getString(R.string.directionStringNotEquals)
};
directionSpinnerAdapter = new ArrayAdapter<String>(this, R.layout.text_view_for_poi_listview_mediumtextsize, ActivityManageTriggerNotification.directions);
spinnerTitleDirection.setAdapter(directionSpinnerAdapter);
spinnerTextDirection.setAdapter(directionSpinnerAdapter);
directionSpinnerAdapter.notifyDataSetChanged();
bSelectApp.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
GetActivityListTask getActivityListTask = new GetActivityListTask();
getActivityListTask.execute();
progressDialog = ProgressDialog.show(ActivityManageTriggerNotification.this, "", ActivityManageTriggerNotification.this.getResources().getString(R.string.gettingListOfInstalledApplications));
}
});
chkNotificationDirection.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener()
{
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
{
if(isChecked)
chkNotificationDirection.setText(getResources().getString(R.string.notificationAppears));
else
chkNotificationDirection.setText(getResources().getString(R.string.notificationDisappears));
}
});
bSaveTriggerNotification.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
String app;
if(tvSelectedApplication.getText().toString().equalsIgnoreCase(getResources().getString(R.string.anyApp)))
app = "-1";
else
app = tvSelectedApplication.getText().toString();
String titleDir = Trigger.getMatchCode(spinnerTitleDirection.getSelectedItem().toString());
String title = etNotificationTitle.getText().toString();
String textDir = Trigger.getMatchCode(spinnerTextDirection.getSelectedItem().toString());
String text = etNotificationText.getText().toString();
if(edit)
{
editedNotificationTrigger.setTriggerParameter(chkNotificationDirection.isChecked());
editedNotificationTrigger.setTriggerParameter2(app + triggerParameter2Split + titleDir + triggerParameter2Split + title + triggerParameter2Split + textDir + triggerParameter2Split + text);
ActivityManageTriggerNotification.this.setResult(RESULT_OK);
}
else
{
Intent data = new Intent();
data.putExtra("direction", chkNotificationDirection.isChecked());
data.putExtra("app", app);
data.putExtra("titleDir", titleDir);
data.putExtra("title", title);
data.putExtra("textDir", textDir);
data.putExtra("text", text);
ActivityManageTriggerNotification.this.setResult(RESULT_OK, data);
}
finish();
}
});
Intent i = getIntent();
if(i.getBooleanExtra("edit", false) == true)
{
edit = true;
loadValuesIntoGui();
}
}
private void loadValuesIntoGui()
{
chkNotificationDirection.setChecked(editedNotificationTrigger.getTriggerParameter());
String[] params = editedNotificationTrigger.getTriggerParameter2().split(triggerParameter2Split);
String app = params[0];
String titleDir = params[1];
String title = params[2];
String textDir = params[3];
String text;
if (params.length >= 5)
text = params[4];
else
text = "";
if(!app.equals("-1"))
tvSelectedApplication.setText(app);
for(int i = 0; i < directions.length; i++)
{
if(Trigger.getMatchCode(directions[i]).equalsIgnoreCase(titleDir))
spinnerTitleDirection.setSelection(i);
if(Trigger.getMatchCode(directions[i]).equalsIgnoreCase(textDir))
spinnerTextDirection.setSelection(i);
}
if(title.length() > 0)
etNotificationTitle.setText(title);
if(text.length() > 0)
etNotificationText.setText(text);
}
private class GetActivityListTask extends AsyncTask<Void, Void, Void>
{
@Override
protected Void doInBackground(Void... params)
{
getActivityList(ActivityManageTriggerNotification.this);
return null;
}
@Override
protected void onPostExecute(Void result)
{
progressDialog.dismiss();
getActionStartActivityDialog1().show();
}
}
}

View File

@ -14,7 +14,7 @@ import java.sql.Time;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
public class ActivityManageTimeFrame extends Activity public class ActivityManageTriggerTimeFrame extends Activity
{ {
Button bSaveTimeFrame; Button bSaveTimeFrame;
TimePicker startPicker, stopPicker; TimePicker startPicker, stopPicker;
@ -27,7 +27,7 @@ public class ActivityManageTimeFrame extends Activity
protected void onCreate(Bundle savedInstanceState) protected void onCreate(Bundle savedInstanceState)
{ {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.trigger_timeframe_editor); setContentView(R.layout.manage_trigger_timeframe);
startPicker = (TimePicker)findViewById(R.id.tpTimeFrameStart); startPicker = (TimePicker)findViewById(R.id.tpTimeFrameStart);
stopPicker = (TimePicker)findViewById(R.id.tpTimeFrameStop); stopPicker = (TimePicker)findViewById(R.id.tpTimeFrameStop);

View File

@ -2,6 +2,7 @@ package com.jens.automation2;
import android.app.Activity; import android.app.Activity;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
@ -15,6 +16,8 @@ import android.view.View;
import android.widget.Button; import android.widget.Button;
import android.widget.TextView; import android.widget.TextView;
import com.jens.automation2.receivers.NotificationListener;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
@ -34,12 +37,13 @@ public class ActivityPermissions extends Activity
private static final int requestCodeForPermissionsWriteSettings = 12043; private static final int requestCodeForPermissionsWriteSettings = 12043;
private static final int requestCodeForPermissionsNotificationPolicy = 12044; private static final int requestCodeForPermissionsNotificationPolicy = 12044;
private static final int requestCodeForPermissionsBackgroundLocation = 12045; private static final int requestCodeForPermissionsBackgroundLocation = 12045;
private static final int requestCodeForPermissionsNotifications = 12046;
protected String[] specificPermissionsToRequest = null; protected String[] specificPermissionsToRequest = null;
public static String intentExtraName = "permissionsToBeRequested"; public static String intentExtraName = "permissionsToBeRequested";
Button bCancelPermissions, bRequestPermissions; Button bCancelPermissions, bRequestPermissions;
TextView tvPermissionsExplanation, tvPermissionosExplanationSystemSettings, tvPermissionsExplanationLong; TextView tvPermissionsExplanation, tvPermissionsExplanationSystemSettings, tvPermissionsExplanationLong;
static ActivityPermissions instance = null; static ActivityPermissions instance = null;
public static final String writeSystemSettingsPermissionName = "android.permission.WRITE_SETTINGS"; public static final String writeSystemSettingsPermissionName = "android.permission.WRITE_SETTINGS";
@ -50,6 +54,7 @@ public class ActivityPermissions extends Activity
public static final String permissionNameLocationBackground = "android.permission.ACCESS_BACKGROUND_LOCATION"; public static final String permissionNameLocationBackground = "android.permission.ACCESS_BACKGROUND_LOCATION";
public static final String permissionNameCall = "android.permission.PROCESS_OUTGOING_CALLS"; public static final String permissionNameCall = "android.permission.PROCESS_OUTGOING_CALLS";
public static final String permissionNameStartService = "android.permission.FOREGROUND_SERVICE"; public static final String permissionNameStartService = "android.permission.FOREGROUND_SERVICE";
public static final String permissionNameReadNotifications = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE";
public static ActivityPermissions getInstance() public static ActivityPermissions getInstance()
{ {
@ -72,7 +77,7 @@ public class ActivityPermissions extends Activity
bCancelPermissions = (Button)findViewById(R.id.bCancelPermissions); bCancelPermissions = (Button)findViewById(R.id.bCancelPermissions);
bRequestPermissions = (Button)findViewById(R.id.bRequestPermissions); bRequestPermissions = (Button)findViewById(R.id.bRequestPermissions);
tvPermissionsExplanation = (TextView)findViewById(R.id.tvPermissionsExplanation); tvPermissionsExplanation = (TextView)findViewById(R.id.tvPermissionsExplanation);
tvPermissionosExplanationSystemSettings = (TextView)findViewById(R.id.tvPermissionsExplanationSystemSettings); tvPermissionsExplanationSystemSettings = (TextView)findViewById(R.id.tvPermissionsExplanationSystemSettings);
tvPermissionsExplanationLong = (TextView)findViewById(R.id.tvPermissionsExplanationLong); tvPermissionsExplanationLong = (TextView)findViewById(R.id.tvPermissionsExplanationLong);
bCancelPermissions.setOnClickListener(new View.OnClickListener() bCancelPermissions.setOnClickListener(new View.OnClickListener()
@ -168,8 +173,6 @@ public class ActivityPermissions extends Activity
explanation.append( explanation.append(
"<br />" + "<br />" +
"<u>" + "<u>" +
getResources().getString(R.string.readLocation) getResources().getString(R.string.readLocation)
+ "</u>" + "</u>"
@ -188,8 +191,6 @@ public class ActivityPermissions extends Activity
explanation.append( explanation.append(
"<br />" + "<br />" +
"<u>" + "<u>" +
getResources().getString(getResources().getIdentifier(s, "string", getPackageName())) getResources().getString(getResources().getIdentifier(s, "string", getPackageName()))
+ "</u>" + "</u>"
@ -208,9 +209,9 @@ public class ActivityPermissions extends Activity
if (s.equalsIgnoreCase(writeSystemSettingsPermissionName)) if (s.equalsIgnoreCase(writeSystemSettingsPermissionName))
{ {
if (requiredPerms.length == 1) if (requiredPerms.length == 1)
tvPermissionosExplanationSystemSettings.setText(getResources().getString(R.string.systemSettingsNote1)); tvPermissionsExplanationSystemSettings.setText(getResources().getString(R.string.systemSettingsNote1));
else if (requiredPerms.length > 1) else if (requiredPerms.length > 1)
tvPermissionosExplanationSystemSettings.setText(getResources().getString(R.string.systemSettingsNote1) + getResources().getString(R.string.systemSettingsNote2)); tvPermissionsExplanationSystemSettings.setText(getResources().getString(R.string.systemSettingsNote1) + getResources().getString(R.string.systemSettingsNote2));
break; break;
} }
@ -231,7 +232,25 @@ public class ActivityPermissions extends Activity
{ {
for (String s : getRequiredPermissions(false)) for (String s : getRequiredPermissions(false))
{ {
if(!s.equalsIgnoreCase(permissionNameLocationBackground) && !s.equalsIgnoreCase(permissionNameLocationFine) && !s.equalsIgnoreCase(permissionNameLocationCoarse) && Miscellaneous.googleToBlameForLocation(true)) if(
s.equalsIgnoreCase(permissionNameLocationBackground)
||
s.equalsIgnoreCase(permissionNameLocationFine)
||
s.equalsIgnoreCase(permissionNameLocationCoarse)
)
{
if (!Miscellaneous.googleToBlameForLocation(true))
if (!havePermission(s, context))
return true;
}
else if(s.equalsIgnoreCase("android.permission.ACTIVITY_RECOGNITION") || s.equalsIgnoreCase("com.google.android.gms.permission.ACTIVITY_RECOGNITION"))
{
if(!BuildConfig.FLAVOR.equalsIgnoreCase("fdroidFlavor"))
if (!havePermission(s, context))
return true;
}
else
if (!havePermission(s, context)) if (!havePermission(s, context))
return true; return true;
} }
@ -256,6 +275,10 @@ public class ActivityPermissions extends Activity
else else
return true; return true;
} }
else if (s.equals(permissionNameReadNotifications))
{
return verifyNotificationPermission();
}
else else
{ {
int res = context.checkCallingOrSelfPermission(s); int res = context.checkCallingOrSelfPermission(s);
@ -285,11 +308,14 @@ public class ActivityPermissions extends Activity
// if (!havePermission(ActivityPermissions.writeExternalStoragePermissionName, workingContext)) // if (!havePermission(ActivityPermissions.writeExternalStoragePermissionName, workingContext))
// addToArrayListUnique(ActivityPermissions.writeExternalStoragePermissionName, requiredPermissions); // addToArrayListUnique(ActivityPermissions.writeExternalStoragePermissionName, requiredPermissions);
for(Profile profile : Profile.getProfileCollection()) if(!havePermission(writeSystemSettingsPermissionName, workingContext))
{ {
if(profile.changeIncomingCallsRingtone) for (Profile profile : Profile.getProfileCollection())
{ {
addToArrayListUnique("android.permission.WRITE_SETTINGS", requiredPermissions); if (profile.changeIncomingCallsRingtone)
{
addToArrayListUnique(writeSystemSettingsPermissionName, requiredPermissions);
}
} }
} }
@ -300,7 +326,24 @@ public class ActivityPermissions extends Activity
for (String singlePermission : getPermissionsForRule(rule)) for (String singlePermission : getPermissionsForRule(rule))
if (!havePermission(singlePermission, workingContext)) if (!havePermission(singlePermission, workingContext))
{ {
if(!singlePermission.equalsIgnoreCase(permissionNameLocationBackground) && !singlePermission.equalsIgnoreCase(permissionNameLocationFine) && !singlePermission.equalsIgnoreCase(permissionNameLocationCoarse) && Miscellaneous.googleToBlameForLocation(true)) if(
singlePermission.equalsIgnoreCase(permissionNameLocationBackground)
||
singlePermission.equalsIgnoreCase(permissionNameLocationFine)
||
singlePermission.equalsIgnoreCase(permissionNameLocationCoarse)
)
{
if (!Miscellaneous.googleToBlameForLocation(true))
addToArrayListUnique(singlePermission, requiredPermissions);
}
else if(singlePermission.equalsIgnoreCase("android.permission.ACTIVITY_RECOGNITION") || singlePermission.equalsIgnoreCase("com.google.android.gms.permission.ACTIVITY_RECOGNITION"))
{
if(!BuildConfig.FLAVOR.equalsIgnoreCase("fdroidFlavor"))
addToArrayListUnique(singlePermission, requiredPermissions);
}
else
addToArrayListUnique(singlePermission, requiredPermissions); addToArrayListUnique(singlePermission, requiredPermissions);
} }
} }
@ -360,7 +403,7 @@ public class ActivityPermissions extends Activity
addToArrayListUnique("android.permission.ACCESS_NETWORK_STATE", requiredPermissions); addToArrayListUnique("android.permission.ACCESS_NETWORK_STATE", requiredPermissions);
break; break;
case batteryLevel: case batteryLevel:
addToArrayListUnique("android.permission.READ_PHONE_STATE", requiredPermissions); // addToArrayListUnique("android.permission.READ_PHONE_STATE", requiredPermissions);
// addToArrayListUnique("android.permission.BATTERY_STATS", requiredPermissions); // addToArrayListUnique("android.permission.BATTERY_STATS", requiredPermissions);
break; break;
case bluetoothConnection: case bluetoothConnection:
@ -425,6 +468,9 @@ public class ActivityPermissions extends Activity
addToArrayListUnique("android.permission.ACCESS_NETWORK_STATE", requiredPermissions); addToArrayListUnique("android.permission.ACCESS_NETWORK_STATE", requiredPermissions);
addToArrayListUnique("android.permission.ACCESS_WIFI_STATE", requiredPermissions); addToArrayListUnique("android.permission.ACCESS_WIFI_STATE", requiredPermissions);
break; break;
case notification:
addToArrayListUnique(permissionNameReadNotifications, requiredPermissions);
break;
default: default:
break; break;
} }
@ -600,6 +646,11 @@ public class ActivityPermissions extends Activity
break; break;
case "android.permission.WRITE_EXTERNAL_STORAGE": case "android.permission.WRITE_EXTERNAL_STORAGE":
usingElements.add(getResources().getString(R.string.storeSettings)); usingElements.add(getResources().getString(R.string.storeSettings));
break;
case permissionNameReadNotifications:
for(String ruleName : getRulesUsing(Trigger.Trigger_Enum.notification))
usingElements.add(String.format(getResources().getString(R.string.ruleXrequiresThis), ruleName));
break; break;
case "com.google.android.gms.permission.ACTIVITY_RECOGNITION": case "com.google.android.gms.permission.ACTIVITY_RECOGNITION":
for(String ruleName : getRulesUsing(Trigger.Trigger_Enum.activityDetection)) for(String ruleName : getRulesUsing(Trigger.Trigger_Enum.activityDetection))
@ -783,6 +834,10 @@ public class ActivityPermissions extends Activity
requestPermissions(cachedPermissionsToRequest, true); requestPermissions(cachedPermissionsToRequest, true);
} }
} }
if (requestCode == requestCodeForPermissionsNotifications)
if(havePermission(permissionNameReadNotifications, ActivityPermissions.this))
requestPermissions(cachedPermissionsToRequest, true);
} }
} }
@ -842,6 +897,14 @@ public class ActivityPermissions extends Activity
startActivityForResult(intent, requestCodeForPermissionsNotificationPolicy); startActivityForResult(intent, requestCodeForPermissionsNotificationPolicy);
return; return;
} }
else if (s.equalsIgnoreCase(permissionNameReadNotifications))
{
requiredPermissions.remove(s);
cachedPermissionsToRequest = requiredPermissions;
Intent intent = new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS");
startActivityForResult(intent, requestCodeForPermissionsNotifications);
return;
}
// else if (s.equalsIgnoreCase(permissionNameLocationBackground) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) // else if (s.equalsIgnoreCase(permissionNameLocationBackground) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
// { // {
// requiredPermissions.remove(s); // requiredPermissions.remove(s);
@ -1392,4 +1455,24 @@ public class ActivityPermissions extends Activity
return false; return false;
} }
public static Boolean verifyNotificationPermission()
{
try
{
String theList = android.provider.Settings.Secure.getString(Miscellaneous.getAnyContext().getContentResolver(), "enabled_notification_listeners");
String[] theListList = theList.split(":");
String me = (new ComponentName(Miscellaneous.getAnyContext(), NotificationListener.class)).flattenToString();
for (String next : theListList)
{
if (me.equals(next))
return true;
}
return false;
}
catch(Exception e)
{
return false;
}
}
} }

View File

@ -33,7 +33,8 @@ public class CompensateCrappyAndroidPaths
* @param uri The Uri to query. * @param uri The Uri to query.
*/ */
@SuppressLint("NewApi") @SuppressLint("NewApi")
public static String getPath(final Context context, final Uri uri) { public static String getPath(final Context context, final Uri uri)
{
// check here to KITKAT or new version // check here to KITKAT or new version
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
String selection = null; String selection = null;

View File

@ -0,0 +1,65 @@
package com.jens.automation2;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.io.File;
import java.io.FileNotFoundException;
import java.security.Provider;
public class FileShareProvider extends ContentProvider
{
@Override
public boolean onCreate()
{
return false;
}
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder)
{
return null;
}
@Nullable
@Override
public String getType(@NonNull Uri uri)
{
return null;
}
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values)
{
return null;
}
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs)
{
return 0;
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs)
{
return 0;
}
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException
{
File cacheDir = getContext().getCacheDir();
File privateFile = new File(cacheDir, Settings.zipFileName);
return ParcelFileDescriptor.open(privateFile, ParcelFileDescriptor.MODE_READ_ONLY);
}
}

View File

@ -7,6 +7,7 @@ import android.app.NotificationChannel;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.app.Service; import android.app.Service;
import android.content.ContentProvider;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
@ -22,6 +23,7 @@ import android.provider.MediaStore;
import android.provider.Settings.Secure; import android.provider.Settings.Secure;
import android.util.Base64; import android.util.Base64;
import android.util.Log; import android.util.Log;
import android.widget.Toast;
import com.jens.automation2.location.LocationProvider; import com.jens.automation2.location.LocationProvider;
import com.jens.automation2.receivers.PhoneStatusListener; import com.jens.automation2.receivers.PhoneStatusListener;
@ -42,6 +44,8 @@ import org.w3c.dom.Element;
import org.xml.sax.InputSource; import org.xml.sax.InputSource;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.File; import java.io.File;
@ -71,6 +75,9 @@ import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.Scanner; import java.util.Scanner;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.HttpsURLConnection;
@ -84,6 +91,7 @@ import javax.xml.parsers.ParserConfigurationException;
import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationCompat;
import static android.provider.CalendarContract.CalendarCache.URI;
import static com.jens.automation2.AutomationService.NOTIFICATION_CHANNEL_ID; import static com.jens.automation2.AutomationService.NOTIFICATION_CHANNEL_ID;
import static com.jens.automation2.AutomationService.channelName; import static com.jens.automation2.AutomationService.channelName;
@ -441,6 +449,25 @@ public class Miscellaneous extends Service
return isEmulator; return isEmulator;
} }
public static boolean compare(String direction, String needle, String haystack)
{
switch(direction)
{
case Trigger.directionEquals:
return haystack.equalsIgnoreCase(needle);
case Trigger.directionNotEquals:
return !haystack.equalsIgnoreCase(needle);
case Trigger.directionContains:
return haystack.toLowerCase().contains(needle.toLowerCase());
case Trigger.directionStartsWith:
return haystack.toLowerCase().startsWith(needle.toLowerCase());
case Trigger.directionEndsWith:
return haystack.toLowerCase().endsWith(needle.toLowerCase());
default:
return false;
}
}
public static int compareTimes(Time time1, Time time2) public static int compareTimes(Time time1, Time time2)
{ {
// Miscellaneous.logEvent("i", "TimeCompare", "To compare: " + time1.toString() + " / " + time2.toString()); // Miscellaneous.logEvent("i", "TimeCompare", "To compare: " + time1.toString() + " / " + time2.toString());
@ -848,7 +875,7 @@ public class Miscellaneous extends Service
mNotificationManager.notify(0, dismissableNotification);*/ mNotificationManager.notify(0, dismissableNotification);*/
} }
public static void createDismissableNotificationSdk26(String textToDisplay, int notificationId, PendingIntent pendingIntent) static void createDismissableNotificationSdk26(String textToDisplay, int notificationId, PendingIntent pendingIntent)
{ {
NotificationManager mNotificationManager = (NotificationManager) AutomationService.getInstance().getSystemService(Context.NOTIFICATION_SERVICE); NotificationManager mNotificationManager = (NotificationManager) AutomationService.getInstance().getSystemService(Context.NOTIFICATION_SERVICE);
@ -1207,4 +1234,103 @@ public class Miscellaneous extends Service
return false; return false;
} }
public static void zip(String[] _files, String zipFileName)
{
int BUFFER = 2048;
try
{
BufferedInputStream origin = null;
FileOutputStream dest = new FileOutputStream(zipFileName);
ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(
dest));
byte data[] = new byte[BUFFER];
for (int i = 0; i < _files.length; i++)
{
Log.v("Compress", "Adding: " + _files[i]);
FileInputStream fi = new FileInputStream(_files[i]);
origin = new BufferedInputStream(fi, BUFFER);
ZipEntry entry = new ZipEntry(_files[i].substring(_files[i].lastIndexOf("/") + 1));
out.putNextEntry(entry);
int count;
while ((count = origin.read(data, 0, BUFFER)) != -1)
{
out.write(data, 0, count);
}
origin.close();
}
out.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
public static void unzip(String _zipFile, String _targetLocation)
{
int BUFFER = 2048;
try
{
FileInputStream fin = new FileInputStream(_zipFile);
ZipInputStream zin = new ZipInputStream(fin);
ZipEntry ze = null;
while ((ze = zin.getNextEntry()) != null)
{
//create dir if required while unzipping
if (ze.isDirectory())
{
// dirChecker(ze.getName());
}
else
{
FileOutputStream fout = new FileOutputStream(_targetLocation + ze.getName());
for (int c = zin.read(); c != -1; c = zin.read())
{
fout.write(c);
}
zin.closeEntry();
fout.close();
}
}
zin.close();
}
catch (Exception e)
{
System.out.println(e);
}
}
public static void sendEmail(Context context, String targetAddress, String subject, String message, Uri fileAttachment)
{
try
{
final Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);
emailIntent.setType("plain/text");
emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, new String[]{targetAddress});
emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, subject);
if (fileAttachment != null)
{
emailIntent.putExtra(Intent.EXTRA_STREAM, fileAttachment);
}
emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, message);
context.startActivity(Intent.createChooser(emailIntent, "Sending email..."));
}
catch (Throwable t)
{
Toast.makeText(context, "Request failed try again: "+ t.toString(), Toast.LENGTH_LONG).show();
}
}
public static boolean doesActivityExist(Intent intent, Context context)
{
return intent.resolveActivityInfo(context.getPackageManager(), 0) != null;
}
} }

View File

@ -68,7 +68,13 @@ public class News
Calendar now = Calendar.getInstance(); Calendar now = Calendar.getInstance();
String newsContent; String newsContent;
String filePath = context.getFilesDir() + "/appNews.xml"; String newsFileName = "appNews.xml";
String filePath = context.getCacheDir() + "/" + newsFileName;
File oldFilePath = new File(context.getFilesDir() + "/" + newsFileName);
if(oldFilePath.exists())
oldFilePath.delete();
if (!(new File(filePath)).exists() || Settings.lastNewsPolltime == -1 || now.getTimeInMillis() >= Settings.lastNewsPolltime + (long)(Settings.newsDisplayForXDays * 24 * 60 * 60 * 1000)) if (!(new File(filePath)).exists() || Settings.lastNewsPolltime == -1 || now.getTimeInMillis() >= Settings.lastNewsPolltime + (long)(Settings.newsDisplayForXDays * 24 * 60 * 60 * 1000))
{ {
@ -80,14 +86,14 @@ public class News
{ {
Settings.lastNewsPolltime = now.getTimeInMillis(); Settings.lastNewsPolltime = now.getTimeInMillis();
Settings.writeSettings(context); Settings.writeSettings(context);
Miscellaneous.logEvent("i", "appNews.xml", "File stored to " + filePath, 5); Miscellaneous.logEvent("i", newsFileName, "File stored to " + filePath, 5);
} }
} }
else else
{ {
// Just read local cache file // Just read local cache file
newsContent = Miscellaneous.readFileToString(filePath); newsContent = Miscellaneous.readFileToString(filePath);
Miscellaneous.logEvent("i", "appNews.xml", "Using cache to retrieve news: " + filePath, 5); Miscellaneous.logEvent("i", newsFileName, "Using cache to retrieve news: " + filePath, 5);
} }
ArrayList<News> returnList = new ArrayList<>(); ArrayList<News> returnList = new ArrayList<>();

View File

@ -273,24 +273,24 @@ public class ReceiverCoordinator
if(Rule.isAnyRuleUsing(Trigger.Trigger_Enum.activityDetection)) if(Rule.isAnyRuleUsing(Trigger.Trigger_Enum.activityDetection))
{ {
Object runResult = Miscellaneous.runMethodReflective("ActivityDetectionReceiver", "isActivityDetectionReceiverRunning", null);; Object runResult = Miscellaneous.runMethodReflective(activityDetectionClassPath, "isActivityDetectionReceiverRunning", null);;
if(runResult instanceof Boolean) if(runResult instanceof Boolean)
{ {
boolean isRunning = (Boolean) runResult; boolean isRunning = (Boolean) runResult;
if (isRunning) if (isRunning)
{ {
Miscellaneous.logEvent("i", "LocationProvider", "Restarting ActivityDetectionReceiver because used in a new/changed rule.", 4); Miscellaneous.logEvent("i", "LocationProvider", "Restarting ActivityDetectionReceiver because used in a new/changed rule.", 4);
boolean haveAllPerms = (Boolean) Miscellaneous.runMethodReflective("ActivityDetectionReceiver", "haveAllPermission", null); boolean haveAllPerms = (Boolean) Miscellaneous.runMethodReflective(activityDetectionClassPath, "haveAllPermission", null);
if (haveAllPerms) if (haveAllPerms)
Miscellaneous.runMethodReflective("ActivityDetectionReceiver", "restartActivityDetectionReceiver", null); Miscellaneous.runMethodReflective(activityDetectionClassPath, "restartActivityDetectionReceiver", null);
// ActivityDetectionReceiver.restartActivityDetectionReceiver(); // ActivityDetectionReceiver.restartActivityDetectionReceiver();
} }
else else
{ {
Miscellaneous.logEvent("i", "LocationProvider", "Starting ActivityDetectionReceiver because used in a new/changed rule.", 4); Miscellaneous.logEvent("i", "LocationProvider", "Starting ActivityDetectionReceiver because used in a new/changed rule.", 4);
boolean haveAllPerms = (Boolean) Miscellaneous.runMethodReflective("ActivityDetectionReceiver", "haveAllPermission", null); boolean haveAllPerms = (Boolean) Miscellaneous.runMethodReflective(activityDetectionClassPath, "haveAllPermission", null);
if (haveAllPerms) if (haveAllPerms)
Miscellaneous.runMethodReflective("ActivityDetectionReceiver", "startActivityDetectionReceiver", null); Miscellaneous.runMethodReflective(activityDetectionClassPath, "startActivityDetectionReceiver", null);
// ActivityDetectionReceiver.startActivityDetectionReceiver(); // ActivityDetectionReceiver.startActivityDetectionReceiver();
} }
} }
@ -304,7 +304,7 @@ public class ReceiverCoordinator
if (isRunning) if (isRunning)
{ {
Miscellaneous.logEvent("i", "LocationProvider", "Shutting down ActivityDetectionReceiver because not used in any rule.", 4); Miscellaneous.logEvent("i", "LocationProvider", "Shutting down ActivityDetectionReceiver because not used in any rule.", 4);
Miscellaneous.runMethodReflective("ActivityDetectionReceiver", "stopActivityDetectionReceiver", null); Miscellaneous.runMethodReflective(activityDetectionClassPath, "stopActivityDetectionReceiver", null);
// ActivityDetectionReceiver.stopActivityDetectionReceiver(); // ActivityDetectionReceiver.stopActivityDetectionReceiver();
} }
} }

View File

@ -16,6 +16,7 @@ public class Settings implements SharedPreferences
public static final int newsPollEveryXDays = 3; public static final int newsPollEveryXDays = 3;
public static final int newsDisplayForXDays = 3; public static final int newsDisplayForXDays = 3;
public static final String folderName = "Automation"; public static final String folderName = "Automation";
public static final String zipFileName = "automation.zip";
public static final String constNewsOptInDone ="newsOptInDone"; public static final String constNewsOptInDone ="newsOptInDone";

View File

@ -21,7 +21,7 @@ public class Trigger
*/ */
public enum Trigger_Enum { public enum Trigger_Enum {
pointOfInterest, timeFrame, charging, batteryLevel, usb_host_connection, speed, noiseLevel, wifiConnection, process_started_stopped, airplaneMode, roaming, nfcTag, activityDetection, bluetoothConnection, headsetPlugged, phoneCall; //phoneCall always needs to be at the very end because of Google's shitty so called privacy pointOfInterest, timeFrame, charging, batteryLevel, usb_host_connection, speed, noiseLevel, wifiConnection, process_started_stopped, airplaneMode, roaming, nfcTag, activityDetection, bluetoothConnection, headsetPlugged, notification, phoneCall; //phoneCall always needs to be at the very end because of Google's shitty so called privacy
public String getFullName(Context context) public String getFullName(Context context)
{ {
@ -59,6 +59,8 @@ public class Trigger
return context.getResources().getString(R.string.bluetoothConnection); return context.getResources().getString(R.string.bluetoothConnection);
case headsetPlugged: case headsetPlugged:
return context.getResources().getString(R.string.triggerHeadsetPlugged); return context.getResources().getString(R.string.triggerHeadsetPlugged);
case notification:
return context.getResources().getString(R.string.notification);
default: default:
return "Unknown"; return "Unknown";
} }
@ -67,6 +69,9 @@ public class Trigger
}; };
private boolean triggerParameter; //if true->started event, if false->stopped private boolean triggerParameter; //if true->started event, if false->stopped
private String triggerParameter2;
public static final String triggerParameter2Split = "tp2split";
private Trigger_Enum triggerType = null; private Trigger_Enum triggerType = null;
private PointOfInterest pointOfInterest = null; private PointOfInterest pointOfInterest = null;
@ -206,6 +211,16 @@ public class Trigger
this.triggerParameter = triggerParameter; this.triggerParameter = triggerParameter;
} }
public String getTriggerParameter2()
{
return triggerParameter2;
}
public void setTriggerParameter2(String triggerParameter2)
{
this.triggerParameter2 = triggerParameter2;
}
public TimeFrame getTimeFrame() public TimeFrame getTimeFrame()
{ {
return timeFrame; return timeFrame;
@ -216,7 +231,6 @@ public class Trigger
this.timeFrame = timeFrame; this.timeFrame = timeFrame;
} }
@RequiresApi(api = Build.VERSION_CODES.KITKAT) @RequiresApi(api = Build.VERSION_CODES.KITKAT)
@SuppressWarnings("unused") @SuppressWarnings("unused")
@Override @Override
@ -440,6 +454,46 @@ public class Trigger
else else
returnString.append(String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.headsetDisconnected), type)); returnString.append(String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.headsetDisconnected), type));
break; break;
case notification:
if(this.getTriggerParameter2().contains(triggerParameter2Split))
{
String[] params = getTriggerParameter2().split(triggerParameter2Split);
String app = params[0];
String titleDir = params[1];
String title = params[2];
String textDir = params[3];
String text;
if (params.length >= 5)
text = params[4];
else
text = "";
StringBuilder triggerBuilder = new StringBuilder();
String appString;
if (app.equalsIgnoreCase("-1"))
appString = Miscellaneous.getAnyContext().getResources().getString(R.string.anyApp);
else
appString = "app " + app;
if(triggerParameter)
triggerBuilder.append(String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.postsNotification), appString));
else
triggerBuilder.append(String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.removedNotification), appString));
if (title.length() > 0)
triggerBuilder.append(", " + Miscellaneous.getAnyContext().getString(R.string.title) + " " + Trigger.getMatchString(titleDir) + " " + title);
if (text.length() > 0)
triggerBuilder.append(", " + Miscellaneous.getAnyContext().getString(R.string.text) + " " + Trigger.getMatchString(textDir) + " " + text);
returnString.append(triggerBuilder.toString());
}
else
{
setTriggerParameter2("-1" + triggerParameter2Split + directionEquals + triggerParameter2Split + triggerParameter2Split + directionEquals + triggerParameter2Split + triggerParameter2Split);
}
break;
default: default:
returnString.append("error"); returnString.append("error");
break; break;
@ -448,6 +502,46 @@ public class Trigger
return returnString.toString(); return returnString.toString();
} }
public static final String directionEquals = "eq";
public static final String directionContains = "ct";
public static final String directionStartsWith = "sw";
public static final String directionEndsWith = "ew";
public static final String directionNotEquals = "ne";
public static String getMatchString(String direction)
{
switch(direction)
{
case directionEquals:
return Miscellaneous.getAnyContext().getString(R.string.directionStringEquals);
case directionContains:
return Miscellaneous.getAnyContext().getString(R.string.directionStringContains);
case directionStartsWith:
return Miscellaneous.getAnyContext().getString(R.string.directionStringStartsWith);
case directionEndsWith:
return Miscellaneous.getAnyContext().getString(R.string.directionStringEndsWith);
case directionNotEquals:
return Miscellaneous.getAnyContext().getString(R.string.directionStringNotEquals);
default:
return Miscellaneous.getAnyContext().getString(R.string.error);
}
}
public static String getMatchCode(String direction)
{
if(direction.equalsIgnoreCase(Miscellaneous.getAnyContext().getString(R.string.directionStringEquals)))
return directionEquals;
else if(direction.equalsIgnoreCase(Miscellaneous.getAnyContext().getString(R.string.directionStringContains)))
return directionContains;
else if(direction.equalsIgnoreCase(Miscellaneous.getAnyContext().getString(R.string.directionStringStartsWith)))
return directionStartsWith;
else if(direction.equalsIgnoreCase(Miscellaneous.getAnyContext().getString(R.string.directionStringEndsWith)))
return directionEndsWith;
else if(direction.equalsIgnoreCase(Miscellaneous.getAnyContext().getString(R.string.directionStringNotEquals)))
return directionNotEquals;
else
return Miscellaneous.getAnyContext().getString(R.string.error);
}
public static String[] getTriggerTypesAsArray() public static String[] getTriggerTypesAsArray()
{ {

View File

@ -271,6 +271,8 @@ public class XmlFileInterface
} }
else if(Rule.getRuleCollection().get(i).getTriggerSet().get(j).getTriggerType() == Trigger_Enum.headsetPlugged) else if(Rule.getRuleCollection().get(i).getTriggerSet().get(j).getTriggerType() == Trigger_Enum.headsetPlugged)
serializer.text(String.valueOf(Rule.getRuleCollection().get(i).getTriggerSet().get(j).getHeadphoneType())); serializer.text(String.valueOf(Rule.getRuleCollection().get(i).getTriggerSet().get(j).getHeadphoneType()));
else if(Rule.getRuleCollection().get(i).getTriggerSet().get(j).getTriggerType() == Trigger_Enum.notification)
serializer.text(String.valueOf(Rule.getRuleCollection().get(i).getTriggerSet().get(j).getTriggerParameter2()));
serializer.endTag(null, "TriggerParameter2"); serializer.endTag(null, "TriggerParameter2");
serializer.endTag(null, "Trigger"); serializer.endTag(null, "Trigger");
} }
@ -377,7 +379,7 @@ public class XmlFileInterface
} }
catch (XmlPullParserException e) catch (XmlPullParserException e)
{ {
e.printStackTrace(); Miscellaneous.logEvent("e", "XmlFileInterface", Log.getStackTraceString(e), 1);
} }
catch(FileNotFoundException e) catch(FileNotFoundException e)
{ {
@ -392,12 +394,12 @@ public class XmlFileInterface
} }
catch(Exception ex) catch(Exception ex)
{ {
Miscellaneous.logEvent("e", "XmlFileInterface", Log.getStackTraceString(e), 1);
} }
} }
catch (IOException e) catch (IOException e)
{ {
e.printStackTrace(); Miscellaneous.logEvent("e", "XmlFileInterface", Log.getStackTraceString(e), 1);
} }
catch(Exception e) catch(Exception e)
{ {
@ -532,11 +534,11 @@ public class XmlFileInterface
} }
catch (NumberFormatException e) catch (NumberFormatException e)
{ {
e.printStackTrace(); Miscellaneous.logEvent("e", "XmlFileInterface", Log.getStackTraceString(e), 1);
} }
catch (Exception e) catch (Exception e)
{ {
e.printStackTrace(); Miscellaneous.logEvent("e", "XmlFileInterface", Log.getStackTraceString(e), 1);
} }
} }
else else
@ -749,13 +751,11 @@ public class XmlFileInterface
} }
catch (XmlPullParserException e) catch (XmlPullParserException e)
{ {
// TODO Auto-generated catch block Miscellaneous.logEvent("e", "XmlFileInterface", Log.getStackTraceString(e), 1);
e.printStackTrace();
} }
catch (IOException e) catch (IOException e)
{ {
// TODO Auto-generated catch block Miscellaneous.logEvent("e", "XmlFileInterface", Log.getStackTraceString(e), 1);
e.printStackTrace();
} }
} }
else if (name.equals("ActionCollection")) else if (name.equals("ActionCollection"))
@ -766,13 +766,11 @@ public class XmlFileInterface
} }
catch (XmlPullParserException e) catch (XmlPullParserException e)
{ {
// TODO Auto-generated catch block Miscellaneous.logEvent("e", "XmlFileInterface", Log.getStackTraceString(e), 1);
e.printStackTrace();
} }
catch (IOException e) catch (IOException e)
{ {
// TODO Auto-generated catch block Miscellaneous.logEvent("e", "XmlFileInterface", Log.getStackTraceString(e), 1);
e.printStackTrace();
} }
} }
else else
@ -863,38 +861,45 @@ public class XmlFileInterface
if (name.equals("TriggerEvent")) if (name.equals("TriggerEvent"))
{ {
String triggerEventString = readTag(parser, "TriggerEvent"); String triggerEventString = readTag(parser, "TriggerEvent");
if(triggerEventString.equals("pointOfInterest")) // if(triggerEventString.equals("pointOfInterest"))
newTrigger.setTriggerType(Trigger_Enum.pointOfInterest); // newTrigger.setTriggerType(Trigger_Enum.pointOfInterest);
else if(triggerEventString.equals("timeFrame")) // else if(triggerEventString.equals("timeFrame"))
newTrigger.setTriggerType(Trigger_Enum.timeFrame); // newTrigger.setTriggerType(Trigger_Enum.timeFrame);
else if(triggerEventString.equals("charging")) // else if(triggerEventString.equals("charging"))
newTrigger.setTriggerType(Trigger_Enum.charging); // newTrigger.setTriggerType(Trigger_Enum.charging);
else if(triggerEventString.equals("usb_host_connection")) // else if(triggerEventString.equals("usb_host_connection"))
newTrigger.setTriggerType(Trigger_Enum.usb_host_connection); // newTrigger.setTriggerType(Trigger_Enum.usb_host_connection);
else if(triggerEventString.equals("batteryLevel")) // else if(triggerEventString.equals("batteryLevel"))
newTrigger.setTriggerType(Trigger_Enum.batteryLevel); // newTrigger.setTriggerType(Trigger_Enum.batteryLevel);
else if(triggerEventString.equals("speed")) // else if(triggerEventString.equals("speed"))
newTrigger.setTriggerType(Trigger_Enum.speed); // newTrigger.setTriggerType(Trigger_Enum.speed);
else if(triggerEventString.equals("noiseLevel")) // else if(triggerEventString.equals("noiseLevel"))
newTrigger.setTriggerType(Trigger_Enum.noiseLevel); // newTrigger.setTriggerType(Trigger_Enum.noiseLevel);
else if(triggerEventString.equals("wifiConnection")) // else if(triggerEventString.equals("wifiConnection"))
newTrigger.setTriggerType(Trigger_Enum.wifiConnection); // newTrigger.setTriggerType(Trigger_Enum.wifiConnection);
else if(triggerEventString.equals("process_started_stopped") | triggerEventString.equals("process_running")) // else
if(triggerEventString.equals("process_started_stopped") | triggerEventString.equals("process_running"))
newTrigger.setTriggerType(Trigger_Enum.process_started_stopped); newTrigger.setTriggerType(Trigger_Enum.process_started_stopped);
else if(triggerEventString.equals("airplaneMode")) // else if(triggerEventString.equals("airplaneMode"))
newTrigger.setTriggerType(Trigger_Enum.airplaneMode); // newTrigger.setTriggerType(Trigger_Enum.airplaneMode);
else if(triggerEventString.equals("roaming")) // else if(triggerEventString.equals("roaming"))
newTrigger.setTriggerType(Trigger_Enum.roaming); // newTrigger.setTriggerType(Trigger_Enum.roaming);
else if(triggerEventString.equals("phoneCall")) // else if(triggerEventString.equals("phoneCall"))
newTrigger.setTriggerType(Trigger_Enum.phoneCall); // newTrigger.setTriggerType(Trigger_Enum.phoneCall);
else if(triggerEventString.equals("nfcTag")) // else if(triggerEventString.equals("nfcTag"))
newTrigger.setTriggerType(Trigger_Enum.nfcTag); // newTrigger.setTriggerType(Trigger_Enum.nfcTag);
else if(triggerEventString.equals("activityDetection")) // else if(triggerEventString.equals("notification"))
newTrigger.setTriggerType(Trigger_Enum.activityDetection); // newTrigger.setTriggerType(Trigger_Enum.notification);
else if(triggerEventString.equals("bluetoothConnection")) // else if(triggerEventString.equals("activityDetection"))
newTrigger.setTriggerType(Trigger_Enum.bluetoothConnection); // newTrigger.setTriggerType(Trigger_Enum.activityDetection);
else if(triggerEventString.equals("headsetPlugged")) // else if(triggerEventString.equals("bluetoothConnection"))
newTrigger.setTriggerType(Trigger_Enum.headsetPlugged); // newTrigger.setTriggerType(Trigger_Enum.bluetoothConnection);
// else if(triggerEventString.equals("headsetPlugged"))
// newTrigger.setTriggerType(Trigger_Enum.headsetPlugged);
// else if(triggerEventString.equals("notification"))
// newTrigger.setTriggerType(Trigger_Enum.notification);
else
newTrigger.setTriggerType(Trigger_Enum.valueOf(triggerEventString));
} }
else if (name.equals("TriggerParameter1")) else if (name.equals("TriggerParameter1"))
{ {
@ -985,6 +990,8 @@ public class XmlFileInterface
newTrigger.setHeadphoneType(-1); newTrigger.setHeadphoneType(-1);
} }
} }
newTrigger.setTriggerParameter2(triggerParameter2);
} }
else else
{ {
@ -1072,19 +1079,20 @@ public class XmlFileInterface
{ {
String actionNameString = readTag(parser, "ActionName"); String actionNameString = readTag(parser, "ActionName");
if(actionNameString.equals("setWifi")) // if(actionNameString.equals("setWifi"))
newAction.setAction(Action_Enum.setWifi); // newAction.setAction(Action_Enum.setWifi);
else if(actionNameString.equals("setBluetooth")) // else if(actionNameString.equals("setBluetooth"))
newAction.setAction(Action_Enum.setBluetooth); // newAction.setAction(Action_Enum.setBluetooth);
else if(actionNameString.equals("setUsbTethering")) // else if(actionNameString.equals("setUsbTethering"))
newAction.setAction(Action_Enum.setUsbTethering); // newAction.setAction(Action_Enum.setUsbTethering);
else if(actionNameString.equals("setWifiTethering")) // else if(actionNameString.equals("setWifiTethering"))
newAction.setAction(Action_Enum.setWifiTethering); // newAction.setAction(Action_Enum.setWifiTethering);
else if(actionNameString.equals("setDisplayRotation")) // else if(actionNameString.equals("setDisplayRotation"))
newAction.setAction(Action_Enum.setDisplayRotation); // newAction.setAction(Action_Enum.setDisplayRotation);
// *** deprecated // *** deprecated
else if(actionNameString.equals("turnWifiOn")) //else
if(actionNameString.equals("turnWifiOn"))
newAction.setAction(Action_Enum.turnWifiOn); newAction.setAction(Action_Enum.turnWifiOn);
else if(actionNameString.equals("turnWifiOff")) else if(actionNameString.equals("turnWifiOff"))
newAction.setAction(Action_Enum.turnWifiOff); newAction.setAction(Action_Enum.turnWifiOff);
@ -1106,28 +1114,30 @@ public class XmlFileInterface
newAction.setAction(Action_Enum.disableScreenRotation); newAction.setAction(Action_Enum.disableScreenRotation);
// *** deprecated // *** deprecated
else if(actionNameString.equals("triggerUrl")) // else if(actionNameString.equals("triggerUrl"))
newAction.setAction(Action_Enum.triggerUrl); // newAction.setAction(Action_Enum.triggerUrl);
else if(actionNameString.equals("changeSoundProfile")) // else if(actionNameString.equals("changeSoundProfile"))
newAction.setAction(Action_Enum.changeSoundProfile); // newAction.setAction(Action_Enum.changeSoundProfile);
else if(actionNameString.equals("startOtherActivity")) // else if(actionNameString.equals("startOtherActivity"))
newAction.setAction(Action_Enum.startOtherActivity); // newAction.setAction(Action_Enum.startOtherActivity);
else if(actionNameString.equals("waitBeforeNextAction")) // else if(actionNameString.equals("waitBeforeNextAction"))
newAction.setAction(Action_Enum.waitBeforeNextAction); // newAction.setAction(Action_Enum.waitBeforeNextAction);
else if(actionNameString.equals("wakeupDevice")) // else if(actionNameString.equals("wakeupDevice"))
newAction.setAction(Action_Enum.wakeupDevice); // newAction.setAction(Action_Enum.wakeupDevice);
else if(actionNameString.equals("setAirplaneMode")) // else if(actionNameString.equals("setAirplaneMode"))
newAction.setAction(Action_Enum.setAirplaneMode); // newAction.setAction(Action_Enum.setAirplaneMode);
else if(actionNameString.equals("setDataConnection")) // else if(actionNameString.equals("setDataConnection"))
newAction.setAction(Action_Enum.setDataConnection); // newAction.setAction(Action_Enum.setDataConnection);
else if(actionNameString.equals("speakText")) // else if(actionNameString.equals("speakText"))
newAction.setAction(Action_Enum.speakText); // newAction.setAction(Action_Enum.speakText);
else if(actionNameString.equals("sendTextMessage")) // else if(actionNameString.equals("sendTextMessage"))
newAction.setAction(Action_Enum.sendTextMessage); // newAction.setAction(Action_Enum.sendTextMessage);
else if(actionNameString.equals("playMusic")) // else if(actionNameString.equals("playMusic"))
newAction.setAction(Action_Enum.playMusic); // newAction.setAction(Action_Enum.playMusic);
else if(actionNameString.equals("setScreenBrightness")) // else if(actionNameString.equals("setScreenBrightness"))
newAction.setAction(Action_Enum.setScreenBrightness); // newAction.setAction(Action_Enum.setScreenBrightness);
else
newAction.setAction(Action_Enum.valueOf(actionNameString));
} }
else if (name.equals("ActionParameter1")) else if (name.equals("ActionParameter1"))
{ {

View File

@ -0,0 +1,178 @@
package com.jens.automation2.receivers;
import android.annotation.SuppressLint;
import android.os.Build;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import androidx.annotation.RequiresApi;
import com.jens.automation2.AutomationService;
import com.jens.automation2.Miscellaneous;
import com.jens.automation2.Rule;
import com.jens.automation2.Trigger;
import java.util.ArrayList;
import java.util.Calendar;
// See here for reference: http://gmariotti.blogspot.com/2013/11/notificationlistenerservice-and-kitkat.html
@SuppressLint("OverrideAbstract")
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public class NotificationListener extends NotificationListenerService
{
static Calendar lastResponseToNotification = null;
static NotificationListener instance;
static SimpleNotification lastNotification = null;
// the title of the notification,
public static final String EXTRA_TITLE = "android.title";
// the main text payload
public static final String EXTRA_TEXT = "android.text";
// a third line of text, as supplied to
public static final String EXTRA_SUB_TEXT = "android.subText";
// a bitmap to be used instead of the small icon when showing the notification payload
public static final String EXTRA_LARGE_ICON = "android.largeIcon";
public static SimpleNotification getLastNotification()
{
return lastNotification;
}
@Override
public void onCreate()
{
super.onCreate();
instance = this;
}
public static NotificationListener getInstance()
{
return instance;
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
public void onNotificationPosted(StatusBarNotification sbn)
{
super.onNotificationPosted(sbn);
if(AutomationService.isMyServiceRunning(NotificationListener.this))
checkNotification(true, sbn);
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
public void onNotificationRemoved(StatusBarNotification sbn)
{
super.onNotificationRemoved(sbn);
if(AutomationService.isMyServiceRunning(NotificationListener.this))
checkNotification(false, sbn);
}
synchronized boolean checkNotification(boolean created, StatusBarNotification sbn)
{
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT)
{
String app = sbn.getPackageName();
String title = sbn.getNotification().extras.getString(EXTRA_TITLE);
String text = sbn.getNotification().extras.getString(EXTRA_TEXT);
lastNotification = new SimpleNotification();
lastNotification.publishTime = Miscellaneous.calendarFromLong(sbn.getPostTime());
lastNotification.created = created;
lastNotification.app = app;
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);
}
return false;
}
public static class SimpleNotification
{
boolean created;
Calendar publishTime;
String app, title, text;
public Calendar getPublishTime()
{
return publishTime;
}
public void setPublishTime(Calendar publishTime)
{
this.publishTime = publishTime;
}
public boolean isCreated()
{
return created;
}
public void setCreated(boolean created)
{
this.created = created;
}
public String getApp()
{
return app;
}
public void setApp(String app)
{
this.app = app;
}
public String getTitle()
{
return title;
}
public void setTitle(String title)
{
this.title = title;
}
public String getText()
{
return text;
}
public void setText(String text)
{
this.text = text;
}
}
@Override
public void onListenerConnected()
{
super.onListenerConnected();
}
@Override
public void onListenerDisconnected()
{
super.onListenerDisconnected();
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -2,15 +2,21 @@
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="10dp" > android:layout_margin="@dimen/default_margin" >
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" > android:orientation="vertical">
<LinearLayout <TableLayout
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:stretchColumns="1"
android:shrinkColumns="1" >
<TableRow
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
@ -20,42 +26,56 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/selectApplication" /> android:text="@string/selectApplication" />
<TextView <EditText
android:id="@+id/tvSelectedActivity" android:id="@+id/etSelectedApplication"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:inputType="textMultiLine"
android:text="" android:text=""
android:textAppearance="?android:attr/textAppearanceMedium" /> android:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout> </TableRow>
<ImageView <TableRow
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_margin="10dp"
android:background="#aa000000" />
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<ImageView
android:layout_width="wrap_content"
android:layout_height="1dp"
android:layout_margin="10dp"
android:background="#aa000000"
android:visibility="invisible" />
<TextView <TextView
android:id="@+id/textView3"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/parameterType" android:inputType="textMultiLine"
android:layout_gravity="center_vertical"/> android:text="@string/startAppChoiceNote" />
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="@string/parameterType" />
<Spinner <Spinner
android:id="@+id/spinnerParameterType" android:id="@+id/spinnerParameterType"
android:layout_width="match_parent" android:layout_width="wrap_content"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout </TableRow>
android:orientation="horizontal"
<TableRow
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<TextView <TextView
android:id="@+id/tvCurrentNfcIdValue" android:id="@+id/tvCurrentNfcIdValue"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -64,18 +84,15 @@
<EditText <EditText
android:id="@+id/etParameterName" android:id="@+id/etParameterName"
android:layout_width="match_parent" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content" />
android:ems="10" >
<requestFocus /> </TableRow>
</EditText>
</LinearLayout>
<LinearLayout <TableRow
android:orientation="horizontal"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<TextView <TextView
android:id="@+id/textView2" android:id="@+id/textView2"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -84,10 +101,12 @@
<EditText <EditText
android:id="@+id/etParameterValue" android:id="@+id/etParameterValue"
android:layout_width="match_parent" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content" />
android:ems="10" />
</LinearLayout> </TableRow>
</TableLayout>
<Button <Button
android:id="@+id/bAddIntentPair" android:id="@+id/bAddIntentPair"
@ -109,9 +128,11 @@
<Button <Button
android:id="@+id/bSaveActionStartOtherActivity" android:id="@+id/bSaveActionStartOtherActivity"
android:layout_marginTop="@dimen/default_margin"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/save" /> android:text="@string/save" />
</LinearLayout> </LinearLayout>
</ScrollView> </ScrollView>

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="40dp"
android:layout_marginBottom="@dimen/default_margin"
android:text="@string/playSound" />
<CheckBox
android:id="@+id/chkPlaySoundAlwaysPlay"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/alwaysPlay" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/alwaysPlayExplanation" />
<EditText
android:id="@+id/etSelectedSoundFile"
android:layout_marginVertical="@dimen/default_margin"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:id="@+id/bSelectSoundFile"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/selectSoundFile" />
<Button
android:id="@+id/bSavePlaySound"
android:layout_marginTop="@dimen/default_margin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/save" />
</LinearLayout>

View File

@ -17,7 +17,7 @@
android:background="@color/barBackgroundColor" > android:background="@color/barBackgroundColor" >
<TextView <TextView
android:id="@+id/tvSelectedActivity" android:id="@+id/etSelectedApplication"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/general" android:text="@string/general"

View File

@ -377,6 +377,13 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
<Button
android:id="@+id/bShareConfigAndLog"
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/shareConfigAndLogFilesWithDev" />
</LinearLayout> </LinearLayout>
</ScrollView> </ScrollView>

View File

@ -84,18 +84,21 @@
<Button <Button
android:id="@+id/cmdTriggerAdd" android:id="@+id/cmdTriggerAdd"
android:layout_weight="1"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/addTrigger" /> android:text="@string/addTrigger" />
<Button <Button
android:id="@+id/cmdActionAdd" android:id="@+id/cmdActionAdd"
android:layout_weight="1"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/addAction" /> android:text="@string/addAction" />
<Button <Button
android:id="@+id/cmdSaveRule" android:id="@+id/cmdSaveRule"
android:layout_weight="1"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/saveRule" /> android:text="@string/saveRule" />

View File

@ -0,0 +1,148 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp" >
<LinearLayout
android:layout_margin="@dimen/default_margin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/notification"
android:textSize="25dp"
android:layout_marginBottom="@dimen/default_margin" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/default_margin"
android:text="@string/notificationTriggerExplanation" />
<TableLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TableRow
android:layout_marginBottom="@dimen/activity_vertical_margin">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/direction"/>
<CheckBox
android:id="@+id/chkNotificationDirection"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/notificationAppears"
android:checked="true"/>
</TableRow>
<TableRow
android:layout_marginBottom="@dimen/activity_vertical_margin">
<TextView
android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/application" />
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/etSelectedApplication"
android:layout_marginHorizontal="@dimen/default_margin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/anyApp"
android:textAppearance="?android:attr/textAppearanceMedium" />
<Button
android:id="@+id/bSelectApp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/selectApplication" />
</LinearLayout>
</TableRow>
<TableRow
android:layout_marginBottom="@dimen/activity_vertical_margin">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="@string/title" />
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Spinner
android:id="@+id/spinnerTitleDirection"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<EditText
android:id="@+id/etNotificationTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10" />
</LinearLayout>
</TableRow>
<TableRow
android:layout_marginBottom="@dimen/activity_vertical_margin">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="@string/text" />
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Spinner
android:id="@+id/spinnerTextDirection"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<EditText
android:id="@+id/etNotificationText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10" />
</LinearLayout>
</TableRow>>
</TableLayout>
<Button
android:id="@+id/bSaveTriggerNotification"
android:layout_marginTop="@dimen/default_margin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/save" />
</LinearLayout>
</ScrollView>

View File

@ -31,7 +31,7 @@
<CheckBoxPreference <CheckBoxPreference
android:key="writeLogFile" android:key="writeLogFile"
android:summary="@string/onOff" android:summary="@string/onOff"
android:title="@string/writeLogFileToSd" /> android:title="@string/writeLogFile" />
<EditTextPreference <EditTextPreference
android:key="logLevel" android:key="logLevel"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android" <TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textSize="20sp"> android:textSize="20sp">

View File

@ -98,7 +98,7 @@
<string name="generalSettings">Allgemeine Einstellungen</string> <string name="generalSettings">Allgemeine Einstellungen</string>
<string name="startAtSystemBoot">Beim Gerätestart mitstarten</string> <string name="startAtSystemBoot">Beim Gerätestart mitstarten</string>
<string name="onOff">Ein/aus</string> <string name="onOff">Ein/aus</string>
<string name="writeLogFileToSd">Protokoll auf SD Karte schreiben</string> <string name="writeLogFile">Protokoll schreiben</string>
<string name="useTextToSpeechOnNormalSummary">TTS auf normal</string> <string name="useTextToSpeechOnNormalSummary">TTS auf normal</string>
<string name="useTextToSpeechOnVibrateSummary">TTS auf vibration</string> <string name="useTextToSpeechOnVibrateSummary">TTS auf vibration</string>
<string name="useTextToSpeechOnSilentSummary">TTS auf stumm</string> <string name="useTextToSpeechOnSilentSummary">TTS auf stumm</string>
@ -598,4 +598,40 @@
<string name="locationEngineDisabledShort">Die Position kann nicht mehr bestimmt werden.</string> <string name="locationEngineDisabledShort">Die Position kann nicht mehr bestimmt werden.</string>
<string name="locationEngineDisabledLong">Leider kann die Position nicht mehr bestimmt werden. Großer Dank dafür geht an Google für seine unendliche Weisheit und Großzügigkeit.\\n\\nBeginnend mit Android 10 wurde eine neue Berechtigung eingeführt, die benötigt wird, um als App die Position auch im Hintergrund bestimmen zu können, was, für eine App wie diese, natürlich notwendig ist.\\n\\nWährend ich das grundsätzlich für eine gute Idee halte, gilt das nicht für die Schikanen, die man Entwicklern damit zumutet.\\n\\nWenn man eine App entwickelt, kann man versuchen sich für diese Berechtigung zu qualifizieren, indem man einen Katalog von Bedingungen erfüllt. Leider wurden neue Versionen meiner Anwendung über einen Zeitraum von drei Monaten immer wieder abgelehnt.\\n\\nDas lief auf die immer gleiche Art ab:\\n\\nIch habe eine neue Version eingereicht, die all diese Anforderungen erfüllt hat.\\n\\nGoogles miserabler Entwickler-Support behauptete ich würde sie nicht einhalten.\\n\\nIch habe Beweise geliefert, daß ich alles einhalte.<br />Ich bekam eine Antwort wie "Ich kann Ihnen nicht weiterhelfen.\\n\\nIrgendwann habe ich aufgegeben.\\n\\nDie Folge davon ist nun, daß die Google Play Version keine Positionsbestimmung mehr im Hintergrund durchführen kann. Meine einzige Alternative wäre es gewesen, daß die ganze Anwendung aus dem Store fliegt.\\n\\nDas tut mir sehr leid, aber ich habe mein Bestes gegeben mit einem Kunden\"dienst\" zu diskutieren, der mehrfach beim Turing-Test durchgefallen ist.\\n\\nDie gute Nachricht: Die Anwendung kann es immer noch!\\n\\nAutomation ist nun Open Source Software und kann ab sofort bei F-Droid heruntergeladen werden. F-Droid ist ein freier Appstore, der Ihre Privatsphäre respektiert - statt nur so zu tun wie Google das macht.\\n\\nSichern Sie Ihre Konfiguratinsdatei, deinstallieren Sie dazu diese Anwendung, installieren sie von F-Droid neu, Konfigurationsdatei zurückspielen und fertig.\\n\\nKlicken Sie hier, um mehr herauszufinden:</string> <string name="locationEngineDisabledLong">Leider kann die Position nicht mehr bestimmt werden. Großer Dank dafür geht an Google für seine unendliche Weisheit und Großzügigkeit.\\n\\nBeginnend mit Android 10 wurde eine neue Berechtigung eingeführt, die benötigt wird, um als App die Position auch im Hintergrund bestimmen zu können, was, für eine App wie diese, natürlich notwendig ist.\\n\\nWährend ich das grundsätzlich für eine gute Idee halte, gilt das nicht für die Schikanen, die man Entwicklern damit zumutet.\\n\\nWenn man eine App entwickelt, kann man versuchen sich für diese Berechtigung zu qualifizieren, indem man einen Katalog von Bedingungen erfüllt. Leider wurden neue Versionen meiner Anwendung über einen Zeitraum von drei Monaten immer wieder abgelehnt.\\n\\nDas lief auf die immer gleiche Art ab:\\n\\nIch habe eine neue Version eingereicht, die all diese Anforderungen erfüllt hat.\\n\\nGoogles miserabler Entwickler-Support behauptete ich würde sie nicht einhalten.\\n\\nIch habe Beweise geliefert, daß ich alles einhalte.<br />Ich bekam eine Antwort wie "Ich kann Ihnen nicht weiterhelfen.\\n\\nIrgendwann habe ich aufgegeben.\\n\\nDie Folge davon ist nun, daß die Google Play Version keine Positionsbestimmung mehr im Hintergrund durchführen kann. Meine einzige Alternative wäre es gewesen, daß die ganze Anwendung aus dem Store fliegt.\\n\\nDas tut mir sehr leid, aber ich habe mein Bestes gegeben mit einem Kunden\"dienst\" zu diskutieren, der mehrfach beim Turing-Test durchgefallen ist.\\n\\nDie gute Nachricht: Die Anwendung kann es immer noch!\\n\\nAutomation ist nun Open Source Software und kann ab sofort bei F-Droid heruntergeladen werden. F-Droid ist ein freier Appstore, der Ihre Privatsphäre respektiert - statt nur so zu tun wie Google das macht.\\n\\nSichern Sie Ihre Konfiguratinsdatei, deinstallieren Sie dazu diese Anwendung, installieren sie von F-Droid neu, Konfigurationsdatei zurückspielen und fertig.\\n\\nKlicken Sie hier, um mehr herauszufinden:</string>
<string name="filesStoredAt">Konfigurations- und Logdateien werden hier gespeichert: %1$s</string> <string name="filesStoredAt">Konfigurations- und Logdateien werden hier gespeichert: %1$s</string>
<string name="directionStringEquals">ist gleich</string>
<string name="directionStringContains">enthält</string>
<string name="directionStringStartsWith">beginnt mit</string>
<string name="directionStringEndsWith">endet mit</string>
<string name="directionStringNotEquals">ist nicht gleich</string>
<string name="positioningEngine">Ortungsroutine</string>
<string name="googleSarcasm">Dank Google\'s unendlicher Weisheit und konstantem Unterfangen jederman\'s Privatsphäre zu schützen (Sarkasmus) müssen Auslöser und Aktionen, die SMS oder den Telefoniestatus betreffen, entfernt werden.</string>
<string name="screenLockSoundNotice">Die Töne bei der Bildschirmsperre können ab Android 6 nicht mehr verändert werden. Was immer Sie hier einstellen, wird voraussichtlich nicht mehr funktionieren.</string>
<string name="googleLocationChicaneryOld">Diese Anwendung sammelt Positionsdaten, um festzustellen, ob Sie sich gerade an einem der Orte aufhalten, die Sie definiert haben. Außerdem wird es benutzt, um Ihre Geschwindigkeit zu ermitteln, falls Sie diese in Regeln verwenden. Das wird auch dann gemacht, wenn das Programm nicht im Vordergrund ist (aber nur, wenn der Dienst aktiv ist).</string>
<string name="error">Fehler</string>
<string name="featureNotInFdroidVersion">Diese Funktion basiert auf nicht-freier Software (Google Bibliotheken). Daher ist sie in der F-Droid Version nicht verfügbar.</string>
<string name="settingsReferringToRestrictedFeatures">Ihre Einstellungen und Regeln verwenden derzeit nicht-freie Funktionen (Google Bibliotheken). Diese sind in der F-Droid Version nicht funktionsfähig. Das schließt die Erkennung Ihrer gegenwärtigen körperlichen Aktivität ein.</string>
<string name="displayNewsOnMainScreen">Nachrichten auf dem Hauptbildschirm anzeigen</string>
<string name="displayNewsOnMainScreenDescription">Nachrichten ausschließlich über diese Anwendung, wir sprechen von 1-2 pro Jahr, nicht mehr.</string>
<string name="newsOptIn">Möchten Sie wichtige Nachrichten über diese Anwendung auf dem Hauptbildschirm angezeigt bekommen? Diese werden von der Webseite des Entwicklers heruntergeladen. Es gibt keine aufdringliche Benachrichtigung, etc., lediglich eine stille Anzeige auf dem Hauptbildschirm.</string>
<string name="locationDisabled">Ortung deaktiviert</string>
<string name="notification">Benachrichtigung</string>
<string name="title">Titel</string>
<string name="text">Text</string>
<string name="anyApp">Irgendeine Anwendung</string>
<string name="postsNotification">%1$s zeigt eine Benachrichtung an</string>
<string name="removedNotification">Benachrichtigung von %1$s wurde entfernt</string>
<string name="notificationAppears">Benachrichtigung wird angezeigt</string>
<string name="notificationDisappears">Benachrichtigung wird entfernt</string>
<string name="direction">Richtung</string>
<string name="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">Systembenachrichtigungen lesen</string>
<string name="playSound">Tondatei abspielen</string>
<string name="alwaysPlay">immer abspielen</string>
<string name="selectSoundFile">Tondatei auswählen</string>
<string name="fileDoesNotExist">Datei existiert nicht.</string>
<string name="noFileManageInstalled">Kein Dateimanager installiert.</string>
<string name="alwaysPlayExplanation">Wenn diese Einstellung aktiv ist, wird der Ton immer abgespielt. Wenn die Einstellung inaktiv ist, wird der Ton nur dann abgespielt, wenn das Telefon weder auf stumm noch auf Vibration steht, d.h. Klingeltöne aktiv sind. Allerdings hat es keinen Einfluß auf die Medien-Lautstärke. D.h., wenn diese stumm ist, werden Sie so oder so nichts zu hören bekommen.</string>
<string name="shareConfigAndLogFilesWithDev">Konfigurations- und Logdatei mit Entwickler teilen (via email).</string>
<string name="shareConfigAndLogExplanation">Dies wird eine neue Email öffnen mit Konfigurations- und Logdateien als Zip-Anhang. Sie wird nicht automatisch versendet. D.h. Sie können so z.B. auch den Adressaten zu sich selbst ändern.</string>
<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="ruleActivationComplete">Regel \"%1$s\" wurde fertig ausgeführt.</string>
</resources> </resources>

View File

@ -98,7 +98,7 @@
<string name="generalSettings">General settings</string> <string name="generalSettings">General settings</string>
<string name="startAtSystemBoot">Start at system boot</string> <string name="startAtSystemBoot">Start at system boot</string>
<string name="onOff">On/Off</string> <string name="onOff">On/Off</string>
<string name="writeLogFileToSd">Write log file to SD card</string> <string name="writeLogFile">Write log file</string>
<string name="useTextToSpeechOnNormalSummary">Use TextToSpeech on normal</string> <string name="useTextToSpeechOnNormalSummary">Use TextToSpeech on normal</string>
<string name="useTextToSpeechOnVibrateSummary">Use TextToSpeech on vibrate</string> <string name="useTextToSpeechOnVibrateSummary">Use TextToSpeech on vibrate</string>
<string name="useTextToSpeechOnSilentSummary">Use TextToSpeech on silent</string> <string name="useTextToSpeechOnSilentSummary">Use TextToSpeech on silent</string>

View File

@ -562,7 +562,7 @@ Selezionare su “Continua” quando si è pronti a procedere.</string>
<string name="wifiState">Stato Wifi</string> <string name="wifiState">Stato Wifi</string>
<string name="with">con</string> <string name="with">con</string>
<string name="withLabel">con etichetta</string> <string name="withLabel">con etichetta</string>
<string name="writeLogFileToSd">Memorizza un file di log su SD card</string> <string name="writeLogFile">Memorizza un file di log</string>
<string name="writingSettingsToPersistentMemory">Scrivo le impostazioni nella memoria di massa.</string> <string name="writingSettingsToPersistentMemory">Scrivo le impostazioni nella memoria di massa.</string>
<string name="yes">Si</string> <string name="yes">Si</string>
<string name="edit">Elaborare</string> <string name="edit">Elaborare</string>

View File

@ -10,5 +10,9 @@
<color name="teal_200">#008080</color> <color name="teal_200">#008080</color>
<color name="teal_700">#008080</color> <color name="teal_700">#008080</color>
<color name="black">#000000</color> <color name="black">#000000</color>
<color name="brightScreenBackgroundColor">#F3F3F3</color>
<color name="brightScreenTextColor">#FFFFFF</color>
<color name="darkScreenBackgroundColor">#FFFFFF</color>
<color name="darkScreenTextColor">#F3F3F3</color>
</resources> </resources>

View File

@ -91,14 +91,14 @@
<string name="selectPoi">Select location</string> <string name="selectPoi">Select location</string>
<string name="selectTypeOfAction">Select type of action</string> <string name="selectTypeOfAction">Select type of action</string>
<string name="selectSoundProfile">Select sound profile</string> <string name="selectSoundProfile">Select sound profile</string>
<string name="whatToDoWithTrigger">What to do with it trigger?</string> <string name="whatToDoWithTrigger">What to do with trigger?</string>
<string name="whatToDoWithAction">What to do with it action?</string> <string name="whatToDoWithAction">What to do with action?</string>
<string name="radiusHasToBePositive">Radius has to be a positive number.</string> <string name="radiusHasToBePositive">Radius has to be a positive number.</string>
<string name="poiStillReferenced">There are still rules that reference this location (%1$s). I can\'t delete it, yet.</string> <string name="poiStillReferenced">There are still rules that reference this location (%1$s). I can\'t delete it, yet.</string>
<string name="generalSettings">General settings</string> <string name="generalSettings">General settings</string>
<string name="startAtSystemBoot">Start at system boot</string> <string name="startAtSystemBoot">Start at system boot</string>
<string name="onOff">On/Off</string> <string name="onOff">On/Off</string>
<string name="writeLogFileToSd">Write log file to SD card</string> <string name="writeLogFile">Write log file</string>
<string name="useTextToSpeechOnNormalSummary">Use TextToSpeech on normal</string> <string name="useTextToSpeechOnNormalSummary">Use TextToSpeech on normal</string>
<string name="useTextToSpeechOnVibrateSummary">Use TextToSpeech on vibrate</string> <string name="useTextToSpeechOnVibrateSummary">Use TextToSpeech on vibrate</string>
<string name="useTextToSpeechOnSilentSummary">Use TextToSpeech on silent</string> <string name="useTextToSpeechOnSilentSummary">Use TextToSpeech on silent</string>
@ -601,7 +601,7 @@
<string name="manageLocations">Create or edit locations</string> <string name="manageLocations">Create or edit locations</string>
<string name="error">Error</string> <string name="error">Error</string>
<string name="featureNotInFdroidVersion">This feature is based on non-free software. Therefore is is not available in the F-Droid version.</string> <string name="featureNotInFdroidVersion">This feature is based on non-free software. Therefore is is not available in the F-Droid version.</string>
<string name="settingsReferringToRestrictedFeatures">Your settings and or rules are currently referencing non-free features that cannot be provided in the F-Droid version.</string> <string name="settingsReferringToRestrictedFeatures">Your settings and or rules are currently referencing non-free features that cannot be provided in the F-Droid version. That includes detecting your current physical activity.</string>
<string name="publishedOn">published on</string> <string name="publishedOn">published on</string>
<string name="displayNewsOnMainScreen">Display application news on main screen</string> <string name="displayNewsOnMainScreen">Display application news on main screen</string>
<string name="displayNewsOnMainScreenDescription">Announcements about this app only, we\'re probably talking about 1-2 per year, not more.</string> <string name="displayNewsOnMainScreenDescription">Announcements about this app only, we\'re probably talking about 1-2 per year, not more.</string>
@ -609,6 +609,33 @@
<string name="newsOptIn">Would you like to receive (only important) news about this app on the main screen? Those are downloaded from the developer\'s website. There will be no intrusive notification, just a text on the main screen when you open the app.</string> <string name="newsOptIn">Would you like to receive (only important) news about this app on the main screen? Those are downloaded from the developer\'s website. There will be no intrusive notification, just a text on the main screen when you open the app.</string>
<string name="locationDisabled">Location disabled</string> <string name="locationDisabled">Location disabled</string>
<string name="locationEngineDisabledShort">Location cannot be determined anymore. Click here to find out why.</string> <string name="locationEngineDisabledShort">Location cannot be determined anymore. Click here to find out why.</string>
<string name="locationEngineDisabledLong">Unfortunately your location cannot be determined anymore. A debt of gratitude is owed to Google for its infinite wisdom and amiableness.\\n\\nLet me explain this further. Starting with Android 10 a new permission was introduced that is needed to determine your location in the background (which of course is required for an app like this). Whilst I consider that a good idea in general the chicanery it involves for developers are not.\\n\\nWhen developing an app you can try to qualify for this permission by abiding to a catalog of requirements. Unfortunately new versions of my app have been rejected over a period of three months. I fulfilled all these requirements, Google\'s shitty development support claimed I would not. After giving them proof that I did after all - I got a response like \"I cannot help you anymore\". Eventually I gave up. \\n\\nAs a consequence the Google Play version can NOT use your location as a trigger anymore. My only alternative option would have been to have this application removed from the store entirely.\\n\\nI\'m very sorry about that, but I\'ve tried my best arguing with a \"support\" that repeatedly failed to pass the Turing test.\\n\\nThe good news: You can still have it all!\\n\\nAutomation is now open source and can be found in F-Droid. That is an app store that really cares about your privacy - rather than just acting like that. Simply backup your config file, uninstall this app, install it again from F-Droid, restore your config file - done.\\n\\nClick here to find out more:</string> <string name="locationEngineDisabledLong">Unfortunately your location cannot be determined anymore. A debt of gratitude is owed to Google for its infinite wisdom and amiableness.\\n\\nLet me explain this further. Starting with Android 10 a new permission was introduced that is needed to determine your location in the background (which of course is required for an app like this). Whilst I consider that a good idea in general the chicanery it involves for developers is not.\\n\\nWhen developing an app you can try to qualify for this permission by abiding to a catalog of requirements. Unfortunately new versions of my app have been rejected over a period of three months. I fulfilled all those requirements, Google\'s shitty development support claimed I would not. After giving them proof that I did after all - I got a response like \"I cannot help you anymore\". Eventually I gave up. \\n\\nAs a consequence the Google Play version can NOT use your location as a trigger anymore. My only alternative option would have been to have this application removed from the store entirely.\\n\\nI\'m very sorry about that, but I\'ve tried my best arguing with a \"support\" that repeatedly failed to pass the Turing test.\\n\\nThe good news: You can still have it all!\\n\\nAutomation is now open source and can be found in F-Droid. That is an app store that really cares about your privacy - rather than just acting like that. Simply backup your config file, uninstall this app, install it again from F-Droid, restore your config file - done.\\n\\nClick here to find out more:</string>
<string name="filesStoredAt">Config and log files are stored in folder %1$s</string> <string name="filesStoredAt">Config and log files are stored in folder %1$s. Click on this text to open a file explorer. Unfortunately this will only work with a rooted device or a debug version. If you want to send me or yourself the config- and logfiles you can use the below button.</string>
<string name="notification">Notification</string>
<string name="title">Title</string>
<string name="text">Text</string>
<string name="directionStringEquals">equals</string>
<string name="directionStringContains">contains</string>
<string name="directionStringStartsWith">starts with</string>
<string name="directionStringEndsWith">ends with</string>
<string name="directionStringNotEquals">not equals</string>
<string name="anyApp">Any app</string>
<string name="notificationTriggerExplanation">This trigger will respond to other applications opening notifications in the notification area (or such being closed). You can specify another application from which the notification has to come from. If you don\'t the notifications from any other application will count. You can also specify strings that must be or must not be in their title or notification body. The comparison is done case-INsensitive.</string>
<string name="postsNotification">%1$s posts notification</string>
<string name="removedNotification">notification from %1$s removed</string>
<string name="notificationAppears">Notification appears</string>
<string name="notificationDisappears">Notification disappears</string>
<string name="direction">Direction</string>
<string name="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">Read system notifications</string>
<string name="playSound">Play sound</string>
<string name="alwaysPlay">always play</string>
<string name="alwaysPlayExplanation">If this settings is active the sound will always be played. If it is deactivated it will only play if your phone is neither on mute nor vibrate. However if active it will not have an effect on the volume. So if your phone is on ring mode it will not increase the media volume for example. So if media volume is on mute you won\'t hear anything either.</string>
<string name="selectSoundFile">Select sound file</string>
<string name="fileDoesNotExist">File does not exist.</string>
<string name="noFileManageInstalled">No file manager installed.</string>
<string name="shareConfigAndLogFilesWithDev">Share config and log files with developer (via email).</string>
<string name="shareConfigAndLogExplanation">This will start a new email with your config and log files attached as zip file. It will not be sent automatically, you still need to hit \"send\". You can also change the recipient to yourself for example.</string>
<string name="startAppChoiceNote">You can enter an activity path manually, but it\'s recommended to use the \"Select\" button.\nIf you choose to enter something manually keep in mind no variables will be resolved. If you want to start the camera for example \"MediaStore.ACTION_IMAGE_CAPTURE\" will not work. You have to look at the Android documentation and use its value instead which would be \"android.media.action.IMAGE_CAPTURE\".</string>
<string name="errorRunningRule">There was an error running a rule.</string>
<string name="cantFindSoundFile">Cannot find sound file %1$s and therefore not play it.</string>
</resources> </resources>

View File

@ -0,0 +1 @@
Fehler behoben, bei dem die App abgestürzt ist, wenn eine Regel gespeichert wurde während der Dienst lief.

View File

@ -0,0 +1,3 @@
Neuer Auslöser: Benachrichtigungen anderer Anwendungen auswerten.
Neue Aktion: Sounddatei abspielen.
Die üblichen Aufräumarbeiten und Fehlerbehebungen.

View File

@ -0,0 +1 @@
Initiale F-Droid Version

View File

@ -0,0 +1,2 @@
Ort verschoben, an dem die Konfigurationsdatei gespeichert wird (nun ein Programm-spezifisches Verzeichnis unterhalb von Android/data).
Wenn Sie das Programm bisher schon verwendet haben, d.h. Ihre Dateien am alten Ort angelegt wurden, werden sie beim ersten Start verschoben. Wenn das erfolgreich war, ist die Berechtigung android.permission.WRITE_EXTERNAL_STORAGE nicht länger notwendig.

View File

@ -0,0 +1,89 @@
Erstellen Sie Regeln, die aus Auslösern und Aktionen bestehen. Ein typisches Beispiel wäre etwas wie "Telefon auf stumm stellen, wenn ich auf der Arbeit bin."
Hier ist eine Liste der möglichen Auslöser und Aktionen:
Mögliche Auslöser:
* Ort
* Tag/Uhrzeit
* Ladezustand (lädt/lädt nicht)
* Akkustand
* USB Verbindung zu einem Computer besteht
* Die gegenwärtige Geschwindigkeit (km/h)
* Hintergrundlautstärke (nur bis Android 7)
* WLAN Verbindung
* Anwendere Anwendung wurde gestartet
* Flugzeugmodus
* Roaming aktiv oder nicht
* NFC tags
* Bluetooth Gerät verbunden
* Headset verbunden
* Telefongespräch im Gange
* Benachrichtigungen anderer Anwendungen
Mögliche Aktionen:
* WLAN ein-/ausschalten
* Bluetooth ein-/ausschalten
* USB Router ein-/ausschalten
* WLAN Router ein-/ausschalten
* Bildschirmdrehung ein-/ausschalten
* HTTP Request im Hintergrund auslösen
* Klingelton und Toneinstellungen ändern
* Eine andere Anwendung starten
* Warten (zwischen anderen Aktionen)
* Den Bildschirm des Geräts einschalten
* Flugzeugmodus ein-/ausschalten
* Datenverbindung ein-/ausschalten
* Text sprechen (TTS)
* Musikplayer öffnen
* Bildschirmhelligkeit ändern
* SMS verschicken
* Sounddatei abspielen.
Es ist ziemlich schwierig diese Anwendung über die vielen verschiedenen Geräte sowie die vielen Änderungen an Android Versionen am Funktionen 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 gemeldet wurden. Aber dafür bin ich auf Ihre Mithilfe angewiesen.
Ein Wort zu den vielen Berechtigungen....
Es liegt in der Natur einer Anwendung wie dieser, daß sie ziemlich viele Berechtigungen benötigt. Allerdings sind praktisch alle davon optional, und werden nur angefragt, wenn Sie eine Regel erstellen, die das erfordert.
Gehen wir sie mal schnell durch:
ACCESS_NETWORK_STATE, CHANGE_NETWORK_STATE: Dinge wie Flugmodus oder Roaming prüfen.
ACCESS_WIFI_STATE, CHANGE_WIFI_STATE: WLAN ein-/ausschalten
INTERNET
Das wird aus drei Gründen benötigt:
- Sie verwenden eine Ortungsmethode, die Mobilfunktürme verwenden (Standardeinstellung)
- Sie verwenden URL aufrufen als Aktion
- Sie aktivieren den Newsdownload in den Einstellungen
BLUETOOTH, BLUETOOTH_ADMIN: Bluetooth Verbindungen prüfen oder Bluetooth ein-/ausschalten
NFC: NFC Tags als Auslöser verwenden
Location (ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION, ACCESS_BACKGROUND_LOCATION): Das sollte selbsterklärend sein - verwenden Sie Orte oder Geschwindigkeit als Auslöser?
PROCESS_OUTGOING_CALLS: Sie können ausgehende Anrufen als Auslöser verwenden. Z.B. "wenn die Frau anruft, dann..."
SEND_SMS: Sie können SMS verschicken lassen. Hier kann eine Zielnummer direkt eingegeben werden oder optional eine aus den Kontakten ausgewählt werden, was uns zu READ_CONTACTS bringt
READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE: Wenn Sie die Anwendung vor März 2021 installiert haben, war das nötig, um die Konfigurationsdatei zu speichern (unter sdcard). Seitdem ist sie nicht mehr notwendig. Die Berechtigung ist noch da, um bei Benutzern, die noch nicht geupdatet haben, ein Migrieren der Dateien zu ermöglichen. Weiterhin ist das Lesen jetzt notwendig, um eine Sounddatei abzuspielen.
GET_TASKS: Für den Auslöser, der prüft, ob eine andere Anwendung läuft.
BATTERY_STATS: Akkustand lesen.
MODIFY_AUDIO_SETTINGS, ACCESS_NOTIFICATION_POLICY:
Für höhere Android Versionen ist das nötig, um Toneinstellungen wie Klingeltöne zu ändern.
https://stackoverflow.com/questions/43123650/android-request-access-notification-policy-and-mute-phone/43127589#43127589
ACCESS_NOTIFICATION_POLICY wird auch verwendet, um für den entsprechenden Auslöser Benachrichtigungen anderer Anwendungen lesen zu können.
RECORD_AUDIO: Für den Auslöser "Hintergrundlautstärke" notwendig. Nebenbei - meine persönliche Anwendung dafür ist: Mein Telefon stellt sich morgens auf laut. Während der Woche ist das recht fr<66>h. Was ist aber, wenn ich einen Tag frei habe? Hierzu wird als zusätzliche Bedingung die Hintergrundlautstärke ausgewertet, um festzustellen, ob ich wirklich schon wach bin. Leider hat Google diese Funktion mit Android 8 deaktiviert.
READ_PHONE_STATE: https://developer.android.com/reference/android/Manifest.permission#READ_PHONE_STATE
RECEIVE_BOOT_COMPLETED, FOREGROUND_SERVICE, WAKE_LOCK: Den Dienst automatisch beim Systemstart starten.
WRITE_SETTINGS: Systemeinstellungen ändern.
ACCESS_SUPERUSER: root ist komplett optional. In der (weiter zurückliegenden) Vergangenheit war es möglich Dinge wie das Ein-/Ausschalten des USB Routers mit normalen Funktionen zu steuern. Leider ist das schon lange nur noch mit Root-Rechten möglich. D.h. root ist nur für wenige Funktionen notwendig.

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

View File

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

View File

@ -0,0 +1 @@
Automation

View File

@ -0,0 +1,3 @@
New trigger: You can now use notifications of other apps.
New action: Play a sound file.
The usual cleanups and bugfixes.

View File

@ -18,6 +18,7 @@ Supported triggers:
* Bluetooth connection * Bluetooth connection
* Headset connected * Headset connected
* Phone call running * Phone call running
* Notifications of other apps
Supported actions: Supported actions:
* Change wifi state * Change wifi state
@ -36,6 +37,7 @@ Supported actions:
* Open music player * Open music player
* Change screen brightness * Change screen brightness
* Send text message * Send text message
* Play sound file
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. 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 reported to me. But for that I'm dependend on your input. 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 reported to me. But for that I'm dependend on your input.
@ -65,7 +67,7 @@ PROCESS_OUTGOING_CALLS: You can use current calls as trigger. E.g. if wife calls
SEND_SMS: You can have SMS sent as action. If you choose to do so you can enter the destination number manually or optionally pick one of your contacts which brings us to READ_CONTACTS SEND_SMS: You can have SMS sent as action. If you choose to do so you can enter the destination number manually or optionally pick one of your contacts which brings us to READ_CONTACTS
READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE: If you initially installed the app after March 2021 this is not required. In the past the app used to store its config file on the regular storage like "sdcard". The permission is still in there to ensure the app is also still working for legacy users. There the app will migrate the files to the new location. READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE: If you initially installed the app after March 2021 this is not required. In the past the app used to store its config file on the regular storage like "sdcard". The permission is still in there to ensure the app is also still working for legacy users. There the app will migrate the files to the new location. Reading is also required if you want to play sound files.
GET_TASKS: For trigger "check if another app is running" GET_TASKS: For trigger "check if another app is running"
@ -74,7 +76,7 @@ BATTERY_STATS: Check battery level as trigger
MODIFY_AUDIO_SETTINGS, ACCESS_NOTIFICATION_POLICY: MODIFY_AUDIO_SETTINGS, ACCESS_NOTIFICATION_POLICY:
From higher versions on this is required to be able to change, e.g. the ringtone or generally the sound settings. From higher versions on this is required to be able to change, e.g. the ringtone or generally the sound settings.
https://stackoverflow.com/questions/43123650/android-request-access-notification-policy-and-mute-phone/43127589#43127589 https://stackoverflow.com/questions/43123650/android-request-access-notification-policy-and-mute-phone/43127589#43127589
ACCESS_NOTIFICATION_POLICY is also included to prepare for a new trigger - to use notifications of other applications as trigger. But this feature has not been implemented, yet. ACCESS_NOTIFICATION_POLICY is also included for the trigger that reads other apps' notifications.
RECORD_AUDIO: For trigger "check background noise". Btw - my use case for this is: My phone will turn on sounds in the morning. During the week that is quite early. But what if I have a day off? Then it will monitor the background noise as an additional condition. If there's noise it's fairly certain I'm actually awake. Unfortunately Google deactivated this feature with Android 8. RECORD_AUDIO: For trigger "check background noise". Btw - my use case for this is: My phone will turn on sounds in the morning. During the week that is quite early. But what if I have a day off? Then it will monitor the background noise as an additional condition. If there's noise it's fairly certain I'm actually awake. Unfortunately Google deactivated this feature with Android 8.