Compare commits
113 Commits
Author | SHA1 | Date | |
---|---|---|---|
dce68d79bd | |||
397dadd8c7 | |||
c51c46707b | |||
d699285b5a | |||
cf3db22ffb | |||
f53abe2b23 | |||
ba2f96713d | |||
21d9351b2b | |||
a8bfc6f7ec | |||
71d9791603 | |||
d71177f3da | |||
eef6c3234a | |||
192142c76b | |||
9a2a0aa6a4 | |||
c18a880ad7 | |||
a845ea7c63 | |||
2d9695344b | |||
24d05e6d87 | |||
07b0513eae | |||
e445b787a9 | |||
82156059fa | |||
b976ff95b6 | |||
a4b2745b7b | |||
844be6a4a7 | |||
49a48fc371 | |||
722750b724 | |||
ab51eb3655 | |||
7b88e7a612 | |||
bb2f5c9842 | |||
883a7e8341 | |||
bfc0e3ac4f | |||
23ded3a851 | |||
6d363fd02d | |||
3c0f889db7 | |||
d018c27f0e | |||
7e36f0f32e | |||
666129de16 | |||
becdbd6546 | |||
d292988737 | |||
21ee06e9b1 | |||
f22e4854ee | |||
7182698b8a | |||
7fd8d1cfd0 | |||
943928089b | |||
f70e45701f | |||
9b33f13f66 | |||
2f3a33b1b8 | |||
6c8ca59e3f | |||
5ffb36a87f | |||
1560fd3343 | |||
a0ff8c80f0 | |||
1ea3bdaea3 | |||
f325b30917 | |||
8ce2a09b3b | |||
4a18a6ed19 | |||
9a8519d3e3 | |||
0a0399c2b0 | |||
3844079781 | |||
191ad904a3 | |||
e988cedf7c | |||
9a7f66fa22 | |||
c926c85dd0 | |||
cddd8cfac5 | |||
e57b888393 | |||
c922f8c7fc | |||
357c7f894f | |||
34091a7b73 | |||
8d26abdede | |||
8d42bb48d2 | |||
f79efa7739 | |||
d257c4ccb0 | |||
e39f0c2497 | |||
327a992cac | |||
9021b03732 | |||
514a9ae0e4 | |||
09298bce55 | |||
74f50d3e13 | |||
1946fb6b9f | |||
acc0f592d1 | |||
2e09ea1c90 | |||
769f227689 | |||
22533fcfee | |||
004ca6993a | |||
0bea81a630 | |||
88decce426 | |||
2341d714c0 | |||
34c0067736 | |||
e0c3b9d450 | |||
c134b15ab1 | |||
6ef6277976 | |||
10e6c74ba8 | |||
b6f3d928ae | |||
e898264178 | |||
0891dca98d | |||
8843a97b79 | |||
1c24af7bcb | |||
ee43e109da | |||
13bcb02ffc | |||
864ed2111e | |||
67e6a38ddc | |||
fb44196a0d | |||
7894504791 | |||
0df5342036 | |||
712a374adb | |||
80f8f9cfe2 | |||
1d9ed8b3ff | |||
5d6221888a | |||
56806f0349 | |||
7127ac45bc | |||
8a43741b21 | |||
b7ebf2cdcd | |||
054ab6d84b | |||
47b56d4978 |
117
.idea/codeStyles/Project.xml
generated
Normal file
@ -0,0 +1,117 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<codeStyleSettings language="XML">
|
||||
<option name="FORCE_REARRANGE_MODE" value="1" />
|
||||
<indentOptions>
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||
</indentOptions>
|
||||
<arrangement>
|
||||
<rules>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:android</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:id</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:name</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>name</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>style</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>ANDROID_ATTRIBUTE_ORDER</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>.*</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
</rules>
|
||||
</arrangement>
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
@ -0,0 +1,5 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
|
||||
</state>
|
||||
</component>
|
10
.idea/runConfigurations.xml
generated
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RunConfigurationProducerService">
|
||||
<option name="ignoredProducers">
|
||||
<set>
|
||||
<option value="com.android.tools.idea.compose.preview.runconfiguration.ComposePreviewRunConfigurationProducer" />
|
||||
</set>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
@ -11,8 +11,8 @@ android {
|
||||
compileSdkVersion 29
|
||||
buildToolsVersion '29.0.2'
|
||||
useLibrary 'org.apache.http.legacy'
|
||||
versionCode 100
|
||||
versionName "1.6.24"
|
||||
versionCode 107
|
||||
versionName "1.6.36"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
@ -40,23 +40,19 @@ android {
|
||||
googlePlayFlavor
|
||||
{
|
||||
dimension "version"
|
||||
// applicationIdSuffix ".googlePlay"
|
||||
versionNameSuffix "-googlePlay"
|
||||
targetSdkVersion 30
|
||||
targetSdkVersion 29
|
||||
}
|
||||
|
||||
fdroidFlavor
|
||||
{
|
||||
dimension "version"
|
||||
// applicationIdSuffix ".fdroid"
|
||||
// versionNameSuffix "-fdroid"
|
||||
targetSdkVersion 28
|
||||
}
|
||||
|
||||
apkFlavor
|
||||
{
|
||||
dimension "version"
|
||||
// applicationIdSuffix ".apk"
|
||||
versionNameSuffix "-apk"
|
||||
targetSdkVersion 28
|
||||
}
|
||||
@ -64,13 +60,18 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
googlePlayFlavorImplementation 'com.google.firebase:firebase-appindexing:19.2.0'
|
||||
googlePlayFlavorImplementation 'com.google.android.gms:play-services-location:17.1.0'
|
||||
googlePlayFlavorImplementation 'com.google.firebase:firebase-appindexing:20.0.0'
|
||||
googlePlayFlavorImplementation 'com.google.android.gms:play-services-location:18.0.0'
|
||||
|
||||
apkFlavorImplementation 'com.google.firebase:firebase-appindexing:19.2.0'
|
||||
apkFlavorImplementation 'com.google.android.gms:play-services-location:17.1.0'
|
||||
apkFlavorImplementation 'com.google.firebase:firebase-appindexing:20.0.0'
|
||||
apkFlavorImplementation 'com.google.android.gms:play-services-location:18.0.0'
|
||||
|
||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||
implementation 'com.linkedin.dexmaker:dexmaker:2.25.0'
|
||||
implementation 'org.apache.commons:commons-lang3:3.0'
|
||||
|
||||
//implementation "androidx.security:security-crypto:1.0.0"
|
||||
//implementation "androidx.security:security-identity-credential:1.0.0-alpha02"
|
||||
implementation 'androidx.appcompat:appcompat:1.3.0'
|
||||
implementation 'com.google.android.material:material:1.3.0'
|
||||
testImplementation 'junit:junit:4.+'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
|
||||
|
@ -5,13 +5,13 @@
|
||||
"kind": "Directory"
|
||||
},
|
||||
"applicationId": "com.jens.automation2",
|
||||
"variantName": "processGooglePlayFlavorReleaseResources",
|
||||
"variantName": "googlePlayFlavorRelease",
|
||||
"elements": [
|
||||
{
|
||||
"type": "SINGLE",
|
||||
"filters": [],
|
||||
"versionCode": 98,
|
||||
"versionName": "1.6.22-googlePlay",
|
||||
"versionCode": 106,
|
||||
"versionName": "1.6.35-googlePlay",
|
||||
"outputFile": "app-googlePlayFlavor-release.apk"
|
||||
}
|
||||
]
|
||||
|
@ -51,6 +51,7 @@
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
|
||||
<!-- <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />-->
|
||||
<uses-permission android:name="android.permission.GET_TASKS" />
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||
<uses-permission android:name="android.permission.NFC" />
|
||||
@ -62,8 +63,8 @@
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS"/>
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||
|
||||
<!-- Commented out because of Google Play policy -->
|
||||
<uses-permission android:name="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"/>
|
||||
<uses-permission android:name="com.wireguard.android.permission.CONTROL_TUNNELS"/>
|
||||
|
||||
<uses-feature
|
||||
android:name="android.hardware.telephony"
|
||||
@ -76,7 +77,7 @@
|
||||
android:allowBackup="true"
|
||||
android:allowClearUserData="true"
|
||||
android:icon="@drawable/gears"
|
||||
android:label="@string/title_activity_main"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme"
|
||||
android:networkSecurityConfig="@xml/network_security_config">
|
||||
|
||||
@ -95,15 +96,15 @@
|
||||
android:label="@string/app_name"></activity>
|
||||
<activity
|
||||
android:name=".ActivityManagePoi"
|
||||
android:label="@string/title_activity_main"></activity>
|
||||
android:label="@string/app_name"></activity>
|
||||
<activity
|
||||
android:name=".ActivitySettings"
|
||||
android:label="@string/title_activity_main"></activity>
|
||||
android:label="@string/app_name"></activity>
|
||||
|
||||
<service
|
||||
android:name=".AutomationService"
|
||||
android:exported="false"
|
||||
android:label="@string/title_activity_main" />
|
||||
android:label="@string/app_name" />
|
||||
|
||||
<receiver android:name=".receivers.StartupIntentReceiver" android:enabled="true" android:exported="true">
|
||||
<intent-filter>
|
||||
@ -136,12 +137,16 @@
|
||||
<receiver android:name=".receivers.TimeZoneListener" />
|
||||
|
||||
<activity android:name=".ActivityManageRule" />
|
||||
<activity android:name=".ActivityEditTriggerUrl" />
|
||||
<activity android:name=".ActivityManageActionTriggerUrl" />
|
||||
<activity android:name=".ActivityDisplayLongMessage" />
|
||||
<activity android:name=".ActivityEditSendTextMessage" />
|
||||
<activity android:name=".ActivityManageTimeFrame" />
|
||||
<activity android:name=".ActivityManageBrightnessSetting" />
|
||||
<activity android:name=".ActivityManageActionSendTextMessage" />
|
||||
<activity android:name=".ActivityManageActionPlaySound" />
|
||||
<activity android:name=".ActivityManageTriggerTimeFrame" />
|
||||
<activity android:name=".ActivityMaintenance" />
|
||||
<activity android:name=".ActivityManageTriggerPhoneCall" />
|
||||
<activity android:name=".ActivityManageActionBrightnessSetting" />
|
||||
<activity android:name=".ActivityHelp" />
|
||||
<activity android:name=".ActivityManageActionVibrate" />
|
||||
<activity
|
||||
android:name=".ActivityMainTabLayout"
|
||||
android:launchMode="singleTask">
|
||||
@ -178,13 +183,31 @@
|
||||
<activity android:name=".ActivityMainPoi" />
|
||||
<activity android:name=".ActivityMainRules" />
|
||||
<activity android:name=".ActivityGeneric" />
|
||||
<activity android:name=".ActivityManageStartActivity" />
|
||||
<activity android:name=".ActivityManageNfc" />
|
||||
<activity android:name=".ActivityEditSpeakText" />
|
||||
<activity android:name=".ActivityManageBluetoothTrigger" />
|
||||
<activity android:name=".ActivityManageActionStartActivity" />
|
||||
<activity android:name=".ActivityManageTriggerNfc" />
|
||||
<activity android:name=".ActivityManageActionSpeakText" />
|
||||
<activity android:name=".ActivityManageTriggerBluetooth" />
|
||||
<activity android:name=".ActivityMainProfiles" />
|
||||
<activity android:name=".ActivityManageProfile" />
|
||||
<activity android:name=".ActivityManageTriggerWifi" />
|
||||
<activity android:name=".ActivityVolumeTest" />
|
||||
<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>
|
||||
|
||||
|
||||
<!-- https://developer.android.com/about/versions/pie/android-9.0-changes-28#apache-p-->
|
||||
<uses-library android:name="org.apache.http.legacy" android:required="false"/>
|
||||
|
||||
|
||||
<service
|
||||
android:name=".receivers.ActivityDetectionReceiver"
|
||||
@ -194,15 +217,15 @@
|
||||
<meta-data
|
||||
android:name="com.google.android.gms.version"
|
||||
android:value="@integer/google_play_services_version" />
|
||||
|
||||
<activity android:name=".ActivityPermissions"></activity>
|
||||
|
||||
|
||||
<!-- https://developer.android.com/about/versions/pie/android-9.0-changes-28#apache-p-->
|
||||
<uses-library android:name="org.apache.http.legacy" android:required="false"/>
|
||||
|
||||
<service android:name=".location.GeofenceIntentService"/>
|
||||
|
||||
|
||||
<provider
|
||||
android:name=".FileShareProvider"
|
||||
android:authorities="com.jens.automation2"
|
||||
android:exported="true"
|
||||
/>
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
@ -1,13 +1,18 @@
|
||||
package com.jens.automation2;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Looper;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.google.android.gms.location.DetectedActivity;
|
||||
import com.jens.automation2.location.LocationProvider;
|
||||
import com.jens.automation2.location.WifiBroadcastReceiver;
|
||||
import com.jens.automation2.receivers.ActivityDetectionReceiver;
|
||||
import com.jens.automation2.receivers.BatteryReceiver;
|
||||
@ -16,6 +21,7 @@ import com.jens.automation2.receivers.ConnectivityReceiver;
|
||||
import com.jens.automation2.receivers.HeadphoneJackListener;
|
||||
import com.jens.automation2.receivers.NfcReceiver;
|
||||
import com.jens.automation2.receivers.NoiseListener;
|
||||
import com.jens.automation2.receivers.NotificationListener;
|
||||
import com.jens.automation2.receivers.PhoneStatusListener;
|
||||
import com.jens.automation2.receivers.ProcessListener;
|
||||
|
||||
@ -24,6 +30,10 @@ import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
import static com.jens.automation2.Trigger.triggerParameter2Split;
|
||||
import static com.jens.automation2.receivers.NotificationListener.EXTRA_TEXT;
|
||||
import static com.jens.automation2.receivers.NotificationListener.EXTRA_TITLE;
|
||||
|
||||
|
||||
public class Rule implements Comparable<Rule>
|
||||
{
|
||||
@ -42,9 +52,20 @@ public class Rule implements Comparable<Rule>
|
||||
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 ruleToggle = false; // rule will run again and do the opposite of its actions if applicable
|
||||
private Calendar lastExecution;
|
||||
|
||||
private static Date lastActivatedRuleActivationTime;
|
||||
|
||||
|
||||
public Calendar getLastExecution()
|
||||
{
|
||||
return lastExecution;
|
||||
}
|
||||
|
||||
public void setLastExecution(Calendar lastExecution)
|
||||
{
|
||||
this.lastExecution = lastExecution;
|
||||
}
|
||||
|
||||
public boolean isRuleToggle()
|
||||
{
|
||||
return ruleToggle;
|
||||
@ -114,6 +135,7 @@ public class Rule implements Comparable<Rule>
|
||||
{
|
||||
return this.getName();
|
||||
}
|
||||
@SuppressLint("NewApi")
|
||||
public String toStringLong()
|
||||
{
|
||||
String returnString = "";
|
||||
@ -153,6 +175,15 @@ public class Rule implements Comparable<Rule>
|
||||
Miscellaneous.logEvent("i", "Rule", "Creating rule: " + this.toString(), 3);
|
||||
ruleCollection.add(this);
|
||||
boolean returnValue = XmlFileInterface.writeFile();
|
||||
|
||||
try
|
||||
{
|
||||
XmlFileInterface.readFile();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Miscellaneous.logEvent("w", "Read file", Log.getStackTraceString(e), 3);
|
||||
}
|
||||
|
||||
if(returnValue)
|
||||
{
|
||||
@ -196,10 +227,23 @@ public class Rule implements Comparable<Rule>
|
||||
|
||||
return XmlFileInterface.writeFile();
|
||||
}
|
||||
|
||||
public boolean cloneRule(Context context)
|
||||
{
|
||||
Rule newRule = new Rule();
|
||||
newRule.setName(this.getName() + " - clone");
|
||||
newRule.setRuleActive(this.isRuleActive());
|
||||
newRule.setRuleToggle(this.isRuleToggle());
|
||||
|
||||
newRule.setTriggerSet(this.getTriggerSet());
|
||||
newRule.setActionSet(this.getActionSet());
|
||||
|
||||
return newRule.create(context);
|
||||
}
|
||||
|
||||
private boolean checkBeforeSaving(Context context, boolean changeExistingRule)
|
||||
{
|
||||
if(this.getName() == null | this.getName().length()==0)
|
||||
if(this.getName() == null || this.getName().length()==0)
|
||||
{
|
||||
Toast.makeText(context, context.getResources().getString(R.string.pleaseEnterValidName), Toast.LENGTH_LONG).show();
|
||||
return false;
|
||||
@ -394,13 +438,13 @@ public class Rule implements Comparable<Rule>
|
||||
&&
|
||||
Miscellaneous.compareTimes(nowTime, oneTrigger.getTimeFrame().getTriggerTimeStop()) > 0
|
||||
)
|
||||
|
|
||||
||
|
||||
// Other case, start time higher than end time, timeframe goes over midnight
|
||||
(
|
||||
Miscellaneous.compareTimes(oneTrigger.getTimeFrame().getTriggerTimeStart(), oneTrigger.getTimeFrame().getTriggerTimeStop()) < 0
|
||||
&&
|
||||
(Miscellaneous.compareTimes(oneTrigger.getTimeFrame().getTriggerTimeStart(), nowTime) >= 0
|
||||
|
|
||||
||
|
||||
Miscellaneous.compareTimes(nowTime, oneTrigger.getTimeFrame().getTriggerTimeStop()) > 0)
|
||||
)
|
||||
|
||||
@ -469,7 +513,7 @@ public class Rule implements Comparable<Rule>
|
||||
{
|
||||
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);
|
||||
return false;
|
||||
@ -477,7 +521,7 @@ public class Rule implements Comparable<Rule>
|
||||
}
|
||||
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);
|
||||
return false;
|
||||
@ -488,7 +532,7 @@ public class Rule implements Comparable<Rule>
|
||||
{
|
||||
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);
|
||||
return false;
|
||||
@ -496,7 +540,7 @@ public class Rule implements Comparable<Rule>
|
||||
}
|
||||
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);
|
||||
return false;
|
||||
@ -527,12 +571,12 @@ public class Rule implements Comparable<Rule>
|
||||
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Checking for wifi state", 4);
|
||||
if(oneTrigger.getTriggerParameter() == WifiBroadcastReceiver.lastConnectedState) // connected / disconnected
|
||||
{
|
||||
if(oneTrigger.getWifiName().length() > 0) // only check if any wifi name specified, otherwise any wifi will do
|
||||
if(oneTrigger.getTriggerParameter2().length() > 0) // only check if any wifi name specified, otherwise any wifi will do
|
||||
{
|
||||
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Wifi name specified, checking that.", 4);
|
||||
if(!WifiBroadcastReceiver.getLastWifiSsid().equals(oneTrigger.getWifiName()))
|
||||
if(!WifiBroadcastReceiver.getLastWifiSsid().equals(oneTrigger.getTriggerParameter2()))
|
||||
{
|
||||
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), String.format(context.getResources().getString(R.string.ruleDoesntApplyNotTheCorrectSsid), oneTrigger.getWifiName(), WifiBroadcastReceiver.getLastWifiSsid()), 3);
|
||||
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), String.format(context.getResources().getString(R.string.ruleDoesntApplyNotTheCorrectSsid), oneTrigger.getTriggerParameter2(), WifiBroadcastReceiver.getLastWifiSsid()), 3);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
@ -580,13 +624,29 @@ public class Rule implements Comparable<Rule>
|
||||
}
|
||||
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.phoneCall))
|
||||
{
|
||||
if(oneTrigger.getPhoneNumber().equals("any") | oneTrigger.getPhoneNumber().equals(PhoneStatusListener.getLastPhoneNumber()))
|
||||
String[] elements = oneTrigger.getTriggerParameter2().split(triggerParameter2Split);
|
||||
// state dir number
|
||||
|
||||
if(elements[2].equals(Trigger.triggerPhoneCallNumberAny) || Miscellaneous.comparePhoneNumbers(PhoneStatusListener.getLastPhoneNumber(), elements[2]) || (Miscellaneous.isRegularExpression(elements[2]) && PhoneStatusListener.getLastPhoneNumber().matches(elements[2])))
|
||||
{
|
||||
if(PhoneStatusListener.isInACall() == oneTrigger.getTriggerParameter())
|
||||
//if(PhoneStatusListener.isInACall() == oneTrigger.getTriggerParameter())
|
||||
if(
|
||||
(elements[0].equals(Trigger.triggerPhoneCallStateRinging) && PhoneStatusListener.getCurrentState() == TelephonyManager.CALL_STATE_RINGING)
|
||||
||
|
||||
(elements[0].equals(Trigger.triggerPhoneCallStateStarted) && PhoneStatusListener.getCurrentState() == TelephonyManager.CALL_STATE_OFFHOOK)
|
||||
||
|
||||
(elements[0].equals(Trigger.triggerPhoneCallStateStopped) && PhoneStatusListener.getCurrentState() == TelephonyManager.CALL_STATE_IDLE)
|
||||
)
|
||||
{
|
||||
if(oneTrigger.getPhoneDirection() == 0 | (oneTrigger.getPhoneDirection() == PhoneStatusListener.getLastPhoneDirection()))
|
||||
if(
|
||||
elements[1].equals(Trigger.triggerPhoneCallDirectionAny)
|
||||
||
|
||||
(elements[1].equals(Trigger.triggerPhoneCallDirectionIncoming) && PhoneStatusListener.getLastPhoneDirection() == 1)
|
||||
||
|
||||
(elements[1].equals(Trigger.triggerPhoneCallDirectionOutgoing) && PhoneStatusListener.getLastPhoneDirection() == 2)
|
||||
)
|
||||
{
|
||||
// Everything's allright
|
||||
// Trigger conditions are met
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -601,7 +661,10 @@ public class Rule implements Comparable<Rule>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Miscellaneous.logEvent("i", "Rule", "Rule doesn't apply. Wrong phone number. Demanded: " + oneTrigger.getPhoneNumber() + ", got: " + PhoneStatusListener.getLastPhoneNumber(), 4);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.nfcTag))
|
||||
{
|
||||
@ -648,109 +711,69 @@ public class Rule implements Comparable<Rule>
|
||||
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.bluetoothConnection))
|
||||
{
|
||||
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Checking for bluetooth...", 4);
|
||||
|
||||
// if( // 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(BluetoothReceiver.isAnyDeviceConnected() != oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
else if((oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)))
|
||||
{
|
||||
if(BluetoothReceiver.isAnyDeviceConnected() != oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// range
|
||||
if(BluetoothReceiver.isAnyDeviceInRange() != oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(oneTrigger.getBluetoothDeviceAddress().equals("<none>"))
|
||||
if(oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED))
|
||||
{
|
||||
if(oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED))
|
||||
{
|
||||
if(BluetoothReceiver.isAnyDeviceConnected() == oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
else if((oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)))
|
||||
{
|
||||
if(BluetoothReceiver.isAnyDeviceConnected() == oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// range
|
||||
if(BluetoothReceiver.isAnyDeviceInRange() == oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
if(BluetoothReceiver.isAnyDeviceConnected() != oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
else if(oneTrigger.getBluetoothDeviceAddress().length() > 0)
|
||||
else if((oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)))
|
||||
{
|
||||
if(oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED))
|
||||
{
|
||||
if(BluetoothReceiver.isDeviceCurrentlyConnected(BluetoothReceiver.getDeviceByAddress(oneTrigger.getBluetoothDeviceAddress())) != oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
else if((oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)))
|
||||
{
|
||||
if(BluetoothReceiver.isDeviceCurrentlyConnected(BluetoothReceiver.getDeviceByAddress(oneTrigger.getBluetoothDeviceAddress())) != oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// range
|
||||
if(BluetoothReceiver.isDeviceInRange(BluetoothReceiver.getDeviceByAddress(oneTrigger.getBluetoothDeviceAddress())) != oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
if(BluetoothReceiver.isAnyDeviceConnected() != oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyStateNotCorrect), 3);
|
||||
return false;
|
||||
// range
|
||||
if(BluetoothReceiver.isAnyDeviceInRange() != oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(oneTrigger.getBluetoothDeviceAddress().equals("<none>"))
|
||||
{
|
||||
if(oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED))
|
||||
{
|
||||
if(BluetoothReceiver.isAnyDeviceConnected() == oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
else if((oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)))
|
||||
{
|
||||
if(BluetoothReceiver.isAnyDeviceConnected() == oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// range
|
||||
if(BluetoothReceiver.isAnyDeviceInRange() == oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(oneTrigger.getBluetoothDeviceAddress().length() > 0)
|
||||
{
|
||||
if(oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED))
|
||||
{
|
||||
if(BluetoothReceiver.isDeviceCurrentlyConnected(BluetoothReceiver.getDeviceByAddress(oneTrigger.getBluetoothDeviceAddress())) != oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
else if((oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)))
|
||||
{
|
||||
if(BluetoothReceiver.isDeviceCurrentlyConnected(BluetoothReceiver.getDeviceByAddress(oneTrigger.getBluetoothDeviceAddress())) != oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// range
|
||||
if(BluetoothReceiver.isDeviceInRange(BluetoothReceiver.getDeviceByAddress(oneTrigger.getBluetoothDeviceAddress())) != oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyStateNotCorrect), 3);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.headsetPlugged))
|
||||
{
|
||||
@ -763,6 +786,109 @@ public class Rule implements Comparable<Rule>
|
||||
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;
|
||||
@ -771,9 +897,11 @@ public class Rule implements Comparable<Rule>
|
||||
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), String.format(context.getResources().getString(R.string.ruleIsDeactivatedCantApply), this.getName()), 3);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private class ActivateRuleTask extends AsyncTask<Object, String, Void>
|
||||
{
|
||||
boolean wasActivated = false;
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Object... params)
|
||||
{
|
||||
@ -788,7 +916,7 @@ public class Rule implements Comparable<Rule>
|
||||
if (Looper.myLooper() == null)
|
||||
Looper.prepare();
|
||||
|
||||
activateInternally((AutomationService)params[0], (Boolean)params[1]);
|
||||
wasActivated = activateInternally((AutomationService)params[0], (Boolean)params[1]);
|
||||
|
||||
return null;
|
||||
}
|
||||
@ -806,27 +934,35 @@ public class Rule implements Comparable<Rule>
|
||||
@Override
|
||||
protected void onPostExecute(Void result)
|
||||
{
|
||||
AutomationService.updateNotification();
|
||||
ActivityMainScreen.updateMainScreen();
|
||||
super.onPostExecute(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();
|
||||
ActivityMainScreen.updateMainScreen();
|
||||
super.onPostExecute(result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Will activate the rule. Should be called by a separate execution thread
|
||||
* @param automationService
|
||||
*/
|
||||
protected void activateInternally(AutomationService automationService, boolean force)
|
||||
protected boolean activateInternally(AutomationService automationService, boolean force)
|
||||
{
|
||||
boolean isActuallyToggable = isActuallyToggable();
|
||||
|
||||
|
||||
boolean notLastActive = getLastActivatedRule() == null || !getLastActivatedRule().equals(Rule.this);
|
||||
boolean doToggle = ruleToggle && isActuallyToggable;
|
||||
|
||||
if(notLastActive | force | doToggle)
|
||||
|
||||
if(notLastActive || force || doToggle)
|
||||
{
|
||||
String message;
|
||||
if(!doToggle)
|
||||
message = String.format(automationService.getResources().getString(R.string.ruleActivate), Rule.this.getName());
|
||||
message = String.format(automationService.getResources().getString(R.string.ruleActivate), Rule.this.getName());
|
||||
else
|
||||
message = String.format(automationService.getResources().getString(R.string.ruleActivateToggle), Rule.this.getName());
|
||||
Miscellaneous.logEvent("i", "Rule", message, 2);
|
||||
@ -834,10 +970,19 @@ public class Rule implements Comparable<Rule>
|
||||
// Toast.makeText(automationService, message, Toast.LENGTH_LONG).show();
|
||||
if(Settings.startNewThreadForRuleActivation)
|
||||
publishProgress(message);
|
||||
|
||||
|
||||
for(int i = 0; i< Rule.this.getActionSet().size(); i++)
|
||||
Rule.this.getActionSet().get(i).run(automationService, doToggle);
|
||||
|
||||
{
|
||||
try
|
||||
{
|
||||
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)
|
||||
try
|
||||
{
|
||||
@ -862,9 +1007,12 @@ public class Rule implements Comparable<Rule>
|
||||
else
|
||||
{
|
||||
Miscellaneous.logEvent("i", "Rule", "Request to activate rule " + Rule.this.getName() + ", but it is the last one that was activated. Won't do it again.", 3);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public void activate(AutomationService automationService, boolean force)
|
||||
{
|
||||
@ -963,7 +1111,7 @@ public class Rule implements Comparable<Rule>
|
||||
if(oneTrigger.getTimeFrame().getTriggerTimeStart().getTime() > oneTrigger.getTimeFrame().getTriggerTimeStop().getTime())
|
||||
{
|
||||
Miscellaneous.logEvent("i", "Timeframe search", "Rule goes over midnight.", 5);
|
||||
if(oneTrigger.getTimeFrame().getTriggerTimeStart().getTime() <= searchTime.getTime() | searchTime.getTime() <= oneTrigger.getTimeFrame().getTriggerTimeStop().getTime()+20000) //add 20 seconds because of delay
|
||||
if(oneTrigger.getTimeFrame().getTriggerTimeStart().getTime() <= searchTime.getTime() || searchTime.getTime() <= oneTrigger.getTimeFrame().getTriggerTimeStop().getTime()+20000) //add 20 seconds because of delay
|
||||
{
|
||||
ruleCandidates.add(oneRule);
|
||||
break innerloop; //if the poi is found we don't need to search the other triggers in the same rule
|
||||
@ -1234,10 +1382,10 @@ public class Rule implements Comparable<Rule>
|
||||
return ruleCandidates;
|
||||
}
|
||||
|
||||
public static ArrayList<Rule> findRuleCandidatesByPhoneCall(boolean triggerParameter)
|
||||
public static ArrayList<Rule> findRuleCandidatesByPhoneCall(String direction)
|
||||
{
|
||||
ArrayList<Rule> ruleCandidates = new ArrayList<Rule>();
|
||||
|
||||
|
||||
for(Rule oneRule : ruleCollection)
|
||||
{
|
||||
innerloop:
|
||||
@ -1245,7 +1393,8 @@ public class Rule implements Comparable<Rule>
|
||||
{
|
||||
if(oneTrigger.getTriggerType() == Trigger.Trigger_Enum.phoneCall)
|
||||
{
|
||||
if(oneTrigger.getTriggerParameter() == triggerParameter)
|
||||
String[] elements = oneTrigger.getTriggerParameter2().split(triggerParameter2Split);
|
||||
if(elements[1].equals(Trigger.triggerPhoneCallDirectionAny) || elements[1].equals(direction))
|
||||
{
|
||||
ruleCandidates.add(oneRule);
|
||||
break innerloop; //we don't need to search the other triggers in the same rule
|
||||
@ -1253,7 +1402,7 @@ public class Rule implements Comparable<Rule>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return ruleCandidates;
|
||||
}
|
||||
|
||||
@ -1279,6 +1428,26 @@ public class Rule implements Comparable<Rule>
|
||||
|
||||
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()
|
||||
{
|
||||
|
@ -60,6 +60,8 @@
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS"/>
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||
<uses-permission android:name="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"/>
|
||||
<uses-permission android:name="com.wireguard.android.permission.CONTROL_TUNNELS"/>
|
||||
|
||||
<uses-feature
|
||||
android:name="android.hardware.telephony"
|
||||
@ -72,7 +74,7 @@
|
||||
android:allowBackup="true"
|
||||
android:allowClearUserData="true"
|
||||
android:icon="@drawable/gears"
|
||||
android:label="@string/title_activity_main"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme"
|
||||
android:networkSecurityConfig="@xml/network_security_config">
|
||||
|
||||
@ -91,15 +93,15 @@
|
||||
android:label="@string/app_name"></activity>
|
||||
<activity
|
||||
android:name=".ActivityManagePoi"
|
||||
android:label="@string/title_activity_main"></activity>
|
||||
android:label="@string/app_name"></activity>
|
||||
<activity
|
||||
android:name=".ActivitySettings"
|
||||
android:label="@string/title_activity_main"></activity>
|
||||
android:label="@string/app_name"></activity>
|
||||
|
||||
<service
|
||||
android:name=".AutomationService"
|
||||
android:exported="false"
|
||||
android:label="@string/title_activity_main" />
|
||||
android:label="@string/app_name" />
|
||||
|
||||
<receiver android:name=".receivers.StartupIntentReceiver" android:enabled="true" android:exported="true">
|
||||
<intent-filter>
|
||||
@ -132,12 +134,16 @@
|
||||
<receiver android:name=".receivers.TimeZoneListener" />
|
||||
|
||||
<activity android:name=".ActivityManageRule" />
|
||||
<activity android:name=".ActivityEditTriggerUrl" />
|
||||
<activity android:name=".ActivityManageActionTriggerUrl" />
|
||||
<activity android:name=".ActivityDisplayLongMessage" />
|
||||
<activity android:name=".ActivityEditSendTextMessage" />
|
||||
<activity android:name=".ActivityManageTimeFrame" />
|
||||
<activity android:name=".ActivityManageBrightnessSetting" />
|
||||
<activity android:name=".ActivityManageActionSendTextMessage" />
|
||||
<activity android:name=".ActivityManageActionPlaySound" />
|
||||
<activity android:name=".ActivityManageTriggerTimeFrame" />
|
||||
<activity android:name=".ActivityMaintenance" />
|
||||
<activity android:name=".ActivityManageTriggerPhoneCall" />
|
||||
<activity android:name=".ActivityManageActionBrightnessSetting" />
|
||||
<activity android:name=".ActivityHelp" />
|
||||
<activity android:name=".ActivityManageActionVibrate" />
|
||||
<activity
|
||||
android:name=".ActivityMainTabLayout"
|
||||
android:launchMode="singleTask">
|
||||
@ -173,18 +179,40 @@
|
||||
<activity android:name=".ActivityMainPoi" />
|
||||
<activity android:name=".ActivityMainRules" />
|
||||
<activity android:name=".ActivityGeneric" />
|
||||
<activity android:name=".ActivityManageStartActivity" />
|
||||
<activity android:name=".ActivityManageNfc" />
|
||||
<activity android:name=".ActivityEditSpeakText" />
|
||||
<activity android:name=".ActivityManageBluetoothTrigger" />
|
||||
<activity android:name=".ActivityManageActionStartActivity" />
|
||||
<activity android:name=".ActivityManageTriggerNfc" />
|
||||
<activity android:name=".ActivityManageActionSpeakText" />
|
||||
<activity android:name=".ActivityManageActionPlaySound" />
|
||||
<activity android:name=".ActivityManageTriggerBluetooth" />
|
||||
<activity android:name=".ActivityMainProfiles" />
|
||||
<activity android:name=".ActivityManageProfile" />
|
||||
<activity android:name=".ActivityManageTriggerWifi" />
|
||||
<activity android:name=".ActivityVolumeTest" />
|
||||
|
||||
<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>
|
||||
|
||||
<activity android:name=".ActivityPermissions" />
|
||||
|
||||
|
||||
<!-- https://developer.android.com/about/versions/pie/android-9.0-changes-28#apache-p-->
|
||||
<uses-library android:name="org.apache.http.legacy" android:required="false"/>
|
||||
|
||||
<provider
|
||||
android:name=".FileShareProvider"
|
||||
android:authorities="com.jens.automation2"
|
||||
android:exported="true"
|
||||
/>
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
@ -1,12 +1,17 @@
|
||||
package com.jens.automation2;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Looper;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.jens.automation2.location.LocationProvider;
|
||||
import com.jens.automation2.location.WifiBroadcastReceiver;
|
||||
import com.jens.automation2.receivers.BatteryReceiver;
|
||||
import com.jens.automation2.receivers.BluetoothReceiver;
|
||||
@ -14,6 +19,7 @@ import com.jens.automation2.receivers.ConnectivityReceiver;
|
||||
import com.jens.automation2.receivers.HeadphoneJackListener;
|
||||
import com.jens.automation2.receivers.NfcReceiver;
|
||||
import com.jens.automation2.receivers.NoiseListener;
|
||||
import com.jens.automation2.receivers.NotificationListener;
|
||||
import com.jens.automation2.receivers.PhoneStatusListener;
|
||||
import com.jens.automation2.receivers.ProcessListener;
|
||||
|
||||
@ -22,6 +28,9 @@ import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
import static com.jens.automation2.Trigger.triggerParameter2Split;
|
||||
import static com.jens.automation2.receivers.NotificationListener.EXTRA_TEXT;
|
||||
import static com.jens.automation2.receivers.NotificationListener.EXTRA_TITLE;
|
||||
|
||||
public class Rule implements Comparable<Rule>
|
||||
{
|
||||
@ -40,8 +49,19 @@ public class Rule implements Comparable<Rule>
|
||||
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 ruleToggle = false; // rule will run again and do the opposite of its actions if applicable
|
||||
private Calendar lastExecution;
|
||||
|
||||
private static Date lastActivatedRuleActivationTime;
|
||||
|
||||
public Calendar getLastExecution()
|
||||
{
|
||||
return lastExecution;
|
||||
}
|
||||
|
||||
public void setLastExecution(Calendar lastExecution)
|
||||
{
|
||||
this.lastExecution = lastExecution;
|
||||
}
|
||||
|
||||
public boolean isRuleToggle()
|
||||
{
|
||||
@ -112,6 +132,7 @@ public class Rule implements Comparable<Rule>
|
||||
{
|
||||
return this.getName();
|
||||
}
|
||||
@SuppressLint("NewApi")
|
||||
public String toStringLong()
|
||||
{
|
||||
String returnString = "";
|
||||
@ -151,6 +172,15 @@ public class Rule implements Comparable<Rule>
|
||||
Miscellaneous.logEvent("i", "Rule", "Creating rule: " + this.toString(), 3);
|
||||
ruleCollection.add(this);
|
||||
boolean returnValue = XmlFileInterface.writeFile();
|
||||
|
||||
try
|
||||
{
|
||||
XmlFileInterface.readFile();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Miscellaneous.logEvent("w", "Read file", Log.getStackTraceString(e), 3);
|
||||
}
|
||||
|
||||
if(returnValue)
|
||||
{
|
||||
@ -197,7 +227,7 @@ public class Rule implements Comparable<Rule>
|
||||
|
||||
private boolean checkBeforeSaving(Context context, boolean changeExistingRule)
|
||||
{
|
||||
if(this.getName() == null | this.getName().length()==0)
|
||||
if(this.getName() == null || this.getName().length()==0)
|
||||
{
|
||||
Toast.makeText(context, context.getResources().getString(R.string.pleaseEnterValidName), Toast.LENGTH_LONG).show();
|
||||
return false;
|
||||
@ -392,13 +422,13 @@ public class Rule implements Comparable<Rule>
|
||||
&&
|
||||
Miscellaneous.compareTimes(nowTime, oneTrigger.getTimeFrame().getTriggerTimeStop()) > 0
|
||||
)
|
||||
|
|
||||
||
|
||||
// Other case, start time higher than end time, timeframe goes over midnight
|
||||
(
|
||||
Miscellaneous.compareTimes(oneTrigger.getTimeFrame().getTriggerTimeStart(), oneTrigger.getTimeFrame().getTriggerTimeStop()) < 0
|
||||
&&
|
||||
(Miscellaneous.compareTimes(oneTrigger.getTimeFrame().getTriggerTimeStart(), nowTime) >= 0
|
||||
|
|
||||
||
|
||||
Miscellaneous.compareTimes(nowTime, oneTrigger.getTimeFrame().getTriggerTimeStop()) > 0)
|
||||
)
|
||||
|
||||
@ -467,7 +497,7 @@ public class Rule implements Comparable<Rule>
|
||||
{
|
||||
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);
|
||||
return false;
|
||||
@ -475,7 +505,7 @@ public class Rule implements Comparable<Rule>
|
||||
}
|
||||
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);
|
||||
return false;
|
||||
@ -486,7 +516,7 @@ public class Rule implements Comparable<Rule>
|
||||
{
|
||||
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);
|
||||
return false;
|
||||
@ -494,7 +524,7 @@ public class Rule implements Comparable<Rule>
|
||||
}
|
||||
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);
|
||||
return false;
|
||||
@ -525,12 +555,12 @@ public class Rule implements Comparable<Rule>
|
||||
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Checking for wifi state", 4);
|
||||
if(oneTrigger.getTriggerParameter() == WifiBroadcastReceiver.lastConnectedState) // connected / disconnected
|
||||
{
|
||||
if(oneTrigger.getWifiName().length() > 0) // only check if any wifi name specified, otherwise any wifi will do
|
||||
if(oneTrigger.getTriggerParameter2().length() > 0) // only check if any wifi name specified, otherwise any wifi will do
|
||||
{
|
||||
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Wifi name specified, checking that.", 4);
|
||||
if(!WifiBroadcastReceiver.getLastWifiSsid().equals(oneTrigger.getWifiName()))
|
||||
if(!WifiBroadcastReceiver.getLastWifiSsid().equals(oneTrigger.getTriggerParameter2()))
|
||||
{
|
||||
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), String.format(context.getResources().getString(R.string.ruleDoesntApplyNotTheCorrectSsid), oneTrigger.getWifiName(), WifiBroadcastReceiver.getLastWifiSsid()), 3);
|
||||
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), String.format(context.getResources().getString(R.string.ruleDoesntApplyNotTheCorrectSsid), oneTrigger.getTriggerParameter2(), WifiBroadcastReceiver.getLastWifiSsid()), 3);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
@ -578,13 +608,29 @@ public class Rule implements Comparable<Rule>
|
||||
}
|
||||
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.phoneCall))
|
||||
{
|
||||
if(oneTrigger.getPhoneNumber().equals("any") | oneTrigger.getPhoneNumber().equals(PhoneStatusListener.getLastPhoneNumber()))
|
||||
String[] elements = oneTrigger.getTriggerParameter2().split(triggerParameter2Split);
|
||||
// state dir number
|
||||
|
||||
if(elements[2].equals(Trigger.triggerPhoneCallNumberAny) || Miscellaneous.comparePhoneNumbers(PhoneStatusListener.getLastPhoneNumber(), elements[2]) || (Miscellaneous.isRegularExpression(elements[2]) && PhoneStatusListener.getLastPhoneNumber().matches(elements[2])))
|
||||
{
|
||||
if(PhoneStatusListener.isInACall() == oneTrigger.getTriggerParameter())
|
||||
//if(PhoneStatusListener.isInACall() == oneTrigger.getTriggerParameter())
|
||||
if(
|
||||
(elements[0].equals(Trigger.triggerPhoneCallStateRinging) && PhoneStatusListener.getCurrentState() == TelephonyManager.CALL_STATE_RINGING)
|
||||
||
|
||||
(elements[0].equals(Trigger.triggerPhoneCallStateStarted) && PhoneStatusListener.getCurrentState() == TelephonyManager.CALL_STATE_OFFHOOK)
|
||||
||
|
||||
(elements[0].equals(Trigger.triggerPhoneCallStateStopped) && PhoneStatusListener.getCurrentState() == TelephonyManager.CALL_STATE_IDLE)
|
||||
)
|
||||
{
|
||||
if(oneTrigger.getPhoneDirection() == 0 | (oneTrigger.getPhoneDirection() == PhoneStatusListener.getLastPhoneDirection()))
|
||||
if(
|
||||
elements[1].equals(Trigger.triggerPhoneCallDirectionAny)
|
||||
||
|
||||
(elements[1].equals(Trigger.triggerPhoneCallDirectionIncoming) && PhoneStatusListener.getLastPhoneDirection() == 1)
|
||||
||
|
||||
(elements[1].equals(Trigger.triggerPhoneCallDirectionOutgoing) && PhoneStatusListener.getLastPhoneDirection() == 2)
|
||||
)
|
||||
{
|
||||
// Everything's allright
|
||||
// Trigger conditions are met
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -599,7 +645,10 @@ public class Rule implements Comparable<Rule>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Miscellaneous.logEvent("i", "Rule", "Rule doesn't apply. Wrong phone number. Demanded: " + oneTrigger.getPhoneNumber() + ", got: " + PhoneStatusListener.getLastPhoneNumber(), 4);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.nfcTag))
|
||||
{
|
||||
@ -617,109 +666,69 @@ public class Rule implements Comparable<Rule>
|
||||
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.bluetoothConnection))
|
||||
{
|
||||
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Checking for bluetooth...", 4);
|
||||
|
||||
// if( // 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(BluetoothReceiver.isAnyDeviceConnected() != oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
else if((oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)))
|
||||
{
|
||||
if(BluetoothReceiver.isAnyDeviceConnected() != oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// range
|
||||
if(BluetoothReceiver.isAnyDeviceInRange() != oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(oneTrigger.getBluetoothDeviceAddress().equals("<none>"))
|
||||
if(oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED))
|
||||
{
|
||||
if(oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED))
|
||||
{
|
||||
if(BluetoothReceiver.isAnyDeviceConnected() == oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
else if((oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)))
|
||||
{
|
||||
if(BluetoothReceiver.isAnyDeviceConnected() == oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// range
|
||||
if(BluetoothReceiver.isAnyDeviceInRange() == oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
if(BluetoothReceiver.isAnyDeviceConnected() != oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
else if(oneTrigger.getBluetoothDeviceAddress().length() > 0)
|
||||
else if((oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)))
|
||||
{
|
||||
if(oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED))
|
||||
{
|
||||
if(BluetoothReceiver.isDeviceCurrentlyConnected(BluetoothReceiver.getDeviceByAddress(oneTrigger.getBluetoothDeviceAddress())) != oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
else if((oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)))
|
||||
{
|
||||
if(BluetoothReceiver.isDeviceCurrentlyConnected(BluetoothReceiver.getDeviceByAddress(oneTrigger.getBluetoothDeviceAddress())) != oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// range
|
||||
if(BluetoothReceiver.isDeviceInRange(BluetoothReceiver.getDeviceByAddress(oneTrigger.getBluetoothDeviceAddress())) != oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
if(BluetoothReceiver.isAnyDeviceConnected() != oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyStateNotCorrect), 3);
|
||||
return false;
|
||||
// range
|
||||
if(BluetoothReceiver.isAnyDeviceInRange() != oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(oneTrigger.getBluetoothDeviceAddress().equals("<none>"))
|
||||
{
|
||||
if(oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED))
|
||||
{
|
||||
if(BluetoothReceiver.isAnyDeviceConnected() == oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
else if((oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)))
|
||||
{
|
||||
if(BluetoothReceiver.isAnyDeviceConnected() == oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// range
|
||||
if(BluetoothReceiver.isAnyDeviceInRange() == oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(oneTrigger.getBluetoothDeviceAddress().length() > 0)
|
||||
{
|
||||
if(oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED))
|
||||
{
|
||||
if(BluetoothReceiver.isDeviceCurrentlyConnected(BluetoothReceiver.getDeviceByAddress(oneTrigger.getBluetoothDeviceAddress())) != oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
else if((oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)))
|
||||
{
|
||||
if(BluetoothReceiver.isDeviceCurrentlyConnected(BluetoothReceiver.getDeviceByAddress(oneTrigger.getBluetoothDeviceAddress())) != oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// range
|
||||
if(BluetoothReceiver.isDeviceInRange(BluetoothReceiver.getDeviceByAddress(oneTrigger.getBluetoothDeviceAddress())) != oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyStateNotCorrect), 3);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.headsetPlugged))
|
||||
{
|
||||
@ -732,6 +741,109 @@ public class Rule implements Comparable<Rule>
|
||||
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;
|
||||
@ -743,6 +855,8 @@ public class Rule implements Comparable<Rule>
|
||||
|
||||
private class ActivateRuleTask extends AsyncTask<Object, String, Void>
|
||||
{
|
||||
boolean wasActivated = false;
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Object... params)
|
||||
{
|
||||
@ -757,7 +871,7 @@ public class Rule implements Comparable<Rule>
|
||||
if (Looper.myLooper() == null)
|
||||
Looper.prepare();
|
||||
|
||||
activateInternally((AutomationService)params[0], (Boolean)params[1]);
|
||||
wasActivated = activateInternally((AutomationService)params[0], (Boolean)params[1]);
|
||||
|
||||
return null;
|
||||
}
|
||||
@ -775,27 +889,35 @@ public class Rule implements Comparable<Rule>
|
||||
@Override
|
||||
protected void onPostExecute(Void result)
|
||||
{
|
||||
AutomationService.updateNotification();
|
||||
ActivityMainScreen.updateMainScreen();
|
||||
super.onPostExecute(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();
|
||||
ActivityMainScreen.updateMainScreen();
|
||||
super.onPostExecute(result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Will activate the rule. Should be called by a separate execution thread
|
||||
* @param automationService
|
||||
*/
|
||||
protected void activateInternally(AutomationService automationService, boolean force)
|
||||
protected boolean activateInternally(AutomationService automationService, boolean force)
|
||||
{
|
||||
boolean isActuallyToggable = isActuallyToggable();
|
||||
|
||||
|
||||
boolean notLastActive = getLastActivatedRule() == null || !getLastActivatedRule().equals(Rule.this);
|
||||
boolean doToggle = ruleToggle && isActuallyToggable;
|
||||
|
||||
if(notLastActive | force | doToggle)
|
||||
|
||||
if(notLastActive || force || doToggle)
|
||||
{
|
||||
String message;
|
||||
if(!doToggle)
|
||||
message = String.format(automationService.getResources().getString(R.string.ruleActivate), Rule.this.getName());
|
||||
message = String.format(automationService.getResources().getString(R.string.ruleActivate), Rule.this.getName());
|
||||
else
|
||||
message = String.format(automationService.getResources().getString(R.string.ruleActivateToggle), Rule.this.getName());
|
||||
Miscellaneous.logEvent("i", "Rule", message, 2);
|
||||
@ -803,10 +925,19 @@ public class Rule implements Comparable<Rule>
|
||||
// Toast.makeText(automationService, message, Toast.LENGTH_LONG).show();
|
||||
if(Settings.startNewThreadForRuleActivation)
|
||||
publishProgress(message);
|
||||
|
||||
|
||||
for(int i = 0; i< Rule.this.getActionSet().size(); i++)
|
||||
Rule.this.getActionSet().get(i).run(automationService, doToggle);
|
||||
|
||||
{
|
||||
try
|
||||
{
|
||||
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)
|
||||
try
|
||||
{
|
||||
@ -831,9 +962,12 @@ public class Rule implements Comparable<Rule>
|
||||
else
|
||||
{
|
||||
Miscellaneous.logEvent("i", "Rule", "Request to activate rule " + Rule.this.getName() + ", but it is the last one that was activated. Won't do it again.", 3);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public void activate(AutomationService automationService, boolean force)
|
||||
{
|
||||
@ -932,7 +1066,7 @@ public class Rule implements Comparable<Rule>
|
||||
if(oneTrigger.getTimeFrame().getTriggerTimeStart().getTime() > oneTrigger.getTimeFrame().getTriggerTimeStop().getTime())
|
||||
{
|
||||
Miscellaneous.logEvent("i", "Timeframe search", "Rule goes over midnight.", 5);
|
||||
if(oneTrigger.getTimeFrame().getTriggerTimeStart().getTime() <= searchTime.getTime() | searchTime.getTime() <= oneTrigger.getTimeFrame().getTriggerTimeStop().getTime()+20000) //add 20 seconds because of delay
|
||||
if(oneTrigger.getTimeFrame().getTriggerTimeStart().getTime() <= searchTime.getTime() || searchTime.getTime() <= oneTrigger.getTimeFrame().getTriggerTimeStop().getTime()+20000) //add 20 seconds because of delay
|
||||
{
|
||||
ruleCandidates.add(oneRule);
|
||||
break innerloop; //if the poi is found we don't need to search the other triggers in the same rule
|
||||
@ -1203,10 +1337,10 @@ public class Rule implements Comparable<Rule>
|
||||
return ruleCandidates;
|
||||
}
|
||||
|
||||
public static ArrayList<Rule> findRuleCandidatesByPhoneCall(boolean triggerParameter)
|
||||
public static ArrayList<Rule> findRuleCandidatesByPhoneCall(String direction)
|
||||
{
|
||||
ArrayList<Rule> ruleCandidates = new ArrayList<Rule>();
|
||||
|
||||
|
||||
for(Rule oneRule : ruleCollection)
|
||||
{
|
||||
innerloop:
|
||||
@ -1214,7 +1348,8 @@ public class Rule implements Comparable<Rule>
|
||||
{
|
||||
if(oneTrigger.getTriggerType() == Trigger.Trigger_Enum.phoneCall)
|
||||
{
|
||||
if(oneTrigger.getTriggerParameter() == triggerParameter)
|
||||
String[] elements = oneTrigger.getTriggerParameter2().split(triggerParameter2Split);
|
||||
if(elements[1].equals(Trigger.triggerPhoneCallDirectionAny) || elements[1].equals(direction))
|
||||
{
|
||||
ruleCandidates.add(oneRule);
|
||||
break innerloop; //we don't need to search the other triggers in the same rule
|
||||
@ -1222,7 +1357,7 @@ public class Rule implements Comparable<Rule>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return ruleCandidates;
|
||||
}
|
||||
|
||||
@ -1248,6 +1383,26 @@ public class Rule implements Comparable<Rule>
|
||||
|
||||
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()
|
||||
{
|
||||
|
@ -61,12 +61,14 @@
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS"/>
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||
<uses-permission android:name="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"/>
|
||||
<uses-permission android:name="com.wireguard.android.permission.CONTROL_TUNNELS"/>
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:allowClearUserData="true"
|
||||
android:icon="@drawable/gears"
|
||||
android:label="@string/title_activity_main"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme"
|
||||
android:networkSecurityConfig="@xml/network_security_config">
|
||||
|
||||
@ -85,15 +87,15 @@
|
||||
android:label="@string/app_name"></activity>
|
||||
<activity
|
||||
android:name=".ActivityManagePoi"
|
||||
android:label="@string/title_activity_main"></activity>
|
||||
android:label="@string/app_name"></activity>
|
||||
<activity
|
||||
android:name=".ActivitySettings"
|
||||
android:label="@string/title_activity_main"></activity>
|
||||
android:label="@string/app_name"></activity>
|
||||
|
||||
<service
|
||||
android:name=".AutomationService"
|
||||
android:exported="false"
|
||||
android:label="@string/title_activity_main" />
|
||||
android:label="@string/app_name" />
|
||||
|
||||
<receiver android:name=".receivers.StartupIntentReceiver" android:enabled="true" android:exported="true">
|
||||
<intent-filter>
|
||||
@ -126,12 +128,16 @@
|
||||
<receiver android:name=".receivers.TimeZoneListener" />
|
||||
|
||||
<activity android:name=".ActivityManageRule" />
|
||||
<activity android:name=".ActivityEditTriggerUrl" />
|
||||
<activity android:name=".ActivityManageActionTriggerUrl" />
|
||||
<activity android:name=".ActivityDisplayLongMessage" />
|
||||
<activity android:name=".ActivityEditSendTextMessage" />
|
||||
<activity android:name=".ActivityManageTimeFrame" />
|
||||
<activity android:name=".ActivityManageBrightnessSetting" />
|
||||
<activity android:name=".ActivityManageActionSendTextMessage" />
|
||||
<activity android:name=".ActivityManageActionPlaySound" />
|
||||
<activity android:name=".ActivityManageTriggerTimeFrame" />
|
||||
<activity android:name=".ActivityMaintenance" />
|
||||
<activity android:name=".ActivityManageTriggerPhoneCall" />
|
||||
<activity android:name=".ActivityManageActionBrightnessSetting" />
|
||||
<activity android:name=".ActivityHelp" />
|
||||
<activity android:name=".ActivityManageActionVibrate" />
|
||||
<activity
|
||||
android:name=".ActivityMainTabLayout"
|
||||
android:launchMode="singleTask">
|
||||
@ -168,13 +174,34 @@
|
||||
<activity android:name=".ActivityMainPoi" />
|
||||
<activity android:name=".ActivityMainRules" />
|
||||
<activity android:name=".ActivityGeneric" />
|
||||
<activity android:name=".ActivityManageStartActivity" />
|
||||
<activity android:name=".ActivityManageNfc" />
|
||||
<activity android:name=".ActivityEditSpeakText" />
|
||||
<activity android:name=".ActivityManageBluetoothTrigger" />
|
||||
<activity android:name=".ActivityManageActionStartActivity" />
|
||||
<activity android:name=".ActivityManageTriggerNfc" />
|
||||
<activity android:name=".ActivityManageActionSpeakText" />
|
||||
<activity android:name=".ActivityManageActionPlaySound" />
|
||||
<activity android:name=".ActivityManageTriggerBluetooth" />
|
||||
<activity android:name=".ActivityMainProfiles" />
|
||||
<activity android:name=".ActivityManageProfile" />
|
||||
<activity android:name=".ActivityManageTriggerWifi" />
|
||||
<activity android:name=".ActivityVolumeTest" />
|
||||
<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>
|
||||
|
||||
<activity android:name=".ActivityPermissions" />
|
||||
|
||||
|
||||
<!-- https://developer.android.com/about/versions/pie/android-9.0-changes-28#apache-p-->
|
||||
<uses-library android:name="org.apache.http.legacy" android:required="false"/>
|
||||
|
||||
|
||||
<service
|
||||
android:name=".receivers.ActivityDetectionReceiver"
|
||||
@ -184,12 +211,14 @@
|
||||
<meta-data
|
||||
android:name="com.google.android.gms.version"
|
||||
android:value="@integer/google_play_services_version" />
|
||||
|
||||
<activity android:name=".ActivityPermissions"></activity>
|
||||
|
||||
<service android:name=".location.GeofenceIntentService"/>
|
||||
|
||||
<uses-library android:name="org.apache.http.legacy" android:required="false"/>
|
||||
|
||||
<provider
|
||||
android:name=".FileShareProvider"
|
||||
android:authorities="com.jens.automation2"
|
||||
android:exported="true"
|
||||
/>
|
||||
|
||||
</application>
|
||||
|
||||
|
@ -1,13 +1,18 @@
|
||||
package com.jens.automation2;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Looper;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.google.android.gms.location.DetectedActivity;
|
||||
import com.jens.automation2.location.LocationProvider;
|
||||
import com.jens.automation2.location.WifiBroadcastReceiver;
|
||||
import com.jens.automation2.receivers.ActivityDetectionReceiver;
|
||||
import com.jens.automation2.receivers.BatteryReceiver;
|
||||
@ -16,6 +21,7 @@ import com.jens.automation2.receivers.ConnectivityReceiver;
|
||||
import com.jens.automation2.receivers.HeadphoneJackListener;
|
||||
import com.jens.automation2.receivers.NfcReceiver;
|
||||
import com.jens.automation2.receivers.NoiseListener;
|
||||
import com.jens.automation2.receivers.NotificationListener;
|
||||
import com.jens.automation2.receivers.PhoneStatusListener;
|
||||
import com.jens.automation2.receivers.ProcessListener;
|
||||
|
||||
@ -24,6 +30,9 @@ import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
import static com.jens.automation2.Trigger.triggerParameter2Split;
|
||||
import static com.jens.automation2.receivers.NotificationListener.EXTRA_TEXT;
|
||||
import static com.jens.automation2.receivers.NotificationListener.EXTRA_TITLE;
|
||||
|
||||
public class Rule implements Comparable<Rule>
|
||||
{
|
||||
@ -42,9 +51,20 @@ public class Rule implements Comparable<Rule>
|
||||
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 ruleToggle = false; // rule will run again and do the opposite of its actions if applicable
|
||||
private Calendar lastExecution;
|
||||
|
||||
private static Date lastActivatedRuleActivationTime;
|
||||
|
||||
|
||||
public Calendar getLastExecution()
|
||||
{
|
||||
return lastExecution;
|
||||
}
|
||||
|
||||
public void setLastExecution(Calendar lastExecution)
|
||||
{
|
||||
this.lastExecution = lastExecution;
|
||||
}
|
||||
|
||||
public boolean isRuleToggle()
|
||||
{
|
||||
return ruleToggle;
|
||||
@ -114,6 +134,7 @@ public class Rule implements Comparable<Rule>
|
||||
{
|
||||
return this.getName();
|
||||
}
|
||||
@SuppressLint("NewApi")
|
||||
public String toStringLong()
|
||||
{
|
||||
String returnString = "";
|
||||
@ -153,6 +174,15 @@ public class Rule implements Comparable<Rule>
|
||||
Miscellaneous.logEvent("i", "Rule", "Creating rule: " + this.toString(), 3);
|
||||
ruleCollection.add(this);
|
||||
boolean returnValue = XmlFileInterface.writeFile();
|
||||
|
||||
try
|
||||
{
|
||||
XmlFileInterface.readFile();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Miscellaneous.logEvent("w", "Read file", Log.getStackTraceString(e), 3);
|
||||
}
|
||||
|
||||
if(returnValue)
|
||||
{
|
||||
@ -196,10 +226,23 @@ public class Rule implements Comparable<Rule>
|
||||
|
||||
return XmlFileInterface.writeFile();
|
||||
}
|
||||
|
||||
public boolean cloneRule(Context context)
|
||||
{
|
||||
Rule newRule = new Rule();
|
||||
newRule.setName(this.getName() + " - clone");
|
||||
newRule.setRuleActive(this.isRuleActive());
|
||||
newRule.setRuleToggle(this.isRuleToggle());
|
||||
|
||||
newRule.setTriggerSet(this.getTriggerSet());
|
||||
newRule.setActionSet(this.getActionSet());
|
||||
|
||||
return newRule.create(context);
|
||||
}
|
||||
|
||||
private boolean checkBeforeSaving(Context context, boolean changeExistingRule)
|
||||
{
|
||||
if(this.getName() == null | this.getName().length()==0)
|
||||
if(this.getName() == null || this.getName().length()==0)
|
||||
{
|
||||
Toast.makeText(context, context.getResources().getString(R.string.pleaseEnterValidName), Toast.LENGTH_LONG).show();
|
||||
return false;
|
||||
@ -394,13 +437,13 @@ public class Rule implements Comparable<Rule>
|
||||
&&
|
||||
Miscellaneous.compareTimes(nowTime, oneTrigger.getTimeFrame().getTriggerTimeStop()) > 0
|
||||
)
|
||||
|
|
||||
||
|
||||
// Other case, start time higher than end time, timeframe goes over midnight
|
||||
(
|
||||
Miscellaneous.compareTimes(oneTrigger.getTimeFrame().getTriggerTimeStart(), oneTrigger.getTimeFrame().getTriggerTimeStop()) < 0
|
||||
&&
|
||||
(Miscellaneous.compareTimes(oneTrigger.getTimeFrame().getTriggerTimeStart(), nowTime) >= 0
|
||||
|
|
||||
||
|
||||
Miscellaneous.compareTimes(nowTime, oneTrigger.getTimeFrame().getTriggerTimeStop()) > 0)
|
||||
)
|
||||
|
||||
@ -469,7 +512,7 @@ public class Rule implements Comparable<Rule>
|
||||
{
|
||||
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);
|
||||
return false;
|
||||
@ -477,7 +520,7 @@ public class Rule implements Comparable<Rule>
|
||||
}
|
||||
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);
|
||||
return false;
|
||||
@ -488,7 +531,7 @@ public class Rule implements Comparable<Rule>
|
||||
{
|
||||
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);
|
||||
return false;
|
||||
@ -496,7 +539,7 @@ public class Rule implements Comparable<Rule>
|
||||
}
|
||||
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);
|
||||
return false;
|
||||
@ -527,12 +570,12 @@ public class Rule implements Comparable<Rule>
|
||||
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Checking for wifi state", 4);
|
||||
if(oneTrigger.getTriggerParameter() == WifiBroadcastReceiver.lastConnectedState) // connected / disconnected
|
||||
{
|
||||
if(oneTrigger.getWifiName().length() > 0) // only check if any wifi name specified, otherwise any wifi will do
|
||||
if(oneTrigger.getTriggerParameter2().length() > 0) // only check if any wifi name specified, otherwise any wifi will do
|
||||
{
|
||||
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Wifi name specified, checking that.", 4);
|
||||
if(!WifiBroadcastReceiver.getLastWifiSsid().equals(oneTrigger.getWifiName()))
|
||||
if(!WifiBroadcastReceiver.getLastWifiSsid().equals(oneTrigger.getTriggerParameter2()))
|
||||
{
|
||||
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), String.format(context.getResources().getString(R.string.ruleDoesntApplyNotTheCorrectSsid), oneTrigger.getWifiName(), WifiBroadcastReceiver.getLastWifiSsid()), 3);
|
||||
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), String.format(context.getResources().getString(R.string.ruleDoesntApplyNotTheCorrectSsid), oneTrigger.getTriggerParameter2(), WifiBroadcastReceiver.getLastWifiSsid()), 3);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
@ -580,13 +623,29 @@ public class Rule implements Comparable<Rule>
|
||||
}
|
||||
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.phoneCall))
|
||||
{
|
||||
if(oneTrigger.getPhoneNumber().equals("any") | oneTrigger.getPhoneNumber().equals(PhoneStatusListener.getLastPhoneNumber()))
|
||||
String[] elements = oneTrigger.getTriggerParameter2().split(triggerParameter2Split);
|
||||
// state dir number
|
||||
|
||||
if(elements[2].equals(Trigger.triggerPhoneCallNumberAny) || Miscellaneous.comparePhoneNumbers(PhoneStatusListener.getLastPhoneNumber(), elements[2]) || (Miscellaneous.isRegularExpression(elements[2]) && PhoneStatusListener.getLastPhoneNumber().matches(elements[2])))
|
||||
{
|
||||
if(PhoneStatusListener.isInACall() == oneTrigger.getTriggerParameter())
|
||||
//if(PhoneStatusListener.isInACall() == oneTrigger.getTriggerParameter())
|
||||
if(
|
||||
(elements[0].equals(Trigger.triggerPhoneCallStateRinging) && PhoneStatusListener.getCurrentState() == TelephonyManager.CALL_STATE_RINGING)
|
||||
||
|
||||
(elements[0].equals(Trigger.triggerPhoneCallStateStarted) && PhoneStatusListener.getCurrentState() == TelephonyManager.CALL_STATE_OFFHOOK)
|
||||
||
|
||||
(elements[0].equals(Trigger.triggerPhoneCallStateStopped) && PhoneStatusListener.getCurrentState() == TelephonyManager.CALL_STATE_IDLE)
|
||||
)
|
||||
{
|
||||
if(oneTrigger.getPhoneDirection() == 0 | (oneTrigger.getPhoneDirection() == PhoneStatusListener.getLastPhoneDirection()))
|
||||
if(
|
||||
elements[1].equals(Trigger.triggerPhoneCallDirectionAny)
|
||||
||
|
||||
(elements[1].equals(Trigger.triggerPhoneCallDirectionIncoming) && PhoneStatusListener.getLastPhoneDirection() == 1)
|
||||
||
|
||||
(elements[1].equals(Trigger.triggerPhoneCallDirectionOutgoing) && PhoneStatusListener.getLastPhoneDirection() == 2)
|
||||
)
|
||||
{
|
||||
// Everything's allright
|
||||
// Trigger conditions are met
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -601,7 +660,10 @@ public class Rule implements Comparable<Rule>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Miscellaneous.logEvent("i", "Rule", "Rule doesn't apply. Wrong phone number. Demanded: " + oneTrigger.getPhoneNumber() + ", got: " + PhoneStatusListener.getLastPhoneNumber(), 4);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.nfcTag))
|
||||
{
|
||||
@ -648,109 +710,69 @@ public class Rule implements Comparable<Rule>
|
||||
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.bluetoothConnection))
|
||||
{
|
||||
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Checking for bluetooth...", 4);
|
||||
|
||||
// if( // 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(BluetoothReceiver.isAnyDeviceConnected() != oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
else if((oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)))
|
||||
{
|
||||
if(BluetoothReceiver.isAnyDeviceConnected() != oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// range
|
||||
if(BluetoothReceiver.isAnyDeviceInRange() != oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(oneTrigger.getBluetoothDeviceAddress().equals("<none>"))
|
||||
if(oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED))
|
||||
{
|
||||
if(oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED))
|
||||
{
|
||||
if(BluetoothReceiver.isAnyDeviceConnected() == oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
else if((oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)))
|
||||
{
|
||||
if(BluetoothReceiver.isAnyDeviceConnected() == oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// range
|
||||
if(BluetoothReceiver.isAnyDeviceInRange() == oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
if(BluetoothReceiver.isAnyDeviceConnected() != oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
else if(oneTrigger.getBluetoothDeviceAddress().length() > 0)
|
||||
else if((oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)))
|
||||
{
|
||||
if(oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED))
|
||||
{
|
||||
if(BluetoothReceiver.isDeviceCurrentlyConnected(BluetoothReceiver.getDeviceByAddress(oneTrigger.getBluetoothDeviceAddress())) != oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
else if((oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)))
|
||||
{
|
||||
if(BluetoothReceiver.isDeviceCurrentlyConnected(BluetoothReceiver.getDeviceByAddress(oneTrigger.getBluetoothDeviceAddress())) != oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// range
|
||||
if(BluetoothReceiver.isDeviceInRange(BluetoothReceiver.getDeviceByAddress(oneTrigger.getBluetoothDeviceAddress())) != oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
if(BluetoothReceiver.isAnyDeviceConnected() != oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyStateNotCorrect), 3);
|
||||
return false;
|
||||
// range
|
||||
if(BluetoothReceiver.isAnyDeviceInRange() != oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(oneTrigger.getBluetoothDeviceAddress().equals("<none>"))
|
||||
{
|
||||
if(oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED))
|
||||
{
|
||||
if(BluetoothReceiver.isAnyDeviceConnected() == oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
else if((oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)))
|
||||
{
|
||||
if(BluetoothReceiver.isAnyDeviceConnected() == oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// range
|
||||
if(BluetoothReceiver.isAnyDeviceInRange() == oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(oneTrigger.getBluetoothDeviceAddress().length() > 0)
|
||||
{
|
||||
if(oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED))
|
||||
{
|
||||
if(BluetoothReceiver.isDeviceCurrentlyConnected(BluetoothReceiver.getDeviceByAddress(oneTrigger.getBluetoothDeviceAddress())) != oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
else if((oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)))
|
||||
{
|
||||
if(BluetoothReceiver.isDeviceCurrentlyConnected(BluetoothReceiver.getDeviceByAddress(oneTrigger.getBluetoothDeviceAddress())) != oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// range
|
||||
if(BluetoothReceiver.isDeviceInRange(BluetoothReceiver.getDeviceByAddress(oneTrigger.getBluetoothDeviceAddress())) != oneTrigger.getTriggerParameter())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyStateNotCorrect), 3);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.headsetPlugged))
|
||||
{
|
||||
@ -763,6 +785,109 @@ public class Rule implements Comparable<Rule>
|
||||
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;
|
||||
@ -774,6 +899,8 @@ public class Rule implements Comparable<Rule>
|
||||
|
||||
private class ActivateRuleTask extends AsyncTask<Object, String, Void>
|
||||
{
|
||||
boolean wasActivated = false;
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Object... params)
|
||||
{
|
||||
@ -788,7 +915,7 @@ public class Rule implements Comparable<Rule>
|
||||
if (Looper.myLooper() == null)
|
||||
Looper.prepare();
|
||||
|
||||
activateInternally((AutomationService)params[0], (Boolean)params[1]);
|
||||
wasActivated = activateInternally((AutomationService)params[0], (Boolean)params[1]);
|
||||
|
||||
return null;
|
||||
}
|
||||
@ -806,27 +933,35 @@ public class Rule implements Comparable<Rule>
|
||||
@Override
|
||||
protected void onPostExecute(Void result)
|
||||
{
|
||||
AutomationService.updateNotification();
|
||||
ActivityMainScreen.updateMainScreen();
|
||||
super.onPostExecute(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();
|
||||
ActivityMainScreen.updateMainScreen();
|
||||
super.onPostExecute(result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Will activate the rule. Should be called by a separate execution thread
|
||||
* @param automationService
|
||||
*/
|
||||
protected void activateInternally(AutomationService automationService, boolean force)
|
||||
protected boolean activateInternally(AutomationService automationService, boolean force)
|
||||
{
|
||||
boolean isActuallyToggable = isActuallyToggable();
|
||||
|
||||
|
||||
boolean notLastActive = getLastActivatedRule() == null || !getLastActivatedRule().equals(Rule.this);
|
||||
boolean doToggle = ruleToggle && isActuallyToggable;
|
||||
|
||||
if(notLastActive | force | doToggle)
|
||||
|
||||
if(notLastActive || force || doToggle)
|
||||
{
|
||||
String message;
|
||||
if(!doToggle)
|
||||
message = String.format(automationService.getResources().getString(R.string.ruleActivate), Rule.this.getName());
|
||||
message = String.format(automationService.getResources().getString(R.string.ruleActivate), Rule.this.getName());
|
||||
else
|
||||
message = String.format(automationService.getResources().getString(R.string.ruleActivateToggle), Rule.this.getName());
|
||||
Miscellaneous.logEvent("i", "Rule", message, 2);
|
||||
@ -834,10 +969,19 @@ public class Rule implements Comparable<Rule>
|
||||
// Toast.makeText(automationService, message, Toast.LENGTH_LONG).show();
|
||||
if(Settings.startNewThreadForRuleActivation)
|
||||
publishProgress(message);
|
||||
|
||||
|
||||
for(int i = 0; i< Rule.this.getActionSet().size(); i++)
|
||||
Rule.this.getActionSet().get(i).run(automationService, doToggle);
|
||||
|
||||
{
|
||||
try
|
||||
{
|
||||
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)
|
||||
try
|
||||
{
|
||||
@ -862,9 +1006,12 @@ public class Rule implements Comparable<Rule>
|
||||
else
|
||||
{
|
||||
Miscellaneous.logEvent("i", "Rule", "Request to activate rule " + Rule.this.getName() + ", but it is the last one that was activated. Won't do it again.", 3);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public void activate(AutomationService automationService, boolean force)
|
||||
{
|
||||
@ -963,7 +1110,7 @@ public class Rule implements Comparable<Rule>
|
||||
if(oneTrigger.getTimeFrame().getTriggerTimeStart().getTime() > oneTrigger.getTimeFrame().getTriggerTimeStop().getTime())
|
||||
{
|
||||
Miscellaneous.logEvent("i", "Timeframe search", "Rule goes over midnight.", 5);
|
||||
if(oneTrigger.getTimeFrame().getTriggerTimeStart().getTime() <= searchTime.getTime() | searchTime.getTime() <= oneTrigger.getTimeFrame().getTriggerTimeStop().getTime()+20000) //add 20 seconds because of delay
|
||||
if(oneTrigger.getTimeFrame().getTriggerTimeStart().getTime() <= searchTime.getTime() || searchTime.getTime() <= oneTrigger.getTimeFrame().getTriggerTimeStop().getTime()+20000) //add 20 seconds because of delay
|
||||
{
|
||||
ruleCandidates.add(oneRule);
|
||||
break innerloop; //if the poi is found we don't need to search the other triggers in the same rule
|
||||
@ -1234,10 +1381,10 @@ public class Rule implements Comparable<Rule>
|
||||
return ruleCandidates;
|
||||
}
|
||||
|
||||
public static ArrayList<Rule> findRuleCandidatesByPhoneCall(boolean triggerParameter)
|
||||
public static ArrayList<Rule> findRuleCandidatesByPhoneCall(String direction)
|
||||
{
|
||||
ArrayList<Rule> ruleCandidates = new ArrayList<Rule>();
|
||||
|
||||
|
||||
for(Rule oneRule : ruleCollection)
|
||||
{
|
||||
innerloop:
|
||||
@ -1245,7 +1392,8 @@ public class Rule implements Comparable<Rule>
|
||||
{
|
||||
if(oneTrigger.getTriggerType() == Trigger.Trigger_Enum.phoneCall)
|
||||
{
|
||||
if(oneTrigger.getTriggerParameter() == triggerParameter)
|
||||
String[] elements = oneTrigger.getTriggerParameter2().split(triggerParameter2Split);
|
||||
if(elements[1].equals(Trigger.triggerPhoneCallDirectionAny) || elements[1].equals(direction))
|
||||
{
|
||||
ruleCandidates.add(oneRule);
|
||||
break innerloop; //we don't need to search the other triggers in the same rule
|
||||
@ -1253,7 +1401,7 @@ public class Rule implements Comparable<Rule>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return ruleCandidates;
|
||||
}
|
||||
|
||||
@ -1279,6 +1427,26 @@ public class Rule implements Comparable<Rule>
|
||||
|
||||
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()
|
||||
{
|
||||
|
@ -3,6 +3,7 @@ package com.jens.automation2;
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
|
||||
@ -12,6 +13,10 @@ import java.util.Locale;
|
||||
|
||||
public class Action
|
||||
{
|
||||
public static final String actionParameter2Split = "ap2split";
|
||||
public static final String intentPairSeperator = "intPairSplit";
|
||||
public static final String vibrateSeparator = ",";
|
||||
|
||||
public enum Action_Enum {
|
||||
setWifi,
|
||||
setBluetooth,
|
||||
@ -33,6 +38,8 @@ public class Action
|
||||
speakText,
|
||||
playMusic,
|
||||
setScreenBrightness,
|
||||
playSound,
|
||||
vibrate,
|
||||
sendTextMessage;
|
||||
|
||||
public String getFullName(Context context)
|
||||
@ -79,6 +86,8 @@ public class Action
|
||||
return context.getResources().getString(R.string.waitBeforeNextAction);
|
||||
case wakeupDevice:
|
||||
return context.getResources().getString(R.string.wakeupDevice);
|
||||
case vibrate:
|
||||
return context.getResources().getString(R.string.vibrate);
|
||||
case setAirplaneMode:
|
||||
return context.getResources().getString(R.string.airplaneMode);
|
||||
case setDataConnection:
|
||||
@ -87,6 +96,8 @@ public class Action
|
||||
return context.getResources().getString(R.string.actionSpeakText);
|
||||
case playMusic:
|
||||
return context.getResources().getString(R.string.actionPlayMusic);
|
||||
case playSound:
|
||||
return context.getResources().getString(R.string.playSound);
|
||||
case sendTextMessage:
|
||||
return context.getResources().getString(R.string.sendTextMessage);
|
||||
case setScreenBrightness:
|
||||
@ -210,9 +221,13 @@ public class Action
|
||||
{
|
||||
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
|
||||
returnString.append(action.toString());
|
||||
|
||||
|
||||
if(this.getAction().equals(Action_Enum.triggerUrl))
|
||||
{
|
||||
String[] components = parameter2.split(";");
|
||||
@ -226,6 +241,10 @@ public class Action
|
||||
else
|
||||
returnString.append(": " + components[0]);
|
||||
}
|
||||
else if(this.getAction().equals(Action_Enum.startOtherActivity))
|
||||
{
|
||||
returnString.append(": " + parameter2.replace(Action.intentPairSeperator, "/"));
|
||||
}
|
||||
else if(this.getAction().equals(Action_Enum.sendTextMessage))
|
||||
{
|
||||
String[] components = parameter2.split(Actions.smsSeparator);
|
||||
@ -320,84 +339,91 @@ public class Action
|
||||
}
|
||||
|
||||
public void run(Context context, boolean toggleActionIfPossible)
|
||||
{
|
||||
switch(this.getAction())
|
||||
{
|
||||
try
|
||||
{
|
||||
case changeSoundProfile:
|
||||
/*
|
||||
* Old version. Those checks should not be necessary anymore. Also they didn't work
|
||||
* because profiles were created with names like silent, vibrate and normal.
|
||||
*/
|
||||
// if(this.getParameter2().equals("silent"))
|
||||
// Actions.setSound(context, AudioManager.RINGER_MODE_SILENT);
|
||||
// else if(this.getParameter2().equals("vibrate"))
|
||||
// Actions.setSound(context, AudioManager.RINGER_MODE_VIBRATE);
|
||||
// else if(this.getParameter2().equals("normal"))
|
||||
// Actions.setSound(context, AudioManager.RINGER_MODE_NORMAL);
|
||||
// else
|
||||
// {
|
||||
switch(this.getAction())
|
||||
{
|
||||
case changeSoundProfile:
|
||||
/*
|
||||
* Old version. Those checks should not be necessary anymore. Also they didn't work
|
||||
* because profiles were created with names like silent, vibrate and normal.
|
||||
*/
|
||||
|
||||
Profile p = Profile.getByName(this.getParameter2());
|
||||
if(p != null)
|
||||
if (p != null)
|
||||
p.activate(context);
|
||||
// }
|
||||
break;
|
||||
case triggerUrl:
|
||||
triggerUrl(context);
|
||||
break;
|
||||
case setBluetooth:
|
||||
Actions.setBluetooth(context, getParameter1(), toggleActionIfPossible);
|
||||
break;
|
||||
case setUsbTethering:
|
||||
Actions.setUsbTethering(context, getParameter1(), toggleActionIfPossible);
|
||||
break;
|
||||
case setWifi:
|
||||
Actions.setWifi(context, getParameter1(), toggleActionIfPossible);
|
||||
break;
|
||||
case setWifiTethering:
|
||||
Actions.setWifiTethering(context, getParameter1(), toggleActionIfPossible);
|
||||
break;
|
||||
case setDisplayRotation:
|
||||
Actions.setDisplayRotation(context, getParameter1(), toggleActionIfPossible);
|
||||
break;
|
||||
case startOtherActivity:
|
||||
Actions.startOtherActivity(getParameter2());
|
||||
break;
|
||||
case waitBeforeNextAction:
|
||||
Actions.waitBeforeNextAction(Long.parseLong(this.getParameter2()));
|
||||
break;
|
||||
case wakeupDevice:
|
||||
Actions.wakeupDevice(Long.parseLong(this.getParameter2()));
|
||||
// wakeupDevice() will create a seperate thread. That'll take some time, we wait 100ms.
|
||||
try
|
||||
{
|
||||
Thread.sleep(100);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
break;
|
||||
case setAirplaneMode:
|
||||
Actions.setAirplaneMode(this.getParameter1(), toggleActionIfPossible);
|
||||
break;
|
||||
case setDataConnection:
|
||||
Actions.MobileDataStuff.setDataConnection(this.getParameter1(), toggleActionIfPossible);
|
||||
break;
|
||||
case speakText:
|
||||
Actions.speakText(this.getParameter2());
|
||||
break;
|
||||
case playMusic:
|
||||
Actions.playMusic(this.getParameter1(), toggleActionIfPossible);
|
||||
break;
|
||||
case sendTextMessage:
|
||||
Actions.sendTextMessage(context, this.getParameter2().split(Actions.smsSeparator));
|
||||
break;
|
||||
case setScreenBrightness:
|
||||
Actions.setScreenBrightness(getParameter1(), Integer.parseInt(getParameter2()));
|
||||
break;
|
||||
default:
|
||||
Miscellaneous.logEvent("w", "Action", context.getResources().getString(R.string.unknownActionSpecified), 3);
|
||||
break;
|
||||
|
||||
break;
|
||||
case triggerUrl:
|
||||
triggerUrl(context);
|
||||
break;
|
||||
case setBluetooth:
|
||||
Actions.setBluetooth(context, getParameter1(), toggleActionIfPossible);
|
||||
break;
|
||||
case setUsbTethering:
|
||||
Actions.setUsbTethering(context, getParameter1(), toggleActionIfPossible);
|
||||
break;
|
||||
case setWifi:
|
||||
Actions.setWifi(context, getParameter1(), toggleActionIfPossible);
|
||||
break;
|
||||
case setWifiTethering:
|
||||
Actions.setWifiTethering(context, getParameter1(), toggleActionIfPossible);
|
||||
break;
|
||||
case setDisplayRotation:
|
||||
Actions.setDisplayRotation(context, getParameter1(), toggleActionIfPossible);
|
||||
break;
|
||||
case startOtherActivity:
|
||||
Actions.startOtherActivity(getParameter1(), getParameter2());
|
||||
break;
|
||||
case waitBeforeNextAction:
|
||||
Actions.waitBeforeNextAction(Long.parseLong(this.getParameter2()));
|
||||
break;
|
||||
case wakeupDevice:
|
||||
Actions.wakeupDevice(Long.parseLong(this.getParameter2()));
|
||||
// wakeupDevice() will create a seperate thread. That'll take some time, we wait 100ms.
|
||||
try
|
||||
{
|
||||
Thread.sleep(100);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
break;
|
||||
case setAirplaneMode:
|
||||
Actions.setAirplaneMode(this.getParameter1(), toggleActionIfPossible);
|
||||
break;
|
||||
case setDataConnection:
|
||||
Actions.MobileDataStuff.setDataConnection(this.getParameter1(), toggleActionIfPossible);
|
||||
break;
|
||||
case speakText:
|
||||
Actions.speakText(this.getParameter2());
|
||||
break;
|
||||
case playMusic:
|
||||
Actions.playMusic(this.getParameter1(), toggleActionIfPossible);
|
||||
break;
|
||||
case sendTextMessage:
|
||||
Actions.sendTextMessage(context, this.getParameter2().split(Actions.smsSeparator));
|
||||
break;
|
||||
case setScreenBrightness:
|
||||
Actions.setScreenBrightness(getParameter1(), Integer.parseInt(getParameter2()));
|
||||
break;
|
||||
case vibrate:
|
||||
Actions.vibrate(getParameter1(), getParameter2());
|
||||
break;
|
||||
case playSound:
|
||||
Actions.playSound(getParameter1(), getParameter2());
|
||||
break;
|
||||
default:
|
||||
Miscellaneous.logEvent("w", "Action", context.getResources().getString(R.string.unknownActionSpecified), 3);
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -433,7 +459,7 @@ public class Action
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Miscellaneous.logEvent("e", "triggerUrl", context.getResources().getString(R.string.errorTriggeringUrl) + ": " + e.getMessage() + ", detailed: " + Log.getStackTraceString(e), 2);
|
||||
Miscellaneous.logEvent("e", "triggerUrl", context.getResources().getString(R.string.logErrorTriggeringUrl) + ": " + e.getMessage() + ", detailed: " + Log.getStackTraceString(e), 2);
|
||||
}
|
||||
}
|
||||
|
||||
@ -464,62 +490,24 @@ public class Action
|
||||
while(attempts <= Settings.httpAttempts && response.equals("httpError"))
|
||||
{
|
||||
Miscellaneous.logEvent("i", "HTTP Request", "Attempt " + String.valueOf(attempts++) + " of " + String.valueOf(Settings.httpAttempts), 3);
|
||||
|
||||
// try
|
||||
// {
|
||||
// Either thorough checking or no encryption
|
||||
if(!Settings.httpAcceptAllCertificates | !urlString.toLowerCase(Locale.getDefault()).contains("https"))
|
||||
// {
|
||||
// URL url = new URL(urlString);
|
||||
// URLConnection urlConnection = url.openConnection();
|
||||
// urlConnection.setReadTimeout(Settings.httpAttemptsTimeout * 1000);
|
||||
// InputStream in = urlConnection.getInputStream();
|
||||
// response = Miscellaneous.convertStreamToString(in);
|
||||
|
||||
response = Miscellaneous.downloadURL(urlString, urlUsername, urlPassword);
|
||||
// }
|
||||
else
|
||||
// {
|
||||
response = Miscellaneous.downloadURLwithoutCertificateChecking(urlString, urlUsername, urlPassword);
|
||||
// post = new HttpGet(new URI(urlString));
|
||||
// final HttpParams httpParams = new BasicHttpParams();
|
||||
// HttpConnectionParams.setConnectionTimeout(httpParams, Settings.httpAttemptsTimeout * 1000);
|
||||
// HttpClient client = new DefaultHttpClient(httpParams);
|
||||
//
|
||||
// client = sslClient(client);
|
||||
//
|
||||
// // Execute HTTP Post Request
|
||||
// HttpResponse result = client.execute(post);
|
||||
// response = EntityUtils.toString(result.getEntity());
|
||||
// }
|
||||
// }
|
||||
// catch (URISyntaxException e)
|
||||
// {
|
||||
// Miscellaneous.logEvent("w", "HTTP RESULT", Log.getStackTraceString(e), 3);
|
||||
// }
|
||||
// catch (ClientProtocolException e)
|
||||
// {
|
||||
// Miscellaneous.logEvent("w", "HTTP RESULT", Log.getStackTraceString(e), 3);
|
||||
// }
|
||||
// catch (IOException e)
|
||||
// {
|
||||
// Miscellaneous.logEvent("w", "HTTP RESULT", Log.getStackTraceString(e), 3);
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// finally
|
||||
// {
|
||||
try
|
||||
{
|
||||
Thread.sleep(Settings.httpAttemptGap * 1000);
|
||||
}
|
||||
catch (InterruptedException e1)
|
||||
{
|
||||
Miscellaneous.logEvent("w", "HTTP RESULT", "Failed to pause between HTTP requests.", 5);
|
||||
}
|
||||
// }
|
||||
|
||||
// Either thorough checking or no encryption
|
||||
if(!Settings.httpAcceptAllCertificates || !urlString.toLowerCase(Locale.getDefault()).contains("https"))
|
||||
response = Miscellaneous.downloadURL(urlString, urlUsername, urlPassword);
|
||||
else
|
||||
response = Miscellaneous.downloadURLwithoutCertificateChecking(urlString, urlUsername, urlPassword);
|
||||
|
||||
try
|
||||
{
|
||||
Thread.sleep(Settings.httpAttemptGap * 1000);
|
||||
}
|
||||
catch (InterruptedException e1)
|
||||
{
|
||||
Miscellaneous.logEvent("w", "HTTP RESULT", "Failed to pause between HTTP requests.", 5);
|
||||
}
|
||||
}
|
||||
|
||||
// Miscellaneous.logEvent("i", "HTTPS RESULT", response, 3);
|
||||
Miscellaneous.logEvent("i", "HTTPS RESULT", response, 5);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.jens.automation2;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
@ -60,11 +61,11 @@ public class ActivityMainPoi extends ActivityGeneric
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ActivityPermissions.havePermission(ActivityPermissions.permissionNameLocationCoarse, ActivityMainPoi.this) || !ActivityPermissions.havePermission(ActivityPermissions.permissionNameLocationFine, ActivityMainPoi.this))
|
||||
if (!ActivityPermissions.havePermission(Manifest.permission.ACCESS_COARSE_LOCATION, ActivityMainPoi.this) || !ActivityPermissions.havePermission(Manifest.permission.ACCESS_FINE_LOCATION, ActivityMainPoi.this))
|
||||
{
|
||||
Intent permissionIntent = new Intent(ActivityMainPoi.this, ActivityPermissions.class);
|
||||
|
||||
permissionIntent.putExtra(ActivityPermissions.intentExtraName, new String[]{ActivityPermissions.permissionNameLocationCoarse, ActivityPermissions.permissionNameLocationFine});
|
||||
permissionIntent.putExtra(ActivityPermissions.intentExtraName, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION});
|
||||
|
||||
startActivityForResult(permissionIntent, requestCodeForPermission);
|
||||
}
|
||||
|
@ -26,10 +26,14 @@ import java.util.ArrayList;
|
||||
public class ActivityMainRules extends ActivityGeneric
|
||||
{
|
||||
private ListView ruleListView;
|
||||
ArrayList<Rule> ruleList = new ArrayList<>();
|
||||
private ArrayAdapter<Rule> ruleListViewAdapter;
|
||||
public static Rule ruleToEdit;
|
||||
protected static ActivityMainRules instance = null;
|
||||
|
||||
public static final int requestCodeCreateRule = 3000;
|
||||
public static final int requestCodeChangeRule = 4000;
|
||||
|
||||
public static ActivityMainRules getInstance()
|
||||
{
|
||||
if(instance == null)
|
||||
@ -52,21 +56,14 @@ public class ActivityMainRules extends ActivityGeneric
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
// if(!ActivityPermissions.havePermission(ActivityPermissions.writeExternalStoragePermissionName, ActivityMainRules.this))
|
||||
// {
|
||||
// Toast.makeText(ActivityMainRules.this, getResources().getString(R.string.appRequiresPermissiontoAccessExternalStorage), Toast.LENGTH_LONG).show();
|
||||
// return;
|
||||
// }
|
||||
|
||||
ruleToEdit = null;
|
||||
Intent startAddRuleIntent = new Intent(ActivityMainRules.this, ActivityManageRule.class);
|
||||
startActivityForResult(startAddRuleIntent, 3000);
|
||||
startActivityForResult(startAddRuleIntent, requestCodeCreateRule);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
ruleListViewAdapter = new RuleArrayAdapter(this, R.layout.view_for_rule_listview, ruleList);
|
||||
ruleListView = (ListView)findViewById(R.id.lvRuleList);
|
||||
|
||||
ruleListViewAdapter = new RuleArrayAdapter(this, R.layout.view_for_rule_listview, Rule.getRuleCollection());
|
||||
ruleListView.setClickable(true);
|
||||
|
||||
ruleListView.setOnItemLongClickListener(new OnItemLongClickListener()
|
||||
@ -112,7 +109,6 @@ public class ActivityMainRules extends ActivityGeneric
|
||||
|
||||
private static class RuleArrayAdapter extends ArrayAdapter<Rule>
|
||||
{
|
||||
|
||||
public RuleArrayAdapter(Context context, int resource, ArrayList<Rule> objects)
|
||||
{
|
||||
super(context, resource, objects);
|
||||
@ -163,13 +159,13 @@ public class ActivityMainRules extends ActivityGeneric
|
||||
if(AutomationService.isMyServiceRunning(this))
|
||||
bindToService();
|
||||
|
||||
if(requestCode == 3000) //add Rule
|
||||
if(requestCode == requestCodeCreateRule) //add Rule
|
||||
{
|
||||
ruleToEdit = null; //clear cache
|
||||
updateListView();
|
||||
}
|
||||
|
||||
if(requestCode == 4000) //editRule
|
||||
if(requestCode == requestCodeChangeRule) //editRule
|
||||
{
|
||||
ruleToEdit = null; //clear cache
|
||||
updateListView();
|
||||
@ -190,7 +186,7 @@ public class ActivityMainRules extends ActivityGeneric
|
||||
{
|
||||
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
|
||||
alertDialogBuilder.setTitle(getResources().getString(R.string.whatToDoWithRule));
|
||||
alertDialogBuilder.setItems(new String[]{ getResources().getString(R.string.runManually), getResources().getString(R.string.edit), getResources().getString(R.string.deleteCapital) }, new DialogInterface.OnClickListener()
|
||||
alertDialogBuilder.setItems(new String[]{ getResources().getString(R.string.runManually), getResources().getString(R.string.edit), getResources().getString(R.string.deleteCapital), getResources().getString(R.string.clone) }, new DialogInterface.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which)
|
||||
@ -212,11 +208,22 @@ public class ActivityMainRules extends ActivityGeneric
|
||||
case 1:
|
||||
ruleToEdit = ruleThisIsAbout;
|
||||
Intent manageSpecificRuleIntent = new Intent (ActivityMainRules.this, ActivityManageRule.class);
|
||||
startActivityForResult(manageSpecificRuleIntent, 4000);
|
||||
startActivityForResult(manageSpecificRuleIntent, requestCodeChangeRule);
|
||||
break;
|
||||
case 2:
|
||||
if(ruleThisIsAbout.delete())
|
||||
{
|
||||
ruleToEdit = null; //clear cache
|
||||
updateListView();
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
ruleToEdit = ruleThisIsAbout;
|
||||
if(ruleToEdit.cloneRule(ActivityMainRules.this))
|
||||
{
|
||||
ruleToEdit = null; //clear cache
|
||||
updateListView();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -229,6 +236,11 @@ public class ActivityMainRules extends ActivityGeneric
|
||||
public void updateListView()
|
||||
{
|
||||
Miscellaneous.logEvent("i", "ListView", "Attempting to update RuleListView", 4);
|
||||
|
||||
ruleList.clear();
|
||||
for(Rule r : Rule.getRuleCollection())
|
||||
ruleList.add(r);
|
||||
|
||||
try
|
||||
{
|
||||
if(ruleListView.getAdapter() == null)
|
||||
@ -249,4 +261,4 @@ public class ActivityMainRules extends ActivityGeneric
|
||||
// AlarmManager instance not prepared, yet.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package com.jens.automation2;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.PendingIntent;
|
||||
@ -10,6 +11,7 @@ import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.util.Xml;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
@ -29,6 +31,8 @@ import com.jens.automation2.AutomationService.serviceCommands;
|
||||
import com.jens.automation2.Trigger.Trigger_Enum;
|
||||
import com.jens.automation2.location.LocationProvider;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
|
||||
@ -39,8 +43,9 @@ public class ActivityMainScreen extends ActivityGeneric
|
||||
|
||||
private static ActivityMainScreen activityMainScreenInstance = null;
|
||||
private ToggleButton toggleService, tbLockSound;
|
||||
private Button bShowHelp, bPrivacy, bSettingsErase, bSettingsSetToDefault, bVolumeTest, bAddSoundLockTIme;
|
||||
private TextView tvActivePoi, tvClosestPoi, tvLastRule, tvMainScreenNotePermissions, tvMainScreenNoteFeaturesFromOtherFlavor, tvMainScreenNoteLocationImpossibleBlameGoogle, tvMainScreenNoteNews, tvlockSoundDuration, tvFileStoreLocation;
|
||||
private Button bShowHelp, bPrivacy, bSettingsErase, bAddSoundLockTIme;
|
||||
private TextView tvActivePoi, tvClosestPoi, tvLastRule, tvMainScreenNotePermissions, tvMainScreenNoteFeaturesFromOtherFlavor, tvMainScreenNoteLocationImpossibleBlameGoogle, tvMainScreenNoteNews, tvlockSoundDuration;
|
||||
private static boolean updateNoteDisplayed = false;
|
||||
|
||||
private ListView lvRuleHistory;
|
||||
private ArrayAdapter<Rule> ruleHistoryListViewAdapter;
|
||||
@ -74,7 +79,6 @@ public class ActivityMainScreen extends ActivityGeneric
|
||||
tvMainScreenNoteLocationImpossibleBlameGoogle = (TextView) findViewById(R.id.tvMainScreenNoteLocationImpossibleBlameGoogle);
|
||||
tvMainScreenNoteNews = (TextView) findViewById(R.id.tvMainScreenNoteNews);
|
||||
tvlockSoundDuration = (TextView)findViewById(R.id.tvlockSoundDuration);
|
||||
tvFileStoreLocation = (TextView)findViewById(R.id.tvFileStoreLocation);
|
||||
tbLockSound = (ToggleButton) findViewById(R.id.tbLockSound);
|
||||
toggleService = (ToggleButton) findViewById(R.id.tbArmMastListener);
|
||||
toggleService.setChecked(AutomationService.isMyServiceRunning(this));
|
||||
@ -130,19 +134,8 @@ public class ActivityMainScreen extends ActivityGeneric
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
Intent myIntent = new Intent(ActivityMainScreen.this, ActivitySettings.class);
|
||||
startActivityForResult(myIntent, 6000);
|
||||
}
|
||||
});
|
||||
|
||||
Button bVolumeTest = (Button) findViewById(R.id.bVolumeTest);
|
||||
bVolumeTest.setOnClickListener(new OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
Intent intent = new Intent(ActivityMainScreen.this, ActivityVolumeTest.class);
|
||||
startActivity(intent);
|
||||
Intent myIntent = new Intent(ActivityMainScreen.this, ActivityMaintenance.class);
|
||||
startActivity(myIntent);
|
||||
}
|
||||
});
|
||||
|
||||
@ -178,25 +171,6 @@ public class ActivityMainScreen extends ActivityGeneric
|
||||
builder.create().show();
|
||||
}
|
||||
});
|
||||
|
||||
/*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()
|
||||
{
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
getDefaultSettingsDialog(ActivityMainScreen.this).show();
|
||||
}
|
||||
});
|
||||
|
||||
lvRuleHistory.setOnTouchListener(new OnTouchListener()
|
||||
{
|
||||
@ -260,25 +234,6 @@ public class ActivityMainScreen extends ActivityGeneric
|
||||
return alertDialog;
|
||||
}
|
||||
|
||||
private static AlertDialog getDefaultSettingsDialog(final Context context)
|
||||
{
|
||||
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(context);
|
||||
alertDialogBuilder.setTitle(context.getResources().getString(R.string.areYouSure));
|
||||
alertDialogBuilder.setPositiveButton(context.getResources().getString(R.string.yes), new DialogInterface.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which)
|
||||
{
|
||||
if (Settings.initializeSettings(context, true))
|
||||
Toast.makeText(context, context.getResources().getString(R.string.settingsSetToDefault), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
alertDialogBuilder.setNegativeButton(context.getResources().getString(R.string.no), null);
|
||||
AlertDialog alertDialog = alertDialogBuilder.create();
|
||||
|
||||
return alertDialog;
|
||||
}
|
||||
|
||||
public static ActivityMainScreen getActivityMainScreenInstance()
|
||||
{
|
||||
return activityMainScreenInstance;
|
||||
@ -370,9 +325,9 @@ public class ActivityMainScreen extends ActivityGeneric
|
||||
if(
|
||||
Rule.isAnyRuleUsing(Trigger_Enum.pointOfInterest)
|
||||
&&
|
||||
ActivityPermissions.havePermission(ActivityPermissions.permissionNameLocationCoarse, AutomationService.getInstance())
|
||||
ActivityPermissions.havePermission(Manifest.permission.ACCESS_COARSE_LOCATION, Miscellaneous.getAnyContext())
|
||||
&&
|
||||
ActivityPermissions.havePermission(ActivityPermissions.permissionNameLocationFine, AutomationService.getInstance())
|
||||
ActivityPermissions.havePermission(Manifest.permission.ACCESS_FINE_LOCATION, Miscellaneous.getAnyContext())
|
||||
)
|
||||
activityMainScreenInstance.tvActivePoi.setText(activityMainScreenInstance.getResources().getString(R.string.stillGettingPosition));
|
||||
else
|
||||
@ -453,12 +408,17 @@ public class ActivityMainScreen extends ActivityGeneric
|
||||
else
|
||||
activityMainScreenInstance.checkForNews();
|
||||
|
||||
if(BuildConfig.FLAVOR.equals("apkFlavor") && Settings.automaticUpdateCheck)
|
||||
{
|
||||
Calendar now = Calendar.getInstance();
|
||||
if (Settings.lastUpdateCheck == Settings.default_lastUpdateCheck || now.getTimeInMillis() >= Settings.lastUpdateCheck + (long)(Settings.updateCheckFrequencyDays * 24 * 60 * 60 * 1000))
|
||||
{
|
||||
activityMainScreenInstance.checkForUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
Settings.considerDone(Settings.constNewsOptInDone);
|
||||
Settings.writeSettings(Miscellaneous.getAnyContext());
|
||||
|
||||
String folder = Miscellaneous.getWriteableFolder();
|
||||
if(folder != null && folder.length() > 0)
|
||||
activityMainScreenInstance.tvFileStoreLocation.setText(String.format(activityMainScreenInstance.getResources().getString(R.string.filesStoredAt), folder));
|
||||
}
|
||||
}
|
||||
|
||||
@ -514,16 +474,6 @@ public class ActivityMainScreen extends ActivityGeneric
|
||||
case ActivityPermissions.requestCodeForPermissions:
|
||||
updateMainScreen();
|
||||
break;
|
||||
case 6000: //settings
|
||||
Settings.readFromPersistentStorage(this);
|
||||
|
||||
if (boundToService && AutomationService.isMyServiceRunning(this))
|
||||
myAutomationService.serviceInterface(serviceCommands.reloadSettings);
|
||||
|
||||
if(AutomationService.isMyServiceRunning(ActivityMainScreen.this))
|
||||
Toast.makeText(this, getResources().getString(R.string.settingsWillTakeTime), Toast.LENGTH_LONG).show();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (AutomationService.isMyServiceRunning(this))
|
||||
@ -648,6 +598,15 @@ public class ActivityMainScreen extends ActivityGeneric
|
||||
Miscellaneous.messageBox(title, text, ActivityMainScreen.getActivityMainScreenInstance());
|
||||
}
|
||||
|
||||
synchronized void checkForUpdate()
|
||||
{
|
||||
if(Settings.automaticUpdateCheck)
|
||||
{
|
||||
AsyncTasks.AsyncTaskUpdateCheck updateCheckTask = new AsyncTasks.AsyncTaskUpdateCheck();
|
||||
updateCheckTask.execute(ActivityMainScreen.this);
|
||||
}
|
||||
}
|
||||
|
||||
synchronized void checkForNews()
|
||||
{
|
||||
if(Settings.displayNewsOnMainScreen)
|
||||
@ -677,4 +636,38 @@ public class ActivityMainScreen extends ActivityGeneric
|
||||
Miscellaneous.logEvent("e", "Error displaying news", Log.getStackTraceString(e), 3);
|
||||
}
|
||||
}
|
||||
|
||||
public void processUpdateCheckResult(Boolean result)
|
||||
{
|
||||
if(result && !updateNoteDisplayed)
|
||||
{
|
||||
updateNoteDisplayed = true;
|
||||
|
||||
AlertDialog.Builder updateNoteBuilder = new AlertDialog.Builder(ActivityMainScreen.this);
|
||||
updateNoteBuilder.setMessage(getResources().getString(R.string.updateAvailable));
|
||||
updateNoteBuilder.setPositiveButton(getResources().getString(R.string.yes), new DialogInterface.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i)
|
||||
{
|
||||
String url = "https://server47.de/automation/";
|
||||
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
|
||||
startActivity(browserIntent);
|
||||
|
||||
updateNoteDisplayed = false;
|
||||
}
|
||||
});
|
||||
updateNoteBuilder.setNegativeButton(getResources().getString(R.string.no), new DialogInterface.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i)
|
||||
{
|
||||
updateNoteDisplayed = false;
|
||||
}
|
||||
});
|
||||
updateNoteBuilder.show();
|
||||
}
|
||||
|
||||
AsyncTasks.AsyncTaskUpdateCheck.checkRunning = false;
|
||||
}
|
||||
}
|
@ -13,12 +13,17 @@ import com.jens.automation2.receivers.NfcReceiver;
|
||||
@SuppressLint("NewApi")
|
||||
public class ActivityMainTabLayout extends TabActivity
|
||||
{
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.main_tab_layout);
|
||||
|
||||
Settings.readFromPersistentStorage(ActivityMainTabLayout.this);
|
||||
|
||||
if(Settings.tabsPlacement == 1)
|
||||
setContentView(R.layout.main_tab_layout_tabs_at_bottom);
|
||||
else
|
||||
setContentView(R.layout.main_tab_layout_tabs_at_top);
|
||||
|
||||
TabHost tabHost = getTabHost();
|
||||
|
||||
|
370
app/src/main/java/com/jens/automation2/ActivityMaintenance.java
Normal file
@ -0,0 +1,370 @@
|
||||
package com.jens.automation2;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ActivityMaintenance extends Activity
|
||||
{
|
||||
final static int requestCodeImport = 1001;
|
||||
final static int requestCodeExport = 1002;
|
||||
final static int requestCodeMoreSettings = 6000;
|
||||
|
||||
final static String prefsFileName = "com.jens.automation2_preferences.xml";
|
||||
|
||||
TextView tvFileStoreLocation, tvAppVersion;
|
||||
Button bVolumeTest, bMoreSettings, bSettingsSetToDefault, bShareConfigAndLog, bImportConfiguration, bExportConfiguration;
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_maintenance);
|
||||
|
||||
bVolumeTest = (Button) findViewById(R.id.bVolumeTest);
|
||||
bVolumeTest.setOnClickListener(new View.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
Intent intent = new Intent(ActivityMaintenance.this, ActivityVolumeTest.class);
|
||||
startActivity(intent);
|
||||
}
|
||||
});
|
||||
|
||||
bShareConfigAndLog = (Button) findViewById(R.id.bShareConfigAndLog);
|
||||
bShareConfigAndLog.setOnClickListener(new View.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
getShareConfigAndLogDialogue(ActivityMaintenance.this).show();
|
||||
}
|
||||
});
|
||||
|
||||
bSettingsSetToDefault = (Button) findViewById(R.id.bSettingsSetToDefault);
|
||||
bSettingsSetToDefault.setOnClickListener(new View.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
getDefaultSettingsDialog(ActivityMaintenance.this).show();
|
||||
}
|
||||
});
|
||||
|
||||
Button bMoreSettings = (Button) findViewById(R.id.bMoreSettings);
|
||||
bMoreSettings.setOnClickListener(new View.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
Intent myIntent = new Intent(ActivityMaintenance.this, ActivitySettings.class);
|
||||
startActivityForResult(myIntent, requestCodeMoreSettings);
|
||||
}
|
||||
});
|
||||
|
||||
bImportConfiguration = (Button) findViewById(R.id.bImportConfiguration);
|
||||
bImportConfiguration.setOnClickListener(new View.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
||||
startActivityForResult(intent, requestCodeImport);
|
||||
}
|
||||
});
|
||||
|
||||
bExportConfiguration = (Button) findViewById(R.id.bExportConfiguration);
|
||||
bExportConfiguration.setOnClickListener(new View.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
||||
startActivityForResult(intent, requestCodeExport);
|
||||
}
|
||||
});
|
||||
|
||||
tvFileStoreLocation = (TextView)findViewById(R.id.tvFileStoreLocation);
|
||||
tvAppVersion = (TextView)findViewById(R.id.tvAppVersion);
|
||||
|
||||
tvAppVersion.setText(
|
||||
"Version: " + BuildConfig.VERSION_NAME + Miscellaneous.lineSeparator +
|
||||
"Version code: " + String.valueOf(BuildConfig.VERSION_CODE) + Miscellaneous.lineSeparator +
|
||||
"Flavor: " + BuildConfig.FLAVOR
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data)
|
||||
{
|
||||
switch(requestCode)
|
||||
{
|
||||
case requestCodeMoreSettings: //settings
|
||||
Settings.readFromPersistentStorage(this);
|
||||
|
||||
if (AutomationService.isMyServiceRunning(this))
|
||||
AutomationService.getInstance().serviceInterface(AutomationService.serviceCommands.reloadSettings);
|
||||
|
||||
if (AutomationService.isMyServiceRunning(ActivityMaintenance.this))
|
||||
Toast.makeText(this, getResources().getString(R.string.settingsWillTakeTime), Toast.LENGTH_LONG).show();
|
||||
|
||||
break;
|
||||
case requestCodeImport:
|
||||
if(resultCode == RESULT_OK)
|
||||
{
|
||||
Uri uriTree = data.getData();
|
||||
importFiles(uriTree);
|
||||
}
|
||||
break;
|
||||
case requestCodeExport:
|
||||
if(resultCode == RESULT_OK)
|
||||
{
|
||||
Uri uriTree = data.getData();
|
||||
exportFiles(uriTree);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void importFiles(Uri uriTree)
|
||||
{
|
||||
// https://stackoverflow.com/questions/46237558/android-strange-behavior-of-documentfile-inputstream
|
||||
|
||||
File dstRules = new File(Miscellaneous.getWriteableFolder() + "/" + XmlFileInterface.settingsFileName);
|
||||
File dstPrefs = new File(Miscellaneous.getWriteableFolder() + "/../shared_prefs/" + prefsFileName);
|
||||
|
||||
DocumentFile directory = DocumentFile.fromTreeUri(this, uriTree);
|
||||
|
||||
int applicableFilesFound = 0;
|
||||
int filesImported = 0;
|
||||
|
||||
if(directory.listFiles().length > 0)
|
||||
{
|
||||
for (DocumentFile file : directory.listFiles())
|
||||
{
|
||||
if (file.getName().equals(XmlFileInterface.settingsFileName))
|
||||
{
|
||||
applicableFilesFound++;
|
||||
|
||||
if(file.canRead())
|
||||
{
|
||||
// import rules, locations, etc.
|
||||
if (Miscellaneous.copyDocumentFileToFile(file, dstRules))
|
||||
filesImported++;
|
||||
else
|
||||
Toast.makeText(ActivityMaintenance.this, getResources().getString(R.string.rulesImportError), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
else if (file.getName().equals(prefsFileName))
|
||||
{
|
||||
applicableFilesFound++;
|
||||
|
||||
if(file.canRead())
|
||||
{
|
||||
// import rules, locations, etc.
|
||||
if (Miscellaneous.copyDocumentFileToFile(file, dstPrefs))
|
||||
filesImported++;
|
||||
else
|
||||
Toast.makeText(ActivityMaintenance.this, getResources().getString(R.string.prefsImportError), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(applicableFilesFound > 0)
|
||||
{
|
||||
if(filesImported == 0)
|
||||
Toast.makeText(ActivityMaintenance.this, getResources().getString(R.string.noFilesImported), Toast.LENGTH_LONG).show();
|
||||
else if(filesImported < applicableFilesFound)
|
||||
Toast.makeText(ActivityMaintenance.this, getResources().getString(R.string.notAllFilesImported), Toast.LENGTH_LONG).show();
|
||||
else if (filesImported == applicableFilesFound)
|
||||
{
|
||||
Toast.makeText(ActivityMaintenance.this, getResources().getString(R.string.configurationImportedSuccessfully), Toast.LENGTH_LONG).show();
|
||||
|
||||
try
|
||||
{
|
||||
XmlFileInterface.readFile();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Miscellaneous.logEvent("e", "Reading import", "Rules re-read failed: " + Log.getStackTraceString(e), 1);
|
||||
Toast.makeText(ActivityMaintenance.this, getResources().getString(R.string.errorReadingPoisAndRulesFromFile), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
Settings.readFromPersistentStorage(ActivityMaintenance.this);
|
||||
}
|
||||
else
|
||||
Toast.makeText(ActivityMaintenance.this, getResources().getString(R.string.noFilesImported), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
else
|
||||
Toast.makeText(ActivityMaintenance.this, getResources().getString(R.string.noApplicableFilesFoundInDirectory), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
else
|
||||
Toast.makeText(ActivityMaintenance.this, getResources().getString(R.string.noApplicableFilesFoundInDirectory), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
void exportFiles(Uri uriTree)
|
||||
{
|
||||
DocumentFile directory = DocumentFile.fromTreeUri(this, uriTree);
|
||||
|
||||
File srcRules = new File(Miscellaneous.getWriteableFolder() + "/" + XmlFileInterface.settingsFileName);
|
||||
File srcPrefs = new File(Miscellaneous.getWriteableFolder() + "/../shared_prefs/" + prefsFileName);
|
||||
|
||||
// Clean up
|
||||
for(DocumentFile file : directory.listFiles())
|
||||
{
|
||||
/*
|
||||
On some few users' devices it seems this caused a crash because file.getName() was null.
|
||||
The reason for that remains unknown, but we don't want the export to crash because of it.
|
||||
*/
|
||||
if(!StringUtils.isEmpty(file.getName()))
|
||||
{
|
||||
if (file.getName().equals(XmlFileInterface.settingsFileName) && file.canWrite())
|
||||
file.delete();
|
||||
else if (file.getName().equals(prefsFileName) && file.canWrite())
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
|
||||
DocumentFile dstRules = directory.createFile("text/xml", XmlFileInterface.settingsFileName);
|
||||
DocumentFile dstPrefs = directory.createFile("text/xml", prefsFileName);
|
||||
|
||||
if(dstRules.canWrite() && dstPrefs.canWrite())
|
||||
{
|
||||
if(Miscellaneous.copyFileToDocumentFile(srcRules, dstRules) && Miscellaneous.copyFileToDocumentFile(srcPrefs, dstPrefs))
|
||||
Toast.makeText(ActivityMaintenance.this, getResources().getString(R.string.configurationExportedSuccessfully), Toast.LENGTH_LONG).show();
|
||||
else
|
||||
Toast.makeText(ActivityMaintenance.this, getResources().getString(R.string.ConfigurationExportError), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
else
|
||||
Toast.makeText(ActivityMaintenance.this, getResources().getString(R.string.ConfigurationExportError), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
private static AlertDialog getDefaultSettingsDialog(final Context context)
|
||||
{
|
||||
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(context);
|
||||
alertDialogBuilder.setTitle(context.getResources().getString(R.string.areYouSure));
|
||||
alertDialogBuilder.setPositiveButton(context.getResources().getString(R.string.yes), new DialogInterface.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which)
|
||||
{
|
||||
if (Settings.initializeSettings(context, true))
|
||||
Toast.makeText(context, context.getResources().getString(R.string.settingsSetToDefault), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
alertDialogBuilder.setNegativeButton(context.getResources().getString(R.string.no), null);
|
||||
AlertDialog alertDialog = alertDialogBuilder.create();
|
||||
|
||||
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);
|
||||
srcFilesList.add(Miscellaneous.getWriteableFolder() + "/../shared_prefs/" + prefsFileName);
|
||||
|
||||
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);
|
||||
emailBody.append("Flavor: " + BuildConfig.FLAVOR);
|
||||
|
||||
Uri uri = Uri.parse("content://com.jens.automation2/" + Settings.zipFileName);
|
||||
|
||||
Miscellaneous.sendEmail(ActivityMaintenance.this, "android-development@gmx.de", "Automation logs", emailBody.toString(), uri);
|
||||
}
|
||||
});
|
||||
alertDialogBuilder.setNegativeButton(context.getResources().getString(R.string.no), null);
|
||||
AlertDialog alertDialog = alertDialogBuilder.create();
|
||||
|
||||
return alertDialog;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume()
|
||||
{
|
||||
super.onResume();
|
||||
|
||||
String folder = Miscellaneous.getWriteableFolder();
|
||||
if (folder != null && folder.length() > 0)
|
||||
{
|
||||
tvFileStoreLocation.setText(String.format(getResources().getString(R.string.filesStoredAt), folder));
|
||||
tvFileStoreLocation.setOnClickListener(new View.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(getPackageManager(), 0) != null)
|
||||
{
|
||||
startActivity(intent);
|
||||
}
|
||||
else
|
||||
{
|
||||
// if you reach this place, it means there is no any file
|
||||
// explorer app installed on your device
|
||||
Toast.makeText(ActivityMaintenance.this, getResources().getString(R.string.noFileManageInstalled), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@ import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public class ActivityManageBrightnessSetting extends Activity
|
||||
public class ActivityManageActionBrightnessSetting extends Activity
|
||||
{
|
||||
CheckBox chkAutoBrightness;
|
||||
SeekBar sbBrightness;
|
@ -0,0 +1,109 @@
|
||||
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.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_action_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -19,12 +19,13 @@ import androidx.annotation.NonNull;
|
||||
import com.jens.automation2.Action.Action_Enum;
|
||||
|
||||
|
||||
public class ActivityEditSendTextMessage extends Activity
|
||||
public class ActivityManageActionSendTextMessage extends Activity
|
||||
{
|
||||
Button bSaveSendTextMessage, bImportNumberFromContacts;
|
||||
EditText etPhoneNumber, etSendTextMessage;
|
||||
|
||||
protected final static int requestCodeForContactsPermissions = 9876;
|
||||
protected final static int requestCodeGetContact = 3235;
|
||||
|
||||
// private String existingUrl = "";
|
||||
|
||||
@ -35,7 +36,7 @@ public class ActivityEditSendTextMessage extends Activity
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
this.setContentView(R.layout.send_textmessage_editor);
|
||||
this.setContentView(R.layout.activity_manage_action_send_textmessage);
|
||||
|
||||
etSendTextMessage = (EditText)findViewById(R.id.etSendTextMessage);
|
||||
etPhoneNumber = (EditText)findViewById(R.id.etPhoneNumber);
|
||||
@ -67,7 +68,7 @@ public class ActivityEditSendTextMessage extends Activity
|
||||
@Override
|
||||
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");
|
||||
}
|
||||
@ -76,30 +77,20 @@ public class ActivityEditSendTextMessage extends Activity
|
||||
}
|
||||
});
|
||||
|
||||
ActivityEditSendTextMessage.edit = getIntent().getBooleanExtra("edit", false);
|
||||
ActivityManageActionSendTextMessage.edit = getIntent().getBooleanExtra("edit", false);
|
||||
if(edit)
|
||||
{
|
||||
String[] parameters = ActivityEditSendTextMessage.resultingAction.getParameter2().split(Actions.smsSeparator);
|
||||
String[] parameters = ActivityManageActionSendTextMessage.resultingAction.getParameter2().split(Actions.smsSeparator);
|
||||
etPhoneNumber.setText(parameters[0]);
|
||||
etSendTextMessage.setText(parameters[1]);
|
||||
}
|
||||
|
||||
|
||||
// String url = getIntent().getStringExtra("urlToTrigger");
|
||||
// if(url != null)
|
||||
// existingUrl = url;
|
||||
}
|
||||
|
||||
private void backToRuleManager()
|
||||
{
|
||||
// Intent returnIntent = new Intent();
|
||||
// returnIntent.putExtra("urlToTrigger", existingUrl);
|
||||
|
||||
// setResult(RESULT_OK, returnIntent);
|
||||
|
||||
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);
|
||||
@ -145,16 +136,14 @@ public class ActivityEditSendTextMessage extends Activity
|
||||
|
||||
private void openContactsDialogue()
|
||||
{
|
||||
// Toast.makeText(ActivityEditSendTextMessage.this, "Opening contacts dialogue", Toast.LENGTH_LONG).show();
|
||||
|
||||
Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.CommonDataKinds.Phone.CONTENT_URI);
|
||||
startActivityForResult(intent, 1000);
|
||||
Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.CommonDataKinds.Phone.CONTENT_URI);
|
||||
startActivityForResult(intent, requestCodeGetContact);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data)
|
||||
{
|
||||
if(requestCode == 1000)
|
||||
if(requestCode == requestCodeGetContact)
|
||||
{
|
||||
if(resultCode == Activity.RESULT_OK)
|
||||
{
|
||||
@ -162,7 +151,7 @@ public class ActivityEditSendTextMessage extends Activity
|
||||
String name = null;
|
||||
|
||||
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())
|
||||
{
|
@ -10,7 +10,7 @@ import android.widget.Toast;
|
||||
|
||||
import com.jens.automation2.Action.Action_Enum;
|
||||
|
||||
public class ActivityEditSpeakText extends Activity
|
||||
public class ActivityManageActionSpeakText extends Activity
|
||||
{
|
||||
private Button bSaveSpeakText;
|
||||
private EditText etSpeakText;
|
||||
@ -24,7 +24,7 @@ public class ActivityEditSpeakText extends Activity
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
this.setContentView(R.layout.speak_text_editor);
|
||||
this.setContentView(R.layout.activity_manage_action_speak_text);
|
||||
|
||||
etSpeakText = (EditText)findViewById(R.id.etTextToSpeak);
|
||||
bSaveSpeakText = (Button)findViewById(R.id.bSaveTriggerUrl);
|
||||
@ -48,9 +48,9 @@ public class ActivityEditSpeakText extends Activity
|
||||
}
|
||||
});
|
||||
|
||||
ActivityEditSpeakText.edit = getIntent().getBooleanExtra("edit", false);
|
||||
ActivityManageActionSpeakText.edit = getIntent().getBooleanExtra("edit", false);
|
||||
if(edit)
|
||||
etSpeakText.setText(ActivityEditSpeakText.resultingAction.getParameter2());
|
||||
etSpeakText.setText(ActivityManageActionSpeakText.resultingAction.getParameter2());
|
||||
|
||||
|
||||
// String url = getIntent().getStringExtra("urlToTrigger");
|
||||
@ -66,7 +66,7 @@ public class ActivityEditSpeakText extends Activity
|
||||
// setResult(RESULT_OK, returnIntent);
|
||||
|
||||
if(edit && resultingAction != null)
|
||||
ActivityEditSpeakText.resultingAction.setParameter2(etSpeakText.getText().toString());
|
||||
ActivityManageActionSpeakText.resultingAction.setParameter2(etSpeakText.getText().toString());
|
||||
|
||||
setResult(RESULT_OK);
|
||||
|
@ -10,6 +10,7 @@ import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.text.InputType;
|
||||
@ -22,10 +23,11 @@ import android.widget.AdapterView.OnItemLongClickListener;
|
||||
import android.widget.AdapterView.OnItemSelectedListener;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ListView;
|
||||
import android.widget.RadioButton;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.jens.automation2.Action.Action_Enum;
|
||||
@ -35,15 +37,23 @@ import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
public class ActivityManageStartActivity extends Activity
|
||||
public class ActivityManageActionStartActivity extends Activity
|
||||
{
|
||||
/*
|
||||
This page might qualify as a help page: https://stackoverflow.com/questions/55323947/open-url-in-firefox-for-android-using-intent
|
||||
*/
|
||||
|
||||
ListView lvIntentPairs;
|
||||
EditText etParameterName, etParameterValue;
|
||||
Button bSelectApp, bAddIntentPair, bSaveActionStartOtherActivity;
|
||||
EditText etParameterName, etParameterValue, etPackageName, etActivityOrActionPath;
|
||||
Button bSelectApp, bAddIntentPair, bSaveActionStartOtherActivity, showStartProgramExamples;
|
||||
Spinner spinnerParameterType;
|
||||
TextView tvSelectedActivity;
|
||||
boolean edit = false;
|
||||
ProgressDialog progressDialog = null;
|
||||
RadioButton rbStartAppSelectByActivity, rbStartAppSelectByAction, rbStartAppByActivity, rbStartAppByBroadcast;
|
||||
|
||||
final String urlShowExamples = "https://server47.de/automation/examples_startProgram.html";
|
||||
final static String startByActivityString = "0";
|
||||
final static String startByBroadcastString = "1";
|
||||
|
||||
private class CustomPackageInfo extends PackageInfo implements Comparable<CustomPackageInfo>
|
||||
{
|
||||
@ -56,12 +66,12 @@ public class ActivityManageStartActivity extends Activity
|
||||
ApplicationInfo aInfo1 = this.applicationInfo;
|
||||
if (aInfo1 != null)
|
||||
{
|
||||
name1 = (String) ActivityManageStartActivity.this.getPackageManager().getApplicationLabel(aInfo1);
|
||||
name1 = (String) ActivityManageActionStartActivity.this.getPackageManager().getApplicationLabel(aInfo1);
|
||||
}
|
||||
ApplicationInfo aInfo2 = another.applicationInfo;
|
||||
if (aInfo2 != null)
|
||||
{
|
||||
name2 = (String) ActivityManageStartActivity.this.getPackageManager().getApplicationLabel(aInfo2);
|
||||
name2 = (String) ActivityManageActionStartActivity.this.getPackageManager().getApplicationLabel(aInfo2);
|
||||
}
|
||||
|
||||
return name1.compareTo(name2);
|
||||
@ -72,7 +82,7 @@ public class ActivityManageStartActivity extends Activity
|
||||
private static List<PackageInfo> pInfos = null;
|
||||
public static Action resultingAction;
|
||||
|
||||
private static final String[] supportedIntentTypes = { "boolean", "byte", "char", "double", "float", "int", "long", "short", "String" };
|
||||
private static final String[] supportedIntentTypes = { "boolean", "byte", "char", "double", "float", "int", "long", "short", "String", "Uri" };
|
||||
private ArrayList<String> intentPairList = new ArrayList<String>();
|
||||
|
||||
ArrayAdapter<String> intentTypeSpinnerAdapter, intentPairAdapter;
|
||||
@ -224,7 +234,7 @@ public class ActivityManageStartActivity extends Activity
|
||||
{
|
||||
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
|
||||
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()
|
||||
{
|
||||
@Override
|
||||
@ -242,14 +252,14 @@ public class ActivityManageStartActivity extends Activity
|
||||
{
|
||||
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
|
||||
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()
|
||||
{
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which)
|
||||
{
|
||||
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 +271,15 @@ public class ActivityManageStartActivity extends Activity
|
||||
{
|
||||
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
|
||||
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()
|
||||
{
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which)
|
||||
{
|
||||
ActivityInfo ai = ActivityManageStartActivity.getActivityInfoForPackageNameAndActivityName(packageName, activityArray[which]);
|
||||
tvSelectedActivity.setText(ai.packageName + ";" + ai.name);
|
||||
ActivityInfo ai = ActivityManageActionStartActivity.getActivityInfoForPackageNameAndActivityName(packageName, activityArray[which]);
|
||||
etPackageName.setText(ai.packageName);
|
||||
etActivityOrActionPath.setText(ai.name);
|
||||
}
|
||||
});
|
||||
AlertDialog alertDialog = alertDialogBuilder.create();
|
||||
@ -280,7 +291,7 @@ public class ActivityManageStartActivity extends Activity
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.action_start_activity);
|
||||
setContentView(R.layout.activity_manage_action_start_activity);
|
||||
|
||||
lvIntentPairs = (ListView)findViewById(R.id.lvIntentPairs);
|
||||
etParameterName = (EditText)findViewById(R.id.etParameterName);
|
||||
@ -289,13 +300,20 @@ public class ActivityManageStartActivity extends Activity
|
||||
bAddIntentPair = (Button)findViewById(R.id.bAddIntentPair);
|
||||
bSaveActionStartOtherActivity = (Button)findViewById(R.id.bSaveActionStartOtherActivity);
|
||||
spinnerParameterType = (Spinner)findViewById(R.id.spinnerParameterType);
|
||||
tvSelectedActivity = (TextView)findViewById(R.id.tvSelectedActivity);
|
||||
etPackageName = (EditText) findViewById(R.id.etPackageName);
|
||||
etActivityOrActionPath = (EditText) findViewById(R.id.etActivityOrActionPath);
|
||||
rbStartAppSelectByActivity = (RadioButton)findViewById(R.id.rbStartAppSelectByActivity);
|
||||
rbStartAppSelectByAction = (RadioButton)findViewById(R.id.rbStartAppSelectByAction);
|
||||
showStartProgramExamples = (Button)findViewById(R.id.showStartProgramExamples);
|
||||
|
||||
rbStartAppByActivity = (RadioButton)findViewById(R.id.rbStartAppByActivity);
|
||||
rbStartAppByBroadcast = (RadioButton)findViewById(R.id.rbStartAppByBroadcast);
|
||||
|
||||
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);
|
||||
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()
|
||||
{
|
||||
@ -304,7 +322,7 @@ public class ActivityManageStartActivity extends Activity
|
||||
{
|
||||
GetActivityListTask getActivityListTask = new GetActivityListTask();
|
||||
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,23 +334,43 @@ public class ActivityManageStartActivity extends Activity
|
||||
// type;name;value
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
else if(etParameterName.getText().toString().contains(Action.intentPairSeperator))
|
||||
{
|
||||
Toast.makeText(ActivityManageActionStartActivity.this, String.format(getResources().getString(R.string.stringNotAllowed), Action.intentPairSeperator), Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
else if(etParameterName.getText().toString().contains(";"))
|
||||
{
|
||||
Toast.makeText(ActivityManageActionStartActivity.this, String.format(getResources().getString(R.string.stringNotAllowed), ";"), Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
else if(etParameterValue.getText().toString().contains(Action.intentPairSeperator))
|
||||
{
|
||||
Toast.makeText(ActivityManageActionStartActivity.this, String.format(getResources().getString(R.string.stringNotAllowed), Action.intentPairSeperator), Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
else if(etParameterValue.getText().toString().contains(";"))
|
||||
{
|
||||
Toast.makeText(ActivityManageActionStartActivity.this, String.format(getResources().getString(R.string.stringNotAllowed), ";"), Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
|
||||
String param = supportedIntentTypes[spinnerParameterType.getSelectedItemPosition()] + "/" + etParameterName.getText().toString() + "/" + etParameterValue.getText().toString();
|
||||
String param = supportedIntentTypes[spinnerParameterType.getSelectedItemPosition()] + Action.intentPairSeperator + etParameterName.getText().toString() + Action.intentPairSeperator + etParameterValue.getText().toString();
|
||||
intentPairList.add(param);
|
||||
|
||||
spinnerParameterType.setSelection(0);
|
||||
@ -340,6 +378,19 @@ public class ActivityManageStartActivity extends Activity
|
||||
etParameterValue.setText("");
|
||||
|
||||
updateIntentPairList();
|
||||
|
||||
if(lvIntentPairs.getVisibility() != View.VISIBLE)
|
||||
lvIntentPairs.setVisibility(View.VISIBLE);
|
||||
}
|
||||
});
|
||||
|
||||
showStartProgramExamples.setOnClickListener(new OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(urlShowExamples));
|
||||
startActivity(browserIntent);
|
||||
}
|
||||
});
|
||||
|
||||
@ -360,7 +411,7 @@ public class ActivityManageStartActivity extends Activity
|
||||
{
|
||||
if(saveAction())
|
||||
{
|
||||
ActivityManageStartActivity.this.setResult(RESULT_OK);
|
||||
ActivityManageActionStartActivity.this.setResult(RESULT_OK);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
@ -382,9 +433,9 @@ public class ActivityManageStartActivity extends Activity
|
||||
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"))
|
||||
ActivityManageStartActivity.this.etParameterValue.setInputType(InputType.TYPE_CLASS_NUMBER);
|
||||
ActivityManageActionStartActivity.this.etParameterValue.setInputType(InputType.TYPE_CLASS_NUMBER);
|
||||
else
|
||||
ActivityManageStartActivity.this.etParameterValue.setInputType(InputType.TYPE_CLASS_TEXT);
|
||||
ActivityManageActionStartActivity.this.etParameterValue.setInputType(InputType.TYPE_CLASS_TEXT);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -394,6 +445,26 @@ public class ActivityManageStartActivity extends Activity
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
rbStartAppSelectByActivity.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener()
|
||||
{
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
|
||||
{
|
||||
if(isChecked)
|
||||
bSelectApp.setEnabled(isChecked);
|
||||
}
|
||||
});
|
||||
|
||||
rbStartAppSelectByAction.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener()
|
||||
{
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
|
||||
{
|
||||
if(isChecked)
|
||||
bSelectApp.setEnabled(!isChecked);
|
||||
}
|
||||
});
|
||||
|
||||
Intent i = getIntent();
|
||||
if(i.getBooleanExtra("edit", false) == true)
|
||||
@ -405,22 +476,46 @@ public class ActivityManageStartActivity extends Activity
|
||||
|
||||
private void loadValuesIntoGui()
|
||||
{
|
||||
boolean selectionByAction = resultingAction.getParameter1();
|
||||
rbStartAppSelectByActivity.setChecked(!selectionByAction);
|
||||
rbStartAppSelectByAction.setChecked(selectionByAction);
|
||||
|
||||
String[] params = resultingAction.getParameter2().split(";");
|
||||
if(params.length >= 2)
|
||||
|
||||
rbStartAppByActivity.setChecked(params[2].equals(startByActivityString));
|
||||
rbStartAppByBroadcast.setChecked(params[2].equals(startByBroadcastString));
|
||||
|
||||
int startIndex = -1;
|
||||
|
||||
if(!selectionByAction)
|
||||
{
|
||||
tvSelectedActivity.setText(params[0] + ";" + params[1]);
|
||||
|
||||
if(params.length > 2)
|
||||
etPackageName.setText(params[0]);
|
||||
etActivityOrActionPath.setText(params[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!params[0].contains(Actions.dummyPackageString))
|
||||
etPackageName.setText(params[0]);
|
||||
|
||||
etActivityOrActionPath.setText(params[1]);
|
||||
}
|
||||
|
||||
if (params.length >= 3)
|
||||
startIndex = 3;
|
||||
|
||||
if(startIndex > -1 && params.length > startIndex)
|
||||
{
|
||||
intentPairList.clear();
|
||||
|
||||
for(int i=startIndex; i<params.length; i++)
|
||||
{
|
||||
intentPairList.clear();
|
||||
|
||||
for(int i=2; i<params.length; i++)
|
||||
{
|
||||
intentPairList.add(params[i]);
|
||||
}
|
||||
|
||||
updateIntentPairList();
|
||||
if(lvIntentPairs.getVisibility() != View.VISIBLE)
|
||||
lvIntentPairs.setVisibility(View.VISIBLE);
|
||||
|
||||
intentPairList.add(params[i]);
|
||||
}
|
||||
|
||||
updateIntentPairList();
|
||||
}
|
||||
}
|
||||
|
||||
@ -434,24 +529,52 @@ public class ActivityManageStartActivity extends Activity
|
||||
|
||||
private boolean saveAction()
|
||||
{
|
||||
if(tvSelectedActivity.getText().toString().length() == 0)
|
||||
if(rbStartAppSelectByActivity.isChecked())
|
||||
{
|
||||
Toast.makeText(ActivityManageStartActivity.this, getResources().getString(R.string.selectApplication), Toast.LENGTH_LONG).show();
|
||||
return false;
|
||||
if (etPackageName.getText().toString().length() == 0)
|
||||
{
|
||||
Toast.makeText(ActivityManageActionStartActivity.this, getResources().getString(R.string.enterPackageName), Toast.LENGTH_LONG).show();
|
||||
return false;
|
||||
}
|
||||
else if (etActivityOrActionPath.getText().toString().length() == 0)
|
||||
{
|
||||
Toast.makeText(ActivityManageActionStartActivity.this, getResources().getString(R.string.selectApplication), Toast.LENGTH_LONG).show();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(tvSelectedActivity.getText().toString().equals(getResources().getString(R.string.selectApplication)))
|
||||
else
|
||||
{
|
||||
Toast.makeText(this, getResources().getString(R.string.selectApplication), Toast.LENGTH_LONG).show();
|
||||
return false;
|
||||
if(etActivityOrActionPath.getText().toString().contains(";"))
|
||||
{
|
||||
Toast.makeText(this, getResources().getString(R.string.enterValidAction), Toast.LENGTH_LONG).show();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(resultingAction == null)
|
||||
resultingAction = new Action();
|
||||
|
||||
resultingAction.setParameter1(rbStartAppSelectByAction.isChecked());
|
||||
|
||||
resultingAction.setAction(Action_Enum.startOtherActivity);
|
||||
|
||||
String parameter2 = tvSelectedActivity.getText().toString();
|
||||
String parameter2 = "";
|
||||
|
||||
if(rbStartAppSelectByActivity.isChecked())
|
||||
parameter2 += etPackageName.getText().toString() + ";" + etActivityOrActionPath.getText().toString();
|
||||
else
|
||||
{
|
||||
if(etPackageName.getText().toString() != null && etPackageName.getText().toString().length() > 0)
|
||||
parameter2 += etPackageName.getText().toString() + ";" + etActivityOrActionPath.getText().toString();
|
||||
else
|
||||
parameter2 += Actions.dummyPackageString + ";" + etActivityOrActionPath.getText().toString();
|
||||
}
|
||||
|
||||
if(rbStartAppByActivity.isChecked())
|
||||
parameter2 += ";" + startByActivityString;
|
||||
else
|
||||
parameter2 += ";" + startByBroadcastString;
|
||||
|
||||
for(String s : intentPairList)
|
||||
parameter2 += ";" + s;
|
||||
|
||||
@ -462,7 +585,7 @@ public class ActivityManageStartActivity extends Activity
|
||||
|
||||
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.setItems(new String[]{getResources().getString(R.string.delete)}, new DialogInterface.OnClickListener()
|
||||
{
|
||||
@ -470,7 +593,7 @@ public class ActivityManageStartActivity extends Activity
|
||||
public void onClick(DialogInterface dialog, int which)
|
||||
{
|
||||
// Only 1 choice at the moment, no need to check
|
||||
ActivityManageStartActivity.this.intentPairList.remove(itemPosition);
|
||||
ActivityManageActionStartActivity.this.intentPairList.remove(itemPosition);
|
||||
updateIntentPairList();
|
||||
}
|
||||
});
|
||||
@ -484,7 +607,7 @@ public class ActivityManageStartActivity extends Activity
|
||||
@Override
|
||||
protected Void doInBackground(Void... params)
|
||||
{
|
||||
getActivityList(ActivityManageStartActivity.this);
|
||||
getActivityList(ActivityManageActionStartActivity.this);
|
||||
return null;
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ import com.jens.automation2.Action.Action_Enum;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class ActivityEditTriggerUrl extends Activity
|
||||
public class ActivityManageActionTriggerUrl extends Activity
|
||||
{
|
||||
Button bSaveTriggerUrl;
|
||||
EditText etTriggerUrl, etTriggerUrlUsername, etTriggerUrlPassword;
|
||||
@ -39,7 +39,7 @@ public class ActivityEditTriggerUrl extends Activity
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
this.setContentView(R.layout.trigger_url_editor);
|
||||
this.setContentView(R.layout.activity_manage_action_trigger_url);
|
||||
|
||||
etTriggerUrl = (EditText)findViewById(R.id.etTriggerUrl);
|
||||
etTriggerUrlUsername = (EditText)findViewById(R.id.etTriggerUrlUsername);
|
||||
@ -70,7 +70,7 @@ public class ActivityEditTriggerUrl extends Activity
|
||||
if(password == null)
|
||||
password = "";
|
||||
|
||||
ActivityEditTriggerUrl.resultingAction.setParameter2(
|
||||
ActivityManageActionTriggerUrl.resultingAction.setParameter2(
|
||||
username + ";" +
|
||||
password + ";" +
|
||||
etTriggerUrl.getText().toString().trim()
|
||||
@ -110,16 +110,16 @@ public class ActivityEditTriggerUrl extends Activity
|
||||
updateListView();
|
||||
|
||||
|
||||
ActivityEditTriggerUrl.edit = getIntent().getBooleanExtra("edit", false);
|
||||
ActivityManageActionTriggerUrl.edit = getIntent().getBooleanExtra("edit", false);
|
||||
if(edit)
|
||||
{
|
||||
// username,password,URL
|
||||
String[] components = ActivityEditTriggerUrl.resultingAction.getParameter2().split(";");
|
||||
String[] components = ActivityManageActionTriggerUrl.resultingAction.getParameter2().split(";");
|
||||
|
||||
if(components.length >= 3)
|
||||
{
|
||||
etTriggerUrl.setText(components[2]);
|
||||
chkTriggerUrlUseAuthentication.setChecked(ActivityEditTriggerUrl.resultingAction.getParameter1());
|
||||
chkTriggerUrlUseAuthentication.setChecked(ActivityManageActionTriggerUrl.resultingAction.getParameter1());
|
||||
etTriggerUrlUsername.setText(components[0]);
|
||||
etTriggerUrlPassword.setText(components[1]);
|
||||
}
|
||||
@ -141,9 +141,9 @@ public class ActivityEditTriggerUrl extends Activity
|
||||
if(password == null)
|
||||
password = "";
|
||||
|
||||
ActivityEditTriggerUrl.resultingAction.setParameter1(chkTriggerUrlUseAuthentication.isChecked());
|
||||
ActivityManageActionTriggerUrl.resultingAction.setParameter1(chkTriggerUrlUseAuthentication.isChecked());
|
||||
|
||||
ActivityEditTriggerUrl.resultingAction.setParameter2(
|
||||
ActivityManageActionTriggerUrl.resultingAction.setParameter2(
|
||||
username + ";" +
|
||||
password + ";" +
|
||||
etTriggerUrl.getText().toString()
|
@ -0,0 +1,85 @@
|
||||
package com.jens.automation2;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.VibrationEffect;
|
||||
import android.os.Vibrator;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
public class ActivityManageActionVibrate extends Activity
|
||||
{
|
||||
TextView etVibratePattern;
|
||||
Button bTestVibratePattern, bSaveVibratePattern;
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_manage_action_vibrate);
|
||||
|
||||
etVibratePattern = (EditText)findViewById(R.id.etVibratePattern);
|
||||
bTestVibratePattern = (Button)findViewById(R.id.bTestVibratePattern);
|
||||
bSaveVibratePattern = (Button)findViewById(R.id.bSaveVibratePattern);
|
||||
|
||||
bSaveVibratePattern.setOnClickListener(new View.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(View view)
|
||||
{
|
||||
if(checkInput())
|
||||
{
|
||||
Intent answer = new Intent();
|
||||
answer.putExtra("vibratePattern", etVibratePattern.getText().toString());
|
||||
setResult(RESULT_OK, answer);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
bTestVibratePattern.setOnClickListener(new View.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
if(checkInput())
|
||||
{
|
||||
if (ActivityPermissions.havePermission(Manifest.permission.VIBRATE, ActivityManageActionVibrate.this))
|
||||
{
|
||||
String pattern = etVibratePattern.getText().toString();
|
||||
Actions.vibrate(false, pattern);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Intent input = getIntent();
|
||||
|
||||
if(input.hasExtra("vibratePattern"))
|
||||
etVibratePattern.setText(input.getStringExtra("vibratePattern"));
|
||||
}
|
||||
|
||||
boolean checkInput()
|
||||
{
|
||||
String vibratePattern = etVibratePattern.getText().toString();
|
||||
String regex = "^[0-9,]+$";
|
||||
if(StringUtils.isEmpty(vibratePattern) || !vibratePattern.matches(regex) || vibratePattern.substring(0, 1).equals(",") || vibratePattern.substring(vibratePattern.length()-1).equals(","))
|
||||
{
|
||||
Toast.makeText(ActivityManageActionVibrate.this, getResources().getString(R.string.pleaseEnterValidVibrationPattern), Toast.LENGTH_SHORT).show();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@ import android.location.LocationListener;
|
||||
import android.location.LocationManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Looper;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
@ -21,6 +22,10 @@ import android.widget.EditText;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
public class ActivityManagePoi extends Activity
|
||||
{
|
||||
public LocationManager myLocationManager;
|
||||
@ -31,6 +36,11 @@ public class ActivityManagePoi extends Activity
|
||||
Button bGetPosition, bSavePoi;
|
||||
ImageButton ibShowOnMap;
|
||||
EditText guiPoiName, guiPoiLatitude, guiPoiLongitude, guiPoiRadius;
|
||||
Calendar locationSearchStart = null;
|
||||
Timer timer = null;
|
||||
|
||||
final static int defaultRadius = 250;
|
||||
final static int searchTimeout = 120;
|
||||
|
||||
private static ProgressDialog progressDialog;
|
||||
|
||||
@ -47,7 +57,7 @@ public class ActivityManagePoi extends Activity
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
this.setContentView(R.layout.manage_specific_poi);
|
||||
this.setContentView(R.layout.activity_manage_specific_poi);
|
||||
|
||||
myLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
|
||||
bGetPosition = (Button)findViewById(R.id.bGetPosition);
|
||||
@ -104,7 +114,7 @@ public class ActivityManagePoi extends Activity
|
||||
myLocationManager.removeUpdates(myLocationListenerGps);
|
||||
ActivityMainPoi.poiToEdit = new PointOfInterest();
|
||||
ActivityMainPoi.poiToEdit.setLocation(new Location("POINT_LOCATION"));
|
||||
if(loadFormValuesToVariable())
|
||||
if(loadFormValuesToVariable(false))
|
||||
if(ActivityMainPoi.poiToEdit.create(this))
|
||||
{
|
||||
this.setResult(RESULT_OK);
|
||||
@ -114,7 +124,7 @@ public class ActivityManagePoi extends Activity
|
||||
private void changePoi()
|
||||
{
|
||||
myLocationManager.removeUpdates(myLocationListenerGps);
|
||||
if(loadFormValuesToVariable())
|
||||
if(loadFormValuesToVariable(false))
|
||||
if(ActivityMainPoi.poiToEdit.change(this))
|
||||
{
|
||||
this.setResult(RESULT_OK);
|
||||
@ -150,47 +160,142 @@ public class ActivityManagePoi extends Activity
|
||||
}
|
||||
else
|
||||
{
|
||||
Miscellaneous.logEvent("i", "POI Manager", getResources().getString(R.string.logGettingPositionWithProvider) + " " + provider1, 3);
|
||||
myLocationManager.requestLocationUpdates(provider1, 500, Settings.satisfactoryAccuracyNetwork, myLocationListenerNetwork);
|
||||
|
||||
locationSearchStart = Calendar.getInstance();
|
||||
startTimeout();
|
||||
|
||||
if(!Settings.privacyLocationing)
|
||||
{
|
||||
Miscellaneous.logEvent("i", "POI Manager", getResources().getString(R.string.logGettingPositionWithProvider) + " " + provider1, 3);
|
||||
myLocationManager.requestLocationUpdates(provider1, 500, Settings.satisfactoryAccuracyNetwork, myLocationListenerNetwork);
|
||||
}
|
||||
else
|
||||
Miscellaneous.logEvent("i", "POI Manager", "Skipping network location query because private locationing is active.", 4);
|
||||
|
||||
Miscellaneous.logEvent("i", "POI Manager", getResources().getString(R.string.logGettingPositionWithProvider) + " " + provider2, 3);
|
||||
myLocationManager.requestLocationUpdates(provider2, 500, Settings.satisfactoryAccuracyGps, myLocationListenerGps);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void compareLocations()
|
||||
|
||||
private void startTimeout()
|
||||
{
|
||||
if(timer != null)
|
||||
stopTimeout();
|
||||
|
||||
timer = new Timer();
|
||||
|
||||
class TimeoutTask extends TimerTask
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
evaluateLocationResults();
|
||||
}
|
||||
}
|
||||
|
||||
Miscellaneous.logEvent("i", "POI Manager", "Starting timeout for location search: " + String.valueOf(searchTimeout) + " seconds", 5);
|
||||
|
||||
TimerTask timeoutTask = new TimeoutTask();
|
||||
timer.schedule(timeoutTask, searchTimeout * 1000);
|
||||
}
|
||||
|
||||
private void stopTimeout()
|
||||
{
|
||||
Miscellaneous.logEvent("i", "POI Manager", "Stopping timeout for location search.", 5);
|
||||
|
||||
if(timer != null)
|
||||
{
|
||||
timer.purge();
|
||||
timer.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
private void evaluateLocationResults()
|
||||
{
|
||||
/*
|
||||
Procedure:
|
||||
If we get a GPS result we take it and suggest a default minimum radius.
|
||||
If private locationing is active that's the only possible outcome other than a timeout.
|
||||
|
||||
If private locationing is not active
|
||||
If we get a network
|
||||
*/
|
||||
|
||||
// We have GPS
|
||||
if(locationGps != null)
|
||||
{
|
||||
myLocationManager.removeUpdates(myLocationListenerNetwork);
|
||||
|
||||
guiPoiLatitude.setText(String.valueOf(locationGps.getLatitude()));
|
||||
guiPoiLongitude.setText(String.valueOf(locationGps.getLongitude()));
|
||||
|
||||
String text;
|
||||
if(locationNetwork != null)
|
||||
{
|
||||
Miscellaneous.logEvent("i", "POI Manager", getResources().getString(R.string.comparing), 4);
|
||||
|
||||
double variance = locationGps.distanceTo(locationNetwork);
|
||||
|
||||
String text = getResources().getString(R.string.distanceBetween) + " " + String.valueOf(Math.round(variance)) + " " + getResources().getString(R.string.radiusSuggestion);
|
||||
// Toast.makeText(getBaseContext(), text, Toast.LENGTH_LONG).show();
|
||||
Miscellaneous.logEvent("i", "POI Manager", text, 4);
|
||||
// if(variance > 50 && guiPoiRadius.getText().toString().length()>0 && Integer.parseInt(guiPoiRadius.getText().toString())<variance)
|
||||
// {
|
||||
// String text = "Positioning via network is off by " + variance + " meters. The radius you specify shouldn't be smaller than that.";
|
||||
getDialog(text, Math.round(variance) + 1).show();
|
||||
// Toast.makeText(getBaseContext(), "Positioning via network is off by " + variance + " meters. The radius you specify shouldn't be smaller than that.", Toast.LENGTH_LONG).show();
|
||||
// }
|
||||
text = String.format(getResources().getString(R.string.distanceBetween), Math.round(variance));
|
||||
getRadiusConfirmationDialog(text, Math.round(variance) + 1).show();
|
||||
}
|
||||
else
|
||||
{
|
||||
progressDialog.dismiss();
|
||||
myLocationManager.removeUpdates(myLocationListenerNetwork);
|
||||
guiPoiRadius.setText("250");
|
||||
text = String.format(getResources().getString(R.string.locationFound), defaultRadius);
|
||||
getRadiusConfirmationDialog(text, defaultRadius).show();
|
||||
}
|
||||
Miscellaneous.logEvent("i", "POI Manager", text, 4);
|
||||
} // we have a great network signal:
|
||||
else if(locationNetwork != null && locationNetwork.getAccuracy() <= Settings.satisfactoryAccuracyGps && locationNetwork.getAccuracy() <= defaultRadius)
|
||||
{
|
||||
/*
|
||||
We do not yet have a GPS result. But we have a network result that is good enough
|
||||
to accept it a sole result. In that case we suggest a default radius, no variance.
|
||||
*/
|
||||
|
||||
guiPoiLatitude.setText(String.valueOf(locationNetwork.getLatitude()));
|
||||
guiPoiLongitude.setText(String.valueOf(locationNetwork.getLongitude()));
|
||||
|
||||
String text = String.format(getResources().getString(R.string.locationFound), defaultRadius);
|
||||
Miscellaneous.logEvent("i", "POI Manager", text, 4);
|
||||
|
||||
getRadiusConfirmationDialog(text, defaultRadius).show();
|
||||
}
|
||||
else if( // we have a bad network signal and nothing else, GPS result may still come in
|
||||
locationNetwork != null
|
||||
&&
|
||||
Calendar.getInstance().getTimeInMillis()
|
||||
<
|
||||
(locationSearchStart.getTimeInMillis() + ((long)searchTimeout * 1000))
|
||||
)
|
||||
{
|
||||
// Only a network location was found and it is also not very accurate.
|
||||
}
|
||||
else if( // we have a bad network signal and nothing else, timeout has expired, nothing else can possibly come in
|
||||
locationNetwork != null
|
||||
&&
|
||||
Calendar.getInstance().getTimeInMillis()
|
||||
>
|
||||
(locationSearchStart.getTimeInMillis() + ((long)searchTimeout * 1000))
|
||||
)
|
||||
{
|
||||
// Only a network location was found and it is also not very accurate.
|
||||
|
||||
guiPoiLatitude.setText(String.valueOf(locationNetwork.getLatitude()));
|
||||
guiPoiLongitude.setText(String.valueOf(locationNetwork.getLongitude()));
|
||||
|
||||
String text = String.format(getResources().getString(R.string.locationFoundInaccurate), defaultRadius);
|
||||
getRadiusConfirmationDialog(text, defaultRadius).show();
|
||||
Miscellaneous.logEvent("i", "POI Manager", text, 4);
|
||||
}
|
||||
else
|
||||
Miscellaneous.logEvent("i", "POI Manager", getResources().getString(R.string.logNotAllMeasurings), 4);
|
||||
{
|
||||
String text = String.format(getResources().getString(R.string.noLocationCouldBeFound), String.valueOf(searchTimeout));
|
||||
Miscellaneous.logEvent("i", "POI Manager", text, 2);
|
||||
|
||||
if(myLocationListenerNetwork != null)
|
||||
myLocationManager.removeUpdates(myLocationListenerNetwork);
|
||||
|
||||
myLocationManager.removeUpdates(myLocationListenerGps);
|
||||
progressDialog.dismiss();
|
||||
getErrorDialog(text).show();
|
||||
}
|
||||
}
|
||||
|
||||
private AlertDialog getNotificationDialog(String text)
|
||||
@ -202,15 +307,6 @@ public class ActivityManagePoi extends Activity
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which)
|
||||
{
|
||||
// switch(which)
|
||||
// {
|
||||
// case DialogInterface.BUTTON_POSITIVE:
|
||||
// guiPoiRadius.setText(String.valueOf(value));
|
||||
// break;
|
||||
// case DialogInterface.BUTTON_NEGATIVE:
|
||||
// break;
|
||||
// }
|
||||
|
||||
progressDialog = ProgressDialog.show(ActivityManagePoi.this, "", getResources().getString(R.string.gettingPosition), true, true);
|
||||
getLocation();
|
||||
}
|
||||
@ -221,8 +317,11 @@ public class ActivityManagePoi extends Activity
|
||||
|
||||
return alertDialog;
|
||||
}
|
||||
private AlertDialog getDialog(String text, final double value)
|
||||
|
||||
private AlertDialog getRadiusConfirmationDialog(String text, final double value)
|
||||
{
|
||||
stopTimeout();
|
||||
|
||||
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
|
||||
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener()
|
||||
{
|
||||
@ -247,10 +346,31 @@ public class ActivityManagePoi extends Activity
|
||||
|
||||
return alertDialog;
|
||||
}
|
||||
|
||||
private AlertDialog getErrorDialog(String text)
|
||||
{
|
||||
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
|
||||
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which)
|
||||
{
|
||||
progressDialog.dismiss();
|
||||
}
|
||||
};
|
||||
alertDialogBuilder.setMessage(text);
|
||||
alertDialogBuilder.setPositiveButton(getResources().getString(R.string.ok), null);
|
||||
|
||||
if (Looper.myLooper() == null)
|
||||
Looper.prepare();
|
||||
|
||||
AlertDialog alertDialog = alertDialogBuilder.create();
|
||||
|
||||
return alertDialog;
|
||||
}
|
||||
|
||||
public class MyLocationListenerGps implements LocationListener
|
||||
{
|
||||
|
||||
@Override
|
||||
public void onLocationChanged(Location location)
|
||||
{
|
||||
@ -260,10 +380,11 @@ public class ActivityManagePoi extends Activity
|
||||
// {
|
||||
// Miscellaneous.logEvent("i", "POI Manager", "satisfactoryNetworkAccuracy of " + String.valueOf(Settings.SATISFACTORY_ACCURACY_GPS) + "m reached. Removing location updates...");
|
||||
|
||||
Miscellaneous.logEvent("i", "POI Manager", "Unsubscribing from GPS location updates.", 5);
|
||||
myLocationManager.removeUpdates(this);
|
||||
locationGps = location;
|
||||
|
||||
compareLocations();
|
||||
evaluateLocationResults();
|
||||
// }
|
||||
}
|
||||
|
||||
@ -287,66 +408,27 @@ public class ActivityManagePoi extends Activity
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
// public class MyLocationListenerWifi implements LocationListener
|
||||
// {
|
||||
//
|
||||
// @Override
|
||||
// public void onLocationChanged(Location location)
|
||||
// {
|
||||
// Miscellaneous.logEvent("i", "POI Manager", getResources().getString(R.string.gotGpsUpdate) + " " + String.valueOf(location.getAccuracy()));
|
||||
// // Deactivate when accuracy reached
|
||||
//// if(location.getAccuracy() < Settings.SATISFACTORY_ACCURACY_GPS)
|
||||
//// {
|
||||
//// Miscellaneous.logEvent("i", "POI Manager", "satisfactoryNetworkAccuracy of " + String.valueOf(Settings.SATISFACTORY_ACCURACY_GPS) + "m reached. Removing location updates...");
|
||||
//
|
||||
// myLocationManager.removeUpdates(this);
|
||||
// locationGps = location;
|
||||
//
|
||||
// compareLocations();
|
||||
//// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onProviderDisabled(String provider)
|
||||
// {
|
||||
// // TODO Auto-generated method stub
|
||||
//
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onProviderEnabled(String provider)
|
||||
// {
|
||||
// // TODO Auto-generated method stub
|
||||
//
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onStatusChanged(String provider, int status, Bundle extras)
|
||||
// {
|
||||
// // TODO Auto-generated method stub
|
||||
//
|
||||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
public class MyLocationListenerNetwork implements LocationListener
|
||||
{
|
||||
|
||||
@Override
|
||||
public void onLocationChanged(Location location)
|
||||
{
|
||||
Miscellaneous.logEvent("i", "POI Manager", getResources().getString(R.string.logGotNetworkUpdate) + " " + String.valueOf(location.getAccuracy()), 3);
|
||||
|
||||
myLocationManager.removeUpdates(this);
|
||||
locationNetwork = location;
|
||||
|
||||
// Deactivate when accuracy reached
|
||||
// if(location.getAccuracy() < Settings.SATISFACTORY_ACCURACY_GPS)
|
||||
// {
|
||||
// String text = "Network position found. satisfactoryNetworkAccuracy of " + String.valueOf(Settings.SATISFACTORY_ACCURACY_NETWORK) + "m reached. Removing location updates...";
|
||||
// Miscellaneous.logEvent("i", "POI Manager", text);
|
||||
myLocationManager.removeUpdates(this);
|
||||
locationNetwork = location;
|
||||
|
||||
compareLocations();
|
||||
// }
|
||||
if(location.getAccuracy() <= Settings.satisfactoryAccuracyGps)
|
||||
{
|
||||
// Accuracy is so good that we don't need to wait for GPS result
|
||||
Miscellaneous.logEvent("i", "POI Manager", "Unsubscribing from network location updates.", 5);
|
||||
myLocationManager.removeUpdates(myLocationListenerGps);
|
||||
}
|
||||
|
||||
evaluateLocationResults();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -369,7 +451,6 @@ public class ActivityManagePoi extends Activity
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void editPoi(PointOfInterest poi)
|
||||
@ -380,19 +461,22 @@ public class ActivityManagePoi extends Activity
|
||||
guiPoiRadius.setText(String.valueOf(poi.getRadius()));
|
||||
}
|
||||
|
||||
public boolean loadFormValuesToVariable()
|
||||
public boolean loadFormValuesToVariable(boolean checkOnlyCoordinates)
|
||||
{
|
||||
if(ActivityMainPoi.poiToEdit == null)
|
||||
ActivityMainPoi.poiToEdit = new PointOfInterest();
|
||||
|
||||
if(guiPoiName.getText().length() == 0)
|
||||
|
||||
if(!checkOnlyCoordinates)
|
||||
{
|
||||
Toast.makeText(this, getResources().getString(R.string.pleaseEnterValidName), Toast.LENGTH_LONG).show();
|
||||
return false;
|
||||
if (guiPoiName.getText().length() == 0)
|
||||
{
|
||||
Toast.makeText(this, getResources().getString(R.string.pleaseEnterValidName), Toast.LENGTH_LONG).show();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
ActivityMainPoi.poiToEdit.setName(guiPoiName.getText().toString());
|
||||
}
|
||||
else
|
||||
ActivityMainPoi.poiToEdit.setName(guiPoiName.getText().toString());
|
||||
|
||||
|
||||
if(ActivityMainPoi.poiToEdit.getLocation() == null)
|
||||
ActivityMainPoi.poiToEdit.setLocation(new Location("POINT_LOCATION"));
|
||||
|
||||
@ -415,28 +499,31 @@ public class ActivityManagePoi extends Activity
|
||||
Toast.makeText(this, getResources().getString(R.string.pleaseEnterValidLongitude), Toast.LENGTH_LONG).show();
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
|
||||
if(!checkOnlyCoordinates)
|
||||
{
|
||||
ActivityMainPoi.poiToEdit.setRadius(Double.parseDouble(guiPoiRadius.getText().toString()), this);
|
||||
try
|
||||
{
|
||||
ActivityMainPoi.poiToEdit.setRadius(Double.parseDouble(guiPoiRadius.getText().toString()), this);
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
Toast.makeText(this, getResources().getString(R.string.pleaseEnterValidRadius), Toast.LENGTH_LONG).show();
|
||||
return false;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Toast.makeText(this, getResources().getString(R.string.unknownError), Toast.LENGTH_LONG).show();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch(NumberFormatException e)
|
||||
{
|
||||
Toast.makeText(this, getResources().getString(R.string.pleaseEnterValidRadius), Toast.LENGTH_LONG).show();
|
||||
return false;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Toast.makeText(this, getResources().getString(R.string.unknownError), Toast.LENGTH_LONG).show();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void showOnMap()
|
||||
{
|
||||
if(loadFormValuesToVariable())
|
||||
if(loadFormValuesToVariable(true))
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -82,7 +82,7 @@ public class ActivityManageProfile extends Activity
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
this.setContentView(R.layout.manage_specific_profile);
|
||||
this.setContentView(R.layout.activity_manage_specific_profile);
|
||||
|
||||
checkBoxChangeSoundMode = (CheckBox)findViewById(R.id.checkBoxChangeSoundMode);
|
||||
checkBoxChangeVolumeMusicVideoGameMedia = (CheckBox)findViewById(R.id.checkBoxChangeVolumeMusicVideoGameMedia);
|
||||
|
@ -95,6 +95,17 @@ public class ActivityManageRule extends Activity
|
||||
final static int requestCodeActionScreenBrightnessAdd = 401;
|
||||
final static int requestCodeActionScreenBrightnessEdit = 402;
|
||||
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;
|
||||
final static int requestCodeTriggerPhoneCallAdd = 601;
|
||||
final static int requestCodeTriggerPhoneCallEdit = 602;
|
||||
final static int requestCodeTriggerWifiAdd = 723;
|
||||
final static int requestCodeTriggerWifiEdit = 724;
|
||||
final static int requestCodeActionSendTextMessageAdd = 5001;
|
||||
final static int requestCodeActionVibrateAdd = 801;
|
||||
final static int requestCodeActionVibrateEdit = 802;
|
||||
|
||||
public static ActivityManageRule getInstance()
|
||||
{
|
||||
@ -220,32 +231,35 @@ public class ActivityManageRule extends Activity
|
||||
Trigger selectedTrigger = (Trigger)triggerListView.getItemAtPosition(arg2);
|
||||
switch(selectedTrigger.getTriggerType())
|
||||
{
|
||||
// case batteryLevel:
|
||||
// break;
|
||||
// case charging:
|
||||
// break;
|
||||
// case noiseLevel:
|
||||
// break;
|
||||
// case pointOfInterest:
|
||||
// break;
|
||||
// case process_started_stopped:
|
||||
// break;
|
||||
// case speed:
|
||||
// break;
|
||||
case timeFrame:
|
||||
ActivityManageTimeFrame.editedTimeFrameTrigger = selectedTrigger;
|
||||
Intent timeFrameEditor = new Intent(ActivityManageRule.this, ActivityManageTimeFrame.class);
|
||||
ActivityManageTriggerTimeFrame.editedTimeFrameTrigger = selectedTrigger;
|
||||
Intent timeFrameEditor = new Intent(ActivityManageRule.this, ActivityManageTriggerTimeFrame.class);
|
||||
startActivityForResult(timeFrameEditor, requestCodeTriggerTimeframeEdit);
|
||||
break;
|
||||
// case usb_host_connection:
|
||||
// break;
|
||||
// case wifiConnection:
|
||||
// break;
|
||||
case bluetoothConnection:
|
||||
ActivityManageBluetoothTrigger.editedBluetoothTrigger = selectedTrigger;
|
||||
Intent bluetoothEditor = new Intent(ActivityManageRule.this, ActivityManageBluetoothTrigger.class);
|
||||
ActivityManageTriggerBluetooth.editedBluetoothTrigger = selectedTrigger;
|
||||
Intent bluetoothEditor = new Intent(ActivityManageRule.this, ActivityManageTriggerBluetooth.class);
|
||||
startActivityForResult(bluetoothEditor, requestCodeTriggerBluetoothEdit);
|
||||
break;
|
||||
case notification:
|
||||
ActivityManageTriggerNotification.editedNotificationTrigger = selectedTrigger;
|
||||
Intent notificationEditor = new Intent(ActivityManageRule.this, ActivityManageTriggerNotification.class);
|
||||
notificationEditor.putExtra("edit", true);
|
||||
startActivityForResult(notificationEditor, requestCodeTriggerNfcNotificationEdit);
|
||||
break;
|
||||
case phoneCall:
|
||||
ActivityManageTriggerPhoneCall.editedPhoneCallTrigger = selectedTrigger;
|
||||
Intent phoneCallEditor = new Intent(ActivityManageRule.this, ActivityManageTriggerPhoneCall.class);
|
||||
phoneCallEditor.putExtra("edit", true);
|
||||
startActivityForResult(phoneCallEditor, requestCodeTriggerPhoneCallEdit);
|
||||
break;
|
||||
case wifiConnection:
|
||||
Intent wifiEditor = new Intent(ActivityManageRule.this, ActivityManageTriggerWifi.class);
|
||||
wifiEditor.putExtra("edit", true);
|
||||
wifiEditor.putExtra("wifiState", selectedTrigger.getTriggerParameter());
|
||||
wifiEditor.putExtra("wifiName", selectedTrigger.getTriggerParameter2());
|
||||
startActivityForResult(wifiEditor, requestCodeTriggerWifiEdit);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -279,66 +293,48 @@ public class ActivityManageRule extends Activity
|
||||
Action a = (Action)actionListView.getItemAtPosition(arg2);
|
||||
switch(a.getAction())
|
||||
{
|
||||
// case changeSoundProfile:
|
||||
// break;
|
||||
// case disableScreenRotation:
|
||||
// break;
|
||||
// case enableScreenRotation:
|
||||
// break;
|
||||
// case setAirplaneMode:
|
||||
// break;
|
||||
case startOtherActivity:
|
||||
Intent intent = new Intent(ActivityManageRule.this, ActivityManageStartActivity.class);
|
||||
ActivityManageStartActivity.resultingAction = a;
|
||||
Intent intent = new Intent(ActivityManageRule.this, ActivityManageActionStartActivity.class);
|
||||
ActivityManageActionStartActivity.resultingAction = a;
|
||||
intent.putExtra("edit", true);
|
||||
startActivityForResult(intent, requestCodeActionStartActivityEdit);
|
||||
break;
|
||||
case triggerUrl:
|
||||
Intent activityEditTriggerUrlIntent = new Intent(ActivityManageRule.this, ActivityEditTriggerUrl.class);
|
||||
// activityEditTriggerUrlIntent.putExtra("urlToTrigger", a.getParameter2());
|
||||
ActivityEditTriggerUrl.resultingAction = a;
|
||||
Intent activityEditTriggerUrlIntent = new Intent(ActivityManageRule.this, ActivityManageActionTriggerUrl.class);
|
||||
ActivityManageActionTriggerUrl.resultingAction = a;
|
||||
activityEditTriggerUrlIntent.putExtra("edit", true);
|
||||
startActivityForResult(activityEditTriggerUrlIntent, requestCodeActionTriggerUrlEdit);
|
||||
break;
|
||||
// case turnBluetoothOff:
|
||||
// break;
|
||||
// case turnBluetoothOn:
|
||||
// break;
|
||||
// case turnUsbTetheringOff:
|
||||
// break;
|
||||
// case turnUsbTetheringOn:
|
||||
// break;
|
||||
// case turnWifiOff:
|
||||
// break;
|
||||
// case turnWifiOn:
|
||||
// break;
|
||||
// case turnWifiTetheringOff:
|
||||
// break;
|
||||
// case turnWifiTetheringOn:
|
||||
// break;
|
||||
// case waitBeforeNextAction:
|
||||
// break;
|
||||
// case wakeupDevice:
|
||||
// break;
|
||||
case speakText:
|
||||
Intent activitySpeakTextIntent = new Intent(ActivityManageRule.this, ActivityEditSpeakText.class);
|
||||
ActivityEditSpeakText.resultingAction = a;
|
||||
Intent activitySpeakTextIntent = new Intent(ActivityManageRule.this, ActivityManageActionSpeakText.class);
|
||||
ActivityManageActionSpeakText.resultingAction = a;
|
||||
activitySpeakTextIntent.putExtra("edit", true);
|
||||
startActivityForResult(activitySpeakTextIntent, requestCodeActionSpeakTextEdit);
|
||||
break;
|
||||
case sendTextMessage:
|
||||
Intent activitySendTextMessageIntent = new Intent(ActivityManageRule.this, ActivityEditSendTextMessage.class);
|
||||
ActivityEditSendTextMessage.resultingAction = a;
|
||||
Intent activitySendTextMessageIntent = new Intent(ActivityManageRule.this, ActivityManageActionSendTextMessage.class);
|
||||
ActivityManageActionSendTextMessage.resultingAction = a;
|
||||
activitySendTextMessageIntent.putExtra("edit", true);
|
||||
startActivityForResult(activitySendTextMessageIntent, requestCodeActionSendTextMessage);
|
||||
break;
|
||||
case setScreenBrightness:
|
||||
Intent activityEditScreenBrightnessIntent = new Intent(ActivityManageRule.this, ActivityManageBrightnessSetting.class);
|
||||
// ActivityEditTriggerUrl.resultingAction = a;
|
||||
Intent activityEditScreenBrightnessIntent = new Intent(ActivityManageRule.this, ActivityManageActionBrightnessSetting.class);
|
||||
activityEditScreenBrightnessIntent.putExtra("autoBrightness", a.getParameter1());
|
||||
activityEditScreenBrightnessIntent.putExtra("brightnessValue", Integer.parseInt(a.getParameter2()));
|
||||
startActivityForResult(activityEditScreenBrightnessIntent, requestCodeActionScreenBrightnessEdit);
|
||||
break;
|
||||
case vibrate:
|
||||
Intent activityEditVibrateIntent = new Intent(ActivityManageRule.this, ActivityManageActionVibrate.class);
|
||||
activityEditVibrateIntent.putExtra("vibratePattern", a.getParameter2());
|
||||
startActivityForResult(activityEditVibrateIntent, requestCodeActionVibrateEdit);
|
||||
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:
|
||||
Miscellaneous.logEvent("w", "Edit action", "Editing of action type " + a.getAction().toString() + " not implemented, yet.", 4);
|
||||
break;
|
||||
@ -466,6 +462,8 @@ public class ActivityManageRule extends Activity
|
||||
items.add(new Item(typesLong[i].toString(), R.drawable.bluetooth));
|
||||
else if(types[i].toString().equals(Trigger_Enum.headsetPlugged.toString()))
|
||||
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
|
||||
items.add(new Item(typesLong[i].toString(), R.drawable.placeholder));
|
||||
}
|
||||
@ -521,8 +519,8 @@ public class ActivityManageRule extends Activity
|
||||
else if(triggerType == Trigger_Enum.timeFrame)
|
||||
{
|
||||
newTrigger.setTriggerType(Trigger_Enum.timeFrame);
|
||||
ActivityManageTimeFrame.editedTimeFrameTrigger = newTrigger;
|
||||
Intent timeFrameEditor = new Intent(myContext, ActivityManageTimeFrame.class);
|
||||
ActivityManageTriggerTimeFrame.editedTimeFrameTrigger = newTrigger;
|
||||
Intent timeFrameEditor = new Intent(myContext, ActivityManageTriggerTimeFrame.class);
|
||||
startActivityForResult(timeFrameEditor, requestCodeTriggerTimeframeAdd);
|
||||
return;
|
||||
}
|
||||
@ -533,15 +531,36 @@ public class ActivityManageRule extends Activity
|
||||
else if(triggerType == Trigger_Enum.speed | triggerType == Trigger_Enum.noiseLevel | triggerType == Trigger_Enum.batteryLevel)
|
||||
booleanChoices = new String[]{getResources().getString(R.string.exceeds), getResources().getString(R.string.dropsBelow)};
|
||||
else if(triggerType == Trigger_Enum.wifiConnection)
|
||||
booleanChoices = new String[]{getResources().getString(R.string.connected), getResources().getString(R.string.disconnected)};
|
||||
{
|
||||
newTrigger.setTriggerType(Trigger_Enum.wifiConnection);
|
||||
Intent wifiTriggerEditor = new Intent(myContext, ActivityManageTriggerWifi.class);
|
||||
startActivityForResult(wifiTriggerEditor, requestCodeTriggerWifiAdd);
|
||||
return;
|
||||
// booleanChoices = new String[]{getResources().getString(R.string.started), getResources().getString(R.string.stopped)};
|
||||
}
|
||||
// else if(triggerType == Trigger_Enum.wifiConnection)
|
||||
// booleanChoices = new String[]{getResources().getString(R.string.connected), getResources().getString(R.string.disconnected)};
|
||||
else if(triggerType == Trigger_Enum.process_started_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)
|
||||
booleanChoices = new String[]{getResources().getString(R.string.activated), getResources().getString(R.string.deactivated)};
|
||||
else if(triggerType == Trigger_Enum.roaming)
|
||||
booleanChoices = new String[]{getResources().getString(R.string.activated), getResources().getString(R.string.deactivated)};
|
||||
else if(triggerType == Trigger_Enum.phoneCall)
|
||||
booleanChoices = new String[]{getResources().getString(R.string.started), getResources().getString(R.string.stopped)};
|
||||
{
|
||||
newTrigger.setTriggerType(Trigger_Enum.phoneCall);
|
||||
Intent phoneTriggerEditor = new Intent(myContext, ActivityManageTriggerPhoneCall.class);
|
||||
startActivityForResult(phoneTriggerEditor, requestCodeTriggerPhoneCallAdd);
|
||||
return;
|
||||
// booleanChoices = new String[]{getResources().getString(R.string.started), getResources().getString(R.string.stopped)};
|
||||
}
|
||||
else if(triggerType == Trigger_Enum.activityDetection)
|
||||
{
|
||||
try
|
||||
@ -572,7 +591,7 @@ public class ActivityManageRule extends Activity
|
||||
if(NfcReceiver.checkNfcRequirements(ActivityManageRule.this, true))
|
||||
{
|
||||
newTrigger.setTriggerType(Trigger_Enum.nfcTag);
|
||||
Intent nfcEditor = new Intent(myContext, ActivityManageNfc.class);
|
||||
Intent nfcEditor = new Intent(myContext, ActivityManageTriggerNfc.class);
|
||||
startActivityForResult(nfcEditor, requestCodeTriggerNfcTagAdd);
|
||||
return;
|
||||
}
|
||||
@ -583,8 +602,8 @@ public class ActivityManageRule extends Activity
|
||||
Miscellaneous.messageBox("Bluetooth", getResources().getString(R.string.deviceDoesNotHaveBluetooth), ActivityManageRule.this).show();;
|
||||
|
||||
newTrigger.setTriggerType(Trigger_Enum.bluetoothConnection);
|
||||
ActivityManageBluetoothTrigger.editedBluetoothTrigger = newTrigger;
|
||||
Intent bluetoothEditor = new Intent(myContext, ActivityManageBluetoothTrigger.class);
|
||||
ActivityManageTriggerBluetooth.editedBluetoothTrigger = newTrigger;
|
||||
Intent bluetoothEditor = new Intent(myContext, ActivityManageTriggerBluetooth.class);
|
||||
startActivityForResult(bluetoothEditor, requestCodeTriggerBluetoothAdd);
|
||||
return;
|
||||
}
|
||||
@ -650,13 +669,6 @@ public class ActivityManageRule extends Activity
|
||||
String[] choices = (String[]) choicesList.toArray(new String[choicesList.size()]);
|
||||
getTriggerNoiseDialog(myContext, choices).show();
|
||||
}
|
||||
// else if(triggerType.equals(Trigger.Event_Enum.timeFrame))
|
||||
// {
|
||||
// newTrigger.setTriggerType(Trigger.Event_Enum.timeFrame);
|
||||
// ActivityManageTimeFrame.editedTimeFrameTrigger = null;
|
||||
// Intent timeFrameEditor = new Intent(myContext, ActivityManageTimeFrame.class);
|
||||
// startActivityForResult(timeFrameEditor, 2000);
|
||||
// }
|
||||
else if(triggerType.equals(Trigger_Enum.wifiConnection))
|
||||
{
|
||||
newTrigger.setTriggerType(Trigger_Enum.wifiConnection);
|
||||
@ -667,7 +679,6 @@ public class ActivityManageRule extends Activity
|
||||
progressDialog = ProgressDialog.show(myContext, null, getResources().getString(R.string.gettingListOfInstalledApplications), true, false);
|
||||
newTrigger.setTriggerType(Trigger_Enum.process_started_stopped);
|
||||
new GenerateApplicationSelectionsDialogTask().execute(ActivityManageRule.this);
|
||||
// getTriggerRunningProcessDialog1(myContext).show();
|
||||
}
|
||||
else if(triggerType.equals(Trigger_Enum.phoneCall))
|
||||
{
|
||||
@ -800,7 +811,7 @@ public class ActivityManageRule extends Activity
|
||||
{
|
||||
public void onClick(DialogInterface dialog, int whichButton)
|
||||
{
|
||||
newTrigger.setWifiName(input.getText().toString());
|
||||
// newTrigger.setWifiName(input.getText().toString());
|
||||
ruleToEdit.getTriggerSet().add(newTrigger);
|
||||
refreshTriggerList();
|
||||
}
|
||||
@ -979,7 +990,7 @@ public class ActivityManageRule extends Activity
|
||||
protected String[] doInBackground(ActivityManageRule... params)
|
||||
{
|
||||
// Looper.prepare();
|
||||
final String[] applicationArray = ActivityManageStartActivity.getApplicationNameListString(params[0]);
|
||||
final String[] applicationArray = ActivityManageActionStartActivity.getApplicationNameListString(params[0]);
|
||||
return applicationArray;
|
||||
}
|
||||
|
||||
@ -1026,7 +1037,7 @@ public class ActivityManageRule extends Activity
|
||||
{
|
||||
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(myContext);
|
||||
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()
|
||||
{
|
||||
@Override
|
||||
@ -1046,7 +1057,7 @@ public class ActivityManageRule extends Activity
|
||||
{
|
||||
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(myContext);
|
||||
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()
|
||||
{
|
||||
@Override
|
||||
@ -1074,7 +1085,7 @@ public class ActivityManageRule extends Activity
|
||||
if(resultCode == RESULT_OK)
|
||||
{
|
||||
//add TriggerUrl
|
||||
ruleToEdit.getActionSet().add(ActivityEditTriggerUrl.resultingAction);
|
||||
ruleToEdit.getActionSet().add(ActivityManageActionTriggerUrl.resultingAction);
|
||||
this.refreshActionList();
|
||||
}
|
||||
}
|
||||
@ -1089,7 +1100,7 @@ public class ActivityManageRule extends Activity
|
||||
else if(requestCode == requestCodeTriggerTimeframeAdd)
|
||||
{
|
||||
//add TimeFrame
|
||||
if(resultCode == RESULT_OK && ActivityManageTimeFrame.editedTimeFrameTrigger != null)
|
||||
if(resultCode == RESULT_OK && ActivityManageTriggerTimeFrame.editedTimeFrameTrigger != null)
|
||||
{
|
||||
ruleToEdit.getTriggerSet().add(newTrigger);
|
||||
this.refreshTriggerList();
|
||||
@ -1100,19 +1111,38 @@ public class ActivityManageRule extends Activity
|
||||
else if(requestCode == requestCodeTriggerTimeframeEdit)
|
||||
{
|
||||
//edit TimeFrame
|
||||
if(resultCode == RESULT_OK && ActivityManageTimeFrame.editedTimeFrameTrigger != null)
|
||||
if(resultCode == RESULT_OK && ActivityManageTriggerTimeFrame.editedTimeFrameTrigger != null)
|
||||
{
|
||||
this.refreshTriggerList();
|
||||
}
|
||||
else
|
||||
Miscellaneous.logEvent("w", "TimeFrameEdit", "No timeframe returned. Assuming abort.", 5);
|
||||
}
|
||||
else if(requestCode == requestCodeTriggerWifiAdd)
|
||||
{
|
||||
if(resultCode == RESULT_OK)
|
||||
{
|
||||
newTrigger.setTriggerParameter(data.getBooleanExtra("wifiState", false));
|
||||
newTrigger.setTriggerParameter2(data.getStringExtra("wifiName"));
|
||||
ruleToEdit.getTriggerSet().add(newTrigger);
|
||||
this.refreshTriggerList();
|
||||
}
|
||||
}
|
||||
else if(requestCode == requestCodeTriggerWifiEdit)
|
||||
{
|
||||
if(resultCode == RESULT_OK)
|
||||
{
|
||||
newTrigger.setTriggerParameter(data.getBooleanExtra("wifiState", false));
|
||||
newTrigger.setTriggerParameter2(data.getStringExtra("wifiName"));
|
||||
this.refreshTriggerList();
|
||||
}
|
||||
}
|
||||
else if(requestCode == requestCodeActionStartActivityAdd)
|
||||
{
|
||||
// manage start of other activity
|
||||
if(resultCode == RESULT_OK)
|
||||
{
|
||||
newAction = ActivityManageStartActivity.resultingAction;
|
||||
newAction = ActivityManageActionStartActivity.resultingAction;
|
||||
ruleToEdit.getActionSet().add(newAction);
|
||||
this.refreshActionList();
|
||||
}
|
||||
@ -1122,7 +1152,7 @@ public class ActivityManageRule extends Activity
|
||||
// manage start of other activity
|
||||
if(resultCode == RESULT_OK)
|
||||
{
|
||||
newAction = ActivityManageStartActivity.resultingAction;
|
||||
newAction = ActivityManageActionStartActivity.resultingAction;
|
||||
// ruleToEdit.getActionSet().add(newAction);
|
||||
this.refreshActionList();
|
||||
}
|
||||
@ -1130,21 +1160,63 @@ public class ActivityManageRule extends Activity
|
||||
else if(requestCode == requestCodeTriggerNfcTagAdd)
|
||||
{
|
||||
//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);
|
||||
this.refreshTriggerList();
|
||||
}
|
||||
else
|
||||
Miscellaneous.logEvent("w", "ActivityManageNfc", "No nfc id returned. Assuming abort.", 5);
|
||||
}
|
||||
else if(requestCode == requestCodeTriggerNotificationAdd)
|
||||
{
|
||||
//add notification
|
||||
if(resultCode == RESULT_OK)
|
||||
{
|
||||
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 if(requestCode == requestCodeTriggerNfcNotificationEdit)
|
||||
{
|
||||
if(resultCode == RESULT_OK)
|
||||
{
|
||||
newTrigger = ActivityManageTriggerNotification.resultingTrigger;
|
||||
this.refreshTriggerList();
|
||||
}
|
||||
}
|
||||
else if(requestCode == requestCodeTriggerPhoneCallAdd)
|
||||
{
|
||||
if(resultCode == RESULT_OK)
|
||||
{
|
||||
ruleToEdit.getTriggerSet().add(newTrigger);
|
||||
newTrigger.setTriggerParameter2(data.getStringExtra("triggerParameter2"));
|
||||
this.refreshTriggerList();
|
||||
}
|
||||
}
|
||||
else if(requestCode == requestCodeTriggerPhoneCallEdit)
|
||||
{
|
||||
if(resultCode == RESULT_OK)
|
||||
{
|
||||
newTrigger = ActivityManageTriggerPhoneCall.resultingTrigger;
|
||||
this.refreshTriggerList();
|
||||
}
|
||||
}
|
||||
else if(requestCode == requestCodeActionSpeakTextAdd)
|
||||
{
|
||||
if(resultCode == RESULT_OK)
|
||||
{
|
||||
//add SpeakText
|
||||
ruleToEdit.getActionSet().add(ActivityEditSpeakText.resultingAction);
|
||||
ruleToEdit.getActionSet().add(ActivityManageActionSpeakText.resultingAction);
|
||||
this.refreshActionList();
|
||||
}
|
||||
}
|
||||
@ -1153,14 +1225,14 @@ public class ActivityManageRule extends Activity
|
||||
if(resultCode == RESULT_OK)
|
||||
{
|
||||
//add SpeakText
|
||||
ruleToEdit.getActionSet().add(ActivityEditSendTextMessage.resultingAction);
|
||||
ruleToEdit.getActionSet().add(ActivityManageActionSendTextMessage.resultingAction);
|
||||
this.refreshActionList();
|
||||
}
|
||||
}
|
||||
else if(requestCode == requestCodeTriggerBluetoothAdd)
|
||||
{
|
||||
//add bluetooth trigger
|
||||
if(resultCode == RESULT_OK && ActivityManageBluetoothTrigger.editedBluetoothTrigger != null)
|
||||
if(resultCode == RESULT_OK && ActivityManageTriggerBluetooth.editedBluetoothTrigger != null)
|
||||
{
|
||||
ruleToEdit.getTriggerSet().add(newTrigger);
|
||||
this.refreshTriggerList();
|
||||
@ -1171,7 +1243,7 @@ public class ActivityManageRule extends Activity
|
||||
else if(requestCode == requestCodeTriggerBluetoothEdit)
|
||||
{
|
||||
//edit bluetooth trigger
|
||||
if(resultCode == RESULT_OK && ActivityManageBluetoothTrigger.editedBluetoothTrigger != null)
|
||||
if(resultCode == RESULT_OK && ActivityManageTriggerBluetooth.editedBluetoothTrigger != null)
|
||||
{
|
||||
this.refreshTriggerList();
|
||||
}
|
||||
@ -1201,6 +1273,48 @@ public class ActivityManageRule extends Activity
|
||||
this.refreshActionList();
|
||||
}
|
||||
}
|
||||
else if(requestCode == requestCodeActionVibrateAdd)
|
||||
{
|
||||
if(resultCode == RESULT_OK)
|
||||
{
|
||||
newAction.setParameter2(data.getStringExtra("vibratePattern"));
|
||||
ruleToEdit.getActionSet().add(newAction);
|
||||
this.refreshActionList();
|
||||
}
|
||||
}
|
||||
else if(requestCode == requestCodeActionVibrateEdit)
|
||||
{
|
||||
if(resultCode == RESULT_OK)
|
||||
{
|
||||
if(data.hasExtra("vibratePattern"))
|
||||
ruleToEdit.getActionSet().get(editIndex).setParameter2(data.getStringExtra("vibratePattern"));
|
||||
|
||||
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.
|
||||
/*try
|
||||
@ -1253,6 +1367,10 @@ public class ActivityManageRule extends Activity
|
||||
items.add(new Item(typesLong[i].toString(), R.drawable.tune));
|
||||
else if(types[i].toString().equals(Action_Enum.setScreenBrightness.toString()))
|
||||
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.vibrate.toString()))
|
||||
items.add(new Item(typesLong[i].toString(), R.drawable.vibrate));
|
||||
else if(types[i].toString().equals(Action_Enum.sendTextMessage.toString()))
|
||||
{
|
||||
// if(ActivityPermissions.isPermissionDeclaratedInManifest(ActivityManageSpecificRule.this, "android.permission.SEND_SMS") && !Miscellaneous.isGooglePlayInstalled(ActivityManageSpecificRule.this))
|
||||
@ -1262,159 +1380,163 @@ public class ActivityManageRule extends Activity
|
||||
else
|
||||
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)
|
||||
{
|
||||
public View getView(int position, View convertView, ViewGroup parent)
|
||||
{
|
||||
//User super class to create the View
|
||||
View v = super.getView(position, convertView, parent);
|
||||
|
||||
TextView tv = (TextView)v.findViewById(android.R.id.text1);
|
||||
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)
|
||||
{
|
||||
//User super class to create the View
|
||||
View v = super.getView(position, convertView, parent);
|
||||
|
||||
//Put the image on the TextView
|
||||
tv.setCompoundDrawablesWithIntrinsicBounds(items.get(position).icon, 0, 0, 0);
|
||||
TextView tv = (TextView)v.findViewById(android.R.id.text1);
|
||||
|
||||
//Add margin between image and text (support various screen densities)
|
||||
int dp5 = (int) (5 * getResources().getDisplayMetrics().density + 0.5f);
|
||||
tv.setCompoundDrawablePadding(dp5);
|
||||
//Put the image on the TextView
|
||||
tv.setCompoundDrawablesWithIntrinsicBounds(items.get(position).icon, 0, 0, 0);
|
||||
|
||||
return v;
|
||||
}
|
||||
};
|
||||
//Add margin between image and text (support various screen densities)
|
||||
int dp5 = (int) (5 * getResources().getDisplayMetrics().density + 0.5f);
|
||||
tv.setCompoundDrawablePadding(dp5);
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this)
|
||||
.setTitle(getResources().getString(R.string.selectTypeOfAction))
|
||||
.setAdapter(adapter, new DialogInterface.OnClickListener()
|
||||
{
|
||||
public void onClick(DialogInterface dialog, int which)
|
||||
{
|
||||
newAction = new Action();
|
||||
|
||||
if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.triggerUrl.toString()))
|
||||
return v;
|
||||
}
|
||||
};
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this)
|
||||
.setTitle(getResources().getString(R.string.selectTypeOfAction))
|
||||
.setAdapter(adapter, new DialogInterface.OnClickListener()
|
||||
{
|
||||
public void onClick(DialogInterface dialog, int which)
|
||||
{
|
||||
newAction = new Action();
|
||||
|
||||
if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.triggerUrl.toString()))
|
||||
{
|
||||
//launch other activity to enter a url and parameters;
|
||||
newAction.setAction(Action_Enum.triggerUrl);
|
||||
ActivityManageActionTriggerUrl.resultingAction = null;
|
||||
Intent editTriggerIntent = new Intent(context, ActivityManageActionTriggerUrl.class);
|
||||
startActivityForResult(editTriggerIntent, 1000);
|
||||
}
|
||||
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.setWifi.toString()))
|
||||
{
|
||||
newAction.setAction(Action_Enum.setWifi);
|
||||
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
|
||||
Toast.makeText(context, context.getResources().getString(R.string.android10WifiToggleNotice), Toast.LENGTH_LONG).show();
|
||||
getActionParameter1Dialog(ActivityManageRule.this).show();
|
||||
}
|
||||
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.setBluetooth.toString()))
|
||||
{
|
||||
if(!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH))
|
||||
Miscellaneous.messageBox("Bluetooth", getResources().getString(R.string.deviceDoesNotHaveBluetooth), ActivityManageRule.this).show();;
|
||||
newAction.setAction(Action_Enum.setBluetooth);
|
||||
getActionParameter1Dialog(ActivityManageRule.this).show();
|
||||
}
|
||||
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.setUsbTethering.toString()))
|
||||
{
|
||||
newAction.setAction(Action_Enum.setUsbTethering);
|
||||
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.GINGERBREAD_MR1)
|
||||
Miscellaneous.messageBox(context.getResources().getString(R.string.warning), context.getResources().getString(R.string.usbTetheringFailForAboveGingerbread), context).show();
|
||||
getActionParameter1Dialog(ActivityManageRule.this).show();
|
||||
}
|
||||
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.setWifiTethering.toString()))
|
||||
{
|
||||
newAction.setAction(Action_Enum.setWifiTethering);
|
||||
getActionParameter1Dialog(ActivityManageRule.this).show();
|
||||
}
|
||||
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.setDisplayRotation.toString()))
|
||||
{
|
||||
newAction.setAction(Action_Enum.setDisplayRotation);
|
||||
getActionParameter1Dialog(ActivityManageRule.this).show();
|
||||
}
|
||||
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.changeSoundProfile.toString()))
|
||||
{
|
||||
if(Profile.getProfileCollection().size() > 0)
|
||||
{
|
||||
//launch other activity to enter a url and parameters;
|
||||
newAction.setAction(Action_Enum.triggerUrl);
|
||||
ActivityEditTriggerUrl.resultingAction = null;
|
||||
Intent editTriggerIntent = new Intent(context, ActivityEditTriggerUrl.class);
|
||||
startActivityForResult(editTriggerIntent, 1000);
|
||||
newAction.setAction(Action_Enum.changeSoundProfile);
|
||||
getActionSoundProfileDialog(context).show();
|
||||
}
|
||||
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.setWifi.toString()))
|
||||
else
|
||||
Toast.makeText(context, getResources().getString(R.string.noProfilesCreateOneFirst), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.startOtherActivity.toString()))
|
||||
{
|
||||
newAction.setAction(Action_Enum.startOtherActivity);
|
||||
Intent intent = new Intent(ActivityManageRule.this, ActivityManageActionStartActivity.class);
|
||||
startActivityForResult(intent, 3000);
|
||||
}
|
||||
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.waitBeforeNextAction.toString()))
|
||||
{
|
||||
newAction.setAction(Action_Enum.waitBeforeNextAction);
|
||||
getActionWaitBeforeNextActionDialog(ActivityManageRule.this).show();
|
||||
}
|
||||
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.wakeupDevice.toString()))
|
||||
{
|
||||
newAction.setAction(Action_Enum.wakeupDevice);
|
||||
getActionWakeupDeviceDialog(ActivityManageRule.this).show();
|
||||
}
|
||||
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.setAirplaneMode.toString()))
|
||||
{
|
||||
newAction.setAction(Action_Enum.setAirplaneMode);
|
||||
getActionParameter1Dialog(ActivityManageRule.this).show();
|
||||
if(Build.VERSION.SDK_INT >= 17)
|
||||
{
|
||||
newAction.setAction(Action_Enum.setWifi);
|
||||
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
|
||||
Toast.makeText(context, context.getResources().getString(R.string.android10WifiToggleNotice), Toast.LENGTH_LONG).show();
|
||||
getActionParameter1Dialog(ActivityManageRule.this).show();
|
||||
// Toast.makeText(context, getResources().getString(R.string.airplaneModeSdk17Warning), Toast.LENGTH_LONG).show();
|
||||
Miscellaneous.messageBox(getResources().getString(R.string.airplaneMode), getResources().getString(R.string.rootExplanation), ActivityManageRule.this).show();
|
||||
}
|
||||
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.setBluetooth.toString()))
|
||||
}
|
||||
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.setDataConnection.toString()))
|
||||
{
|
||||
newAction.setAction(Action_Enum.setDataConnection);
|
||||
getActionParameter1Dialog(ActivityManageRule.this).show();
|
||||
Miscellaneous.messageBox(getResources().getString(R.string.actionDataConnection), getResources().getString(R.string.rootExplanation), ActivityManageRule.this).show();
|
||||
}
|
||||
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.speakText.toString()))
|
||||
{
|
||||
//launch other activity to enter a url and parameters;
|
||||
newAction.setAction(Action_Enum.speakText);
|
||||
ActivityManageActionSpeakText.resultingAction = null;
|
||||
Intent editTriggerIntent = new Intent(context, ActivityManageActionSpeakText.class);
|
||||
startActivityForResult(editTriggerIntent, 5000);
|
||||
}
|
||||
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.sendTextMessage.toString()))
|
||||
{
|
||||
if(ActivityPermissions.isPermissionDeclaratedInManifest(ActivityManageRule.this, "android.permission.SEND_SMS"))
|
||||
{
|
||||
if(!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH))
|
||||
Miscellaneous.messageBox("Bluetooth", getResources().getString(R.string.deviceDoesNotHaveBluetooth), ActivityManageRule.this).show();;
|
||||
newAction.setAction(Action_Enum.setBluetooth);
|
||||
getActionParameter1Dialog(ActivityManageRule.this).show();
|
||||
//launch other activity to enter parameters;
|
||||
newAction.setAction(Action_Enum.sendTextMessage);
|
||||
ActivityManageActionSendTextMessage.resultingAction = null;
|
||||
Intent editTriggerIntent = new Intent(context, ActivityManageActionSendTextMessage.class);
|
||||
startActivityForResult(editTriggerIntent, requestCodeActionSendTextMessageAdd);
|
||||
}
|
||||
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.setUsbTethering.toString()))
|
||||
{
|
||||
newAction.setAction(Action_Enum.setUsbTethering);
|
||||
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.GINGERBREAD_MR1)
|
||||
Toast.makeText(context, context.getResources().getString(R.string.usbTetheringFailForAboveGingerbread), Toast.LENGTH_LONG).show();
|
||||
getActionParameter1Dialog(ActivityManageRule.this).show();
|
||||
}
|
||||
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.setWifiTethering.toString()))
|
||||
{
|
||||
newAction.setAction(Action_Enum.setWifiTethering);
|
||||
getActionParameter1Dialog(ActivityManageRule.this).show();
|
||||
}
|
||||
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.setDisplayRotation.toString()))
|
||||
{
|
||||
newAction.setAction(Action_Enum.setDisplayRotation);
|
||||
getActionParameter1Dialog(ActivityManageRule.this).show();
|
||||
}
|
||||
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.changeSoundProfile.toString()))
|
||||
{
|
||||
if(Profile.getProfileCollection().size() > 0)
|
||||
{
|
||||
newAction.setAction(Action_Enum.changeSoundProfile);
|
||||
getActionSoundProfileDialog(context).show();
|
||||
}
|
||||
else
|
||||
Toast.makeText(context, getResources().getString(R.string.noProfilesCreateOneFirst), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.startOtherActivity.toString()))
|
||||
{
|
||||
newAction.setAction(Action_Enum.startOtherActivity);
|
||||
Intent intent = new Intent(ActivityManageRule.this, ActivityManageStartActivity.class);
|
||||
startActivityForResult(intent, 3000);
|
||||
}
|
||||
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.waitBeforeNextAction.toString()))
|
||||
{
|
||||
newAction.setAction(Action_Enum.waitBeforeNextAction);
|
||||
getActionWaitBeforeNextActionDialog(ActivityManageRule.this).show();
|
||||
}
|
||||
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.wakeupDevice.toString()))
|
||||
{
|
||||
newAction.setAction(Action_Enum.wakeupDevice);
|
||||
getActionWakeupDeviceDialog(ActivityManageRule.this).show();
|
||||
}
|
||||
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.setAirplaneMode.toString()))
|
||||
{
|
||||
if(Build.VERSION.SDK_INT >= 17)
|
||||
{
|
||||
Toast.makeText(context, getResources().getString(R.string.airplaneModeSdk17Warning), Toast.LENGTH_LONG).show();
|
||||
Miscellaneous.messageBox(getResources().getString(R.string.airplaneMode), getResources().getString(R.string.rootExplanation), ActivityManageRule.this).show();
|
||||
}
|
||||
newAction.setAction(Action_Enum.setAirplaneMode);
|
||||
getActionParameter1Dialog(ActivityManageRule.this).show();
|
||||
}
|
||||
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.setDataConnection.toString()))
|
||||
{
|
||||
newAction.setAction(Action_Enum.setDataConnection);
|
||||
getActionParameter1Dialog(ActivityManageRule.this).show();
|
||||
Miscellaneous.messageBox(getResources().getString(R.string.actionDataConnection), getResources().getString(R.string.rootExplanation), ActivityManageRule.this).show();
|
||||
}
|
||||
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.speakText.toString()))
|
||||
{
|
||||
//launch other activity to enter a url and parameters;
|
||||
newAction.setAction(Action_Enum.speakText);
|
||||
ActivityEditSpeakText.resultingAction = null;
|
||||
Intent editTriggerIntent = new Intent(context, ActivityEditSpeakText.class);
|
||||
startActivityForResult(editTriggerIntent, 5000);
|
||||
}
|
||||
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.sendTextMessage.toString()))
|
||||
{
|
||||
// if(ActivityPermissions.isPermissionDeclaratedInManifest(ActivityManageSpecificRule.this, "android.permission.SEND_SMS") && !Miscellaneous.isGooglePlayInstalled(ActivityManageSpecificRule.this))
|
||||
if(ActivityPermissions.isPermissionDeclaratedInManifest(ActivityManageRule.this, "android.permission.SEND_SMS"))
|
||||
{
|
||||
//launch other activity to enter parameters;
|
||||
newAction.setAction(Action_Enum.sendTextMessage);
|
||||
ActivityEditSendTextMessage.resultingAction = null;
|
||||
Intent editTriggerIntent = new Intent(context, ActivityEditSendTextMessage.class);
|
||||
startActivityForResult(editTriggerIntent, 5001);
|
||||
}
|
||||
}
|
||||
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.playMusic.toString()))
|
||||
{
|
||||
newAction.setAction(Action_Enum.playMusic);
|
||||
ruleToEdit.getActionSet().add(newAction);
|
||||
refreshActionList();
|
||||
}
|
||||
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.setScreenBrightness.toString()))
|
||||
{
|
||||
newAction.setAction(Action_Enum.setScreenBrightness);
|
||||
Intent actionScreenBrightnessIntent = new Intent(context, ActivityManageBrightnessSetting.class);
|
||||
startActivityForResult(actionScreenBrightnessIntent, requestCodeActionScreenBrightnessAdd);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return builder.create();
|
||||
}
|
||||
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.playMusic.toString()))
|
||||
{
|
||||
newAction.setAction(Action_Enum.playMusic);
|
||||
ruleToEdit.getActionSet().add(newAction);
|
||||
refreshActionList();
|
||||
}
|
||||
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.vibrate.toString()))
|
||||
{
|
||||
newAction.setAction(Action_Enum.vibrate);
|
||||
Intent intent = new Intent(ActivityManageRule.this, ActivityManageActionVibrate.class);
|
||||
startActivityForResult(intent, requestCodeActionVibrateAdd);
|
||||
}
|
||||
else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.setScreenBrightness.toString()))
|
||||
{
|
||||
newAction.setAction(Action_Enum.setScreenBrightness);
|
||||
Intent actionScreenBrightnessIntent = new Intent(context, ActivityManageActionBrightnessSetting.class);
|
||||
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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return builder.create();
|
||||
}
|
||||
private AlertDialog getActionSoundProfileDialog(final Context myContext)
|
||||
{
|
||||
@ -1516,63 +1638,6 @@ public class ActivityManageRule extends Activity
|
||||
return alertDialog;
|
||||
}
|
||||
|
||||
/*private AlertDialog getActionStartActivityDialog1(final Context myContext)
|
||||
{
|
||||
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(context);
|
||||
alertDialogBuilder.setTitle(myContext.getResources().getString(R.string.selectApplication));
|
||||
final String[] applicationArray = ActivityManageStartActivity.getApplicationNameListString(ActivityManageSpecificRule.this);
|
||||
alertDialogBuilder.setItems(applicationArray, new DialogInterface.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which)
|
||||
{
|
||||
getActionStartActivityDialog2(myContext, applicationArray[which]).show();
|
||||
}
|
||||
});
|
||||
AlertDialog alertDialog = alertDialogBuilder.create();
|
||||
|
||||
return alertDialog;
|
||||
}
|
||||
private AlertDialog getActionStartActivityDialog2(final Context myContext, String applicationName)
|
||||
{
|
||||
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(context);
|
||||
alertDialogBuilder.setTitle(myContext.getResources().getString(R.string.selectPackageOfApplication));
|
||||
final String[] packageArray = ActivityManageStartActivity.getPackageListString(ActivityManageSpecificRule.this, applicationName);
|
||||
alertDialogBuilder.setItems(packageArray, new DialogInterface.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which)
|
||||
{
|
||||
getActionStartActivityDialog3(ActivityManageSpecificRule.this, packageArray[which]).show();
|
||||
}
|
||||
});
|
||||
AlertDialog alertDialog = alertDialogBuilder.create();
|
||||
|
||||
return alertDialog;
|
||||
}
|
||||
private AlertDialog getActionStartActivityDialog3(final Context myContext, final String packageName)
|
||||
{
|
||||
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(context);
|
||||
alertDialogBuilder.setTitle(myContext.getResources().getString(R.string.selectActivityToBeStarted));
|
||||
final String activityArray[] = ActivityManageStartActivity.getActivityListForPackageName(packageName);
|
||||
alertDialogBuilder.setItems(activityArray, new DialogInterface.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which)
|
||||
{
|
||||
ActivityInfo ai = ActivityManageStartActivity.getActivityInfoForPackageNameAndActivityName(packageName, activityArray[which]);
|
||||
// Log.i("Selected", ai.packageName + " / " + ai.name);
|
||||
newAction.setParameter2(ai.packageName + ";" + ai.name);
|
||||
newAction.toString();
|
||||
ruleToEdit.getActionSet().add(newAction);
|
||||
refreshActionList();
|
||||
}
|
||||
});
|
||||
AlertDialog alertDialog = alertDialogBuilder.create();
|
||||
|
||||
return alertDialog;
|
||||
}*/
|
||||
|
||||
private AlertDialog getActionWaitBeforeNextActionDialog(final Context myContext)
|
||||
{
|
||||
AlertDialog.Builder alertDialog = new AlertDialog.Builder(this);
|
||||
|
@ -16,7 +16,7 @@ import android.widget.Toast;
|
||||
|
||||
import com.jens.automation2.receivers.BluetoothReceiver;
|
||||
|
||||
public class ActivityManageBluetoothTrigger extends Activity
|
||||
public class ActivityManageTriggerBluetooth extends Activity
|
||||
{
|
||||
protected static Trigger editedBluetoothTrigger;
|
||||
RadioButton radioAnyBluetoothDevice, radioNoDevice, radioDeviceFromList, radioBluetoothConnected, radioBluetoothDisconnected, radioBluetoothInRange, radioBluetoothOutRange;
|
||||
@ -29,7 +29,7 @@ public class ActivityManageBluetoothTrigger extends Activity
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_bluetooth_trigger);
|
||||
setContentView(R.layout.activity_manage_trigger_bluetooth);
|
||||
|
||||
radioAnyBluetoothDevice = (RadioButton)findViewById(R.id.radioAnyBluetoothDevice);
|
||||
radioNoDevice = (RadioButton)findViewById(R.id.radioNoDevice);
|
||||
@ -109,7 +109,7 @@ public class ActivityManageBluetoothTrigger extends Activity
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@ -138,7 +138,7 @@ public class ActivityManageBluetoothTrigger extends Activity
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ import android.widget.Toast;
|
||||
import com.jens.automation2.receivers.NfcReceiver;
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
public class ActivityManageNfc extends Activity
|
||||
public class ActivityManageTriggerNfc extends Activity
|
||||
{
|
||||
public static String generatedId = null;
|
||||
private static Tag discoveredTag = null;
|
||||
@ -39,7 +39,7 @@ public class ActivityManageNfc extends Activity
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.manage_nfc);
|
||||
setContentView(R.layout.activity_manage_trigger_nfc);
|
||||
|
||||
etNewNfcIdValue = (EditText)findViewById(R.id.etNewNfcIdValue);
|
||||
bReadNfcTag = (Button)findViewById(R.id.bReadNfcTag);
|
||||
@ -59,7 +59,7 @@ public class ActivityManageNfc extends Activity
|
||||
}
|
||||
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
|
||||
public void onCancel(DialogInterface dialog)
|
||||
@ -88,7 +88,7 @@ public class ActivityManageNfc extends Activity
|
||||
}
|
||||
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
|
||||
public void onCancel(DialogInterface dialog)
|
||||
@ -118,7 +118,7 @@ public class ActivityManageNfc extends Activity
|
||||
}
|
||||
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
|
||||
public void onCancel(DialogInterface dialog)
|
||||
@ -255,7 +255,7 @@ public class ActivityManageNfc extends Activity
|
||||
if(generatedId.length() == 0)
|
||||
{
|
||||
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;
|
||||
}
|
||||
else
|
||||
@ -267,14 +267,14 @@ public class ActivityManageNfc extends Activity
|
||||
if(NfcReceiver.writeTag(generatedId, discoveredTag))
|
||||
{
|
||||
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);
|
||||
finish();
|
||||
}
|
||||
else
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -285,14 +285,14 @@ public class ActivityManageNfc extends Activity
|
||||
if(checkEnteredText(false))
|
||||
{
|
||||
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);
|
||||
finish();
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
@ -0,0 +1,398 @@
|
||||
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;
|
||||
boolean edit = false;
|
||||
ProgressDialog progressDialog = null;
|
||||
|
||||
EditText etNotificationTitle, etNotificationText;
|
||||
Button bSelectApp, bSaveTriggerNotification;
|
||||
Spinner spinnerTitleDirection, spinnerTextDirection;
|
||||
TextView tvSelectedApplication;
|
||||
CheckBox chkNotificationDirection;
|
||||
|
||||
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.activity_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.etActivityOrActionPath);
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,212 @@
|
||||
package com.jens.automation2;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.provider.ContactsContract;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.RadioButton;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import static com.jens.automation2.Trigger.triggerParameter2Split;
|
||||
|
||||
public class ActivityManageTriggerPhoneCall extends Activity
|
||||
{
|
||||
public static Trigger editedPhoneCallTrigger;
|
||||
boolean edit = false;
|
||||
public static Trigger resultingTrigger;
|
||||
ProgressDialog progressDialog = null;
|
||||
protected final static int requestCodeForContactsPermissions = 2345;
|
||||
protected final static int requestCodeGetContact = 3235;
|
||||
|
||||
EditText etTriggerPhoneCallPhoneNumber;
|
||||
RadioButton rbTriggerPhoneCallStateRinging, rbTriggerPhoneCallStateStarted, rbTriggerPhoneCallStateStopped, rbTriggerPhoneCallDirectionAny, rbTriggerPhoneCallDirectionIncoming, rbTriggerPhoneCallDirectionOutgoing;
|
||||
Button bSaveTriggerPhoneCall, bTriggerPhoneCallImportFromContacts;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_manage_trigger_phone_call);
|
||||
|
||||
etTriggerPhoneCallPhoneNumber = (EditText)findViewById(R.id.etTriggerPhoneCallPhoneNumber);
|
||||
rbTriggerPhoneCallStateRinging = (RadioButton)findViewById(R.id.rbTriggerPhoneCallStateRinging);
|
||||
rbTriggerPhoneCallStateStarted = (RadioButton)findViewById(R.id.rbTriggerPhoneCallStateStarted);
|
||||
rbTriggerPhoneCallStateStopped = (RadioButton)findViewById(R.id.rbTriggerPhoneCallStateStopped);
|
||||
rbTriggerPhoneCallDirectionAny = (RadioButton)findViewById(R.id.rbTriggerPhoneCallDirectionAny);
|
||||
rbTriggerPhoneCallDirectionIncoming = (RadioButton)findViewById(R.id.rbTriggerPhoneCallDirectionIncoming);
|
||||
rbTriggerPhoneCallDirectionOutgoing = (RadioButton)findViewById(R.id.rbTriggerPhoneCallDirectionOutgoing);
|
||||
bTriggerPhoneCallImportFromContacts = (Button) findViewById(R.id.bTriggerPhoneCallImportFromContacts);
|
||||
bSaveTriggerPhoneCall = (Button) findViewById(R.id.bSaveTriggerPhoneCall);
|
||||
|
||||
bSaveTriggerPhoneCall.setOnClickListener(new View.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
String tp2Result = "";
|
||||
|
||||
if(rbTriggerPhoneCallStateRinging.isChecked())
|
||||
tp2Result += Trigger.triggerPhoneCallStateRinging;
|
||||
else if(rbTriggerPhoneCallStateStarted.isChecked())
|
||||
tp2Result += Trigger.triggerPhoneCallStateStarted;
|
||||
else if(rbTriggerPhoneCallStateStopped.isChecked())
|
||||
tp2Result += Trigger.triggerPhoneCallStateStopped;
|
||||
|
||||
tp2Result += triggerParameter2Split;
|
||||
|
||||
if(rbTriggerPhoneCallDirectionAny.isChecked())
|
||||
tp2Result += Trigger.triggerPhoneCallDirectionAny;
|
||||
else if(rbTriggerPhoneCallDirectionIncoming.isChecked())
|
||||
tp2Result += Trigger.triggerPhoneCallDirectionIncoming;
|
||||
else if(rbTriggerPhoneCallDirectionOutgoing.isChecked())
|
||||
tp2Result += Trigger.triggerPhoneCallDirectionOutgoing;
|
||||
|
||||
tp2Result += triggerParameter2Split;
|
||||
|
||||
if(etTriggerPhoneCallPhoneNumber.getText() != null && etTriggerPhoneCallPhoneNumber.getText().toString().length() > 0)
|
||||
tp2Result += etTriggerPhoneCallPhoneNumber.getText().toString();
|
||||
else
|
||||
tp2Result += Trigger.triggerPhoneCallNumberAny;
|
||||
|
||||
if(edit)
|
||||
{
|
||||
editedPhoneCallTrigger.setTriggerParameter(false);
|
||||
editedPhoneCallTrigger.setTriggerParameter2(tp2Result);
|
||||
ActivityManageTriggerPhoneCall.this.setResult(RESULT_OK);
|
||||
}
|
||||
else
|
||||
{
|
||||
Intent data = new Intent();
|
||||
data.putExtra("triggerParameter", false);
|
||||
data.putExtra("triggerParameter2", tp2Result);
|
||||
ActivityManageTriggerPhoneCall.this.setResult(RESULT_OK, data);
|
||||
}
|
||||
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
||||
bTriggerPhoneCallImportFromContacts.setOnClickListener(new View.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(View view)
|
||||
{
|
||||
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !ActivityPermissions.havePermission("android.permission.READ_CONTACTS", ActivityManageTriggerPhoneCall.this))
|
||||
{
|
||||
requestPermissions("android.permission.READ_CONTACTS");
|
||||
}
|
||||
else
|
||||
openContactsDialogue();
|
||||
}
|
||||
});
|
||||
|
||||
Intent i = getIntent();
|
||||
if(i.getBooleanExtra("edit", false) == true)
|
||||
{
|
||||
edit = true;
|
||||
loadValuesIntoGui();
|
||||
}
|
||||
}
|
||||
|
||||
protected void requestPermissions(String... requiredPermissions)
|
||||
{
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
|
||||
{
|
||||
if(requiredPermissions.length > 0)
|
||||
{
|
||||
StringBuilder permissions = new StringBuilder();
|
||||
for (String perm : requiredPermissions)
|
||||
permissions.append(perm + "; ");
|
||||
if (permissions.length() > 0)
|
||||
permissions.delete(permissions.length() - 2, permissions.length());
|
||||
|
||||
Miscellaneous.logEvent("i", "Permissions", "Requesting permissions: " + permissions, 2);
|
||||
|
||||
requestPermissions(requiredPermissions, requestCodeForContactsPermissions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void openContactsDialogue()
|
||||
{
|
||||
Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.CommonDataKinds.Phone.CONTENT_URI);
|
||||
startActivityForResult(intent, requestCodeGetContact);
|
||||
}
|
||||
|
||||
private void loadValuesIntoGui()
|
||||
{
|
||||
String[] parts = editedPhoneCallTrigger.getTriggerParameter2().split(triggerParameter2Split);
|
||||
|
||||
if(parts[0].equals(Trigger.triggerPhoneCallStateRinging))
|
||||
rbTriggerPhoneCallStateRinging.setChecked(true);
|
||||
else if(parts[0].equals(Trigger.triggerPhoneCallStateStarted))
|
||||
rbTriggerPhoneCallStateStarted.setChecked(true);
|
||||
else if(parts[0].equals(Trigger.triggerPhoneCallStateStopped))
|
||||
rbTriggerPhoneCallStateStopped.setChecked(true);
|
||||
|
||||
if(parts[1].equals(Trigger.triggerPhoneCallDirectionAny))
|
||||
rbTriggerPhoneCallDirectionAny.setChecked(true);
|
||||
else if(parts[1].equals(Trigger.triggerPhoneCallDirectionIncoming))
|
||||
rbTriggerPhoneCallDirectionIncoming.setChecked(true);
|
||||
else if(parts[1].equals(Trigger.triggerPhoneCallDirectionOutgoing))
|
||||
rbTriggerPhoneCallDirectionOutgoing.setChecked(true);
|
||||
|
||||
if(!parts[2].equals(Trigger.triggerPhoneCallNumberAny))
|
||||
etTriggerPhoneCallPhoneNumber.setText(parts[2]);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data)
|
||||
{
|
||||
if(requestCode == requestCodeGetContact)
|
||||
{
|
||||
if(resultCode == Activity.RESULT_OK)
|
||||
{
|
||||
String phoneNo = null;
|
||||
String name = null;
|
||||
|
||||
Uri uri = data.getData();
|
||||
Cursor cursor = ActivityManageTriggerPhoneCall.this.getContentResolver().query(uri, null, null, null, null);
|
||||
|
||||
if (cursor.moveToFirst())
|
||||
{
|
||||
int phoneIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
|
||||
int nameIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
|
||||
|
||||
phoneNo = cursor.getString(phoneIndex);
|
||||
name = cursor.getString(nameIndex);
|
||||
|
||||
etTriggerPhoneCallPhoneNumber.setText(phoneNo);
|
||||
}
|
||||
}
|
||||
}
|
||||
//super.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
|
||||
{
|
||||
if(requestCode == requestCodeForContactsPermissions)
|
||||
{
|
||||
for(int i=0; i<permissions.length; i++)
|
||||
{
|
||||
if(permissions[i].equals("android.permission.READ_CONTACTS"))
|
||||
{
|
||||
if(grantResults[i] == PackageManager.PERMISSION_GRANTED)
|
||||
{
|
||||
openContactsDialogue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -14,7 +14,7 @@ import java.sql.Time;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
|
||||
public class ActivityManageTimeFrame extends Activity
|
||||
public class ActivityManageTriggerTimeFrame extends Activity
|
||||
{
|
||||
Button bSaveTimeFrame;
|
||||
TimePicker startPicker, stopPicker;
|
||||
@ -27,7 +27,7 @@ public class ActivityManageTimeFrame extends Activity
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.trigger_timeframe_editor);
|
||||
setContentView(R.layout.activity_manage_trigger_timeframe);
|
||||
|
||||
startPicker = (TimePicker)findViewById(R.id.tpTimeFrameStart);
|
||||
stopPicker = (TimePicker)findViewById(R.id.tpTimeFrameStop);
|
@ -0,0 +1,163 @@
|
||||
package com.jens.automation2;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.wifi.WifiConfiguration;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.RadioButton;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
|
||||
import com.jens.automation2.receivers.BluetoothReceiver;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class ActivityManageTriggerWifi extends Activity
|
||||
{
|
||||
RadioButton rbTriggerWifiConnected, rbTriggerWifiDisconnected;
|
||||
EditText etTriggerWifiName;
|
||||
Spinner spinnerWifiList;
|
||||
Button btriggerWifiSave, bLoadWifiList;
|
||||
List<String> wifiList = new ArrayList<>();
|
||||
ArrayAdapter<String> wifiSpinnerAdapter;
|
||||
private final static int requestCodeLocationPermission = 124;
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_manage_trigger_wifi);
|
||||
|
||||
rbTriggerWifiConnected = (RadioButton) findViewById(R.id.rbTriggerWifiConnected);
|
||||
rbTriggerWifiDisconnected = (RadioButton) findViewById(R.id.rbTriggerWifiDisconnected);
|
||||
etTriggerWifiName = (EditText) findViewById(R.id.etTriggerWifiName);
|
||||
spinnerWifiList = (Spinner) findViewById(R.id.spinnerWifiList);
|
||||
btriggerWifiSave = (Button) findViewById(R.id.btriggerWifiSave);
|
||||
bLoadWifiList = (Button) findViewById(R.id.bLoadWifiList);
|
||||
|
||||
wifiSpinnerAdapter = new ArrayAdapter<String>(this, R.layout.text_view_for_poi_listview_mediumtextsize, wifiList);
|
||||
spinnerWifiList.setAdapter(wifiSpinnerAdapter);
|
||||
|
||||
if (getIntent().hasExtra("edit"))
|
||||
{
|
||||
boolean connected = getIntent().getBooleanExtra("wifiState", false);
|
||||
String wifiName = getIntent().getStringExtra("wifiName");
|
||||
|
||||
rbTriggerWifiConnected.setChecked(connected);
|
||||
rbTriggerWifiDisconnected.setChecked(!connected);
|
||||
|
||||
etTriggerWifiName.setText(wifiName);
|
||||
}
|
||||
|
||||
btriggerWifiSave.setOnClickListener(new View.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
Intent response = new Intent();
|
||||
response.putExtra("wifiState", rbTriggerWifiConnected.isChecked());
|
||||
response.putExtra("wifiName", etTriggerWifiName.getText().toString());
|
||||
setResult(RESULT_OK, response);
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
||||
spinnerWifiList.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener()
|
||||
{
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id)
|
||||
{
|
||||
etTriggerWifiName.setText(wifiList.get(position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent)
|
||||
{
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
bLoadWifiList.setOnClickListener(new View.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
loadWifis();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void loadWifis()
|
||||
{
|
||||
if(!ActivityPermissions.havePermission(Manifest.permission.ACCESS_FINE_LOCATION, ActivityManageTriggerWifi.this))
|
||||
{
|
||||
AlertDialog dialog = Miscellaneous.messageBox(getResources().getString(R.string.permissionsTitle), getResources().getString(R.string.needLocationPermForWifiList), ActivityManageTriggerWifi.this);
|
||||
dialog.setOnDismissListener(new DialogInterface.OnDismissListener()
|
||||
{
|
||||
@Override
|
||||
public void onDismiss(DialogInterface dialog)
|
||||
{
|
||||
ActivityCompat.requestPermissions(ActivityManageTriggerWifi.this, new String[] { Manifest.permission.ACCESS_FINE_LOCATION }, requestCodeLocationPermission);
|
||||
}
|
||||
});
|
||||
dialog.show();
|
||||
}
|
||||
else
|
||||
{
|
||||
reallyLoadWifiList();
|
||||
}
|
||||
}
|
||||
|
||||
void reallyLoadWifiList()
|
||||
{
|
||||
WifiManager myWifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
|
||||
|
||||
for (WifiConfiguration wifi : myWifiManager.getConfiguredNetworks())
|
||||
wifiList.add(wifi.SSID.replaceAll("\"+$", "").replaceAll("^\"+", ""));
|
||||
|
||||
if(wifiList.size() > 0)
|
||||
{
|
||||
spinnerWifiList.setEnabled(true);
|
||||
Collections.sort(wifiList);
|
||||
}
|
||||
else
|
||||
{
|
||||
spinnerWifiList.setEnabled(false);
|
||||
Toast.makeText(ActivityManageTriggerWifi.this, getResources().getString(R.string.noKnownWifis), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
wifiSpinnerAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
|
||||
{
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
|
||||
switch (requestCode)
|
||||
{
|
||||
case requestCodeLocationPermission:
|
||||
if(grantResults[0] == PackageManager.PERMISSION_GRANTED)
|
||||
reallyLoadWifiList();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package com.jens.automation2;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.preference.CheckBoxPreference;
|
||||
import android.preference.ListPreference;
|
||||
import android.preference.PreferenceActivity;
|
||||
|
||||
@ -9,11 +10,18 @@ import com.jens.automation2.R.layout;
|
||||
public class ActivitySettings extends PreferenceActivity
|
||||
{
|
||||
ListPreference lpStartScreenOptionsValues;
|
||||
CheckBoxPreference chkPrefUpdateCheck;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
addPreferencesFromResource(layout.settings);
|
||||
addPreferencesFromResource(layout.activity_settings);
|
||||
|
||||
if(BuildConfig.FLAVOR.equals("apkFlavor"))
|
||||
{
|
||||
chkPrefUpdateCheck = (CheckBoxPreference) findPreference("automaticUpdateCheck");
|
||||
chkPrefUpdateCheck.setEnabled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
65
app/src/main/java/com/jens/automation2/AsyncTasks.java
Normal file
@ -0,0 +1,65 @@
|
||||
package com.jens.automation2;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
|
||||
public class AsyncTasks
|
||||
{
|
||||
public static class AsyncTaskUpdateCheck extends AsyncTask<Context, Void, Boolean>
|
||||
{
|
||||
public static boolean checkRunning = false;
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Context... contexts)
|
||||
{
|
||||
if(checkRunning)
|
||||
return false;
|
||||
else
|
||||
checkRunning = true;
|
||||
|
||||
try
|
||||
{
|
||||
String result = Miscellaneous.downloadURL("https://server47.de/automation/?action=getLatestVersionCode", null, null).trim();
|
||||
int latestVersion = Integer.parseInt(result);
|
||||
|
||||
// At this point the update check itself has already been successful.
|
||||
|
||||
Settings.lastUpdateCheck = Calendar.getInstance().getTimeInMillis();
|
||||
Settings.writeSettings(contexts[0]);
|
||||
|
||||
if (latestVersion > BuildConfig.VERSION_CODE)
|
||||
{
|
||||
// There's a new update
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Miscellaneous.logEvent("e", "Error checking for update", Log.getStackTraceString(e), 3);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean result)
|
||||
{
|
||||
try
|
||||
{
|
||||
ActivityMainScreen.getActivityMainScreenInstance().processUpdateCheckResult(result);
|
||||
}
|
||||
catch (NullPointerException e)
|
||||
{
|
||||
Miscellaneous.logEvent("e", "NewsDownload", "There was a problem displaying the update check result, probably ActivityMainScreen isn't currently shown: " + Log.getStackTraceString(e), 2);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Miscellaneous.logEvent("e", "NewsDownload", "There was a problem displaying the update check result: " + Log.getStackTraceString(e), 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package com.jens.automation2;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityManager.RunningServiceInfo;
|
||||
@ -121,14 +122,14 @@ public class AutomationService extends Service implements OnInitListener
|
||||
|
||||
if(Build.VERSION.SDK_INT >= 28)
|
||||
{
|
||||
if (!ActivityPermissions.havePermission(ActivityPermissions.permissionNameStartService, AutomationService.this))
|
||||
if (!ActivityPermissions.havePermission(Manifest.permission.FOREGROUND_SERVICE, AutomationService.this))
|
||||
{
|
||||
/*
|
||||
Don't have permission to start service. This is a show stopper.
|
||||
*/
|
||||
Miscellaneous.logEvent("e", "Permission", "Don't have permission to start foreground service. Will request it now.", 4);
|
||||
// Toast.makeText(AutomationService.this, getResources().getString(R.string.appRequiresPermissiontoAccessExternalStorage), Toast.LENGTH_LONG).show();
|
||||
ActivityPermissions.requestSpecificPermission(ActivityPermissions.permissionNameStartService);
|
||||
ActivityPermissions.requestSpecificPermission(Manifest.permission.FOREGROUND_SERVICE);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -196,7 +197,7 @@ public class AutomationService extends Service implements OnInitListener
|
||||
|
||||
if (checkStartupRequirements(this, startAtBoot))
|
||||
{
|
||||
Miscellaneous.logEvent("i", "Service", this.getResources().getString(R.string.logServiceStarting), 1);
|
||||
Miscellaneous.logEvent("i", "Service", this.getResources().getString(R.string.logServiceStarting) + " VERSION_CODE: " + BuildConfig.VERSION_CODE + ", VERSION_NAME: " + BuildConfig.VERSION_NAME + ", flavor: " + BuildConfig.FLAVOR, 1);
|
||||
|
||||
startUpRoutine();
|
||||
|
||||
@ -210,7 +211,7 @@ public class AutomationService extends Service implements OnInitListener
|
||||
ActivityMainScreen.updateMainScreen();
|
||||
|
||||
this.isRunning = true;
|
||||
Miscellaneous.logEvent("i", "Service", this.getResources().getString(R.string.serviceStarted) + " " + String.format(this.getResources().getString(R.string.version), BuildConfig.VERSION_NAME + "(Build " + BuildConfig.VERSION_CODE + ")"), 1);
|
||||
Miscellaneous.logEvent("i", "Service", this.getResources().getString(R.string.serviceStarted) + " VERSION_CODE: " + BuildConfig.VERSION_CODE + ", VERSION_NAME: " + BuildConfig.VERSION_NAME + ", flavor: " + BuildConfig.FLAVOR, 1);
|
||||
Toast.makeText(this, this.getResources().getString(R.string.serviceStarted), Toast.LENGTH_LONG).show();
|
||||
// ********** Test area **********
|
||||
// Miscellaneous.logEvent("i", "setNetworkType", "bin hier.", 3);
|
||||
@ -257,7 +258,8 @@ public class AutomationService extends Service implements OnInitListener
|
||||
case reloadSettings:
|
||||
Settings.readFromPersistentStorage(this);
|
||||
applySettingsAndRules();
|
||||
myLocationProvider.applySettingsAndRules();
|
||||
if(myLocationProvider != null)
|
||||
myLocationProvider.applySettingsAndRules();
|
||||
break;
|
||||
case updateNotification:
|
||||
this.updateNotification();
|
||||
@ -341,6 +343,9 @@ public class AutomationService extends Service implements OnInitListener
|
||||
{
|
||||
boolean displayNotification = false;
|
||||
|
||||
String rule = "";
|
||||
|
||||
outerLoop:
|
||||
for(Rule r : Rule.getRuleCollection())
|
||||
{
|
||||
if(r.isRuleActive())
|
||||
@ -353,7 +358,11 @@ public class AutomationService extends Service implements OnInitListener
|
||||
// r.setRuleActive(false);
|
||||
// r.change(AutomationService.this);
|
||||
if(!displayNotification)
|
||||
{
|
||||
displayNotification = true;
|
||||
rule = r.getName();
|
||||
break outerLoop;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -361,18 +370,16 @@ public class AutomationService extends Service implements OnInitListener
|
||||
|
||||
if(displayNotification)
|
||||
{
|
||||
// Toast.makeText(Miscellaneous.getAnyContext(), "Require more permissions.", Toast.LENGTH_LONG).show();
|
||||
// Update notification or show new one that notifiies of the lack or permissions.
|
||||
|
||||
Intent intent = new Intent(AutomationService.this, ActivityPermissions.class);
|
||||
PendingIntent pi = PendingIntent.getActivity(AutomationService.this, 0, intent, 0);
|
||||
|
||||
Miscellaneous.logEvent("w", "Features disabled", "Features disabled because of rule " + rule, 5);
|
||||
|
||||
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1)
|
||||
Miscellaneous.createDismissableNotificationWithDelay(1010, getResources().getString(R.string.featuresDisabled), ActivityPermissions.notificationIdPermissions, pi);
|
||||
else
|
||||
Miscellaneous.createDismissableNotification(getResources().getString(R.string.featuresDisabled), ActivityPermissions.notificationIdPermissions, pi);
|
||||
}
|
||||
// else
|
||||
// Toast.makeText(Miscellaneous.getAnyContext(), "Have all required permissions.", Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
@ -389,6 +396,9 @@ public class AutomationService extends Service implements OnInitListener
|
||||
Intent intent = new Intent(AutomationService.this, ActivityMainTabLayout.class);
|
||||
PendingIntent pi = PendingIntent.getActivity(AutomationService.this, 0, intent, 0);
|
||||
// Miscellaneous.createDismissableNotification(getResources().getString(R.string.settingsReferringToRestrictedFeatures), ActivityPermissions.notificationIdPermissions, pi);
|
||||
|
||||
Miscellaneous.logEvent("w", "Features disabled", "Background location disabled because Google to blame.", 5);
|
||||
|
||||
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1)
|
||||
Miscellaneous.createDismissableNotificationWithDelay(3300, getResources().getString(R.string.featuresDisabled), notificationIdRestrictions, pi);
|
||||
else
|
||||
@ -404,6 +414,8 @@ public class AutomationService extends Service implements OnInitListener
|
||||
Intent intent = new Intent(AutomationService.this, ActivityMainTabLayout.class);
|
||||
PendingIntent pi = PendingIntent.getActivity(AutomationService.this, 0, intent, 0);
|
||||
|
||||
Miscellaneous.logEvent("w", "Features disabled", "Background location disabled because Google to blame.", 5);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1)
|
||||
Miscellaneous.createDismissableNotificationWithDelay(2200, getResources().getString(R.string.featuresDisabled), notificationIdLocationRestriction, pi);
|
||||
else
|
||||
@ -445,7 +457,8 @@ public class AutomationService extends Service implements OnInitListener
|
||||
|
||||
private void stopRoutine()
|
||||
{
|
||||
Log.i("STOP", "Stopping");
|
||||
Miscellaneous.logEvent("i", "Service", "Stopping service...", 3);
|
||||
// Log.i("STOP", "Stopping");
|
||||
try
|
||||
{
|
||||
myLocationProvider.stopLocationService();
|
||||
@ -581,11 +594,11 @@ public class AutomationService extends Service implements OnInitListener
|
||||
if(activePoi == null)
|
||||
{
|
||||
PointOfInterest closestPoi = PointOfInterest.getClosestPOI(instance.getLocationProvider().getCurrentLocation());
|
||||
bodyText = "Active POI: none" + "\n" + "Closest POI: " + closestPoi.getName() + lastRuleString;
|
||||
bodyText = AutomationService.getInstance().getResources().getString(R.string.activePoi) + ": " + AutomationService.getInstance().getResources().getString(R.string.none) + "\n" + AutomationService.getInstance().getResources().getString(R.string.closestPoi) + ": " + closestPoi.getName() + lastRuleString;
|
||||
}
|
||||
else
|
||||
{
|
||||
bodyText = "Active POI: " + activePoi.getName() + lastRuleString;
|
||||
bodyText = AutomationService.getInstance().getResources().getString(R.string.activePoi) + ": " + activePoi.getName() + lastRuleString;
|
||||
}
|
||||
}
|
||||
catch(NullPointerException e)
|
||||
@ -593,9 +606,9 @@ public class AutomationService extends Service implements OnInitListener
|
||||
if(
|
||||
Rule.isAnyRuleUsing(Trigger_Enum.pointOfInterest)
|
||||
&&
|
||||
ActivityPermissions.havePermission(ActivityPermissions.permissionNameLocationCoarse, AutomationService.getInstance())
|
||||
ActivityPermissions.havePermission(Manifest.permission.ACCESS_COARSE_LOCATION, AutomationService.getInstance())
|
||||
&&
|
||||
ActivityPermissions.havePermission(ActivityPermissions.permissionNameLocationFine, AutomationService.getInstance())
|
||||
ActivityPermissions.havePermission(Manifest.permission.ACCESS_FINE_LOCATION, AutomationService.getInstance())
|
||||
)
|
||||
bodyText = instance.getResources().getString(R.string.stillGettingPosition);
|
||||
else
|
||||
|
@ -33,7 +33,8 @@ public class CompensateCrappyAndroidPaths
|
||||
* @param uri The Uri to query.
|
||||
*/
|
||||
@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
|
||||
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
|
||||
String selection = null;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package com.jens.automation2;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Notification;
|
||||
@ -7,6 +8,7 @@ import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.ContentProvider;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
@ -20,10 +22,14 @@ import android.os.Environment;
|
||||
import android.os.IBinder;
|
||||
import android.provider.MediaStore;
|
||||
import android.provider.Settings.Secure;
|
||||
import android.telephony.PhoneNumberUtils;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.jens.automation2.location.LocationProvider;
|
||||
import com.jens.automation2.receivers.NotificationListener;
|
||||
import com.jens.automation2.receivers.PhoneStatusListener;
|
||||
|
||||
import org.apache.http.HttpEntity;
|
||||
@ -42,6 +48,8 @@ import org.w3c.dom.Element;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
@ -71,6 +79,9 @@ import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
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.HttpsURLConnection;
|
||||
@ -83,12 +94,14 @@ import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
|
||||
import static android.provider.CalendarContract.CalendarCache.URI;
|
||||
import static com.jens.automation2.AutomationService.NOTIFICATION_CHANNEL_ID;
|
||||
import static com.jens.automation2.AutomationService.channelName;
|
||||
|
||||
public class Miscellaneous extends Service
|
||||
{
|
||||
{
|
||||
protected static String writeableFolderStringCache = null;
|
||||
public static final String lineSeparator = System.getProperty("line.separator");
|
||||
|
||||
@ -108,15 +121,6 @@ public class Miscellaneous extends Service
|
||||
if(url.toLowerCase().contains("https"))
|
||||
{
|
||||
connection = (HttpsURLConnection) urlObject.openConnection();
|
||||
|
||||
// if(Settings.httpAcceptAllCertificates)
|
||||
// {
|
||||
// SSLContext sc = SSLContext.getInstance("TLS");
|
||||
// sc.init(null, getInsecureTrustManager(), new java.security.SecureRandom());
|
||||
// HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
|
||||
// Miscellaneous.disableSSLCertificateChecking();
|
||||
// HttpsURLConnection.setDefaultHostnameVerifier(getInsecureHostnameVerifier());
|
||||
// }
|
||||
}
|
||||
else
|
||||
connection = (HttpURLConnection) urlObject.openConnection();
|
||||
@ -324,7 +328,7 @@ public class Miscellaneous extends Service
|
||||
migration:
|
||||
if (!newConfigFile.exists())
|
||||
{
|
||||
if (ActivityPermissions.havePermission(ActivityPermissions.writeExternalStoragePermissionName, Miscellaneous.getAnyContext()))
|
||||
if (ActivityPermissions.havePermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, Miscellaneous.getAnyContext()))
|
||||
{
|
||||
// We have the storage permission, probably because it's an old installation. Files should be migrated to app-specific folder.
|
||||
|
||||
@ -440,6 +444,25 @@ public class Miscellaneous extends Service
|
||||
// Miscellaneous.logEvent("i", TAG, "isEmulator=" + 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)
|
||||
{
|
||||
@ -568,6 +591,26 @@ public class Miscellaneous extends Service
|
||||
source = source.replace("[s]", String.valueOf(cal.get(Calendar.SECOND)));
|
||||
source = source.replace("[ms]", String.valueOf(cal.get(Calendar.MILLISECOND)));
|
||||
}
|
||||
|
||||
if(source.contains("[notificationTitle]"))
|
||||
{
|
||||
String notificationTitle = NotificationListener.getLastNotification().getTitle();
|
||||
|
||||
if(notificationTitle != null && notificationTitle.length() > 0)
|
||||
source = source.replace("[notificationTitle]", notificationTitle);
|
||||
else
|
||||
Miscellaneous.logEvent("w", "Variable replacement", "notificationTitle was empty.", 3);
|
||||
}
|
||||
|
||||
if(source.contains("[notificationText]"))
|
||||
{
|
||||
String notificationText = NotificationListener.getLastNotification().getText();
|
||||
|
||||
if(notificationText != null && notificationText.length() > 0)
|
||||
source = source.replace("[notificationText]", notificationText);
|
||||
else
|
||||
Miscellaneous.logEvent("w", "Variable replacement", "notificationText was empty.", 3);
|
||||
}
|
||||
|
||||
// Miscellaneous.logEvent("i", "URL after replace", source);
|
||||
|
||||
@ -848,7 +891,7 @@ public class Miscellaneous extends Service
|
||||
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);
|
||||
|
||||
@ -1187,6 +1230,122 @@ public class Miscellaneous extends Service
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
public static boolean copyDocumentFileToFile(DocumentFile src, File dst)
|
||||
{
|
||||
InputStream in = null;
|
||||
OutputStream out = null;
|
||||
String error = null;
|
||||
|
||||
try
|
||||
{
|
||||
in = Miscellaneous.getAnyContext().getContentResolver().openInputStream(src.getUri());
|
||||
out = new FileOutputStream(dst);
|
||||
|
||||
byte[] buffer = new byte[1024];
|
||||
int read;
|
||||
|
||||
while ((read = in.read(buffer)) != -1)
|
||||
{
|
||||
out.write(buffer, 0, read);
|
||||
}
|
||||
|
||||
in.close();
|
||||
// write the output file (You have now copied the file)
|
||||
out.flush();
|
||||
out.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (FileNotFoundException fnfe1)
|
||||
{
|
||||
error = fnfe1.getMessage();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
error = e.getMessage();
|
||||
}
|
||||
|
||||
return false;
|
||||
// return error;
|
||||
}
|
||||
|
||||
public static boolean copyFileToDocumentFile(File src, DocumentFile dst)
|
||||
{
|
||||
InputStream in = null;
|
||||
OutputStream out = null;
|
||||
String error = null;
|
||||
|
||||
try
|
||||
{
|
||||
in = new FileInputStream(src);
|
||||
out = Miscellaneous.getAnyContext().getContentResolver().openOutputStream(dst.getUri());
|
||||
|
||||
byte[] buffer = new byte[1024];
|
||||
int read;
|
||||
|
||||
while ((read = in.read(buffer)) != -1)
|
||||
{
|
||||
out.write(buffer, 0, read);
|
||||
}
|
||||
|
||||
in.close();
|
||||
// write the output file (You have now copied the file)
|
||||
out.flush();
|
||||
out.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (FileNotFoundException fnfe1)
|
||||
{
|
||||
error = fnfe1.getMessage();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
error = e.getMessage();
|
||||
}
|
||||
|
||||
return false;
|
||||
// return error;
|
||||
}
|
||||
|
||||
/*public static String copyDocumentFile(String inputPath, String inputFile, Uri treeUri)
|
||||
{
|
||||
InputStream in = null;
|
||||
OutputStream out = null;
|
||||
String error = null;
|
||||
DocumentFile pickedDir = DocumentFile.fromTreeUri(getActivity(), treeUri);
|
||||
String extension = inputFile.substring(inputFile.lastIndexOf(".")+1,inputFile.length());
|
||||
|
||||
try
|
||||
{
|
||||
DocumentFile newFile = pickedDir.createFile("audio/"+extension, inputFile);
|
||||
out = getActivity().getContentResolver().openOutputStream(newFile.getUri());
|
||||
in = new FileInputStream(inputPath + inputFile);
|
||||
|
||||
byte[] buffer = new byte[1024];
|
||||
int read;
|
||||
while ((read = in.read(buffer)) != -1)
|
||||
{
|
||||
out.write(buffer, 0, read);
|
||||
}
|
||||
in.close();
|
||||
// write the output file (You have now copied the file)
|
||||
out.flush();
|
||||
out.close();
|
||||
|
||||
}
|
||||
catch (FileNotFoundException fnfe1)
|
||||
{
|
||||
error = fnfe1.getMessage();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
error = e.getMessage();
|
||||
}
|
||||
|
||||
return error;
|
||||
}*/
|
||||
|
||||
public static boolean googleToBlameForLocation(boolean checkExistingRules)
|
||||
{
|
||||
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
|
||||
@ -1207,4 +1366,130 @@ public class Miscellaneous extends Service
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public static boolean isRegularExpression(String regex)
|
||||
{
|
||||
try
|
||||
{
|
||||
"compareString".matches(regex); //will cause expection if no valid regex
|
||||
return true;
|
||||
}
|
||||
catch(java.util.regex.PatternSyntaxException e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean comparePhoneNumbers(String number1, String number2)
|
||||
{
|
||||
/* To be activated when Android S SDK comes out
|
||||
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.Q)
|
||||
{
|
||||
TelephonyManager tm = (TelephonyManager)Miscellaneous.getAnyContext().getSystemService(Context.TELEPHONY_SERVICE);
|
||||
return PhoneNumberUtils.areSamePhoneNumber(number1, number2, tm.getNetworkCountryIso());
|
||||
}
|
||||
else*/
|
||||
return PhoneNumberUtils.compare(number1, number2);
|
||||
}
|
||||
}
|
@ -68,9 +68,15 @@ public class News
|
||||
Calendar now = Calendar.getInstance();
|
||||
String newsContent;
|
||||
|
||||
String filePath = context.getFilesDir() + "/appNews.xml";
|
||||
String newsFileName = "appNews.xml";
|
||||
|
||||
if (!(new File(filePath)).exists() || Settings.lastNewsPolltime == -1 || now.getTimeInMillis() >= Settings.lastNewsPolltime + (long)(Settings.newsDisplayForXDays * 24 * 60 * 60 * 1000))
|
||||
String filePath = context.getCacheDir() + "/" + newsFileName;
|
||||
|
||||
File oldFilePath = new File(context.getFilesDir() + "/" + newsFileName);
|
||||
if(oldFilePath.exists())
|
||||
oldFilePath.delete();
|
||||
|
||||
if (!(new File(filePath)).exists() || Settings.lastNewsPolltime == Settings.default_lastNewsPolltime || now.getTimeInMillis() >= Settings.lastNewsPolltime + (long)(Settings.newsDisplayForXDays * 24 * 60 * 60 * 1000))
|
||||
{
|
||||
String newsUrl = "https://server47.de/automation/appNews.php";
|
||||
newsContent = Miscellaneous.downloadURL(newsUrl, null, null);
|
||||
@ -80,14 +86,14 @@ public class News
|
||||
{
|
||||
Settings.lastNewsPolltime = now.getTimeInMillis();
|
||||
Settings.writeSettings(context);
|
||||
Miscellaneous.logEvent("i", "appNews.xml", "File stored to " + filePath, 5);
|
||||
Miscellaneous.logEvent("i", newsFileName, "File stored to " + filePath, 5);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Just read local cache file
|
||||
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<>();
|
||||
|
@ -491,9 +491,17 @@ public class PointOfInterest implements Comparable<PointOfInterest>
|
||||
AutomationService service = AutomationService.getInstance();
|
||||
if (service != null)
|
||||
{
|
||||
service.applySettingsAndRules();
|
||||
//Easiest way to check for changes in location, reset the last known location.
|
||||
service.getLocationProvider().setCurrentLocation(service.getLocationProvider().getCurrentLocation(), true);
|
||||
try
|
||||
{
|
||||
service.applySettingsAndRules();
|
||||
//Easiest way to check for changes in location, reset the last known location.
|
||||
service.getLocationProvider().setCurrentLocation(service.getLocationProvider().getCurrentLocation(), true);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
// Just log the event. This should not cause an interruption in the program flow.
|
||||
Miscellaneous.logEvent("e", "save POI", "Error when trying to apply settings and rules: " + Log.getStackTraceString(e), 2);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -530,14 +538,18 @@ public class PointOfInterest implements Comparable<PointOfInterest>
|
||||
PointOfInterest.writePoisToFile();
|
||||
|
||||
AutomationService service = AutomationService.getInstance();
|
||||
if(service != null)
|
||||
|
||||
try
|
||||
{
|
||||
service.applySettingsAndRules();
|
||||
|
||||
//Easiest way to check for changes in location, reset the last known location.
|
||||
service.getLocationProvider().setCurrentLocation(service.getLocationProvider().getCurrentLocation(), true);
|
||||
}
|
||||
|
||||
catch(Exception e)
|
||||
{
|
||||
// Just log the event. This should not cause an interruption in the program flow.
|
||||
Miscellaneous.logEvent("e", "save POI", "Error when trying to apply settings and rules: " + Log.getStackTraceString(e), 2);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -793,6 +805,7 @@ public class PointOfInterest implements Comparable<PointOfInterest>
|
||||
{
|
||||
String text = String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.overlapBetweenPois), otherPoi.getName(), String.valueOf(overlap));
|
||||
Miscellaneous.logEvent("w", "POI", text, 2);
|
||||
// Miscellaneous.messageBox("POI", text, Miscellaneous.getAnyContext()).show();
|
||||
Toast.makeText(Miscellaneous.getAnyContext(), text, Toast.LENGTH_LONG).show();
|
||||
return false;
|
||||
}
|
||||
|
@ -271,34 +271,46 @@ public class ReceiverCoordinator
|
||||
ProcessListener.stopProcessListener(AutomationService.getInstance());
|
||||
}
|
||||
|
||||
if(Rule.isAnyRuleUsing(Trigger.Trigger_Enum.activityDetection))
|
||||
if(!BuildConfig.FLAVOR.equalsIgnoreCase("fdroidFlavor"))
|
||||
{
|
||||
boolean isRunning = (Boolean)Miscellaneous.runMethodReflective("ActivityDetectionReceiver", "isActivityDetectionReceiverRunning", null);
|
||||
if(isRunning)
|
||||
if (Rule.isAnyRuleUsing(Trigger.Trigger_Enum.activityDetection))
|
||||
{
|
||||
Miscellaneous.logEvent("i", "LocationProvider", "Restarting ActivityDetectionReceiver because used in a new/changed rule.", 4);
|
||||
boolean haveAllPerms = (Boolean)Miscellaneous.runMethodReflective("ActivityDetectionReceiver", "haveAllPermission", null);
|
||||
if(haveAllPerms)
|
||||
Miscellaneous.runMethodReflective("ActivityDetectionReceiver", "restartActivityDetectionReceiver", null);
|
||||
Object runResult = Miscellaneous.runMethodReflective(activityDetectionClassPath, "isActivityDetectionReceiverRunning", null);
|
||||
|
||||
if (runResult instanceof Boolean)
|
||||
{
|
||||
boolean isRunning = (Boolean) runResult;
|
||||
if (isRunning)
|
||||
{
|
||||
Miscellaneous.logEvent("i", "LocationProvider", "Restarting ActivityDetectionReceiver because used in a new/changed rule.", 4);
|
||||
boolean haveAllPerms = (Boolean) Miscellaneous.runMethodReflective(activityDetectionClassPath, "haveAllPermission", null);
|
||||
if (haveAllPerms)
|
||||
Miscellaneous.runMethodReflective(activityDetectionClassPath, "restartActivityDetectionReceiver", null);
|
||||
// ActivityDetectionReceiver.restartActivityDetectionReceiver();
|
||||
}
|
||||
else
|
||||
{
|
||||
Miscellaneous.logEvent("i", "LocationProvider", "Starting ActivityDetectionReceiver because used in a new/changed rule.", 4);
|
||||
boolean haveAllPerms = (Boolean) Miscellaneous.runMethodReflective(activityDetectionClassPath, "haveAllPermission", null);
|
||||
if (haveAllPerms)
|
||||
Miscellaneous.runMethodReflective(activityDetectionClassPath, "startActivityDetectionReceiver", null);
|
||||
// ActivityDetectionReceiver.startActivityDetectionReceiver();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Miscellaneous.logEvent("i", "LocationProvider", "Starting ActivityDetectionReceiver because used in a new/changed rule.", 4);
|
||||
boolean haveAllPerms = (Boolean)Miscellaneous.runMethodReflective("ActivityDetectionReceiver", "haveAllPermission", null);
|
||||
if(haveAllPerms)
|
||||
Miscellaneous.runMethodReflective("ActivityDetectionReceiver", "startActivityDetectionReceiver", null);
|
||||
// ActivityDetectionReceiver.startActivityDetectionReceiver();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
boolean isRunning = (Boolean)Miscellaneous.runMethodReflective("ActivityDetectionReceiver", "isActivityDetectionReceiverRunning", null);
|
||||
if(isRunning)
|
||||
{
|
||||
Miscellaneous.logEvent("i", "LocationProvider", "Shutting down ActivityDetectionReceiver because not used in any rule.", 4);
|
||||
Miscellaneous.runMethodReflective("ActivityDetectionReceiver", "stopActivityDetectionReceiver", null);
|
||||
Object runResult = Miscellaneous.runMethodReflective(activityDetectionClassPath, "isActivityDetectionReceiverRunning", null);
|
||||
if (runResult instanceof Boolean)
|
||||
{
|
||||
boolean isRunning = (Boolean) runResult;
|
||||
if (isRunning)
|
||||
{
|
||||
Miscellaneous.logEvent("i", "LocationProvider", "Shutting down ActivityDetectionReceiver because not used in any rule.", 4);
|
||||
Miscellaneous.runMethodReflective(activityDetectionClassPath, "stopActivityDetectionReceiver", null);
|
||||
// ActivityDetectionReceiver.stopActivityDetectionReceiver();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,9 @@ public class Settings implements SharedPreferences
|
||||
public final static int lockSoundChangesInterval = 15;
|
||||
public static final int newsPollEveryXDays = 3;
|
||||
public static final int newsDisplayForXDays = 3;
|
||||
public static final int updateCheckFrequencyDays = 7;
|
||||
public static final String folderName = "Automation";
|
||||
public static final String zipFileName = "automation.zip";
|
||||
|
||||
public static final String constNewsOptInDone ="newsOptInDone";
|
||||
|
||||
@ -58,12 +60,16 @@ public class Settings implements SharedPreferences
|
||||
public static int activityDetectionRequiredProbability;
|
||||
public static boolean privacyLocationing;
|
||||
public static int startScreen;
|
||||
public static int tabsPlacement;
|
||||
public static boolean executeRulesAndProfilesWithSingleClick;
|
||||
public static boolean displayNewsOnMainScreen;
|
||||
public static boolean automaticUpdateCheck;
|
||||
|
||||
public static boolean lockSoundChanges;
|
||||
public static boolean noticeAndroid9MicrophoneShown;
|
||||
public static boolean noticeAndroid10WifiShown;
|
||||
public static long lastNewsPolltime;
|
||||
public static long lastUpdateCheck;
|
||||
|
||||
public static ArrayList<String> whatHasBeenDone;
|
||||
|
||||
@ -111,10 +117,13 @@ public class Settings implements SharedPreferences
|
||||
protected static final int default_activityDetectionRequiredProbability = 75;
|
||||
protected static final boolean default_privacyLocationing = false;
|
||||
protected static final int default_startScreen = 0;
|
||||
protected static final int default_tabsPlacement = 0;
|
||||
protected static final boolean default_executeRulesAndProfilesWithSingleClick = false;
|
||||
protected static final boolean default_displayNewsOnMainScreen = false;
|
||||
protected static final boolean default_automaticUpdateCheck = false;
|
||||
protected static final boolean default_lockSoundChanges = false;
|
||||
protected static final long default_lastNewsPolltime = -1;
|
||||
protected static final long default_lastUpdateCheck = -1;
|
||||
|
||||
@Override
|
||||
public boolean contains(String arg0)
|
||||
@ -246,8 +255,10 @@ public class Settings implements SharedPreferences
|
||||
|
||||
privacyLocationing = prefs.getBoolean("privacyLocationing", default_privacyLocationing);
|
||||
startScreen = Integer.parseInt(prefs.getString("startScreen", String.valueOf(default_startScreen)));
|
||||
tabsPlacement = Integer.parseInt(prefs.getString("tabsPlacement", String.valueOf(default_tabsPlacement)));
|
||||
|
||||
executeRulesAndProfilesWithSingleClick = prefs.getBoolean("executeRulesAndProfilesWithSingleClick", default_executeRulesAndProfilesWithSingleClick);
|
||||
automaticUpdateCheck = prefs.getBoolean("automaticUpdateCheck", default_automaticUpdateCheck);
|
||||
displayNewsOnMainScreen = prefs.getBoolean("displayNewsOnMainScreen", default_displayNewsOnMainScreen);
|
||||
|
||||
lockSoundChanges = prefs.getBoolean("lockSoundChanges", default_lockSoundChanges);
|
||||
@ -255,6 +266,7 @@ public class Settings implements SharedPreferences
|
||||
noticeAndroid10WifiShown = prefs.getBoolean("noticeAndroid10WifiShown", false);
|
||||
|
||||
lastNewsPolltime = prefs.getLong("lastNewsPolltime", default_lastNewsPolltime);
|
||||
lastUpdateCheck = prefs.getLong("lastUpdateCheck", default_lastUpdateCheck);
|
||||
|
||||
String whbdString = prefs.getString("whatHasBeenDone", "");
|
||||
if(whbdString != null && whbdString.length() > 0)
|
||||
@ -431,9 +443,15 @@ public class Settings implements SharedPreferences
|
||||
if(!prefs.contains("startScreen") | force)
|
||||
editor.putString("startScreen", String.valueOf(default_startScreen));
|
||||
|
||||
if(!prefs.contains("tabsPlacement") | force)
|
||||
editor.putString("tabsPlacement", String.valueOf(default_tabsPlacement));
|
||||
|
||||
if(!prefs.contains("executeRulesAndProfilesWithSingleClick") | force)
|
||||
editor.putBoolean("executeRulesAndProfilesWithSingleClick", default_executeRulesAndProfilesWithSingleClick);
|
||||
|
||||
if(!prefs.contains("automaticUpdateCheck") | force)
|
||||
editor.putBoolean("automaticUpdateCheck", default_automaticUpdateCheck);
|
||||
|
||||
if(!prefs.contains("displayNewsOnMainScreen") | force)
|
||||
editor.putBoolean("displayNewsOnMainScreen", default_displayNewsOnMainScreen);
|
||||
|
||||
@ -446,6 +464,9 @@ public class Settings implements SharedPreferences
|
||||
if(!prefs.contains("lastNewsPolltime") | force)
|
||||
editor.putLong("lastNewsPolltime", default_lastNewsPolltime);
|
||||
|
||||
if(!prefs.contains("lastUpdateCheck") | force)
|
||||
editor.putLong("lastUpdateCheck", default_lastUpdateCheck);
|
||||
|
||||
if(!prefs.contains("whatHasBeenDone") | force)
|
||||
editor.putString("whatHasBeenDone", "");
|
||||
|
||||
@ -509,7 +530,9 @@ public class Settings implements SharedPreferences
|
||||
editor.putString("activityDetectionRequiredProbability", String.valueOf(activityDetectionRequiredProbability));
|
||||
editor.putBoolean("privacyLocationing", privacyLocationing);
|
||||
editor.putString("startScreen", String.valueOf(startScreen));
|
||||
editor.putString("tabsPlacement", String.valueOf(tabsPlacement));
|
||||
editor.putBoolean("executeRulesAndProfilesWithSingleClick", executeRulesAndProfilesWithSingleClick);
|
||||
editor.putBoolean("automaticUpdateCheck", automaticUpdateCheck);
|
||||
editor.putBoolean("displayNewsOnMainScreen", displayNewsOnMainScreen);
|
||||
|
||||
editor.putBoolean("lockSoundChanges", lockSoundChanges);
|
||||
@ -517,6 +540,7 @@ public class Settings implements SharedPreferences
|
||||
editor.putBoolean("noticeAndroid10WifiShown", noticeAndroid10WifiShown);
|
||||
|
||||
editor.putLong("lastNewsPolltime", lastNewsPolltime);
|
||||
editor.putLong("lastUpdateCheck", lastUpdateCheck);
|
||||
|
||||
editor.putString("whatHasBeenDone", Miscellaneous.explode(";", whatHasBeenDone));
|
||||
|
||||
@ -558,4 +582,4 @@ public class Settings implements SharedPreferences
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -21,7 +21,7 @@ public class Trigger
|
||||
*/
|
||||
|
||||
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)
|
||||
{
|
||||
@ -59,6 +59,8 @@ public class Trigger
|
||||
return context.getResources().getString(R.string.bluetoothConnection);
|
||||
case headsetPlugged:
|
||||
return context.getResources().getString(R.string.triggerHeadsetPlugged);
|
||||
case notification:
|
||||
return context.getResources().getString(R.string.notification);
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
@ -67,15 +69,25 @@ public class Trigger
|
||||
};
|
||||
|
||||
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 PointOfInterest pointOfInterest = null;
|
||||
private TimeFrame timeFrame;
|
||||
|
||||
public static String triggerPhoneCallStateRinging = "ringing";
|
||||
public static String triggerPhoneCallStateStarted = "started";
|
||||
public static String triggerPhoneCallStateStopped = "stopped";
|
||||
public static String triggerPhoneCallDirectionIncoming = "incoming";
|
||||
public static String triggerPhoneCallDirectionOutgoing = "outgoing";
|
||||
public static String triggerPhoneCallDirectionAny = "any";
|
||||
public static String triggerPhoneCallNumberAny = "any";
|
||||
|
||||
private double speed; //km/h
|
||||
private long noiseLevelDb;
|
||||
private String wifiName = "";
|
||||
private String processName = null;
|
||||
private String processName = null;
|
||||
private int batteryLevel;
|
||||
private int phoneDirection = 0; // 0=any, 1=incoming, 2=outgoing
|
||||
private String phoneNumber = null;
|
||||
@ -206,6 +218,16 @@ public class Trigger
|
||||
this.triggerParameter = triggerParameter;
|
||||
}
|
||||
|
||||
public String getTriggerParameter2()
|
||||
{
|
||||
return triggerParameter2;
|
||||
}
|
||||
|
||||
public void setTriggerParameter2(String triggerParameter2)
|
||||
{
|
||||
this.triggerParameter2 = triggerParameter2;
|
||||
}
|
||||
|
||||
public TimeFrame getTimeFrame()
|
||||
{
|
||||
return timeFrame;
|
||||
@ -216,7 +238,6 @@ public class Trigger
|
||||
this.timeFrame = timeFrame;
|
||||
}
|
||||
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
||||
@SuppressWarnings("unused")
|
||||
@Override
|
||||
@ -292,10 +313,10 @@ public class Trigger
|
||||
break;
|
||||
case wifiConnection:
|
||||
String wifiDisplayName = "";
|
||||
if(this.getWifiName().length() == 0)
|
||||
if(this.getTriggerParameter2().length() == 0)
|
||||
wifiDisplayName += Miscellaneous.getAnyContext().getResources().getString(R.string.anyWifi);
|
||||
else
|
||||
wifiDisplayName += this.getWifiName();
|
||||
wifiDisplayName += this.getTriggerParameter2();
|
||||
|
||||
if(getTriggerParameter())
|
||||
returnString.append(String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.connectedToWifi), wifiDisplayName));
|
||||
@ -325,21 +346,45 @@ public class Trigger
|
||||
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.roaming));
|
||||
break;
|
||||
case phoneCall:
|
||||
if(getPhoneDirection() == 1)
|
||||
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.incomingAdjective) + " ");
|
||||
else if(getPhoneDirection() == 2)
|
||||
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.outgoingAdjective) + " ");
|
||||
String[] elements = triggerParameter2.split(triggerParameter2Split);
|
||||
|
||||
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.phoneCall));
|
||||
if(phoneNumber != null && !phoneNumber.equals("any"))
|
||||
returnString.append(" " + Miscellaneous.getAnyContext().getResources().getString(R.string.with) + " " + Miscellaneous.getAnyContext().getResources().getString(R.string.number) + " " + phoneNumber);
|
||||
|
||||
returnString.append(" ");
|
||||
|
||||
if(elements[1].equals(triggerPhoneCallDirectionAny))
|
||||
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.with));
|
||||
else if(elements[1].equals(triggerPhoneCallDirectionIncoming))
|
||||
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.from));
|
||||
else if(elements[1].equals(triggerPhoneCallDirectionOutgoing))
|
||||
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.to));
|
||||
|
||||
returnString.append(" ");
|
||||
|
||||
if(elements[2].equals(Trigger.triggerPhoneCallNumberAny))
|
||||
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.any) + " " + Miscellaneous.getAnyContext().getResources().getString(R.string.number));
|
||||
else
|
||||
returnString.append(" " + Miscellaneous.getAnyContext().getResources().getString(R.string.with) + " " + Miscellaneous.getAnyContext().getResources().getString(R.string.anyNumber));
|
||||
|
||||
if(getTriggerParameter())
|
||||
returnString.append(" " + Miscellaneous.getAnyContext().getResources().getString(R.string.started));
|
||||
else
|
||||
returnString.append(" " + Miscellaneous.getAnyContext().getResources().getString(R.string.stopped));
|
||||
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.number) + " " + Miscellaneous.getAnyContext().getResources().getString(R.string.matching) + " " + elements[2]);
|
||||
|
||||
returnString.append(" ");
|
||||
|
||||
if(elements[0].equals(Trigger.triggerPhoneCallStateRinging))
|
||||
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.ringing));
|
||||
else if(elements[0].equals(Trigger.triggerPhoneCallStateStarted))
|
||||
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.started));
|
||||
else if(elements[0].equals(Trigger.triggerPhoneCallStateStopped))
|
||||
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.stopped));
|
||||
|
||||
// returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.phoneCall));
|
||||
// if(phoneNumber != null && !phoneNumber.equals("any"))
|
||||
// returnString.append(" " + Miscellaneous.getAnyContext().getResources().getString(R.string.with) + " " + Miscellaneous.getAnyContext().getResources().getString(R.string.number) + " " + phoneNumber);
|
||||
// else
|
||||
// returnString.append(" " + Miscellaneous.getAnyContext().getResources().getString(R.string.with) + " " + Miscellaneous.getAnyContext().getResources().getString(R.string.anyNumber));
|
||||
//
|
||||
// if(getTriggerParameter())
|
||||
// returnString.append(" " + Miscellaneous.getAnyContext().getResources().getString(R.string.started));
|
||||
// else
|
||||
// returnString.append(" " + Miscellaneous.getAnyContext().getResources().getString(R.string.stopped));
|
||||
break;
|
||||
case nfcTag:
|
||||
// This type doesn't have an activate/deactivate equivalent
|
||||
@ -440,6 +485,46 @@ public class Trigger
|
||||
else
|
||||
returnString.append(String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.headsetDisconnected), type));
|
||||
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:
|
||||
returnString.append("error");
|
||||
break;
|
||||
@ -447,7 +532,47 @@ public class Trigger
|
||||
|
||||
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()
|
||||
{
|
||||
@ -478,15 +603,6 @@ public class Trigger
|
||||
return (String[])triggerTypesList.toArray(new String[triggerTypesList.size()]);
|
||||
}
|
||||
|
||||
public String getWifiName()
|
||||
{
|
||||
return wifiName;
|
||||
}
|
||||
|
||||
public void setWifiName(String wifiName)
|
||||
{
|
||||
this.wifiName = wifiName;
|
||||
}
|
||||
public void setBluetoothEvent(String string)
|
||||
{
|
||||
this.bluetoothEvent = string;
|
||||
|
@ -23,6 +23,8 @@ import java.security.GeneralSecurityException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
import static com.jens.automation2.Trigger.triggerParameter2Split;
|
||||
|
||||
public class XmlFileInterface
|
||||
{
|
||||
public static String settingsFileName = "Automation_settings.xml";
|
||||
@ -91,7 +93,7 @@ public class XmlFileInterface
|
||||
{
|
||||
//start a tag called "root"
|
||||
serializer.startTag(null, "PointOfInterest");
|
||||
|
||||
|
||||
//i indent code just to have a view similar to xml-tree
|
||||
serializer.startTag(null, "name");
|
||||
serializer.text(PointOfInterest.getPointOfInterestCollection().get(i).getName());
|
||||
@ -253,13 +255,13 @@ public class XmlFileInterface
|
||||
else if(Rule.getRuleCollection().get(i).getTriggerSet().get(j).getTriggerType() == Trigger_Enum.noiseLevel)
|
||||
serializer.text(String.valueOf(Rule.getRuleCollection().get(i).getTriggerSet().get(j).getNoiseLevelDb()));
|
||||
else if(Rule.getRuleCollection().get(i).getTriggerSet().get(j).getTriggerType() == Trigger_Enum.wifiConnection)
|
||||
serializer.text(Rule.getRuleCollection().get(i).getTriggerSet().get(j).getWifiName());
|
||||
serializer.text(Rule.getRuleCollection().get(i).getTriggerSet().get(j).getTriggerParameter2());
|
||||
else if(Rule.getRuleCollection().get(i).getTriggerSet().get(j).getTriggerType() == Trigger_Enum.process_started_stopped)
|
||||
serializer.text(Rule.getRuleCollection().get(i).getTriggerSet().get(j).getProcessName());
|
||||
else if(Rule.getRuleCollection().get(i).getTriggerSet().get(j).getTriggerType() == Trigger_Enum.batteryLevel)
|
||||
serializer.text(String.valueOf(Rule.getRuleCollection().get(i).getTriggerSet().get(j).getBatteryLevel()));
|
||||
else if(Rule.getRuleCollection().get(i).getTriggerSet().get(j).getTriggerType() == Trigger_Enum.phoneCall)
|
||||
serializer.text(String.valueOf(Rule.getRuleCollection().get(i).getTriggerSet().get(j).getPhoneDirection()) + "," + String.valueOf(Rule.getRuleCollection().get(i).getTriggerSet().get(j).getPhoneNumber()));
|
||||
// else if(Rule.getRuleCollection().get(i).getTriggerSet().get(j).getTriggerType() == Trigger_Enum.phoneCall)
|
||||
// serializer.text(String.valueOf(Rule.getRuleCollection().get(i).getTriggerSet().get(j).getPhoneDirection()) + "," + String.valueOf(Rule.getRuleCollection().get(i).getTriggerSet().get(j).getPhoneNumber()));
|
||||
else if(Rule.getRuleCollection().get(i).getTriggerSet().get(j).getTriggerType() == Trigger_Enum.nfcTag)
|
||||
serializer.text(Rule.getRuleCollection().get(i).getTriggerSet().get(j).getNfcTagId());
|
||||
else if(Rule.getRuleCollection().get(i).getTriggerSet().get(j).getTriggerType() == Trigger_Enum.activityDetection)
|
||||
@ -271,6 +273,10 @@ public class XmlFileInterface
|
||||
}
|
||||
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()));
|
||||
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()));
|
||||
else
|
||||
serializer.text(String.valueOf(Rule.getRuleCollection().get(i).getTriggerSet().get(j).getTriggerParameter2()));
|
||||
serializer.endTag(null, "TriggerParameter2");
|
||||
serializer.endTag(null, "Trigger");
|
||||
}
|
||||
@ -377,7 +383,7 @@ public class XmlFileInterface
|
||||
}
|
||||
catch (XmlPullParserException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
Miscellaneous.logEvent("e", "XmlFileInterface", Log.getStackTraceString(e), 1);
|
||||
}
|
||||
catch(FileNotFoundException e)
|
||||
{
|
||||
@ -392,12 +398,12 @@ public class XmlFileInterface
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
|
||||
Miscellaneous.logEvent("e", "XmlFileInterface", Log.getStackTraceString(e), 1);
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
Miscellaneous.logEvent("e", "XmlFileInterface", Log.getStackTraceString(e), 1);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
@ -532,11 +538,11 @@ public class XmlFileInterface
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
Miscellaneous.logEvent("e", "XmlFileInterface", Log.getStackTraceString(e), 1);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
Miscellaneous.logEvent("e", "XmlFileInterface", Log.getStackTraceString(e), 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -749,13 +755,11 @@ public class XmlFileInterface
|
||||
}
|
||||
catch (XmlPullParserException e)
|
||||
{
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
Miscellaneous.logEvent("e", "XmlFileInterface", Log.getStackTraceString(e), 1);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
Miscellaneous.logEvent("e", "XmlFileInterface", Log.getStackTraceString(e), 1);
|
||||
}
|
||||
}
|
||||
else if (name.equals("ActionCollection"))
|
||||
@ -766,13 +770,11 @@ public class XmlFileInterface
|
||||
}
|
||||
catch (XmlPullParserException e)
|
||||
{
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
Miscellaneous.logEvent("e", "XmlFileInterface", Log.getStackTraceString(e), 1);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
Miscellaneous.logEvent("e", "XmlFileInterface", Log.getStackTraceString(e), 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -863,38 +865,11 @@ public class XmlFileInterface
|
||||
if (name.equals("TriggerEvent"))
|
||||
{
|
||||
String triggerEventString = readTag(parser, "TriggerEvent");
|
||||
if(triggerEventString.equals("pointOfInterest"))
|
||||
newTrigger.setTriggerType(Trigger_Enum.pointOfInterest);
|
||||
else if(triggerEventString.equals("timeFrame"))
|
||||
newTrigger.setTriggerType(Trigger_Enum.timeFrame);
|
||||
else if(triggerEventString.equals("charging"))
|
||||
newTrigger.setTriggerType(Trigger_Enum.charging);
|
||||
else if(triggerEventString.equals("usb_host_connection"))
|
||||
newTrigger.setTriggerType(Trigger_Enum.usb_host_connection);
|
||||
else if(triggerEventString.equals("batteryLevel"))
|
||||
newTrigger.setTriggerType(Trigger_Enum.batteryLevel);
|
||||
else if(triggerEventString.equals("speed"))
|
||||
newTrigger.setTriggerType(Trigger_Enum.speed);
|
||||
else if(triggerEventString.equals("noiseLevel"))
|
||||
newTrigger.setTriggerType(Trigger_Enum.noiseLevel);
|
||||
else if(triggerEventString.equals("wifiConnection"))
|
||||
newTrigger.setTriggerType(Trigger_Enum.wifiConnection);
|
||||
else if(triggerEventString.equals("process_started_stopped") | triggerEventString.equals("process_running"))
|
||||
|
||||
if(triggerEventString.equals("process_started_stopped") | triggerEventString.equals("process_running"))
|
||||
newTrigger.setTriggerType(Trigger_Enum.process_started_stopped);
|
||||
else if(triggerEventString.equals("airplaneMode"))
|
||||
newTrigger.setTriggerType(Trigger_Enum.airplaneMode);
|
||||
else if(triggerEventString.equals("roaming"))
|
||||
newTrigger.setTriggerType(Trigger_Enum.roaming);
|
||||
else if(triggerEventString.equals("phoneCall"))
|
||||
newTrigger.setTriggerType(Trigger_Enum.phoneCall);
|
||||
else if(triggerEventString.equals("nfcTag"))
|
||||
newTrigger.setTriggerType(Trigger_Enum.nfcTag);
|
||||
else if(triggerEventString.equals("activityDetection"))
|
||||
newTrigger.setTriggerType(Trigger_Enum.activityDetection);
|
||||
else if(triggerEventString.equals("bluetoothConnection"))
|
||||
newTrigger.setTriggerType(Trigger_Enum.bluetoothConnection);
|
||||
else if(triggerEventString.equals("headsetPlugged"))
|
||||
newTrigger.setTriggerType(Trigger_Enum.headsetPlugged);
|
||||
else
|
||||
newTrigger.setTriggerType(Trigger_Enum.valueOf(triggerEventString));
|
||||
}
|
||||
else if (name.equals("TriggerParameter1"))
|
||||
{
|
||||
@ -917,42 +892,91 @@ public class XmlFileInterface
|
||||
Miscellaneous.logEvent("e", "XmlFileInterface", Log.getStackTraceString(e), 2);
|
||||
Toast.makeText(context, "Error while writing file: " + Log.getStackTraceString(e), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
newTrigger.setTriggerParameter2(triggerParameter2);
|
||||
}
|
||||
else if(newTrigger.getTriggerType() == Trigger_Enum.timeFrame)
|
||||
{
|
||||
newTrigger.setTimeFrame(new TimeFrame(triggerParameter2));
|
||||
newTrigger.setTriggerParameter2(triggerParameter2);
|
||||
}
|
||||
else if(newTrigger.getTriggerType() == Trigger_Enum.batteryLevel)
|
||||
{
|
||||
newTrigger.setBatteryLevel(Integer.parseInt(triggerParameter2));
|
||||
newTrigger.setTriggerParameter2(triggerParameter2);
|
||||
}
|
||||
else if(newTrigger.getTriggerType() == Trigger_Enum.speed)
|
||||
{
|
||||
newTrigger.setSpeed(Double.parseDouble(triggerParameter2));
|
||||
newTrigger.setTriggerParameter2(triggerParameter2);
|
||||
}
|
||||
else if(newTrigger.getTriggerType() == Trigger_Enum.noiseLevel)
|
||||
{
|
||||
newTrigger.setNoiseLevelDb(Long.parseLong(triggerParameter2));
|
||||
newTrigger.setTriggerParameter2(triggerParameter2);
|
||||
}
|
||||
else if(newTrigger.getTriggerType() == Trigger_Enum.wifiConnection)
|
||||
{
|
||||
newTrigger.setWifiName(triggerParameter2);
|
||||
// newTrigger.setWifiName(triggerParameter2);
|
||||
newTrigger.setTriggerParameter2(triggerParameter2);
|
||||
}
|
||||
else if(newTrigger.getTriggerType() == Trigger_Enum.process_started_stopped)
|
||||
{
|
||||
newTrigger.setProcessName(triggerParameter2);
|
||||
newTrigger.setTriggerParameter2(triggerParameter2);
|
||||
}
|
||||
else if(newTrigger.getTriggerType() == Trigger_Enum.phoneCall)
|
||||
{
|
||||
// 0/1/2,number
|
||||
int direction = Integer.parseInt(triggerParameter2.substring(0, 1));
|
||||
String number = triggerParameter2.substring(2);
|
||||
newTrigger.setPhoneDirection(direction);
|
||||
newTrigger.setPhoneNumber(number);
|
||||
String[] elements = triggerParameter2.split(",");
|
||||
if(elements.length == 2) //old format
|
||||
{
|
||||
// 0/1/2,number
|
||||
int direction = Integer.parseInt(elements[0]);
|
||||
|
||||
String number = elements[1];
|
||||
newTrigger.setPhoneDirection(direction);
|
||||
newTrigger.setPhoneNumber(number);
|
||||
|
||||
String tp2String = "";
|
||||
|
||||
if(newTrigger.getTriggerParameter())
|
||||
tp2String+= Trigger.triggerPhoneCallStateStarted;
|
||||
else
|
||||
tp2String+= Trigger.triggerPhoneCallStateStopped;
|
||||
|
||||
tp2String += triggerParameter2Split;
|
||||
|
||||
switch(direction)
|
||||
{
|
||||
case 0:
|
||||
tp2String += Trigger.triggerPhoneCallDirectionAny;
|
||||
break;
|
||||
case 1:
|
||||
tp2String += Trigger.triggerPhoneCallDirectionIncoming;
|
||||
break;
|
||||
case 2:
|
||||
tp2String += Trigger.triggerPhoneCallDirectionOutgoing;
|
||||
break;
|
||||
}
|
||||
|
||||
tp2String += triggerParameter2Split;
|
||||
|
||||
tp2String += number;
|
||||
|
||||
newTrigger.setTriggerParameter2(tp2String);
|
||||
}
|
||||
/*else // new format
|
||||
{
|
||||
//tp1 is now irrelevant
|
||||
elements = triggerParameter2.split(Trigger.triggerParameter2Split);
|
||||
// state/direction/number
|
||||
}*/
|
||||
else
|
||||
newTrigger.setTriggerParameter2(triggerParameter2);
|
||||
}
|
||||
else if(newTrigger.getTriggerType() == Trigger_Enum.nfcTag)
|
||||
{
|
||||
newTrigger.setNfcTagId(triggerParameter2);
|
||||
newTrigger.setTriggerParameter2(triggerParameter2);
|
||||
}
|
||||
else if(newTrigger.getTriggerType() == Trigger_Enum.activityDetection)
|
||||
{
|
||||
@ -964,6 +988,7 @@ public class XmlFileInterface
|
||||
{
|
||||
newTrigger.setActivityDetectionType(0);
|
||||
}
|
||||
newTrigger.setTriggerParameter2(triggerParameter2);
|
||||
}
|
||||
else if(newTrigger.getTriggerType() == Trigger_Enum.bluetoothConnection)
|
||||
{
|
||||
@ -973,6 +998,7 @@ public class XmlFileInterface
|
||||
newTrigger.setBluetoothEvent(substrings[0]);
|
||||
newTrigger.setBluetoothDeviceAddress(substrings[1]);
|
||||
}
|
||||
newTrigger.setTriggerParameter2(triggerParameter2);
|
||||
}
|
||||
else if(newTrigger.getTriggerType() == Trigger_Enum.headsetPlugged)
|
||||
{
|
||||
@ -984,7 +1010,10 @@ public class XmlFileInterface
|
||||
{
|
||||
newTrigger.setHeadphoneType(-1);
|
||||
}
|
||||
newTrigger.setTriggerParameter2(triggerParameter2);
|
||||
}
|
||||
else
|
||||
newTrigger.setTriggerParameter2(triggerParameter2);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1072,19 +1101,9 @@ public class XmlFileInterface
|
||||
{
|
||||
String actionNameString = readTag(parser, "ActionName");
|
||||
|
||||
if(actionNameString.equals("setWifi"))
|
||||
newAction.setAction(Action_Enum.setWifi);
|
||||
else if(actionNameString.equals("setBluetooth"))
|
||||
newAction.setAction(Action_Enum.setBluetooth);
|
||||
else if(actionNameString.equals("setUsbTethering"))
|
||||
newAction.setAction(Action_Enum.setUsbTethering);
|
||||
else if(actionNameString.equals("setWifiTethering"))
|
||||
newAction.setAction(Action_Enum.setWifiTethering);
|
||||
else if(actionNameString.equals("setDisplayRotation"))
|
||||
newAction.setAction(Action_Enum.setDisplayRotation);
|
||||
|
||||
// *** deprecated
|
||||
else if(actionNameString.equals("turnWifiOn"))
|
||||
//else
|
||||
if(actionNameString.equals("turnWifiOn"))
|
||||
newAction.setAction(Action_Enum.turnWifiOn);
|
||||
else if(actionNameString.equals("turnWifiOff"))
|
||||
newAction.setAction(Action_Enum.turnWifiOff);
|
||||
@ -1105,29 +1124,9 @@ public class XmlFileInterface
|
||||
else if(actionNameString.equals("disableScreenRotation"))
|
||||
newAction.setAction(Action_Enum.disableScreenRotation);
|
||||
// *** deprecated
|
||||
|
||||
else if(actionNameString.equals("triggerUrl"))
|
||||
newAction.setAction(Action_Enum.triggerUrl);
|
||||
else if(actionNameString.equals("changeSoundProfile"))
|
||||
newAction.setAction(Action_Enum.changeSoundProfile);
|
||||
else if(actionNameString.equals("startOtherActivity"))
|
||||
newAction.setAction(Action_Enum.startOtherActivity);
|
||||
else if(actionNameString.equals("waitBeforeNextAction"))
|
||||
newAction.setAction(Action_Enum.waitBeforeNextAction);
|
||||
else if(actionNameString.equals("wakeupDevice"))
|
||||
newAction.setAction(Action_Enum.wakeupDevice);
|
||||
else if(actionNameString.equals("setAirplaneMode"))
|
||||
newAction.setAction(Action_Enum.setAirplaneMode);
|
||||
else if(actionNameString.equals("setDataConnection"))
|
||||
newAction.setAction(Action_Enum.setDataConnection);
|
||||
else if(actionNameString.equals("speakText"))
|
||||
newAction.setAction(Action_Enum.speakText);
|
||||
else if(actionNameString.equals("sendTextMessage"))
|
||||
newAction.setAction(Action_Enum.sendTextMessage);
|
||||
else if(actionNameString.equals("playMusic"))
|
||||
newAction.setAction(Action_Enum.playMusic);
|
||||
else if(actionNameString.equals("setScreenBrightness"))
|
||||
newAction.setAction(Action_Enum.setScreenBrightness);
|
||||
|
||||
else
|
||||
newAction.setAction(Action_Enum.valueOf(actionNameString));
|
||||
}
|
||||
else if (name.equals("ActionParameter1"))
|
||||
{
|
||||
@ -1213,8 +1212,43 @@ public class XmlFileInterface
|
||||
{
|
||||
newAction.setParameter2(tag);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
androidx.security.crypto.MasterKey.Builder
|
||||
|
||||
MasterKey mainKey = new MasterKey.Builder(context)
|
||||
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
|
||||
.build();
|
||||
*/
|
||||
}
|
||||
}
|
||||
else if(newAction.getAction().equals(Action_Enum.startOtherActivity)) // separator has been changed, convert in old files
|
||||
{
|
||||
String newTag;
|
||||
|
||||
if(tag.contains(Action.intentPairSeperator)) // already has new format
|
||||
newTag = tag;
|
||||
else
|
||||
newTag = tag.replace("/", Action.intentPairSeperator);
|
||||
|
||||
String[] newTagPieces = newTag.split(";");
|
||||
|
||||
if(newTagPieces.length < 2 || (!newTagPieces[0].contains(Actions.dummyPackageString) && newTagPieces[1].contains(Action.intentPairSeperator)))
|
||||
{
|
||||
newTag = Actions.dummyPackageString + ";" + newTag;
|
||||
newTagPieces = newTag.split(";");
|
||||
}
|
||||
|
||||
if(newTagPieces.length < 3)
|
||||
newTag += ";" + ActivityManageActionStartActivity.startByActivityString;
|
||||
else if(newTagPieces.length >= 3)
|
||||
{
|
||||
if(newTagPieces[2].contains(Action.intentPairSeperator))
|
||||
newTag = newTagPieces[0] + ";" + newTagPieces[1] + ";" + ActivityManageActionStartActivity.startByActivityString + ";" + newTagPieces[2];
|
||||
}
|
||||
|
||||
newAction.setParameter2(newTag);
|
||||
}
|
||||
else
|
||||
newAction.setParameter2(tag);
|
||||
}
|
||||
|
@ -0,0 +1,19 @@
|
||||
package com.jens.automation2.actions.wifi_router;
|
||||
|
||||
/*
|
||||
Class taken from here:
|
||||
https://github.com/aegis1980/WifiHotSpot
|
||||
*/
|
||||
|
||||
public abstract class MyOnStartTetheringCallback
|
||||
{
|
||||
/**
|
||||
* Called when tethering has been successfully started.
|
||||
*/
|
||||
public abstract void onTetheringStarted();
|
||||
|
||||
/**
|
||||
* Called when starting tethering failed.
|
||||
*/
|
||||
public abstract void onTetheringFailed();
|
||||
}
|
@ -0,0 +1,205 @@
|
||||
package com.jens.automation2.actions.wifi_router;
|
||||
|
||||
/*
|
||||
Class taken from here:
|
||||
https://github.com/aegis1980/WifiHotSpot
|
||||
*/
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.wifi.WifiConfiguration;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import com.android.dx.stock.ProxyBuilder;
|
||||
import com.jens.automation2.Miscellaneous;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Created by jonro on 19/03/2018.
|
||||
*/
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
public class MyOreoWifiManager
|
||||
{
|
||||
private static final String TAG = MyOreoWifiManager.class.getSimpleName();
|
||||
|
||||
private Context mContext;
|
||||
private WifiManager mWifiManager;
|
||||
private ConnectivityManager mConnectivityManager;
|
||||
|
||||
public MyOreoWifiManager(Context c)
|
||||
{
|
||||
mContext = c;
|
||||
mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
|
||||
mConnectivityManager = (ConnectivityManager) mContext.getSystemService(ConnectivityManager.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* This sets the Wifi SSID and password
|
||||
* Call this before {@code startTethering} if app is a system/privileged app
|
||||
* Requires: android.permission.TETHER_PRIVILEGED which is only granted to system apps
|
||||
*/
|
||||
public void configureHotspot(String name, String password)
|
||||
{
|
||||
WifiConfiguration apConfig = new WifiConfiguration();
|
||||
apConfig.SSID = name;
|
||||
apConfig.preSharedKey = password;
|
||||
apConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
|
||||
try
|
||||
{
|
||||
Method setConfigMethod = mWifiManager.getClass().getMethod("setWifiApConfiguration", WifiConfiguration.class);
|
||||
boolean status = (boolean) setConfigMethod.invoke(mWifiManager, apConfig);
|
||||
Miscellaneous.logEvent("i", "configureHotspot()", "setWifiApConfiguration - success? " + status, 2);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Miscellaneous.logEvent("e", "configureHotspot()", "Error in configureHotspot: " + Log.getStackTraceString(e), 2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks where tethering is on.
|
||||
* This is determined by the getTetheredIfaces() method,
|
||||
* that will return an empty array if not devices are tethered
|
||||
*
|
||||
* @return true if a tethered device is found, false if not found
|
||||
*/
|
||||
public boolean isTetherActive()
|
||||
{
|
||||
try
|
||||
{
|
||||
Method method = mConnectivityManager.getClass().getDeclaredMethod("getTetheredIfaces");
|
||||
if (method == null)
|
||||
{
|
||||
Miscellaneous.logEvent("i", "getTetheredIfaces()", "getTetheredIfaces is null", 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
String res[] = (String []) method.invoke(mConnectivityManager, null);
|
||||
Miscellaneous.logEvent("i", "isTetherActive()", "getTetheredIfaces invoked", 5);
|
||||
Miscellaneous.logEvent("i", "isTetherActive()", Arrays.toString(res), 4);
|
||||
|
||||
if (res.length > 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Miscellaneous.logEvent("e", "isTetherActive()", "Error in getTetheredIfaces: " + Log.getStackTraceString(e), 2);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This enables tethering using the ssid/password defined in Settings App>Hotspot & tethering
|
||||
* Does not require app to have system/privileged access
|
||||
* Credit: Vishal Sharma - https://stackoverflow.com/a/52219887
|
||||
*/
|
||||
public boolean startTethering(final MyOnStartTetheringCallback callback)
|
||||
{
|
||||
// On Pie if we try to start tethering while it is already on, it will
|
||||
// be disabled. This is needed when startTethering() is called programmatically.
|
||||
if (isTetherActive())
|
||||
{
|
||||
Miscellaneous.logEvent("i", "startTethering()", "Tether already active, returning", 2);
|
||||
return false;
|
||||
}
|
||||
|
||||
File outputDir = mContext.getCodeCacheDir();
|
||||
Object proxy;
|
||||
try
|
||||
{
|
||||
proxy = ProxyBuilder.forClass(OnStartTetheringCallbackClass())
|
||||
.dexCache(outputDir).handler(new InvocationHandler()
|
||||
{
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
|
||||
{
|
||||
switch (method.getName())
|
||||
{
|
||||
case "onTetheringStarted":
|
||||
callback.onTetheringStarted();
|
||||
break;
|
||||
case "onTetheringFailed":
|
||||
callback.onTetheringFailed();
|
||||
break;
|
||||
default:
|
||||
ProxyBuilder.callSuper(proxy, method, args);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}).build();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Miscellaneous.logEvent("e", "startTethering()", "Error in enableTethering ProxyBuilder", 2);
|
||||
return false;
|
||||
}
|
||||
|
||||
Method method = null;
|
||||
try
|
||||
{
|
||||
method = mConnectivityManager.getClass().getDeclaredMethod("startTethering", int.class, boolean.class, OnStartTetheringCallbackClass(), Handler.class);
|
||||
if (method == null)
|
||||
{
|
||||
Miscellaneous.logEvent("w", "startTethering()", "startTetheringMethod is null", 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
method.invoke(mConnectivityManager, ConnectivityManager.TYPE_MOBILE, false, proxy, null);
|
||||
Miscellaneous.logEvent("i", "startTethering()", "startTethering invoked", 5);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Miscellaneous.logEvent("w", "startTethering()", "Error in enableTethering: " + Log.getStackTraceString(e), 2);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void stopTethering()
|
||||
{
|
||||
try
|
||||
{
|
||||
Method method = mConnectivityManager.getClass().getDeclaredMethod("stopTethering", int.class);
|
||||
if (method == null)
|
||||
{
|
||||
Miscellaneous.logEvent("w", "stopTethering", "stopTetheringMethod is null", 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
method.invoke(mConnectivityManager, ConnectivityManager.TYPE_MOBILE);
|
||||
Miscellaneous.logEvent("i", "stopTethering", "stopTethering invoked", 5);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Miscellaneous.logEvent("e", "stopTethering", "stopTethering error: " + Log.getStackTraceString(e), 1);
|
||||
}
|
||||
}
|
||||
|
||||
private Class OnStartTetheringCallbackClass()
|
||||
{
|
||||
try
|
||||
{
|
||||
return Class.forName("android.net.ConnectivityManager$OnStartTetheringCallback");
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
Miscellaneous.logEvent("e", "OnStartTetheringCallbackClass()", "OnStartTetheringCallbackClass error: " + Log.getStackTraceString(e), 1);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -144,8 +144,33 @@ public class LocationProvider
|
||||
}
|
||||
else
|
||||
{
|
||||
speedCalculation:
|
||||
if (locationList.size() >= 2)
|
||||
{
|
||||
while (locationList.size() > 2)
|
||||
{
|
||||
// Remove all entries except for the last 2
|
||||
Miscellaneous.logEvent("i", "Speed", "About to delete oldest position record until only 2 left. Currently have " + String.valueOf(locationList.size()) + " records.", 4);
|
||||
locationList.remove(0);
|
||||
}
|
||||
|
||||
/*
|
||||
The two most recent locations in the list must have a usable accuracy.
|
||||
*/
|
||||
for(int i = 0; i < 2; i++)
|
||||
{
|
||||
if
|
||||
(
|
||||
(locationList.get(i).getProvider().equals(LocationManager.GPS_PROVIDER) && locationList.get(i).getAccuracy() > Settings.satisfactoryAccuracyGps)
|
||||
||
|
||||
(locationList.get(i).getProvider().equals(LocationManager.NETWORK_PROVIDER) && locationList.get(i).getAccuracy() > Settings.satisfactoryAccuracyNetwork)
|
||||
)
|
||||
{
|
||||
Miscellaneous.logEvent("i", "Speed", "Not using 2 most recent locations for speed calculation because at least one does not have a satisfactory accuracy: " + locationList.get(i).toString(), 4);
|
||||
break speedCalculation;
|
||||
}
|
||||
}
|
||||
|
||||
Miscellaneous.logEvent("i", "Speed", "Trying to calculate speed based on the last locations.", 4);
|
||||
|
||||
double currentSpeed;
|
||||
@ -184,14 +209,6 @@ public class LocationProvider
|
||||
}
|
||||
else
|
||||
Miscellaneous.logEvent("i", "Speed", "Last two locations are too far apart in terms of time. Cannot use them for speed calculation.", 4);
|
||||
|
||||
|
||||
while (locationList.size() > 2)
|
||||
{
|
||||
// Remove all entries except for the last 2
|
||||
Miscellaneous.logEvent("i", "Speed", "About to delete oldest position record until only 2 left. Currently have " + String.valueOf(locationList.size()) + " records.", 4);
|
||||
locationList.remove(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -489,18 +506,10 @@ public class LocationProvider
|
||||
{
|
||||
// time is up, no cell location updates since x minutes, start accelerometer
|
||||
String text = "Timer triggered. Based on the last location and speed we may be at a POI. Forcing location update in case CellLocationChangedReceiver didn\'t fire.";
|
||||
// Miscellaneous.logEvent("i", "AccelerometerHandler", text, 5);
|
||||
// CellLocationChangedReceiver.stopCellLocationChangedReceiver();
|
||||
// startAccelerometerReceiver();
|
||||
|
||||
Location currentLocation = CellLocationChangedReceiver.getInstance().getLocation("coarse");
|
||||
AutomationService.getInstance().getLocationProvider().setCurrentLocation(currentLocation, false);
|
||||
}
|
||||
/*else if(msg.what == 0)
|
||||
{
|
||||
String text = "Abort command received, deactivating SpeedReceiver";
|
||||
Miscellaneous.logEvent("i", "SpeedHandler", text, 4);
|
||||
stopAccelerometerReceiver();
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
@ -10,6 +10,7 @@ import android.net.NetworkInfo;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.util.Log;
|
||||
|
||||
import com.jens.automation2.AutomationService;
|
||||
import com.jens.automation2.Miscellaneous;
|
||||
import com.jens.automation2.PointOfInterest;
|
||||
import com.jens.automation2.R;
|
||||
@ -28,9 +29,7 @@ public class WifiBroadcastReceiver extends BroadcastReceiver
|
||||
protected static WifiBroadcastReceiver wifiBrInstance;
|
||||
protected static IntentFilter wifiListenerIntentFilter;
|
||||
protected static boolean wifiListenerActive=false;
|
||||
|
||||
|
||||
|
||||
|
||||
public static String getLastWifiSsid()
|
||||
{
|
||||
return lastWifiSsid;
|
||||
@ -103,7 +102,7 @@ public class WifiBroadcastReceiver extends BroadcastReceiver
|
||||
Miscellaneous.logEvent("i", "WifiReceiver", context.getResources().getString(R.string.poiHasNoWifiNotStoppingCellLocationListener), 2);
|
||||
}
|
||||
|
||||
findRules(parentLocationProvider);
|
||||
findRules(AutomationService.getInstance());
|
||||
}
|
||||
else if(myWifi.isConnectedOrConnecting()) // first time connect from wifi-listener-perspective
|
||||
{
|
||||
@ -115,7 +114,7 @@ public class WifiBroadcastReceiver extends BroadcastReceiver
|
||||
String ssid = myWifiManager.getConnectionInfo().getSSID();
|
||||
setLastWifiSsid(ssid);
|
||||
lastConnectedState = true;
|
||||
findRules(parentLocationProvider);
|
||||
findRules(AutomationService.getInstance());
|
||||
}
|
||||
else if(!myWifi.isConnectedOrConnecting()) // really disconnected? because sometimes also fires on connect
|
||||
{
|
||||
@ -128,7 +127,7 @@ public class WifiBroadcastReceiver extends BroadcastReceiver
|
||||
mayCellLocationChangedReceiverBeActivatedFromWifiPointOfWifi = true;
|
||||
CellLocationChangedReceiver.startCellLocationChangedReceiver();
|
||||
lastConnectedState = false;
|
||||
findRules(parentLocationProvider);
|
||||
findRules(AutomationService.getInstance());
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
@ -143,13 +142,13 @@ public class WifiBroadcastReceiver extends BroadcastReceiver
|
||||
}
|
||||
}
|
||||
|
||||
public static void findRules(LocationProvider parentLocationProvider)
|
||||
public static void findRules(AutomationService automationServiceInstance)
|
||||
{
|
||||
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByWifiConnection();
|
||||
for(Rule oneRule : ruleCandidates)
|
||||
{
|
||||
if(oneRule.applies(parentLocationProvider.parentService))
|
||||
oneRule.activate(parentLocationProvider.parentService, false);
|
||||
if(oneRule.applies(automationServiceInstance))
|
||||
oneRule.activate(automationServiceInstance, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -161,7 +161,7 @@ public class ConnectivityReceiver extends BroadcastReceiver implements Automatio
|
||||
WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
|
||||
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
|
||||
WifiBroadcastReceiver.setLastWifiSsid(wifiInfo.getSSID());
|
||||
WifiBroadcastReceiver.findRules(automationServiceRef.getLocationProvider());
|
||||
WifiBroadcastReceiver.findRules(automationServiceRef);
|
||||
break;
|
||||
case ConnectivityManager.TYPE_MOBILE:
|
||||
boolean isRoaming = isRoaming(context);
|
||||
@ -219,7 +219,7 @@ public class ConnectivityReceiver extends BroadcastReceiver implements Automatio
|
||||
// This will serve as a disconnected event. Happens if wifi is connected, then module deactivated.
|
||||
Miscellaneous.logEvent("i", "Connectivity", "Wifi deactivated while having been connected before.", 4);
|
||||
WifiBroadcastReceiver.lastConnectedState = false;
|
||||
WifiBroadcastReceiver.findRules(automationServiceRef.getLocationProvider());
|
||||
WifiBroadcastReceiver.findRules(automationServiceRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
package com.jens.automation2.receivers;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Service;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@ -13,16 +15,18 @@ import com.jens.automation2.AutomationService;
|
||||
import com.jens.automation2.Miscellaneous;
|
||||
import com.jens.automation2.R;
|
||||
import com.jens.automation2.Rule;
|
||||
import com.jens.automation2.Trigger;
|
||||
import com.jens.automation2.Trigger.Trigger_Enum;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class PhoneStatusListener implements AutomationListenerInterface
|
||||
{
|
||||
protected static int currentStateIncoming = -1;
|
||||
protected static int currentStateOutgoing = -1;
|
||||
// protected static int currentStateIncoming = -1;
|
||||
// protected static int currentStateOutgoing = -1;
|
||||
protected static String lastPhoneNumber="";
|
||||
protected static int lastPhoneDirection = -1; //0=incoming, 1=outgoing
|
||||
protected static int currentState = -1;
|
||||
|
||||
protected static boolean incomingCallsReceiverActive = false;
|
||||
protected static boolean outgoingCallsReceiverActive = false;
|
||||
@ -31,7 +35,6 @@ public class PhoneStatusListener implements AutomationListenerInterface
|
||||
protected static IncomingCallsReceiver incomingCallsReceiverInstance;
|
||||
protected static BroadcastReceiver outgoingCallsReceiverInstance;
|
||||
|
||||
|
||||
public static boolean isIncomingCallsReceiverActive()
|
||||
{
|
||||
return incomingCallsReceiverActive;
|
||||
@ -58,7 +61,17 @@ public class PhoneStatusListener implements AutomationListenerInterface
|
||||
{
|
||||
return lastPhoneNumber;
|
||||
}
|
||||
|
||||
|
||||
public static void setCurrentState(int currentState)
|
||||
{
|
||||
PhoneStatusListener.currentState = currentState;
|
||||
}
|
||||
|
||||
public static int getCurrentState()
|
||||
{
|
||||
return currentState;
|
||||
}
|
||||
|
||||
public static class IncomingCallsReceiver extends PhoneStateListener
|
||||
{
|
||||
@Override
|
||||
@ -66,174 +79,126 @@ public class PhoneStatusListener implements AutomationListenerInterface
|
||||
{
|
||||
// Miscellaneous.logEvent("i", "Call state", "New call state: " + String.valueOf(state), 4);
|
||||
|
||||
if(incomingNumber != null && incomingNumber.length() > 0) // check for null in case call comes in with suppressed number.
|
||||
setLastPhoneNumber(incomingNumber);
|
||||
|
||||
switch(state)
|
||||
/*
|
||||
Unfortunately receivers for incoming and outgoing calls behave pretty differently:
|
||||
|
||||
The Outgoing-Receiver is called when starting a call (ringing)
|
||||
It is not called when that outgoing call ends however, only the incoming receiver.
|
||||
|
||||
If the last call was outgoing the state has not changed to idle this is kind of a fake alert.
|
||||
*/
|
||||
|
||||
if(lastPhoneDirection == 2 && currentState != TelephonyManager.CALL_STATE_IDLE)
|
||||
{
|
||||
case TelephonyManager.CALL_STATE_IDLE:
|
||||
Miscellaneous.logEvent("i", "Call state", "New call state: CALL_STATE_IDLE", 4);
|
||||
if(currentStateIncoming == TelephonyManager.CALL_STATE_OFFHOOK)
|
||||
setCurrentStateIncoming(state);
|
||||
else if(currentStateOutgoing == TelephonyManager.CALL_STATE_OFFHOOK)
|
||||
setCurrentStateOutgoing(state);
|
||||
else
|
||||
currentStateIncoming = state;
|
||||
currentStateOutgoing = state;
|
||||
break;
|
||||
case TelephonyManager.CALL_STATE_OFFHOOK:
|
||||
Miscellaneous.logEvent("i", "Call state", "New call state: CALL_STATE_OFFHOOK", 4);
|
||||
if(currentStateIncoming == TelephonyManager.CALL_STATE_RINGING)
|
||||
setCurrentStateIncoming(state);
|
||||
else if(currentStateOutgoing == TelephonyManager.CALL_STATE_RINGING)
|
||||
setCurrentStateOutgoing(state);
|
||||
break;
|
||||
case TelephonyManager.CALL_STATE_RINGING:
|
||||
String number = "unknown";
|
||||
if(incomingNumber != null && incomingNumber.length() > 0)
|
||||
number = incomingNumber;
|
||||
Miscellaneous.logEvent("i", "Call state", String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.incomingCallFrom), number), 4);
|
||||
|
||||
setCurrentStateIncoming(state);
|
||||
break;
|
||||
// This status update is actually for an outgoing call
|
||||
setCurrentState(state);
|
||||
|
||||
if(incomingNumber != null && incomingNumber.length() > 0) // check for null in case call comes in with suppressed number.
|
||||
setLastPhoneNumber(incomingNumber);
|
||||
|
||||
switch(state)
|
||||
{
|
||||
case TelephonyManager.CALL_STATE_IDLE:
|
||||
Miscellaneous.logEvent("i", "Call state", "New call state: CALL_STATE_IDLE", 4);
|
||||
break;
|
||||
case TelephonyManager.CALL_STATE_OFFHOOK:
|
||||
Miscellaneous.logEvent("i", "Call state", "New call state: CALL_STATE_OFFHOOK", 4);
|
||||
break;
|
||||
case TelephonyManager.CALL_STATE_RINGING:
|
||||
Miscellaneous.logEvent("i", "Call state", String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.outgoingCallTo), incomingNumber), 4);
|
||||
break;
|
||||
}
|
||||
|
||||
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByPhoneCall(Trigger.triggerPhoneCallDirectionOutgoing);
|
||||
for(int i=0; i<ruleCandidates.size(); i++)
|
||||
{
|
||||
AutomationService asInstance = AutomationService.getInstance();
|
||||
if(asInstance != null)
|
||||
if(ruleCandidates.get(i).applies(asInstance))
|
||||
ruleCandidates.get(i).activate(asInstance, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// state != TelephonyManager.CALL_STATE_IDLE &&
|
||||
|
||||
setCurrentState(state);
|
||||
setLastPhoneDirection(1);
|
||||
|
||||
if (incomingNumber != null && incomingNumber.length() > 0) // check for null in case call comes in with suppressed number.
|
||||
setLastPhoneNumber(incomingNumber);
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case TelephonyManager.CALL_STATE_IDLE:
|
||||
Miscellaneous.logEvent("i", "Call state", "New call state: CALL_STATE_IDLE", 4);
|
||||
break;
|
||||
case TelephonyManager.CALL_STATE_OFFHOOK:
|
||||
Miscellaneous.logEvent("i", "Call state", "New call state: CALL_STATE_OFFHOOK", 4);
|
||||
break;
|
||||
case TelephonyManager.CALL_STATE_RINGING:
|
||||
Miscellaneous.logEvent("i", "Call state", String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.incomingCallFrom), incomingNumber), 4);
|
||||
break;
|
||||
}
|
||||
|
||||
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByPhoneCall(Trigger.triggerPhoneCallDirectionIncoming);
|
||||
for (int i = 0; i < ruleCandidates.size(); i++)
|
||||
{
|
||||
AutomationService asInstance = AutomationService.getInstance();
|
||||
if (asInstance != null)
|
||||
if (ruleCandidates.get(i).applies(asInstance))
|
||||
ruleCandidates.get(i).activate(asInstance, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void setLastPhoneDirection(int i)
|
||||
{
|
||||
lastPhoneDirection = i;
|
||||
}
|
||||
|
||||
public static class OutgoingCallsReceiver extends BroadcastReceiver
|
||||
{
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent)
|
||||
{
|
||||
setCurrentStateOutgoing(2);
|
||||
setLastPhoneNumber(intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER));
|
||||
Miscellaneous.logEvent("i", "Call state", String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.outgoingCallFrom), getLastPhoneNumber()), 4);
|
||||
/*
|
||||
This receiver is ONLY triggered when outgoing calls ring, not when that call is established or ends.
|
||||
*/
|
||||
setLastPhoneDirection(2);
|
||||
|
||||
// TelephonyManager tm = (TelephonyManager)context.getSystemService(Service.TELEPHONY_SERVICE);
|
||||
// int newState = tm.getCallState();
|
||||
// setCurrentState(newState);
|
||||
|
||||
setCurrentState(TelephonyManager.CALL_STATE_RINGING);
|
||||
|
||||
String phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
|
||||
setLastPhoneNumber(phoneNumber);
|
||||
Miscellaneous.logEvent("i", "Call state", String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.outgoingCallTo), getLastPhoneNumber()), 4);
|
||||
|
||||
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByPhoneCall(Trigger.triggerPhoneCallDirectionOutgoing);
|
||||
for(int i=0; i<ruleCandidates.size(); i++)
|
||||
{
|
||||
AutomationService asInstance = AutomationService.getInstance();
|
||||
if(asInstance != null)
|
||||
if(ruleCandidates.get(i).applies(asInstance))
|
||||
ruleCandidates.get(i).activate(asInstance, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isInACall()
|
||||
{
|
||||
if(isInIncomingCall() | isInOutgoingCall())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isInIncomingCall()
|
||||
{
|
||||
// Miscellaneous.logEvent("i", "Incoming call state", String.valueOf(currentStateIncoming), 5);
|
||||
switch(currentStateIncoming)
|
||||
{
|
||||
// case -1:
|
||||
// return false;
|
||||
// case 0:
|
||||
// return false;
|
||||
// case 1:
|
||||
// return true;
|
||||
case 2:
|
||||
return true;
|
||||
// case 3:
|
||||
// return true;
|
||||
// case 4:
|
||||
// return true;
|
||||
// default:
|
||||
// return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isInOutgoingCall()
|
||||
{
|
||||
// Miscellaneous.logEvent("i", "Outgoing call state", String.valueOf(currentStateOutgoing), 5);
|
||||
switch(currentStateOutgoing)
|
||||
{
|
||||
// case -1:
|
||||
// return false;
|
||||
// case 0:
|
||||
// return false;
|
||||
// case 1:
|
||||
// return true;
|
||||
case 2:
|
||||
return true;
|
||||
// case 3:
|
||||
// return true;
|
||||
// case 4:
|
||||
// return true;
|
||||
// default:
|
||||
// return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void setCurrentStateIncoming(int state)
|
||||
{
|
||||
// Miscellaneous.logEvent("i", "Call state", "New incoming call state: " + String.valueOf(state), 4);
|
||||
if(currentStateIncoming != state)
|
||||
{
|
||||
if(lastPhoneDirection != 1)
|
||||
lastPhoneDirection = 1;
|
||||
|
||||
if(
|
||||
(state == 0 && currentStateIncoming == 2)
|
||||
|
|
||||
(state == 2 && (currentStateIncoming == 0 | currentStateIncoming == 1))
|
||||
)
|
||||
{
|
||||
currentStateIncoming = state;
|
||||
|
||||
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByPhoneCall(isInIncomingCall());
|
||||
for(int i=0; i<ruleCandidates.size(); i++)
|
||||
{
|
||||
AutomationService asInstance = AutomationService.getInstance();
|
||||
if(asInstance != null)
|
||||
if(ruleCandidates.get(i).applies(asInstance))
|
||||
ruleCandidates.get(i).activate(asInstance, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
currentStateIncoming = state;
|
||||
}
|
||||
}
|
||||
public static int getCurrentStateIncoming()
|
||||
{
|
||||
return currentStateIncoming;
|
||||
return getCurrentState() != TelephonyManager.CALL_STATE_IDLE;
|
||||
}
|
||||
|
||||
public static void setCurrentStateOutgoing(int state)
|
||||
{
|
||||
if(currentStateOutgoing != state)
|
||||
{
|
||||
if(lastPhoneDirection != 2)
|
||||
lastPhoneDirection = 2;
|
||||
|
||||
if(
|
||||
(state == 0 && currentStateOutgoing == 2)
|
||||
|
|
||||
(state == 2 && (currentStateOutgoing == 0 | currentStateOutgoing == 1)))
|
||||
{
|
||||
PhoneStatusListener.currentStateOutgoing = state;
|
||||
|
||||
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByPhoneCall(isInOutgoingCall());
|
||||
for(int i=0; i<ruleCandidates.size(); i++)
|
||||
{
|
||||
AutomationService asInstance = AutomationService.getInstance();
|
||||
if(asInstance != null)
|
||||
if(ruleCandidates.get(i).applies(asInstance))
|
||||
ruleCandidates.get(i).activate(asInstance, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
PhoneStatusListener.currentStateOutgoing = state;
|
||||
}
|
||||
}
|
||||
public static int getCurrentStateOutgoing()
|
||||
{
|
||||
return currentStateOutgoing;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Future remark:
|
||||
Apps that redirect outgoing calls should use the android.telecom.CallRedirectionService API.
|
||||
Apps that perform call screening should use the android.telecom.CallScreeningService API.
|
||||
*/
|
||||
|
||||
public static void startPhoneStatusListener(AutomationService automationService)
|
||||
{
|
||||
@ -312,9 +277,9 @@ public class PhoneStatusListener implements AutomationListenerInterface
|
||||
public static boolean haveAllPermission()
|
||||
{
|
||||
return
|
||||
ActivityPermissions.havePermission("android.permission.READ_PHONE_STATE", Miscellaneous.getAnyContext())
|
||||
ActivityPermissions.havePermission(Manifest.permission.READ_PHONE_STATE, Miscellaneous.getAnyContext())
|
||||
&&
|
||||
ActivityPermissions.havePermission(ActivityPermissions.permissionNameCall, Miscellaneous.getAnyContext());
|
||||
ActivityPermissions.havePermission(Manifest.permission.PROCESS_OUTGOING_CALLS, Miscellaneous.getAnyContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2014 Jorrit "Chainfire" Jongma
|
||||
* Copyright (C) 2012-2019 Jorrit "Chainfire" Jongma
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -20,18 +20,24 @@ import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.AnyThread;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Base application class to extend from, solving some issues with
|
||||
* toasts and AsyncTasks you are likely to run into
|
||||
*/
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public class Application extends android.app.Application {
|
||||
/**
|
||||
* Shows a toast message
|
||||
*
|
||||
*
|
||||
* @param context Any context belonging to this application
|
||||
* @param message The message to show
|
||||
*/
|
||||
public static void toast(Context context, String message) {
|
||||
@AnyThread
|
||||
public static void toast(@Nullable Context context, @NonNull String message) {
|
||||
// this is a static method so it is easier to call,
|
||||
// as the context checking and casting is done for you
|
||||
|
||||
@ -45,7 +51,7 @@ public class Application extends android.app.Application {
|
||||
final Context c = context;
|
||||
final String m = message;
|
||||
|
||||
((Application)context).runInApplicationThread(new Runnable() {
|
||||
((Application) context).runInApplicationThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Toast.makeText(c, m, Toast.LENGTH_LONG).show();
|
||||
@ -54,14 +60,15 @@ public class Application extends android.app.Application {
|
||||
}
|
||||
}
|
||||
|
||||
private static Handler mApplicationHandler = new Handler();
|
||||
private static final Handler mApplicationHandler = new Handler();
|
||||
|
||||
/**
|
||||
* Run a runnable in the main application thread
|
||||
*
|
||||
*
|
||||
* @param r Runnable to run
|
||||
*/
|
||||
public void runInApplicationThread(Runnable r) {
|
||||
@AnyThread
|
||||
public void runInApplicationThread(@NonNull Runnable r) {
|
||||
mApplicationHandler.post(r);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2014 Jorrit "Chainfire" Jongma
|
||||
* Copyright (C) 2012-2019 Jorrit "Chainfire" Jongma
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -18,12 +18,19 @@ package eu.chainfire.libsuperuser;
|
||||
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
import android.os.Process;
|
||||
|
||||
import androidx.annotation.AnyThread;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.jens.automation2.BuildConfig;
|
||||
|
||||
/**
|
||||
* Utility class for logging and debug features that (by default) does nothing when not in debug mode
|
||||
*/
|
||||
@SuppressWarnings({"WeakerAccess", "UnusedReturnValue", "unused"})
|
||||
@AnyThread
|
||||
public class Debug {
|
||||
|
||||
// ----- DEBUGGING -----
|
||||
@ -32,23 +39,23 @@ public class Debug {
|
||||
|
||||
/**
|
||||
* <p>Enable or disable debug mode</p>
|
||||
*
|
||||
*
|
||||
* <p>By default, debug mode is enabled for development
|
||||
* builds and disabled for exported APKs - see
|
||||
* BuildConfig.DEBUG</p>
|
||||
*
|
||||
*
|
||||
* @param enable Enable debug mode ?
|
||||
*/
|
||||
public static void setDebug(boolean enable) {
|
||||
debug = enable;
|
||||
*/
|
||||
public static void setDebug(boolean enable) {
|
||||
debug = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Is debug mode enabled ?</p>
|
||||
*
|
||||
*
|
||||
* @return Debug mode enabled
|
||||
*/
|
||||
public static boolean getDebug() {
|
||||
public static boolean getDebug() {
|
||||
return debug;
|
||||
}
|
||||
|
||||
@ -63,25 +70,27 @@ public class Debug {
|
||||
public static final int LOG_GENERAL = 0x0001;
|
||||
public static final int LOG_COMMAND = 0x0002;
|
||||
public static final int LOG_OUTPUT = 0x0004;
|
||||
public static final int LOG_POOL = 0x0008;
|
||||
|
||||
public static final int LOG_NONE = 0x0000;
|
||||
public static final int LOG_ALL = 0xFFFF;
|
||||
|
||||
private static int logTypes = LOG_ALL;
|
||||
|
||||
@Nullable
|
||||
private static OnLogListener logListener = null;
|
||||
|
||||
/**
|
||||
* <p>Log a message (internal)</p>
|
||||
*
|
||||
* <p>Current debug and enabled logtypes decide what gets logged -
|
||||
* even if a custom callback is registered</p>
|
||||
*
|
||||
* @param type Type of message to log
|
||||
*
|
||||
* <p>Current debug and enabled logtypes decide what gets logged -
|
||||
* even if a custom callback is registered</p>
|
||||
*
|
||||
* @param type Type of message to log
|
||||
* @param typeIndicator String indicator for message type
|
||||
* @param message The message to log
|
||||
* @param message The message to log
|
||||
*/
|
||||
private static void logCommon(int type, String typeIndicator, String message) {
|
||||
private static void logCommon(int type, @NonNull String typeIndicator, @NonNull String message) {
|
||||
if (debug && ((logTypes & type) == type)) {
|
||||
if (logListener != null) {
|
||||
logListener.onLog(type, typeIndicator, message);
|
||||
@ -89,52 +98,61 @@ public class Debug {
|
||||
Log.d(TAG, "[" + TAG + "][" + typeIndicator + "]" + (!message.startsWith("[") && !message.startsWith(" ") ? " " : "") + message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Log a "general" message</p>
|
||||
*
|
||||
*
|
||||
* <p>These messages are infrequent and mostly occur at startup/shutdown or on error</p>
|
||||
*
|
||||
*
|
||||
* @param message The message to log
|
||||
*/
|
||||
public static void log(String message) {
|
||||
public static void log(@NonNull String message) {
|
||||
logCommon(LOG_GENERAL, "G", message);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Log a "per-command" message</p>
|
||||
*
|
||||
*
|
||||
* <p>This could produce a lot of output if the client runs many commands in the session</p>
|
||||
*
|
||||
*
|
||||
* @param message The message to log
|
||||
*/
|
||||
public static void logCommand(String message) {
|
||||
public static void logCommand(@NonNull String message) {
|
||||
logCommon(LOG_COMMAND, "C", message);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Log a line of stdout/stderr output</p>
|
||||
*
|
||||
*
|
||||
* <p>This could produce a lot of output if the shell commands are noisy</p>
|
||||
*
|
||||
*
|
||||
* @param message The message to log
|
||||
*/
|
||||
public static void logOutput(String message) {
|
||||
public static void logOutput(@NonNull String message) {
|
||||
logCommon(LOG_OUTPUT, "O", message);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Log pool event</p>
|
||||
*
|
||||
* @param message The message to log
|
||||
*/
|
||||
public static void logPool(@NonNull String message) {
|
||||
logCommon(LOG_POOL, "P", message);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Enable or disable logging specific types of message</p>
|
||||
*
|
||||
*
|
||||
* <p>You may | (or) LOG_* constants together. Note that
|
||||
* debug mode must also be enabled for actual logging to
|
||||
* occur.</p>
|
||||
*
|
||||
* @param type LOG_* constants
|
||||
*
|
||||
* @param type LOG_* constants
|
||||
* @param enable Enable or disable
|
||||
*/
|
||||
public static void setLogTypeEnabled(int type, boolean enable) {
|
||||
public static void setLogTypeEnabled(int type, boolean enable) {
|
||||
if (enable) {
|
||||
logTypes |= type;
|
||||
} else {
|
||||
@ -144,26 +162,28 @@ public class Debug {
|
||||
|
||||
/**
|
||||
* <p>Is logging for specific types of messages enabled ?</p>
|
||||
*
|
||||
*
|
||||
* <p>You may | (or) LOG_* constants together, to learn if
|
||||
* <b>all</b> passed message types are enabled for logging. Note
|
||||
* that debug mode must also be enabled for actual logging
|
||||
* to occur.</p>
|
||||
*
|
||||
*
|
||||
* @param type LOG_* constants
|
||||
* @return enabled?
|
||||
*/
|
||||
public static boolean getLogTypeEnabled(int type) {
|
||||
return ((logTypes & type) == type);
|
||||
public static boolean getLogTypeEnabled(int type) {
|
||||
return ((logTypes & type) == type);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Is logging for specific types of messages enabled ?</p>
|
||||
*
|
||||
*
|
||||
* <p>You may | (or) LOG_* constants together, to learn if
|
||||
* <b>all</b> message types are enabled for logging. Takes
|
||||
* debug mode into account for the result.</p>
|
||||
*
|
||||
*
|
||||
* @param type LOG_* constants
|
||||
* @return enabled and in debug mode?
|
||||
*/
|
||||
public static boolean getLogTypeEnabledEffective(int type) {
|
||||
return getDebug() && getLogTypeEnabled(type);
|
||||
@ -171,22 +191,23 @@ public class Debug {
|
||||
|
||||
/**
|
||||
* <p>Register a custom log handler</p>
|
||||
*
|
||||
*
|
||||
* <p>Replaces the log method (write to logcat) with your own
|
||||
* handler. Whether your handler gets called is still dependent
|
||||
* on debug mode and message types being enabled for logging.</p>
|
||||
*
|
||||
*
|
||||
* @param onLogListener Custom log listener or NULL to revert to default
|
||||
*/
|
||||
public static void setOnLogListener(OnLogListener onLogListener) {
|
||||
public static void setOnLogListener(@Nullable OnLogListener onLogListener) {
|
||||
logListener = onLogListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Get the currently registered custom log handler</p>
|
||||
*
|
||||
* @return Current custom log handler or NULL if none is present
|
||||
*
|
||||
* @return Current custom log handler or NULL if none is present
|
||||
*/
|
||||
@Nullable
|
||||
public static OnLogListener getOnLogListener() {
|
||||
return logListener;
|
||||
}
|
||||
@ -197,10 +218,10 @@ public class Debug {
|
||||
|
||||
/**
|
||||
* <p>Enable or disable sanity checks</p>
|
||||
*
|
||||
* <p>Enables or disables the library crashing when su is called
|
||||
*
|
||||
* <p>Enables or disables the library crashing when su is called
|
||||
* from the main thread.</p>
|
||||
*
|
||||
*
|
||||
* @param enable Enable or disable
|
||||
*/
|
||||
public static void setSanityChecksEnabled(boolean enable) {
|
||||
@ -209,10 +230,10 @@ public class Debug {
|
||||
|
||||
/**
|
||||
* <p>Are sanity checks enabled ?</p>
|
||||
*
|
||||
*
|
||||
* <p>Note that debug mode must also be enabled for actual
|
||||
* sanity checks to occur.</p>
|
||||
*
|
||||
* sanity checks to occur.</p>
|
||||
*
|
||||
* @return True if enabled
|
||||
*/
|
||||
public static boolean getSanityChecksEnabled() {
|
||||
@ -221,9 +242,9 @@ public class Debug {
|
||||
|
||||
/**
|
||||
* <p>Are sanity checks enabled ?</p>
|
||||
*
|
||||
* <p>Takes debug mode into account for the result.</p>
|
||||
*
|
||||
*
|
||||
* <p>Takes debug mode into account for the result.</p>
|
||||
*
|
||||
* @return True if enabled
|
||||
*/
|
||||
public static boolean getSanityChecksEnabledEffective() {
|
||||
@ -232,11 +253,11 @@ public class Debug {
|
||||
|
||||
/**
|
||||
* <p>Are we running on the main thread ?</p>
|
||||
*
|
||||
*
|
||||
* @return Running on main thread ?
|
||||
*/
|
||||
*/
|
||||
public static boolean onMainThread() {
|
||||
return ((Looper.myLooper() != null) && (Looper.myLooper() == Looper.getMainLooper()));
|
||||
return ((Looper.myLooper() != null) && (Looper.myLooper() == Looper.getMainLooper()) && (Process.myUid() != 0));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2014 Jorrit "Chainfire" Jongma
|
||||
* Copyright (C) 2012-2019 Jorrit "Chainfire" Jongma
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -37,6 +37,7 @@ import android.content.Intent;
|
||||
* window possibly obscuring SuperSU dialogs".
|
||||
* </p>
|
||||
*/
|
||||
@SuppressWarnings({"unused"})
|
||||
public abstract class HideOverlaysReceiver extends BroadcastReceiver {
|
||||
public static final String ACTION_HIDE_OVERLAYS = "eu.chainfire.supersu.action.HIDE_OVERLAYS";
|
||||
public static final String CATEGORY_HIDE_OVERLAYS = Intent.CATEGORY_INFO;
|
||||
@ -45,15 +46,17 @@ public abstract class HideOverlaysReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public final void onReceive(Context context, Intent intent) {
|
||||
if (intent.hasExtra(EXTRA_HIDE_OVERLAYS)) {
|
||||
onHideOverlays(intent.getBooleanExtra(EXTRA_HIDE_OVERLAYS, false));
|
||||
onHideOverlays(context, intent, intent.getBooleanExtra(EXTRA_HIDE_OVERLAYS, false));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when overlays <em>should</em> be hidden or <em>may</em> be shown
|
||||
* again.
|
||||
*
|
||||
*
|
||||
* @param context App context
|
||||
* @param intent Received intent
|
||||
* @param hide Should overlays be hidden?
|
||||
*/
|
||||
public abstract void onHideOverlays(boolean hide);
|
||||
public abstract void onHideOverlays(Context context, Intent intent, boolean hide);
|
||||
}
|
||||
|
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2019 Jorrit "Chainfire" Jongma
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package eu.chainfire.libsuperuser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import androidx.annotation.AnyThread;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
@AnyThread
|
||||
public class MarkerInputStream extends InputStream {
|
||||
private static final String EXCEPTION_EOF = "EOF encountered, shell probably died";
|
||||
|
||||
@NonNull
|
||||
private final StreamGobbler gobbler;
|
||||
private final InputStream inputStream;
|
||||
private final byte[] marker;
|
||||
private final int markerLength;
|
||||
private final int markerMaxLength;
|
||||
private final byte[] read1 = new byte[1];
|
||||
private final byte[] buffer = new byte[65536];
|
||||
private int bufferUsed = 0;
|
||||
private volatile boolean eof = false;
|
||||
private volatile boolean done = false;
|
||||
|
||||
public MarkerInputStream(@NonNull StreamGobbler gobbler, @NonNull String marker) throws UnsupportedEncodingException {
|
||||
this.gobbler = gobbler;
|
||||
this.gobbler.suspendGobbling();
|
||||
this.inputStream = gobbler.getInputStream();
|
||||
this.marker = marker.getBytes("UTF-8");
|
||||
this.markerLength = marker.length();
|
||||
this.markerMaxLength = marker.length() + 5; // marker + space + exitCode(max(3)) + \n
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
while (true) {
|
||||
int r = read(read1, 0, 1);
|
||||
if (r < 0) return -1;
|
||||
if (r == 0) {
|
||||
// wait for data to become available
|
||||
try {
|
||||
Thread.sleep(16);
|
||||
} catch (InterruptedException e) {
|
||||
// no action
|
||||
}
|
||||
continue;
|
||||
}
|
||||
return (int)read1[0] & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(@NonNull byte[] b) throws IOException {
|
||||
return read(b, 0, b.length);
|
||||
}
|
||||
|
||||
private void fill(int safeSizeToWaitFor) {
|
||||
// fill up our own buffer
|
||||
if (isEOF()) return;
|
||||
try {
|
||||
int a;
|
||||
while (((a = inputStream.available()) > 0) || (safeSizeToWaitFor > 0)) {
|
||||
int left = buffer.length - bufferUsed;
|
||||
if (left == 0) return;
|
||||
int r = inputStream.read(buffer, bufferUsed, Math.max(safeSizeToWaitFor, Math.min(a, left)));
|
||||
if (r >= 0) {
|
||||
bufferUsed += r;
|
||||
safeSizeToWaitFor -= r;
|
||||
} else {
|
||||
// This shouldn't happen *unless* we have both the full content and the end
|
||||
// marker, otherwise the shell was interrupted/died. An IOException is raised
|
||||
// in read() below if that is the case.
|
||||
setEOF();
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
setEOF();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int read(@NonNull byte[] b, int off, int len) throws IOException {
|
||||
if (done) return -1;
|
||||
|
||||
fill(markerLength - bufferUsed);
|
||||
|
||||
// we need our buffer to be big enough to detect the marker
|
||||
if (bufferUsed < markerLength) return 0;
|
||||
|
||||
// see if we have our marker
|
||||
int match = -1;
|
||||
for (int i = Math.max(0, bufferUsed - markerMaxLength); i < bufferUsed - markerLength; i++) {
|
||||
boolean found = true;
|
||||
for (int j = 0; j < markerLength; j++) {
|
||||
if (buffer[i + j] != marker[j]) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
match = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (match == 0) {
|
||||
// marker is at the front of the buffer
|
||||
while (buffer[bufferUsed -1] != (byte)'\n') {
|
||||
if (isEOF()) throw new IOException(EXCEPTION_EOF);
|
||||
fill(1);
|
||||
}
|
||||
if (gobbler.getOnLineListener() != null) gobbler.getOnLineListener().onLine(new String(buffer, 0, bufferUsed - 1, "UTF-8"));
|
||||
done = true;
|
||||
return -1;
|
||||
} else {
|
||||
int ret;
|
||||
if (match == -1) {
|
||||
if (isEOF()) throw new IOException(EXCEPTION_EOF);
|
||||
|
||||
// marker isn't in the buffer, drain as far as possible while keeping some space
|
||||
// leftover so we can still find the marker if its read is split between two fill()
|
||||
// calls
|
||||
ret = Math.min(len, bufferUsed - markerMaxLength);
|
||||
} else {
|
||||
// even if eof, it is possibly we have both the content and the end marker, which
|
||||
// counts as a completed command, so we don't throw IOException here
|
||||
|
||||
// marker found, max drain up to marker, this will eventually cause the marker to be
|
||||
// at the front of the buffer
|
||||
ret = Math.min(len, match);
|
||||
}
|
||||
if (ret > 0) {
|
||||
System.arraycopy(buffer, 0, b, off, ret);
|
||||
bufferUsed -= ret;
|
||||
System.arraycopy(buffer, ret, buffer, 0, bufferUsed);
|
||||
} else {
|
||||
try {
|
||||
// prevent 100% CPU on reading from for example /dev/random
|
||||
Thread.sleep(4);
|
||||
} catch (Exception e) {
|
||||
// no action
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("StatementWithEmptyBody")
|
||||
@Override
|
||||
public synchronized void close() throws IOException {
|
||||
if (!isEOF() && !done) {
|
||||
// drain
|
||||
byte[] buffer = new byte[1024];
|
||||
while (read(buffer) >= 0) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized boolean isEOF() {
|
||||
return eof;
|
||||
}
|
||||
|
||||
public synchronized void setEOF() {
|
||||
eof = true;
|
||||
}
|
||||
}
|
243
app/src/main/java/eu/chainfire/libsuperuser/Policy.java
Normal file
@ -0,0 +1,243 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2019 Jorrit "Chainfire" Jongma
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package eu.chainfire.libsuperuser;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.AnyThread;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
/**
|
||||
* Helper class for modifying SELinux policies, reducing the number of calls to a minimum.
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
*
|
||||
* private class Policy extends eu.chainfire.libsuperuser.Policy {
|
||||
* {@literal @}Override protected String[] getPolicies() {
|
||||
* return new String[] {
|
||||
* "allow sdcardd unlabeled dir { append create execute write relabelfrom link unlink ioctl getattr setattr read rename lock mounton quotaon swapon rmdir audit_access remove_name add_name reparent execmod search open }",
|
||||
* "allow sdcardd unlabeled file { append create write relabelfrom link unlink ioctl getattr setattr read rename lock mounton quotaon swapon audit_access open }",
|
||||
* "allow unlabeled unlabeled filesystem associate"
|
||||
* };
|
||||
* }
|
||||
* };
|
||||
* private Policy policy = new Policy();
|
||||
*
|
||||
* public void someFunctionNotCalledOnMainThread() {
|
||||
* policy.inject();
|
||||
* }
|
||||
*
|
||||
* </code>
|
||||
* </pre>
|
||||
*/
|
||||
@SuppressWarnings({"WeakerAccess", "UnusedReturnValue", "unused"})
|
||||
public abstract class Policy {
|
||||
/**
|
||||
* supolicy should be called as little as possible. We batch policies together. The command
|
||||
* line is guaranteed to be able to take 4096 characters. Reduce by a bit for supolicy itself.
|
||||
*/
|
||||
private static final int MAX_POLICY_LENGTH = 4096 - 32;
|
||||
|
||||
private static final Object synchronizer = new Object();
|
||||
@Nullable
|
||||
private static volatile Boolean canInject = null;
|
||||
private static volatile boolean injected = false;
|
||||
|
||||
/**
|
||||
* @return Have we injected our policies already?
|
||||
*/
|
||||
@AnyThread
|
||||
public static boolean haveInjected() {
|
||||
return injected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset policies-have-been-injected state, if you really need to inject them again. Extremely
|
||||
* rare, you will probably never need this.
|
||||
*/
|
||||
@AnyThread
|
||||
public static void resetInjected() {
|
||||
synchronized (synchronizer) {
|
||||
injected = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method to return a array of strings containing the policies you want to inject.
|
||||
*
|
||||
* @return Policies to inject
|
||||
*/
|
||||
@NonNull
|
||||
protected abstract String[] getPolicies();
|
||||
|
||||
/**
|
||||
* Detects availability of the supolicy tool. Only useful if Shell.SU.isSELinuxEnforcing()
|
||||
* returns true. Caches return value, can safely be called from the UI thread <b>if</b> a
|
||||
* a cached value exists.
|
||||
*
|
||||
* @see #resetCanInject()
|
||||
*
|
||||
* @return canInject?
|
||||
*/
|
||||
@SuppressWarnings({"deprecation", "ConstantConditions"})
|
||||
@WorkerThread // first call only
|
||||
public static boolean canInject() {
|
||||
synchronized (synchronizer) {
|
||||
if (canInject != null) return canInject;
|
||||
|
||||
canInject = false;
|
||||
|
||||
// We are making the assumption here that if supolicy is called without parameters,
|
||||
// it will return output (such as a usage notice) on STDOUT (not STDERR) that contains
|
||||
// at least the word "supolicy". This is true at least for SuperSU.
|
||||
|
||||
List<String> result = Shell.run("sh", new String[] { "supolicy" }, null, false);
|
||||
if (result != null) {
|
||||
for (String line : result) {
|
||||
if (line.contains("supolicy")) {
|
||||
canInject = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return canInject;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset cached can-inject state and force redetection on nect canInject() call
|
||||
*/
|
||||
@AnyThread
|
||||
public static void resetCanInject() {
|
||||
synchronized (synchronizer) {
|
||||
canInject = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform the policies defined by getPolicies() into a set of shell commands
|
||||
*
|
||||
* @return Possibly empty List of commands, or null
|
||||
*/
|
||||
@Nullable
|
||||
protected List<String> getInjectCommands() {
|
||||
return getInjectCommands(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform the policies defined by getPolicies() into a set of shell commands
|
||||
*
|
||||
* @param allowBlocking allow method to perform blocking I/O for extra checks
|
||||
* @return Possibly empty List of commands, or null
|
||||
*/
|
||||
@Nullable
|
||||
@SuppressWarnings("all")
|
||||
@WorkerThread // if allowBlocking
|
||||
protected List<String> getInjectCommands(boolean allowBlocking) {
|
||||
synchronized (synchronizer) {
|
||||
// No reason to bother if we're in permissive mode
|
||||
if (!Shell.SU.isSELinuxEnforcing()) return null;
|
||||
|
||||
// If we can't inject, no use continuing
|
||||
if (allowBlocking && !canInject()) return null;
|
||||
|
||||
// Been there, done that
|
||||
if (injected) return null;
|
||||
|
||||
// Retrieve policies
|
||||
String[] policies = getPolicies();
|
||||
if ((policies != null) && (policies.length > 0)) {
|
||||
List<String> commands = new ArrayList<String>();
|
||||
|
||||
// Combine the policies into a minimal number of commands
|
||||
String command = "";
|
||||
for (String policy : policies) {
|
||||
if ((command.length() == 0) || (command.length() + policy.length() + 3 < MAX_POLICY_LENGTH)) {
|
||||
command = command + " \"" + policy + "\"";
|
||||
} else {
|
||||
commands.add("supolicy --live" + command);
|
||||
command = "";
|
||||
}
|
||||
}
|
||||
if (command.length() > 0) {
|
||||
commands.add("supolicy --live" + command);
|
||||
}
|
||||
|
||||
return commands;
|
||||
}
|
||||
|
||||
// No policies
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject the policies defined by getPolicies(). Throws an exception if called from
|
||||
* the main thread in debug mode.
|
||||
*/
|
||||
@SuppressWarnings({"deprecation"})
|
||||
@WorkerThread
|
||||
public void inject() {
|
||||
synchronized (synchronizer) {
|
||||
// Get commands that inject our policies
|
||||
List<String> commands = getInjectCommands();
|
||||
|
||||
// Execute them, if any
|
||||
if ((commands != null) && (commands.size() > 0)) {
|
||||
Shell.SU.run(commands);
|
||||
}
|
||||
|
||||
// We survived without throwing
|
||||
injected = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject the policies defined by getPolicies(). Throws an exception if called from
|
||||
* the main thread in debug mode if waitForIdle is true. If waitForIdle is false
|
||||
* however, it cannot be guaranteed the command was executed and the policies injected
|
||||
* upon return.
|
||||
*
|
||||
* @param shell Interactive shell to execute commands on
|
||||
* @param waitForIdle wait for the command to complete before returning?
|
||||
*/
|
||||
@WorkerThread // if waitForIdle
|
||||
public void inject(@NonNull Shell.Interactive shell, boolean waitForIdle) {
|
||||
synchronized (synchronizer) {
|
||||
// Get commands that inject our policies
|
||||
List<String> commands = getInjectCommands(waitForIdle);
|
||||
|
||||
// Execute them, if any
|
||||
if ((commands != null) && (commands.size() > 0)) {
|
||||
shell.addCommand(commands);
|
||||
if (waitForIdle) {
|
||||
shell.waitForIdle();
|
||||
}
|
||||
}
|
||||
|
||||
// We survived without throwing
|
||||
injected = true;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2014 Jorrit "Chainfire" Jongma
|
||||
* Copyright (C) 2012-2019 Jorrit "Chainfire" Jongma
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -21,78 +21,139 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import androidx.annotation.AnyThread;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
/**
|
||||
* Thread utility class continuously reading from an InputStream
|
||||
*/
|
||||
public class StreamGobbler extends Thread {
|
||||
@SuppressWarnings({"WeakerAccess"})
|
||||
public class StreamGobbler extends Thread {
|
||||
private static int threadCounter = 0;
|
||||
private static int incThreadCounter() {
|
||||
synchronized (StreamGobbler.class) {
|
||||
int ret = threadCounter;
|
||||
threadCounter++;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Line callback interface
|
||||
*/
|
||||
public interface OnLineListener {
|
||||
public interface OnLineListener {
|
||||
/**
|
||||
* <p>Line callback</p>
|
||||
*
|
||||
*
|
||||
* <p>This callback should process the line as quickly as possible.
|
||||
* Delays in this callback may pause the native process or even
|
||||
* result in a deadlock</p>
|
||||
*
|
||||
*
|
||||
* @param line String that was gobbled
|
||||
*/
|
||||
void onLine(String line);
|
||||
}
|
||||
|
||||
private String shell = null;
|
||||
private BufferedReader reader = null;
|
||||
private List<String> writer = null;
|
||||
private OnLineListener listener = null;
|
||||
/**
|
||||
* Stream closed callback interface
|
||||
*/
|
||||
public interface OnStreamClosedListener {
|
||||
/**
|
||||
* <p>Stream closed callback</p>
|
||||
*/
|
||||
void onStreamClosed();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private final String shell;
|
||||
@NonNull
|
||||
private final InputStream inputStream;
|
||||
@NonNull
|
||||
private final BufferedReader reader;
|
||||
@Nullable
|
||||
private final List<String> writer;
|
||||
@Nullable
|
||||
private final OnLineListener lineListener;
|
||||
@Nullable
|
||||
private final OnStreamClosedListener streamClosedListener;
|
||||
private volatile boolean active = true;
|
||||
private volatile boolean calledOnClose = false;
|
||||
|
||||
/**
|
||||
* <p>StreamGobbler constructor</p>
|
||||
*
|
||||
* <p>We use this class because shell STDOUT and STDERR should be read as quickly as
|
||||
*
|
||||
* <p>We use this class because shell STDOUT and STDERR should be read as quickly as
|
||||
* possible to prevent a deadlock from occurring, or Process.waitFor() never
|
||||
* returning (as the buffer is full, pausing the native process)</p>
|
||||
*
|
||||
*
|
||||
* @param shell Name of the shell
|
||||
* @param inputStream InputStream to read from
|
||||
* @param outputList List<String> to write to, or null
|
||||
* @param outputList {@literal List<String>} to write to, or null
|
||||
*/
|
||||
public StreamGobbler(String shell, InputStream inputStream, List<String> outputList) {
|
||||
@AnyThread
|
||||
public StreamGobbler(@NonNull String shell, @NonNull InputStream inputStream, @Nullable List<String> outputList) {
|
||||
super("Gobbler#" + incThreadCounter());
|
||||
this.shell = shell;
|
||||
this.inputStream = inputStream;
|
||||
reader = new BufferedReader(new InputStreamReader(inputStream));
|
||||
writer = outputList;
|
||||
lineListener = null;
|
||||
streamClosedListener = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>StreamGobbler constructor</p>
|
||||
*
|
||||
* <p>We use this class because shell STDOUT and STDERR should be read as quickly as
|
||||
*
|
||||
* <p>We use this class because shell STDOUT and STDERR should be read as quickly as
|
||||
* possible to prevent a deadlock from occurring, or Process.waitFor() never
|
||||
* returning (as the buffer is full, pausing the native process)</p>
|
||||
*
|
||||
*
|
||||
* @param shell Name of the shell
|
||||
* @param inputStream InputStream to read from
|
||||
* @param onLineListener OnLineListener callback
|
||||
* @param onStreamClosedListener OnStreamClosedListener callback
|
||||
*/
|
||||
public StreamGobbler(String shell, InputStream inputStream, OnLineListener onLineListener) {
|
||||
@AnyThread
|
||||
public StreamGobbler(@NonNull String shell, @NonNull InputStream inputStream, @Nullable OnLineListener onLineListener, @Nullable OnStreamClosedListener onStreamClosedListener) {
|
||||
super("Gobbler#" + incThreadCounter());
|
||||
this.shell = shell;
|
||||
this.inputStream = inputStream;
|
||||
reader = new BufferedReader(new InputStreamReader(inputStream));
|
||||
listener = onLineListener;
|
||||
lineListener = onLineListener;
|
||||
streamClosedListener = onStreamClosedListener;
|
||||
writer = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
// keep reading the InputStream until it ends (or an error occurs)
|
||||
// optionally pausing when a command is executed that consumes the InputStream itself
|
||||
try {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
Debug.logOutput(String.format("[%s] %s", shell, line));
|
||||
Debug.logOutput(String.format(Locale.ENGLISH, "[%s] %s", shell, line));
|
||||
if (writer != null) writer.add(line);
|
||||
if (listener != null) listener.onLine(line);
|
||||
if (lineListener != null) lineListener.onLine(line);
|
||||
while (!active) {
|
||||
synchronized (this) {
|
||||
try {
|
||||
this.wait(128);
|
||||
} catch (InterruptedException e) {
|
||||
// no action
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// reader probably closed, expected exit condition
|
||||
if (streamClosedListener != null) {
|
||||
calledOnClose = true;
|
||||
streamClosedListener.onStreamClosed();
|
||||
}
|
||||
}
|
||||
|
||||
// make sure our stream is closed and resources will be freed
|
||||
@ -101,5 +162,96 @@ public class StreamGobbler extends Thread {
|
||||
} catch (IOException e) {
|
||||
// read already closed
|
||||
}
|
||||
|
||||
if (!calledOnClose) {
|
||||
if (streamClosedListener != null) {
|
||||
calledOnClose = true;
|
||||
streamClosedListener.onStreamClosed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Resume consuming the input from the stream</p>
|
||||
*/
|
||||
@AnyThread
|
||||
public void resumeGobbling() {
|
||||
if (!active) {
|
||||
synchronized (this) {
|
||||
active = true;
|
||||
this.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Suspend gobbling, so other code may read from the InputStream instead</p>
|
||||
*
|
||||
* <p>This should <i>only</i> be called from the OnLineListener callback!</p>
|
||||
*/
|
||||
@AnyThread
|
||||
public void suspendGobbling() {
|
||||
synchronized (this) {
|
||||
active = false;
|
||||
this.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Wait for gobbling to be suspended</p>
|
||||
*
|
||||
* <p>Obviously this cannot be called from the same thread as {@link #suspendGobbling()}</p>
|
||||
*/
|
||||
@WorkerThread
|
||||
public void waitForSuspend() {
|
||||
synchronized (this) {
|
||||
while (active) {
|
||||
try {
|
||||
this.wait(32);
|
||||
} catch (InterruptedException e) {
|
||||
// no action
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Is gobbling suspended ?</p>
|
||||
*
|
||||
* @return is gobbling suspended?
|
||||
*/
|
||||
@AnyThread
|
||||
public boolean isSuspended() {
|
||||
synchronized (this) {
|
||||
return !active;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Get current source InputStream</p>
|
||||
*
|
||||
* @return source InputStream
|
||||
*/
|
||||
@NonNull
|
||||
@AnyThread
|
||||
public InputStream getInputStream() {
|
||||
return inputStream;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Get current OnLineListener</p>
|
||||
*
|
||||
* @return OnLineListener
|
||||
*/
|
||||
@Nullable
|
||||
@AnyThread
|
||||
public OnLineListener getOnLineListener() {
|
||||
return lineListener;
|
||||
}
|
||||
|
||||
void conditionalJoin() throws InterruptedException {
|
||||
if (calledOnClose) return; // deadlock from callback, we're inside exit procedure
|
||||
if (Thread.currentThread() == this) return; // can't join self
|
||||
join();
|
||||
}
|
||||
}
|
||||
|
122
app/src/main/java/eu/chainfire/libsuperuser/Toolbox.java
Normal file
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2019 Jorrit "Chainfire" Jongma
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package eu.chainfire.libsuperuser;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
/**
|
||||
* Utility class to decide between toolbox and toybox calls on M.
|
||||
* Note that some calls (such as 'ls') are present in both, this
|
||||
* class will favor toybox variants.
|
||||
*
|
||||
* This may not be what you want, as both syntax and output may
|
||||
* differ between the variants.
|
||||
*
|
||||
* Very specific warning, the 'mount' included with toybox tends
|
||||
* to segfault, at least on the first few 6.0 firmwares.
|
||||
*/
|
||||
@SuppressWarnings({"unused", "WeakerAccess", "deprecation"})
|
||||
public class Toolbox {
|
||||
private static final int TOYBOX_SDK = 23;
|
||||
|
||||
private static final Object synchronizer = new Object();
|
||||
@Nullable
|
||||
private static volatile String toybox = null;
|
||||
|
||||
/**
|
||||
* Initialize. Asks toybox which commands it supports. Throws an exception if called from
|
||||
* the main thread in debug mode.
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
@WorkerThread
|
||||
public static void init() {
|
||||
// already inited ?
|
||||
if (toybox != null) return;
|
||||
|
||||
// toybox is M+
|
||||
if (Build.VERSION.SDK_INT < TOYBOX_SDK) {
|
||||
toybox = "";
|
||||
} else {
|
||||
if (Debug.getSanityChecksEnabledEffective() && Debug.onMainThread()) {
|
||||
Debug.log(Shell.ShellOnMainThreadException.EXCEPTION_TOOLBOX);
|
||||
throw new Shell.ShellOnMainThreadException(Shell.ShellOnMainThreadException.EXCEPTION_TOOLBOX);
|
||||
}
|
||||
|
||||
// ask toybox which commands it has, and store the info
|
||||
synchronized (synchronizer) {
|
||||
toybox = "";
|
||||
|
||||
List<String> output = Shell.SH.run("toybox");
|
||||
if (output != null) {
|
||||
toybox = " ";
|
||||
for (String line : output) {
|
||||
toybox = toybox + line.trim() + " ";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a command string, deciding on toolbox or toybox for its execution
|
||||
*
|
||||
* If init() has not already been called, it is called for you, which may throw an exception
|
||||
* if we're in the main thread.
|
||||
*
|
||||
* Example:
|
||||
* Toolbox.command("chmod 0.0 %s", "/some/file/somewhere");
|
||||
*
|
||||
* Output:
|
||||
* < M: "toolbox chmod 0.0 /some/file/somewhere"
|
||||
* M+ : "toybox chmod 0.0 /some/file/somewhere"
|
||||
*
|
||||
* @param format String to format. First word is the applet name.
|
||||
* @param args Arguments passed to String.format
|
||||
* @return Formatted String prefixed with either toolbox or toybox
|
||||
*/
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@WorkerThread // if init() not yet called
|
||||
public static String command(@NonNull String format, Object... args) {
|
||||
if (Build.VERSION.SDK_INT < TOYBOX_SDK) {
|
||||
return String.format(Locale.ENGLISH, "toolbox " + format, args);
|
||||
}
|
||||
|
||||
if (toybox == null) init();
|
||||
|
||||
format = format.trim();
|
||||
String applet;
|
||||
int p = format.indexOf(' ');
|
||||
if (p >= 0) {
|
||||
applet = format.substring(0, p);
|
||||
} else {
|
||||
applet = format;
|
||||
}
|
||||
|
||||
if (toybox.contains(" " + applet + " ")) {
|
||||
return String.format(Locale.ENGLISH, "toybox " + format, args);
|
||||
} else {
|
||||
return String.format(Locale.ENGLISH, "toolbox " + format, args);
|
||||
}
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 5.2 KiB |
BIN
app/src/main/res/drawable-hdpi/notification.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 4.2 KiB |
BIN
app/src/main/res/drawable-hdpi/vibrate.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
@ -1,117 +0,0 @@
|
||||
<?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_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical" >
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<Button
|
||||
android:id="@+id/bSelectApp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/selectApplication" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvSelectedActivity"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text=""
|
||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
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_height="wrap_content">
|
||||
<TextView
|
||||
android:id="@+id/textView3"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/parameterType"
|
||||
android:layout_gravity="center_vertical"/>
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/spinnerParameterType"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<TextView
|
||||
android:id="@+id/tvCurrentNfcIdValue"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/parameterName" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/etParameterName"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ems="10" >
|
||||
|
||||
<requestFocus />
|
||||
</EditText>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<TextView
|
||||
android:id="@+id/textView2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/parameterValue" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/etParameterValue"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ems="10" />
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/bAddIntentPair"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/addIntentValue" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_margin="10dp"
|
||||
android:background="#aa000000" />
|
||||
|
||||
<ListView
|
||||
android:id="@+id/lvIntentPairs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="115dp" >
|
||||
</ListView>
|
||||
|
||||
<Button
|
||||
android:id="@+id/bSaveActionStartOtherActivity"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/save" />
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
111
app/src/main/res/layout/activity_maintenance.xml
Normal file
@ -0,0 +1,111 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<ScrollView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/default_margin" >
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Headline"
|
||||
android:text="@string/settings"
|
||||
android:layout_marginBottom="@dimen/default_margin"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/bMoreSettings"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/moreSettings" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_span="2"
|
||||
android:layout_height="1dp"
|
||||
android:layout_margin="@dimen/default_margin"
|
||||
android:background="#aa000000" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/default_margin"
|
||||
android:text="@string/importExportExplanation" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/bImportConfiguration"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/importConfiguration" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/bExportConfiguration"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/exportConfiguration" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_span="2"
|
||||
android:layout_height="1dp"
|
||||
android:layout_margin="@dimen/default_margin"
|
||||
android:background="#aa000000" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/bVolumeTest"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/volumeTest" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_span="2"
|
||||
android:layout_height="1dp"
|
||||
android:layout_margin="@dimen/default_margin"
|
||||
android:background="#aa000000" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/bSettingsSetToDefault"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/defaultSettings" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_span="2"
|
||||
android:layout_height="1dp"
|
||||
android:layout_margin="@dimen/default_margin"
|
||||
android:background="#aa000000" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/bShareConfigAndLog"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/shareConfigAndLogFilesWithDev" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvFileStoreLocation"
|
||||
android:layout_marginVertical="@dimen/default_margin"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:gravity="center_horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvAppVersion"
|
||||
android:layout_marginTop="@dimen/default_margin"
|
||||
android:layout_marginVertical="@dimen/default_margin"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:gravity="center_horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
</ScrollView>
|
@ -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="match_parent"
|
||||
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>
|
@ -2,7 +2,7 @@
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_margin="10dp" >
|
||||
android:layout_margin="@dimen/default_margin" >
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
@ -0,0 +1,322 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/default_margin" >
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TableLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:stretchColumns="1"
|
||||
android:shrinkColumns="1" >
|
||||
|
||||
<TableRow
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_span="2"
|
||||
android:textSize="25dp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="@dimen/default_margin"
|
||||
android:text="@string/selectApplication" />
|
||||
|
||||
</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_span="2"
|
||||
android:inputType="textMultiLine"
|
||||
android:text="@string/startAppChoiceNote" />
|
||||
|
||||
</TableRow>
|
||||
|
||||
<TableRow
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" >
|
||||
|
||||
<Button
|
||||
android:id="@+id/showStartProgramExamples"
|
||||
android:layout_marginTop="@dimen/default_margin"
|
||||
android:layout_span="2"
|
||||
android:text="@string/openExamplesPage" />
|
||||
|
||||
</TableRow>
|
||||
|
||||
<TableRow
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:gravity="center_vertical"
|
||||
android:text="@string/startAppSelectionType" />
|
||||
|
||||
<RadioGroup
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rbStartAppSelectByActivity"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:checked="true"
|
||||
android:text="@string/startAppByActivity" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rbStartAppSelectByAction"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/startAppByAction" />
|
||||
|
||||
</RadioGroup>
|
||||
|
||||
</TableRow>
|
||||
|
||||
<TableRow
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_span="2"
|
||||
android:layout_height="1dp"
|
||||
android:layout_margin="10dp"
|
||||
android:background="#aa000000" />
|
||||
|
||||
</TableRow>
|
||||
|
||||
<TableRow
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:gravity="center_vertical"
|
||||
android:text="@string/startAppStartType" />
|
||||
|
||||
<RadioGroup
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rbStartAppByActivity"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:checked="true"
|
||||
android:text="@string/startAppByStartActivity" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rbStartAppByBroadcast"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/startAppBySendBroadcast" />
|
||||
|
||||
</RadioGroup>
|
||||
|
||||
</TableRow>
|
||||
|
||||
<TableRow
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_span="2"
|
||||
android:layout_height="1dp"
|
||||
android:layout_margin="10dp"
|
||||
android:background="#aa000000" />
|
||||
|
||||
</TableRow>
|
||||
|
||||
<TableRow
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" >
|
||||
|
||||
<Button
|
||||
android:id="@+id/bSelectApp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/selectApplication" />
|
||||
|
||||
<TextView
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content" />
|
||||
|
||||
</TableRow>
|
||||
|
||||
<TableRow
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@string/packageName" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/etPackageName"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="textMultiLine"
|
||||
android:text=""
|
||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||
|
||||
</TableRow>
|
||||
|
||||
<TableRow
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@string/activityOrActionName" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/etActivityOrActionPath"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="textMultiLine"
|
||||
android:text=""
|
||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||
|
||||
</TableRow>
|
||||
|
||||
<TableRow
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_span="2"
|
||||
android:layout_height="1dp"
|
||||
android:layout_margin="10dp"
|
||||
android:background="#aa000000" />
|
||||
|
||||
</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_span="2"
|
||||
android:textSize="25dp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="@dimen/default_margin"
|
||||
android:text="@string/addParameters" />
|
||||
|
||||
</TableRow>
|
||||
|
||||
<TableRow>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_span="2"
|
||||
android:layout_marginBottom="@dimen/default_margin"
|
||||
android:text="@string/intentDataComment" />
|
||||
|
||||
</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
|
||||
android:id="@+id/spinnerParameterType"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</TableRow>
|
||||
|
||||
<TableRow
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvCurrentNfcIdValue"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/parameterName" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/etParameterName"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</TableRow>
|
||||
|
||||
<TableRow
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/parameterValue" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/etParameterValue"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</TableRow>
|
||||
|
||||
</TableLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/bAddIntentPair"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/addIntentValue" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_margin="10dp"
|
||||
android:background="#aa000000" />
|
||||
|
||||
<ListView
|
||||
android:id="@+id/lvIntentPairs"
|
||||
android:visibility="gone"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="115dp"
|
||||
android:layout_marginBottom="@dimen/default_margin" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/bSaveActionStartOtherActivity"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/save" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
@ -2,17 +2,24 @@
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_margin="10dp" >
|
||||
android:layout_margin="@dimen/default_margin" >
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical" >
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/urlToTriggerExplanation"
|
||||
android:layout_marginBottom="@dimen/default_margin"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvRuleTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textStyle="bold"
|
||||
android:text="@string/urlToTrigger" />
|
||||
|
||||
<EditText
|
47
app/src/main/res/layout/activity_manage_action_vibrate.xml
Normal file
@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/default_margin" >
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_span="2"
|
||||
android:textSize="25dp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="@dimen/default_margin"
|
||||
android:text="@string/vibrate" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/VibrateExplanation" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/etVibratePattern"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginVertical="@dimen/default_margin"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/bTestVibratePattern"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginVertical="@dimen/default_margin"
|
||||
android:text="@string/test" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/bSaveVibratePattern"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/save" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
@ -4,6 +4,15 @@
|
||||
android:layout_height="match_parent"
|
||||
android:layout_margin="@dimen/default_margin">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_span="2"
|
||||
android:textSize="25dp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="@dimen/default_margin"
|
||||
android:text="@string/setScreenBrightness" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/chkAutoBrightness"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -1,7 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" >
|
||||
android:layout_height="match_parent"
|
||||
android:layout_margin="@dimen/default_margin">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
@ -9,7 +10,6 @@
|
||||
android:orientation="vertical" >
|
||||
|
||||
<LinearLayout
|
||||
android:layout_marginTop="10dp"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@ -92,7 +92,7 @@
|
||||
|
||||
<Button
|
||||
android:id="@+id/bSaveBluetoothTrigger"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginTop="@dimen/default_margin"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/save" />
|
@ -3,7 +3,8 @@
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical" >
|
||||
android:orientation="vertical"
|
||||
android:layout_margin="@dimen/default_margin" >
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
150
app/src/main/res/layout/activity_manage_trigger_notification.xml
Normal file
@ -0,0 +1,150 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/default_margin" >
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical" >
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/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"
|
||||
android:shrinkColumns="1"
|
||||
android:stretchColumns="1">
|
||||
|
||||
<TableRow
|
||||
android:layout_marginBottom="@dimen/activity_vertical_margin">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/direction"/>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/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="vertical"
|
||||
android:layout_marginHorizontal="@dimen/default_margin"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/etActivityOrActionPath"
|
||||
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_marginTop="10dp"
|
||||
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>
|
194
app/src/main/res/layout/activity_manage_trigger_phone_call.xml
Normal file
@ -0,0 +1,194 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/default_margin" >
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical" >
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Headline"
|
||||
android:text="@string/phoneCall" />
|
||||
|
||||
<TableLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:shrinkColumns="1"
|
||||
android:stretchColumns="1" >
|
||||
|
||||
<TableRow
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" >
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:text="@string/state" />
|
||||
|
||||
<RadioGroup
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" >
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rbTriggerPhoneCallStateRinging"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:checked="true"
|
||||
android:text="@string/ringing" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rbTriggerPhoneCallStateStarted"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/started" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rbTriggerPhoneCallStateStopped"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/stopped" />
|
||||
|
||||
</RadioGroup>
|
||||
|
||||
</TableRow>
|
||||
|
||||
<TableRow
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:layout_span="2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_margin="10dp"
|
||||
android:background="#aa000000" />
|
||||
|
||||
</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/phoneDirection" />
|
||||
|
||||
<RadioGroup
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" >
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rbTriggerPhoneCallDirectionAny"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:checked="true"
|
||||
android:text="@string/any" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rbTriggerPhoneCallDirectionIncoming"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/incoming" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rbTriggerPhoneCallDirectionOutgoing"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/outgoing" />
|
||||
|
||||
</RadioGroup>
|
||||
|
||||
</TableRow>
|
||||
|
||||
<TableRow
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:layout_span="2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_margin="10dp"
|
||||
android:background="#aa000000" />
|
||||
|
||||
</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/phoneNumber" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/etTriggerPhoneCallPhoneNumber"
|
||||
android:inputType="text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical" />
|
||||
|
||||
</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_span="2"
|
||||
android:text="@string/phoneNumberExplanation" />
|
||||
|
||||
</TableRow>
|
||||
|
||||
<TableRow
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" >
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:layout_span="2"
|
||||
android:text="@string/urlRegex" />
|
||||
|
||||
</TableRow>
|
||||
|
||||
<TableRow
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" >
|
||||
|
||||
<Button
|
||||
android:id="@+id/bTriggerPhoneCallImportFromContacts"
|
||||
android:drawableLeft="@drawable/contacts"
|
||||
android:layout_marginVertical="@dimen/default_margin"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_span="2"
|
||||
android:text="@string/importNumberFromContacts" />
|
||||
|
||||
</TableRow>
|
||||
|
||||
</TableLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/bSaveTriggerPhoneCall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/save" />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
</ScrollView>
|
@ -3,7 +3,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_weight="30"
|
||||
android:layout_margin="10dp" >
|
||||
android:layout_margin="@dimen/default_margin" >
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
@ -34,18 +34,18 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_margin="10dp"
|
||||
android:background="#aa000000" />
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_margin="10dp"
|
||||
android:background="#aa000000" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/insideOrOutsideTimeFrames"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge" />
|
||||
<TextView
|
||||
android:id="@+id/textView2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/insideOrOutsideTimeFrames"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge" />
|
||||
|
||||
<RadioGroup
|
||||
android:layout_width="match_parent"
|
||||
@ -65,18 +65,18 @@
|
||||
android:text="@string/leaving" />
|
||||
</RadioGroup>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_margin="10dp"
|
||||
android:background="#aa000000" />
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_margin="10dp"
|
||||
android:background="#aa000000" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvCurrentNfcIdValue"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/timeFrameWhichDays"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge" />
|
||||
<TextView
|
||||
android:id="@+id/tvCurrentNfcIdValue"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/timeFrameWhichDays"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/checkMonday"
|
||||
@ -122,6 +122,7 @@
|
||||
|
||||
<Button
|
||||
android:id="@+id/bSaveTimeFrame"
|
||||
android:layout_marginTop="@dimen/default_margin"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/save" />
|
90
app/src/main/res/layout/activity_manage_trigger_wifi.xml
Normal file
@ -0,0 +1,90 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.appcompat.widget.LinearLayoutCompat 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="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/wifiConnection"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Headline"
|
||||
android:layout_marginBottom="@dimen/default_margin" />
|
||||
|
||||
<TableLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:shrinkColumns="1"
|
||||
android:stretchColumns="1" >
|
||||
|
||||
<TableRow>
|
||||
|
||||
<TextView
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:paddingRight="@dimen/default_margin"
|
||||
android:text="@string/state"/>
|
||||
|
||||
<RadioGroup
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent">
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rbTriggerWifiConnected"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:checked="true"
|
||||
android:text="@string/connected" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rbTriggerWifiDisconnected"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/disconnected" />
|
||||
|
||||
</RadioGroup>
|
||||
|
||||
</TableRow>
|
||||
|
||||
<TableRow>
|
||||
|
||||
<TextView
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:paddingRight="@dimen/default_margin"
|
||||
android:text="@string/name"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/etTriggerWifiName"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent" />
|
||||
|
||||
</TableRow>
|
||||
|
||||
<TableRow>
|
||||
|
||||
<Button
|
||||
android:id="@+id/bLoadWifiList"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/loadWifiList" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/spinnerWifiList"
|
||||
android:enabled="false"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</TableRow>
|
||||
|
||||
</TableLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btriggerWifiSave"
|
||||
android:layout_marginTop="@dimen/default_margin"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/save" />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
@ -31,7 +31,7 @@
|
||||
<CheckBoxPreference
|
||||
android:key="writeLogFile"
|
||||
android:summary="@string/onOff"
|
||||
android:title="@string/writeLogFileToSd" />
|
||||
android:title="@string/writeLogFile" />
|
||||
|
||||
<EditTextPreference
|
||||
android:key="logLevel"
|
||||
@ -52,10 +52,23 @@
|
||||
android:entries="@array/startScreenOptions"
|
||||
android:entryValues="@array/startScreenOptionsValues" />
|
||||
|
||||
<ListPreference
|
||||
android:key="tabsPlacement"
|
||||
android:title="@string/tabsPlacement"
|
||||
android:summary="@string/tabsPlacementSummary"
|
||||
android:entries="@array/tabsPlacementOptions"
|
||||
android:entryValues="@array/tabsPlacementOptionsValues" />
|
||||
|
||||
<CheckBoxPreference
|
||||
android:key="executeRulesAndProfilesWithSingleClick"
|
||||
android:title="@string/executeRulesAndProfilesWithSingleClickTitle" />
|
||||
|
||||
<CheckBoxPreference
|
||||
android:key="automaticUpdateCheck"
|
||||
android:enabled="false"
|
||||
android:title="@string/automaticUpdateCheck"
|
||||
android:summary="@string/automaticUpdateCheckSummary"/>
|
||||
|
||||
<CheckBoxPreference
|
||||
android:key="displayNewsOnMainScreen"
|
||||
android:title="@string/displayNewsOnMainScreen"
|
@ -3,7 +3,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:layout_margin="10dp" >
|
||||
android:layout_margin="@dimen/default_margin" >
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvVolumeTestExplanation"
|
||||
|
@ -17,7 +17,7 @@
|
||||
android:background="@color/barBackgroundColor" >
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvSelectedActivity"
|
||||
android:id="@+id/etActivityOrActionPath"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/general"
|
||||
|
@ -302,80 +302,38 @@
|
||||
</TableRow>
|
||||
|
||||
</TableLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_margin="10dp"
|
||||
android:layout_marginTop="30dp"
|
||||
android:gravity="top" >
|
||||
|
||||
<Button
|
||||
android:id="@+id/bShowHelp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/showHelp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/bVolumeTest"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/volumeTest"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/bPrivacy"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_weight="1"
|
||||
android:enabled="true"
|
||||
android:text="@string/privacy" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:orientation="vertical"
|
||||
android:layout_margin="10dp"
|
||||
android:layout_marginTop="30dp"
|
||||
android:gravity="center_horizontal" >
|
||||
|
||||
|
||||
<Button
|
||||
android:id="@+id/bShowHelp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/showHelp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/bPrivacy"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:enabled="true"
|
||||
android:text="@string/privacy" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/bSettings"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="top"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/menu_settings" />
|
||||
|
||||
<!-- <Button
|
||||
android:id="@+id/bSettingsErase"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/eraseSettings" /> -->
|
||||
|
||||
<Button
|
||||
android:id="@+id/bSettingsSetToDefault"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/defaultSettings" />
|
||||
android:text="@string/settings" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvFileStoreLocation"
|
||||
android:layout_marginVertical="@dimen/default_margin"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:gravity="center_horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
@ -40,7 +40,7 @@
|
||||
android:id="@+id/tvRuleTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/profileList"
|
||||
android:text="@string/profiles"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge" />
|
||||
|
||||
|
@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@android:id/tabhost"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
<TabWidget
|
||||
android:id="@android:id/tabs"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
<FrameLayout
|
||||
android:id="@android:id/tabcontent"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"/>
|
||||
</LinearLayout>
|
||||
</TabHost>
|
27
app/src/main/res/layout/main_tab_layout_tabs_at_bottom.xml
Normal file
@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@android:id/tabhost"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@android:id/tabcontent"
|
||||
android:layout_weight="1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<TabWidget
|
||||
android:id="@android:id/tabs"
|
||||
android:layout_weight="0"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</TabHost>
|
27
app/src/main/res/layout/main_tab_layout_tabs_at_top.xml
Normal file
@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@android:id/tabhost"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TabWidget
|
||||
android:id="@android:id/tabs"
|
||||
android:layout_weight="0"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@android:id/tabcontent"
|
||||
android:layout_weight="1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</TabHost>
|
@ -84,18 +84,21 @@
|
||||
|
||||
<Button
|
||||
android:id="@+id/cmdTriggerAdd"
|
||||
android:layout_weight="1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/addTrigger" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/cmdActionAdd"
|
||||
android:layout_weight="1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/addAction" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/cmdSaveRule"
|
||||
android:layout_weight="1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/saveRule" />
|
||||
|
@ -1,5 +1,5 @@
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:id="@+id/menu_settings"
|
||||
android:title="@string/menu_settings"
|
||||
android:title="@string/settings"
|
||||
android:orderInCategory="100" />
|
||||
</menu>
|
||||
|
@ -1,8 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="menu_settings">Einstellungen</string>
|
||||
<string name="app_name">Automation</string>
|
||||
<string name="title_activity_main">Automation</string>
|
||||
<string name="ruleActivate">Aktiviere Regel %1$s</string>
|
||||
<string name="profileActivate">Aktiviere Profil %1$s</string>
|
||||
<string name="ruleActivateToggle">Aktiviere Regel %1$s im Umschaltmodus</string>
|
||||
@ -16,28 +13,15 @@
|
||||
<string name="serviceWontStart">Weder Orte noch Regeln sind definitiv. Dienst wird nicht starten.</string>
|
||||
<string name="serviceStarted">Automations-Dienst gestarted.</string>
|
||||
<string name="version">Version %1$s.</string>
|
||||
<string name="logServiceStarting">Dienst wird gestartet.</string>
|
||||
<string name="logNotAllMeasurings">Es stehen noch nicht alle Messwerte zur Verfügung. Es kann noch kein Vergleich vorgenommen werden.</string>
|
||||
<string name="distanceBetween">Der Abstand zwischen GPS- und Mobilfunk-Position beträgt</string>
|
||||
<string name="radiusSuggestion">Meter. Dies +1 sollte der minimale Radius sein.</string>
|
||||
<string name="comparing">Sowohl Netzwerk- als auch GPS Position sind bekannt. Vergleiche...</string>
|
||||
<string name="logNoSuitableProvider">Kein brauchbarer Positionsanbieter verfügbar.</string>
|
||||
<string name="positioningWindowNotice">Falls Sie in einem Gebäude sind wird empfohlen das Gerät in die Nähe eines Fensters zu bringen bis eine Position ermittelt werden konnte. Andernfalls kann es sehr lange dauern oder es funktioniert gar nicht.</string>
|
||||
<string name="distanceBetween">Der Abstand zwischen GPS- und Mobilfunk-Position beträgt %1$d m. Dies +1 sollte der minimale Radius sein.</string>
|
||||
<string name="positioningWindowNotice">Falls Sie in einem Gebäude sind, wird empfohlen das Gerät in die Nähe eines Fensters zu bringen bis eine Position ermittelt werden konnte. Andernfalls kann es sehr lange dauern oder es funktioniert gar nicht.</string>
|
||||
<string name="gettingPosition">Position wird ermittelt. Bitte warten...</string>
|
||||
<string name="logGettingPositionWithProvider">Position wird ermittelt mit Anbieter:</string>
|
||||
<string name="yes">Ja</string>
|
||||
<string name="no">Nein</string>
|
||||
<string name="logGotGpsUpdate">GPS Position erhalten. Genauigkeit:</string>
|
||||
<string name="logGotNetworkUpdate">Netzwerk Position erhalten. Genauigkeit:</string>
|
||||
<string name="pleaseEnterValidLatitude">Bitte geben Sie einen gültigen Breitengrad an.</string>
|
||||
<string name="pleaseEnterValidLongitude">Bitte geben Sie einen gültigen Längengrad an.</string>
|
||||
<string name="pleaseEnterValidRadius">Bitte geben Sie einen gültigen positiven Radius an.</string>
|
||||
<string name="selectOneDay">Bitte wählen Sie wenigstens einen Tag aus.</string>
|
||||
<string name="logAttemptingToBindToService">Versuche zum Dienst zu verbinden... </string>
|
||||
<string name="logAttemptingToUnbindFromService">Versuche vom Dienst zu trennen... </string>
|
||||
<string name="logBoundToService">Zum Dienst verbunden.</string>
|
||||
<string name="logUnboundFromService">Vom Dienst getrennt.</string>
|
||||
<string name="logServiceAlreadyRunning">Befehl zum Starten des Dienstes, aber er läuft bereits.</string>
|
||||
<string name="whatToDoWithRule">Was soll mit der Regel gemacht werden?</string>
|
||||
<string name="whatToDoWithPoi">Was soll mit dem Ort gemacht werden?</string>
|
||||
<string name="whatToDoWithProfile">Was soll mit dem Profil gemacht werden?</string>
|
||||
@ -73,7 +57,7 @@
|
||||
<string name="end">Ende</string>
|
||||
<string name="save">Speichern</string>
|
||||
<string name="urlToTrigger">URL, die ausgelöst werden soll:</string>
|
||||
<string name="urlLegend">Variablen:\nSie können die folgenden Variablen verwenden. Vor dem Auslösen werden sie mit dem entsprechenden Wert Ihres Geräts ersetzt. Die Klammern müssen in den Text mit aufgenommen werden.\n\n[uniqueid] - Die Unique ID Ihres Geräts\n[serialnr] - Die Seriennummer Ihres Geräts\n[latitude] - Ihr gegenwärtiger Breitengrad\n[longitude] - Ihr gegenwärtiger Längengrad\n[phonenr] - Nummer des letzten ein- oder ausgehenden Anrufs\n[d] - Tag des Monats, 2-stellig mit führender Null\n[m] - Monat als Zahl, mit führenden Nullen\n[Y] - Vierstellige Jahreszahl\n[h] - Stunde im 12-Stunden-Format, mit führenden Nullen\n[H] - Stunde im 24-Stunden-Format, mit führenden Nullen\n[i] - Minuten, mit führenden Nullen\n[s] - Sekunden, mit führenden Nullen\n[ms] - milliseconds</string>
|
||||
<string name="urlLegend">Variablen:\nSie können die folgenden Variablen verwenden. Vor dem Auslösen werden sie mit dem entsprechenden Wert Ihres Geräts ersetzt. Die Klammern müssen in den Text mit aufgenommen werden.\n\n[uniqueid] - Die Unique ID Ihres Geräts\n[serialnr] - Die Seriennummer Ihres Geräts\n[latitude] - Ihr gegenwärtiger Breitengrad\n[longitude] - Ihr gegenwärtiger Längengrad\n[phonenr] - Nummer des letzten ein- oder ausgehenden Anrufs\n[d] - Tag des Monats, 2-stellig mit führender Null\n[m] - Monat als Zahl, mit führenden Nullen\n[Y] - Vierstellige Jahreszahl\n[h] - Stunde im 12-Stunden-Format, mit führenden Nullen\n[H] - Stunde im 24-Stunden-Format, mit führenden Nullen\n[i] - Minuten, mit führenden Nullen\n[s] - Sekunden, mit führenden Nullen\n[ms] - milliseconds\n[notificationTitle] - Titel der letzten Benachrichtigung\n[notificationText] - Text der letzten Benachrichtigung</string>
|
||||
<string name="wifi">WLAN</string>
|
||||
<string name="activating">Aktiviere</string>
|
||||
<string name="deactivating">Deaktiviere</string>
|
||||
@ -98,7 +82,7 @@
|
||||
<string name="generalSettings">Allgemeine Einstellungen</string>
|
||||
<string name="startAtSystemBoot">Beim Gerätestart mitstarten</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="useTextToSpeechOnVibrateSummary">TTS auf vibration</string>
|
||||
<string name="useTextToSpeechOnSilentSummary">TTS auf stumm</string>
|
||||
@ -123,14 +107,14 @@
|
||||
<string name="gpsAccuracy">GPS Genauigkeit [m]</string>
|
||||
<string name="satisfactoryAccuracyNetwork">Genauigkeit für Mobilfunk Änderungen in Metern</string>
|
||||
<string name="networkAccuracy">Mobilfunk Genauigkeit [m]</string>
|
||||
<string name="minimumTimeForLocationUpdates">Minimale Zeitänderung in Sekunden für Positionsupdates</string>
|
||||
<string name="minimumTimeForLocationUpdates">Minimale Zeitänderung in Millisekunden für Positionsupdates</string>
|
||||
<string name="timeForUpdate">Zeit für Updates [millisek]</string>
|
||||
<string name="soundSettings">Ton Einstellungen</string>
|
||||
<string name="showHelp">Hilfe</string>
|
||||
<string name="rules">Regeln</string>
|
||||
<string name="helpTextRules">Alle Auslöser sind UND-verknüpft. D.h. die Regel wird nur zutreffen, wenn alle Bedingungen erfüllt sind. Wenn Sie eine ODER-Verknüpfung möchten, müssen Sie eine weitere Regel erstellen.</string>
|
||||
<string name="timeframes">Zeiträume</string>
|
||||
<string name="helpTextTimeFrame">Wenn Sie eine Regel mit einem oder mehreren Zeiträumen erstellen, haben Sie zwei Möglichkeiten. Sie können wählen, ob der Auslöser besagt, daß der Zeitraum entweder verlassen ODER betreten wird. In jedem Fall wird die Regel nur einmal ausgelöst.\nWenn eine Regel z.B. besagt \"betrete timeframe xyz\" und das Klingeltonprofil in Vibration ändert, bedeutet das NICHT, daß das Gerät hinterher automatisch wieder zum normalen Klingelprofil zurückschaltet. Wenn das erwünscht ist, muß eine weitere Regel mit einem Folgezeitraum erstellen werden.</string>
|
||||
<string name="helpTextTimeFrame">Wenn Sie eine Regel mit einem Zeitraum erstellen, haben Sie zwei Möglichkeiten. Sie können wählen, ob der Auslöser besagt, daß der Zeitraum entweder verlassen ODER betreten wird. In jedem Fall wird die Regel nur einmal ausgelöst. Wenn eine Regel z.B. besagt \"betrete timeframe xyz\" und das Klingeltonprofil in Vibration ändert, bedeutet das NICHT, daß das Gerät hinterher automatisch wieder zum normalen Klingelprofil zurückschaltet. Wenn das erwünscht ist, muß eine weitere Regel mit einem Folgezeitraum erstellen werden.</string>
|
||||
<string name="helpTextSound">Auf dem Hauptbildschirm können Sie die Funktion Tonänderunugen sperren benutzen, um vorrübergehend regelbasierte Tonänderungen zu deaktivieren. Z.B. könnten Sie in einer Situation oder an einem Ort sein, wo Klingeltöne normalerweise in Ordnung sind, aber dieses eine Mal würde es stören. Die Funktion wird automatisch wieder deaktiviert nachdem die eingestellte Zeit abgelaufen ist. Klicken Sie den + Knopf, um die angezeigte Zeit zur Frist hinzuzufügen. Sobald es aktiv ist, können Sie es mit dem Schalter rechts wieder abschalten (und so regelbasierte Tonänderungen wieder ermöglichen).</string>
|
||||
<string name="toggableRules">Umkehrbare Regeln</string>
|
||||
<string name="helpTextToggable">Regeln haben eine Einstellung namens \"Umschaltbar\". Das bedeutet: Wurde eine Regel ausgeführt und anschließend treten dieselben Auslöser wieder ein, wird die Regel nochmal in umgekehrter Weise ausgeführt, wo es möglich ist. Gegenwärtig funktioniert das nur im Zusammenspiel mit NFC Tags. Wenn Sie einen Tag zwei Mal berühren und es eine umschaltbare Regel zu diesem Tag gibt, wird das Programm das Gegenteil von gegenwärtigen Zustand tun, z.B. WLAN ausschalten, wenn es gegenwärtig eingeschaltet ist.</string>
|
||||
@ -148,7 +132,7 @@
|
||||
<string name="lengthOfNoiseLevelMeasurementsTitle">Länge einer Lautstärkemessung in Sekunden</string>
|
||||
<string name="referenceValueForNoiseLevelMeasurementsSummary">Physikalischer Referenzwert für Lautstärkemessungen</string>
|
||||
<string name="referenceValueForNoiseLevelMeasurementsTitle">Referenz für Lautstärkemessungen</string>
|
||||
<string name="logLevelSummary">Protokollierungsgrad (1=minimum, 5=maximum)</string>
|
||||
<string name="logLevelSummary">Protokollierungsgrad (1=Minimum, 5=Maximum)</string>
|
||||
<string name="logLevelTitle">Protokollierungsgrad</string>
|
||||
<string name="ruleActive">Regel aktiv</string>
|
||||
<string name="triggerPointOfInterest">Ort</string>
|
||||
@ -190,38 +174,13 @@
|
||||
<string name="serviceNotRunning">Dienst läuft nicht.</string>
|
||||
<string name="general">Allgemein</string>
|
||||
<string name="generalText">Um dieses Programm zu benutzen, müssen Sie Regeln anlegen. Diese enthalten Auslöser (z.B. ob Sie ein bestimmtes Gebiet betreten oder eine bestimmte Zeitspanne beginnt). Nachdem Sie dies erledigt haben, klicken Sie auf den Ein/Aus Schalter auf dem Hauptbildschirm.</string>
|
||||
<string name="unknownActionSpecified">Unbekannte Aktion definiert.</string>
|
||||
<string name="errorTriggeringUrl">Fehler beim Aufrufen der URL</string>
|
||||
<string name="errorChangingScreenRotation">Fehler beim Ändern der Bildschirmrotation</string>
|
||||
<string name="errorDeterminingWifiApState">Fehler bei der Statusprüfung des WLAN Routers</string>
|
||||
<string name="errorActivatingWifiAp">Fehler beim Aktivieren des WLAN Routers</string>
|
||||
<string name="failedToTriggerBluetooth">Fehler beim Ändern des Bluetooth Status. Hat dieses Gerät Bluetooth?</string>
|
||||
<string name="logAttemptingDownloadOf">Versuche Download von</string>
|
||||
<string name="logErrorGettingConnectionManagerService">Fehler beim Anbinden an den connectionManager Dienst. Ändere nichts am Usb-Router Status.</string>
|
||||
<string name="logErrorDeterminingCurrentUsbTetheringState">Fehler beim Aufrufen des gegenwärtigen USB-Router Status.</string>
|
||||
<string name="logDetectingTetherableUsbInterface">Überprüfe routingfähiges Interface.</string>
|
||||
<string name="logClearingBothLocationListeners">Stoppe beide LocationListener.</string>
|
||||
<string name="logStartingServiceAfterAppUpdate">Starte Dienst nach Programm Aktualisierung. Er lief vor der Aktualisierung schon.</string>
|
||||
<string name="logNotStartingServiceAfterAppUpdate">Starte Dienst nicht automatisch nach Programm Aktualisierung. Er lief davor nicht.</string>
|
||||
<string name="logStartingServiceAtPhoneBoot">Starte Dienst nach Neustart des Telefons.</string>
|
||||
<string name="logNotStartingServiceAtPhoneBoot">Starte Dienst nicht automatisch nach Neustart des Telefons.</string>
|
||||
<string name="applicationHasBeenUpdated">Die Anwendung wurde aktualisiert.</string>
|
||||
<string name="startServiceAfterAppUpdate">Dienst nach Anwendungsupdate automatisch wieder starten, wenn er vorher lief.</string>
|
||||
<string name="startServiceAfterAppUpdateShort">Starte Dienst nach Update</string>
|
||||
<string name="wifiConnection">WLAN Verbindung</string>
|
||||
<string name="wifiName">WLAN name</string>
|
||||
<string name="enterWifiName">Geben Sie den Namen des WLANs ein (SSID). Leer lassen für irgendein WLAN.</string>
|
||||
<string name="cancel">Abbrechen</string>
|
||||
<string name="ruleDoesntApplyWeAreSlowerThan">Regel trifft nicht zu. Wir sind langsamer als</string>
|
||||
<string name="ruleDoesntApplyWeAreFasterThan">Regel trifft nicht zu. Wir sind schneller als</string>
|
||||
<string name="ruleDoesntApplyItsQuieterThan">Regel trifft nicht zu. Es ist ruhiger als</string>
|
||||
<string name="ruleDoesntApplyItsLouderThan">Regel trifft nicht zu. Es ist lauter als</string>
|
||||
<string name="ruleDoesntApplyBatteryLowerThan">Regel trifft nicht zu. Akkustand ist niedriger als</string>
|
||||
<string name="ruleDoesntApplyBatteryHigherThan">Regel trifft nicht zu. Akkustand ist höher als</string>
|
||||
<string name="ruleDoesntApplyNotTheCorrectSsid">Regel trifft nicht zu. Nicht die korrekte SSID (gefordert: \"%1$s\", gegeben: \"%2$s\").</string>
|
||||
<string name="ruleDoesntApplyNoTagLabel">Regel trifft nicht zu. Keine Tag Bezeichnung oder kein Tag.</string>
|
||||
<string name="ruleDoesntApplyWrongTagLabel">Regel trifft nicht zu. Falsche Tag Bezeichnung.</string>
|
||||
<string name="ruleIsDeactivatedCantApply">Regel %1$s ist deaktiviert, kann nicht zutreffen.</string>
|
||||
<string name="starting">starte</string>
|
||||
<string name="stopping">stoppe</string>
|
||||
<string name="connecting">verbinde</string>
|
||||
@ -244,12 +203,8 @@
|
||||
<string name="runManually">Manuell ausführen</string>
|
||||
<string name="serviceHasToRunForThat">Der Dienst muß dafür laufen.</string>
|
||||
<string name="gpsComparison">GPS Vergleich</string>
|
||||
<string name="gpsComparisonTimeoutStop">Stoppe GPS Vergleichsmessung, Zeitlimit überschritten.</string>
|
||||
<string name="timeoutForGpsComparisonsTitle">GPS Zeitlimit [sek]</string>
|
||||
<string name="timeoutForGpsComparisonsSummary">Zeitlimit in Sekunden wie lange versucht wird eine GPS Vergleichsposition zu finden. Danach wird die letzte bekannte Position übernommen.</string>
|
||||
<string name="startingGpsTimeout">Starting GPS timeout.</string>
|
||||
<string name="forcedLocationUpdate">Erzwungenes Positionsupdate</string>
|
||||
<string name="forcedLocationUpdateLong">Da Zeitlimit für Vergleichsmessung überschritten wird jetzt die letzte bekannte Position übernommen.</string>
|
||||
<string name="rememberLastActivePoiSummary">Wenn Sie an einem Ort sind, Ihr Gerät oder die Anwendung neustarten und den Ort verlassen wird die Anwendung beim nächsten Start Regeln ausführen, die für das Verlassen des Orts definiert sind.</string>
|
||||
<string name="rememberLastActivePoiTitle">Merke den zuletzt aktiven Ort</string>
|
||||
<string name="muteTextToSpeechDuringCallsTitle">Während Telefonaten stumm</string>
|
||||
@ -257,7 +212,7 @@
|
||||
<string name="anotherPoiByThatName">Es gibt bereits einen Ort mit diesem Namen.</string>
|
||||
<string name="anotherRuleByThatName">Es gibt bereits eine Regel mit diesem Namen.</string>
|
||||
<string name="startOtherActivity">Programm starten</string>
|
||||
<string name="selectApplication">Wählen Sie eine Anwendung</string>
|
||||
<string name="selectApplication">Anwendung wählen</string>
|
||||
<string name="selectPackageOfApplication">Wählen Sie ein Paket der Anwendung</string>
|
||||
<string name="selectActivityToBeStarted">Wählen Sie die Activity des Pakets</string>
|
||||
<string name="errorStartingOtherActivity">Fehler beim Starten einer anderen Anwendung</string>
|
||||
@ -265,35 +220,14 @@
|
||||
<string name="settingsCategoryProcessMonitoring">Prozess Überwachung</string>
|
||||
<string name="timeBetweenProcessMonitoringsTitle">Sekunden zwischen Prozess-Überwachungen</string>
|
||||
<string name="timeBetweenProcessMonitoringsSummary">Je niedriger desto höher der Akkuverbrauch</string>
|
||||
<string name="refreshingProcessList">Refreshing process list.</string>
|
||||
<string name="processes">Processes</string>
|
||||
<string name="startingPeriodicProcessMonitoringEngine">Starting periodic process monitoring engine.</string>
|
||||
<string name="processMonitoring">Prozessüberwachung</string>
|
||||
<string name="periodicProcessMonitoringIsAlreadyRunning">Periodische Prozessüberwachung läuft bereits. Kann sie nicht nochmal starten.</string>
|
||||
<string name="stoppingPeriodicProcessMonitoringEngine">Stoppe Prozessüberwachungs-Dienst.</string>
|
||||
<string name="periodicProcessMonitoringIsNotActive">Prozessüberwachung läuft nicht. Kann sie nicht stoppen.</string>
|
||||
<string name="periodicProcessMonitoringStarted">Prozessüberwachung gestarted.</string>
|
||||
<string name="periodicProcessMonitoringStopped">Prozessüberwachung gestopped.</string>
|
||||
<string name="rearmingProcessMonitoringMessage">Prozessüberwachung wird erneut scharf geschaltet.</string>
|
||||
<string name="notRearmingProcessMonitoringMessageStopRequested">Schalte Prozessüberwachung nicht erneut scharf, Stop angefragt.</string>
|
||||
<string name="messageReceivedStatingProcessMonitoringIsComplete">Nachricht erhalten, die besagt, daß Prozessüberwachung fertig ist.</string>
|
||||
<string name="appStarted">App gestarted.</string>
|
||||
<string name="appStopped">App gestopped.</string>
|
||||
<string name="runningApp">Laufende app</string>
|
||||
<string name="errorWritingSettingsToPersistentMemory">Fehler beim Speichern der Einstellungen.</string>
|
||||
<string name="settings">Einstellungen</string>
|
||||
<string name="writingSettingsToPersistentMemory">Einstellungen werden gespeichert.</string>
|
||||
<string name="refreshingSettingsFromFileToMemory">Einstellungen werden neu geladen.</string>
|
||||
<string name="errorReadingSettings">Fehler beim Lesen der Einstellungen.</string>
|
||||
<string name="invalidStuffStoredInSettingsErasing">Ungültige Daten in den Einstellungen gefunden. Einstellungen werden gelöscht.</string>
|
||||
<string name="initializingSettingsToPersistentMemory">Einstellungen werden in nicht flüchtigen Speicher initialisiert.</string>
|
||||
<string name="errorInitializingSettingsToPersistentMemory">Fehler beim Initialisieren der Einstellungen.</string>
|
||||
<string name="settingsErased">Einstellungen gelöscht.</string>
|
||||
<string name="settingsSetToDefault">Einstellungen auf Standardwerte gesetzt.</string>
|
||||
<string name="batteryLevel">Akkustand</string>
|
||||
<string name="selectSpeed">Geschwindigkeit wählen</string>
|
||||
<string name="selectBattery">Akkustand wählen</string>
|
||||
<string name="applyingSettingsAndRules">Aktualisiere Einstellungen, Regeln und Orte.</string>
|
||||
<string name="privacy">Datenschutzerklärung</string>
|
||||
<string name="privacyConfirmationText">Ein Browser wird nun geöffnet und die Datenschutzerklärung von der Webseite des Entwicklers laden.</string>
|
||||
<string name="waitBeforeNextAction">Vor der nächsten Aktion warten</string>
|
||||
@ -305,15 +239,10 @@
|
||||
<string name="moveDown">Herunterschieben</string>
|
||||
<string name="cantMoveUp">Das Objekt kann nicht weiter hochgeschoben werden.</string>
|
||||
<string name="cantMoveDown">Das Objekt kann nicht weiter heruntergeschoben werden.</string>
|
||||
<string name="wifiNameSpecifiedCheckingThat">WLAN SSID angegeben, überprüfe...</string>
|
||||
<string name="wifiNameMatchesRuleWillApply">WLAN SSID stimmt überein. Regel trifft zu.</string>
|
||||
<string name="noWifiNameSpecifiedAnyWillDo">Keine WLAN SSID angegeben. Jedes WLAN trifft zu.</string>
|
||||
<string name="ruleCheckOf">RuleCheck von %1$s</string>
|
||||
<string name="airplaneMode">Flugmodus</string>
|
||||
<string name="activate">Aktivieren</string>
|
||||
<string name="deactivate">Deaktivieren</string>
|
||||
<string name="airplaneModeSdk17Warning">Seit Android Version 4.2 funktioniert diese Funktion - wenn überhaupt - nur noch mit gerooteten Geräten.</string>
|
||||
<string name="triggerUrlReplacementPositionError">Laut Ihren Einstellungen sollte der aufzurufenden Adresse eine Position hinzugefügt werden. Leider ist der im Moment nicht möglich, daß noch keine Position bekannt ist.</string>
|
||||
<string name="addIntentValue">Parameter-Paar hinzufügen</string>
|
||||
<string name="parameterName">Parameter Name</string>
|
||||
<string name="parameterValue">Parameter Wert</string>
|
||||
@ -342,7 +271,7 @@
|
||||
<string name="with">mit</string>
|
||||
<string name="phoneNumber">Telefonnummer</string>
|
||||
<string name="enterPhoneNumber">Geben Sie eine Telefonnummer ein. Leer lassen für irgendeine Nummer.</string>
|
||||
<string name="phoneDirection">Wählen Sie die Gesprächsrichtung</string>
|
||||
<string name="phoneDirection">Wählen Sie die\nGesprächsrichtung</string>
|
||||
<string name="any">egal</string>
|
||||
<string name="incoming">eingehend</string>
|
||||
<string name="outgoing">ausgehend</string>
|
||||
@ -366,7 +295,6 @@
|
||||
<string name="nfcNoNdefIntentBut">Kein NFC NDEF intent, sondern</string>
|
||||
<string name="nfcNotSupportedInThisAndroidVersionYet">NFC wird in dieser Android Version noch nicht unterstützt.</string>
|
||||
<string name="cantRunRule">Regeln können nicht ausgeführt werden.</string>
|
||||
<string name="cantDownloadTooFewRequestsInSettings">Kann nichts runterladen. Menge an erlaubten Versuchen ist in den Einstellungen auf weniger als 1 gesetzt.</string>
|
||||
<string name="nfcApplyTagToRule">Aktuellen Tag in Regel übernehmen</string>
|
||||
<string name="nfcTagReadSuccessfully">Tag erfolgreich gelesen.</string>
|
||||
<string name="nfcValueNotSuitable">Gepspeicherter Wert nicht geeignet.</string>
|
||||
@ -381,30 +309,24 @@
|
||||
<string name="toggling">Schalte um</string>
|
||||
<string name="toggle">umzuschalten</string>
|
||||
<string name="overlapBetweenPois">Überschneidung mit Ort %1$s von %2$s Metern festgestellt. Reduzieren Sie den Radius um mindestens diesen Wert.</string>
|
||||
<string name="noOverLap">Keine Überschneidung mit anderen Orten festgestellt.</string>
|
||||
<string name="ruleToggable">Regel %1$s ist umkehrbar.</string>
|
||||
<string name="ruleNotToggable">Regel %1$s ist nicht umkehrbar.</string>
|
||||
<string name="none">keiner</string>
|
||||
<string name="anyLocation">irgendein Ort</string>
|
||||
<string name="invalidPoiName">Ungültiger Name für einen Ort.</string>
|
||||
<string name="eraseSettings">Einstellungen löschen</string>
|
||||
<string name="defaultSettings">Standard Einstellungen</string>
|
||||
<string name="areYouSure">Sind sie sicher?</string>
|
||||
<string name="poiCouldBeInRange">Mindestens Ort %1$s könnte im nahen Umkreis liegen, wenn nicht noch andere.</string>
|
||||
<string name="noPoiInRelevantRange">Kein Ort im näheren Umkreis.</string>
|
||||
<string name="activityDetection">Aktivitätserkennung</string>
|
||||
<string name="detectedActivity">Erkannte Tätigkeit:</string>
|
||||
<string name="detectedActivityInVehicle">In einem Fahrzeug (Auto/Bus)</string>
|
||||
<string name="detectedActivityOnBicycle">Auf dem Fahrrad</string>
|
||||
<string name="detectedActivityOnFoot">Zu Fuß</string>
|
||||
<string name="detectedActivityStill">Ruhe</string>
|
||||
<string name="detectedActivityUnknown">Unbekannt</string>
|
||||
<string name="detectedActivityUnknown">unbekannt</string>
|
||||
<string name="detectedActivityTilting">Kippen</string>
|
||||
<string name="detectedActivityWalking">Gehen</string>
|
||||
<string name="detectedActivityRunning">Laufen</string>
|
||||
<string name="detectedActivityInvalidStatus">Ungültige Tätigkeit</string>
|
||||
<string name="ruleDoesntApplyActivityGivenButTooLowProbability">Regel trifft nicht zu. Erkannte Tätigkeit %1$s gegebenem, aber mit zu niedriger Wahrscheinlichkeit (%2$s %%), gefordert %3$s %%.</string>
|
||||
<string name="ruleDoesntApplyActivityNotPresent">Regel trifft nicht zu. Geforderte Tätigkeit %1$s passiert gerade nicht.</string>
|
||||
<string name="selectTypeOfActivity">Art der Tätigkeit auswählen</string>
|
||||
<string name="triggerOnlyAvailableIfPlayServicesInstalled">Dieser Auslöser kann nur verwendet werden, wenn die Google Play Dienste installiert sind.</string>
|
||||
<string name="activityDetectionFrequencyTitle">Frequenz für Aktivitätserkennung [sek]</string>
|
||||
@ -412,7 +334,7 @@
|
||||
<string name="activityDetectionRequiredProbabilityTitle">Wahrscheinlichkeit für Aktivitätserkennungen</string>
|
||||
<string name="activityDetectionRequiredProbabilitySummary">Wahrscheinlichkeit, ab der eine Aktivität als gegeben gilt.</string>
|
||||
<string name="incomingCallFrom">Eingehender Telefonanruf von %1$s.</string>
|
||||
<string name="outgoingCallFrom">Ausgehender Telefonanruf von %1$s.</string>
|
||||
<string name="outgoingCallTo">Ausgehender Telefonanruf von %1$s.</string>
|
||||
<string name="actionSpeakText">Text sprechen</string>
|
||||
<string name="textToSpeak">Zu sprechender Text</string>
|
||||
<string name="toggleNotAllowed">Die Umschaltfunktion ist momentan nur für Regeln erlaubt, die NFC Tags als Auslöser haben. Für weitere Informationen lesen Sie die Hilfe.</string>
|
||||
@ -424,9 +346,7 @@
|
||||
<string name="bluetoothDeviceInRange">Bluetooth Gerät %1$s in Reichweite.</string>
|
||||
<string name="bluetoothDeviceOutOfRange">Bluetooth Gerät %1$s außer Reichweite.</string>
|
||||
<string name="anyDevice">irgendeinem Gerät</string>
|
||||
<string name="ruleDoesntApplyNotTheCorrectDeviceName">Regel trifft nicht zu. Nicht der korrekte Bluetooth-Geräte-Name.</string>
|
||||
<string name="ruleDoesntApplyNotTheCorrectDeviceAddress">Regel trifft nicht zu. Nicht die korrekte Bluetooth-Geräte-Adresse.</string>
|
||||
<string name="noDevice">kein Gerät</string>
|
||||
<string name="noDevice">kein Gerät</string>
|
||||
<string name="selectDeviceFromList">Gerät aus Liste</string>
|
||||
<string name="connectionToDevice">Gerät verbunden</string>
|
||||
<string name="disconnectionFromDevice">Gerät getrennt</string>
|
||||
@ -434,9 +354,7 @@
|
||||
<string name="deviceOutOfRange">Gerät außer Reichweite</string>
|
||||
<string name="selectDeviceOption">Wählen Sie eine Geräteoption.</string>
|
||||
<string name="selectConnectionOption">Wählen Sie eine Verbindungsoption.</string>
|
||||
<string name="ruleDoesntApplyDeviceInRangeButShouldNotBe">Regel trifft nicht zu. Gerät ist in Reichweite, aber sollte nicht sein.</string>
|
||||
<string name="ruleDoesntApplyStateNotCorrect">Regel trifft nicht zu. Falscher Status.</string>
|
||||
<string name="triggerHeadsetPlugged">Headset Verbindung</string>
|
||||
<string name="triggerHeadsetPlugged">Headset Verbindung</string>
|
||||
<string name="actionPlayMusic">Musikplayer öffnen</string>
|
||||
<string name="headsetConnected">Headset (type: %1$s) verbunden</string>
|
||||
<string name="headsetDisconnected">Headset (type: %1$s) getrennt</string>
|
||||
@ -444,28 +362,17 @@
|
||||
<string name="headphoneMicrophone">Mikrofon</string>
|
||||
<string name="headphoneAny">Egal</string>
|
||||
<string name="headphoneSelectType">Kopfhörer Typ auswählen</string>
|
||||
<string name="ruleDoesntApplyWrongHeadphoneType">Regel trifft nicht zu. Falscher Kopfhörertyp.</string>
|
||||
<string name="ignoringActivityDetectionUpdateTooSoon">Ignoriere Aktivitätserkennungsupdate. Kam früher rein als %1$s Sekunden.</string>
|
||||
<string name="whatsThis">Was ist das?</string>
|
||||
<string name="atLeastRuleXisUsingY">Mindestens Regel \"%1$s\" nutzt einen Auslöser vom Typ \"%2$s\".</string>
|
||||
<string name="privacyLocationingTitle">Private Ortung verwenden</string>
|
||||
<string name="whatsThis">Was ist das?</string>
|
||||
<string name="privacyLocationingTitle">Private Ortung verwenden</string>
|
||||
<string name="privacyLocationingSummary">Ortungsmethoden vermeiden, die Ihre Position dazu an einen Anbieter übermitteln, z.B. Google. Dies wird nur GPS verwenden und daher langsam sein oder nicht ausreichend zuverlässig funktionieren.</string>
|
||||
<string name="enforcingGps">Private Ortung aktiviert, erzwinge GPS Verwendung.</string>
|
||||
<string name="notEnforcingGps">Private Ortung nicht aktiviert, verwende reguläre Anbieterauswahl.</string>
|
||||
<string name="gpsMeasurement">GPS Messung</string>
|
||||
<string name="gpsMeasurementTimeout">GPS Messung aufgrund Timeout gestoppt.</string>
|
||||
<string name="cellMastChanged">Mobilfunkmast geändert: %1$s</string>
|
||||
<string name="noiseDetectionHint">Wenn Sie denken die Lautstärkeerkennung arbeitet nicht korrekt (abhängig von dem Wert, den Sie angeben), bedenken Sie bitte, daß jedes Telefon unterschiedlich ist. In den Einstellungen können Sie daher die \"Referenz für Lautstärkemessungen\" ändern. Für weitere Informationen siehe http://de.wikipedia.org/wiki/Schalldruckpegel. Sie können den Lautstärkentester vom Hauptbildschirm aus aufrufen, um Ihr Gerät zu kalibrieren.</string>
|
||||
<string name="noiseDetectionHint">Wenn Sie denken die Lautstärkeerkennung arbeitet nicht korrekt (abhängig von dem Wert, den Sie angeben), bedenken Sie bitte, daß jedes Telefon unterschiedlich ist. In den Einstellungen können Sie daher die \"Referenz für Lautstärkemessungen\" ändern. Für weitere Informationen siehe http://de.wikipedia.org/wiki/Schalldruckpegel. Sie können den Lautstärkentester vom Hauptbildschirm aus aufrufen, um Ihr Gerät zu kalibrieren.</string>
|
||||
<string name="hint">Hinweis</string>
|
||||
<string name="selectNoiseLevel">Lautstärkepegel auswählen</string>
|
||||
<string name="poiHasWifiStoppingCellLocationListener">Ort hat WLAN. Stoppe CellLocationListener.</string>
|
||||
<string name="poiHasNoWifiNotStoppingCellLocationListener">Ort hat kein WLAN. Stoppe CellLocationListener nicht.</string>
|
||||
<string name="showOnMap">Auf Karte zeigen</string>
|
||||
<string name="showOnMap">Auf Karte zeigen</string>
|
||||
<string name="noMapsApplicationFound">Auf Ihrem Gerät konnte keine Kartenanwendung gefunden werden.</string>
|
||||
<string name="locationEngineNotActive">Positionsbestimmung nicht aktiv.</string>
|
||||
<string name="addProfile">Profil erstellen</string>
|
||||
<string name="profileList">Profile</string>
|
||||
<string name="profile">Profil</string>
|
||||
<string name="profile">Profil</string>
|
||||
<string name="soundMode">Tonmodus</string>
|
||||
<string name="volumes">Lautstärken</string>
|
||||
<string name="incomingCallsRingtone">Ton für eingehende Anrufe</string>
|
||||
@ -482,7 +389,7 @@
|
||||
<string name="soundModeNormal">Normal</string>
|
||||
<string name="soundModeVibrate">Vibration</string>
|
||||
<string name="soundModeSilent">Stumm</string>
|
||||
<string name="enterAname">Enter a name!</string>
|
||||
<string name="enterAname">Enter a name.</string>
|
||||
<string name="noChangeSelectedProfileDoesntMakeSense">Keine Veränderungen ausgewählt. Profil macht so keinen Sinn.</string>
|
||||
<string name="noProfilesCreateOneFirst">Es existieren keine Profile. Erstellen Sie erst eins.</string>
|
||||
<string name="errorActivatingProfile">Fehler beim Aktivieren des Profils:</string>
|
||||
@ -506,10 +413,6 @@
|
||||
<string name="volumeTest">Lautstärkentest</string>
|
||||
<string name="volumeTesterExplanation">Um einen dB Wert für die Lautstärkemessung zu berechnen müssen Sie einen sogenannten physikalischen Referenzwert angeben. Bitte lesen Sie bei Wikipedia nach, um mehr zu erfahren. Dieser Wert wird höchstwahrscheinlich für jedes Smartphone oder Tablet anders sein, deshalb diese Testanwendung. Verschieben Sie den Regler, um den gegenwärtig definierten Wert zu ändern. Je höher der Referenzwert desto niedriger wird der dB Wert. Es werden alle paar %1$s Sekunden neue Messungen vorgenommen und das Ergebnis unten angezeigt. Drücken Sie den zurück-Button, wenn Sie einen passenden Wert gefunden haben.</string>
|
||||
<string name="settingsWillTakeTime">Manche Einstellungen können nicht übernommen werden bevor der Dienst neu gestartet wird.</string>
|
||||
<string name="phoneIsRooted">Das Gerät ist gerootet.</string>
|
||||
<string name="phoneIsNotRooted">Das Gerät ist nicht gerootet.</string>
|
||||
<string name="dataConWithRootSuccess">Die Datenverbindung wurde mit superUser Rechten erfolgreich geändert.</string>
|
||||
<string name="dataConWithRootFail">Die Datenverbindung konnte mit superUser Rechten nicht geändert werden.</string>
|
||||
<string name="rootExplanation">Sie müssen Ihr Telefon rooten, damit diese Funktion funktionieren kann. Danach müssen Sie "Regel manuell ausführen", um den SuperUser Berechtigungsdialog zu zeigen. Wenn dieser erscheint, müssen Sie den Haken setzen, der es immer erlaubt. Ansonsten kann die Regel nicht funktionieren, wenn Sie das Telefon gerade nicht benutzen und demnach den nächsten Dialog nicht genehmigen können.</string>
|
||||
<string name="errorWritingConfig">Fehler beim Schreiben der Konfiguration. Gibt es einen beschreibbaren Speicher, und wurde alle Berechtigungen gegeben?</string>
|
||||
<string name="phoneNrReplacementError">Die letzte Telefonnummer konnte nicht in die Variable integriert werden. Sie liegt mir nicht vor.</string>
|
||||
@ -533,7 +436,6 @@
|
||||
<string name="appRequiresPermissiontoAccessExternalStorage">Automation benötigt Rechte, um auf den Speicher zuzugreifen, um seine Konfiguration und Regeln lesen zu können.</string>
|
||||
<string name="mainScreenPermissionNote">Automation benötigt mehr Rechte, um vollständig funktionsfähig zu sein. Klicken Sie auf diesen Text, um mehr zu erfahren und die fehlenden Rechte zu beantragen.</string>
|
||||
<string name="invalidDevice">Ungültiges Gerät</string>
|
||||
<string name="google_app_id">your app id</string>
|
||||
<string name="logFileMaxSizeSummary">Maximale Größe der Protokolldatei in Megabyte. Wenn sie größer wird, wird sie rotiert.</string>
|
||||
<string name="logFileMaxSizeTitle">Maximale Größe des Protokolls [Mb]</string>
|
||||
<string name="android.permission.READ_CALL_LOG">Telefonprotokoll lesen</string>
|
||||
@ -595,7 +497,101 @@
|
||||
<string name="manageLocations">Orte anlegen oder ändern</string>
|
||||
<string name="publishedOn">veröffentlicht am</string>
|
||||
<string name="filesHaveBeenMovedTo">Automation benutzt jetzt ein anderes Verzeichnis, um Ihre Daten zu speichern. Alle Ihre Automation-Dateien wurden hierhin verschoben: \"%s\". Die Berechtigung für den externen Speicher wird nun nicht mehr benötigt; Sie können Sie entfernen. In einer künftigen Version wird sie entfernt werden.</string>
|
||||
<string name="locationEngineDisabledShort">Die Position kann nicht mehr bestimmt werden.</string>
|
||||
<string name="locationEngineDisabledShort">Die Position kann nicht mehr im Hintergrund bestimmt werden. Klicken Sie hier für mehr Infos.</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. Klicken Sie hier auf diesen Text, um dieses Verzeichnis in einem Datei-Explorer zu öffnen. Leider funktioniert das nur auf gerooteten Geräten.\n\nFür alle anderen Geräte: Benutzen Sie einfach den Export Button, wenn Sie eine Sicherung anlegen wollen.</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="addParameters">Parameter hinzufügen</string>
|
||||
<string name="errorRunningRule">Fehler beim Ausführen einer Regel.</string>
|
||||
<string name="startAppChoiceNote">Hier haben Sie 2 grundsätzliche Optionen:\n\n1. Sie können ein Programm starten, indem Sie eine Activity auswählen.\nStellen Sie sich das so vor, daß Sie ein bestimmtes Fenster einer Anwendung vorauswählen, in das man direkt springt. Behalten Sie im Kopf, daß das nicht immer funktionieren wird. Das liegt daran, daß die Fenster einer Anwendung miteinander interagieren können, sich u.U. Parameter übergeben. Wenn man jetzt ganz kalt in ein bestimmtes Fenster springt, könnte dieses zum Start z.B. bestimmte Parameter erwarten - die fehlen. So könnte es passieren, daß das Fenster zwar versucht zu öffnen, das aber nicht klappt und es somit nie wirlich sichtbar wird. Versuchen Sie\'s trotzdem!\nSie können den Pfad manuell eingeben, sollten aber den Auswählen-Knopf benutzen. Wenn Sie es dennoch manuell eingeben, geben Sie den PackageName ins obere Feld ein und den vollen Pfad der Activity ins untere.\n\n2. Auswahl per Action\nIm Gegensatz zur Auswahl eines bestimmten Fensters, können Sie ein Programm auch über eine Action starten lassen. Stellen Sie sich das so vor als würden Sie in den Wald rufen \"Ich hätte gerne XYZ\" und falls eine Anwendung installiert ist, die das liefern kann, wird sie gestartet. Ein gutes Beispiel wäre zum Beispiel "Browser starten" - es könnten sogar mehrere installiert sein, die das können (aber normalerweise gibts eine, die als Standard eingestellt ist).\nDiese Action müssen Sie manuell eingeben. Der PackageName ist hier optional. Behalten Sie dabei im Auge, daß mögliche Variablen nicht aufgelöst werden. Beispielsweise werden Sie häufig im Internet finden, daß man die Kamera über die Action \"MediaStore.ACTION_IMAGE_CAPTURE\" starten kann. Das ist grundsätzlich nicht richtig, wird aber nicht direkt funktionieren, denn das ist nur eine Variable. Sie müssen dann einen Blick in die Android Dokumentation werfen, wo Sie sehen werden, daß sich hinter dieser Variable eigentlich der Wert \"android.media.action.IMAGE_CAPTURE\" verbirgt. Gibt man diesen in das Feld ein, wird\'s funktionieren.</string>
|
||||
<string name="cantFindSoundFile">Kann die Audiodatei %1$s nicht finden und daher auch nicht abspielen.</string>
|
||||
<string name="startAppByActivity">per Activity</string>
|
||||
<string name="startAppByAction">per Action</string>
|
||||
<string name="startAppSelectionType">Auswahlmethode</string>
|
||||
<string name="com.wireguard.android.permission.CONTROL_TUNNELS">Tunnelverbindungen der Wireguard Anwendung steuern</string>
|
||||
<string name="enterPackageName">Geben Sie einen gültigen Paketnamen ein.</string>
|
||||
<string name="configurationExportedSuccessfully">Konfiguration erfolgreich exportiert.</string>
|
||||
<string name="ConfigurationExportError">Beim Exportieren der Konfiguration ist ein Fehler aufgetreten.</string>
|
||||
<string name="configurationImportedSuccessfully">Konfiguration erfolgreich importiert.</string>
|
||||
<string name="enterValidAction">Geben Sie eine gültige Action ein.</string>
|
||||
<string name="exportConfiguration">Konfiguration exportieren</string>
|
||||
<string name="importConfiguration">Konfiguration importieren</string>
|
||||
<string name="moreSettings">Mehr Einstellungen</string>
|
||||
<string name="importExportExplanation">Wenn Sie auf im- oder exportieren klicken, müssen Sie im nächsten Schritt das Verzeichnis auswählen, in das Dateien exportiert oder von dem Dateien importiert werden. Im Falle des Exports können vorhandene Dateien in diesem Ordner überschrieben werden.</string>
|
||||
<string name="intentDataComment">Wenn Ihr Parameter vom Typ \"Uri\" ist und Sie \"IntentName\" als Name angeben (Groß-/Kleinschreibung ist irrelevant), wird der Parameter nicht als normaler Parameter mit putExtra() angehängt, sondern wird stattdessen mit setData() angehängt.</string>
|
||||
<string name="noApplicableFilesFoundInDirectory">Keine passenden Dateien im Ordner gefunden.</string>
|
||||
<string name="noFilesImported">Keine Dateien konnten importiert werden.</string>
|
||||
<string name="notAllFilesImported">Nicht alle passenden Dateien konnten importiert werden.</string>
|
||||
<string name="openExamplesPage">Webseite mit Beispielen öffnen</string>
|
||||
<string name="phoneNumberExplanation">Sie können eine bestimmte Nummer eingeben, aber müssen nicht. Wenn Sie eine angeben wollen, können Sie auch eine aus dem Adressbuch auswählen. Außerdem können Sie reguläre Audrücke verwenden. Zum Testen selbiger mag ich die Seite:</string>
|
||||
<string name="prefsImportError">Fehler beim Importieren der Einstellungen.</string>
|
||||
<string name="rulesImportedSuccessfully">Regeln und Orte wurden erfolgreich importiert.</string>
|
||||
<string name="rulesImportError">Fehler beim Importieren der Regeln.</string>
|
||||
<string name="startAppBySendBroadcast">per sendBroadcast()</string>
|
||||
<string name="startAppByStartActivity">per startActivity()</string>
|
||||
<string name="startAppStartType">Start-Typ wählen</string>
|
||||
<string name="state">Status</string>
|
||||
<string name="stringNotAllowed">Zeichenkette %1$s is nicht erlaubt.</string>
|
||||
<string name="android.permission.ACTIVITY_RECOGNITION">Aktivitätserkennung</string>
|
||||
<string name="packageName">Paketname</string>
|
||||
<string name="activityOrActionName">Acitivity/Action name</string>
|
||||
<string name="warning">Warnung</string>
|
||||
<string name="ringing">klingelt</string>
|
||||
<string name="from">von</string>
|
||||
<string name="to">an</string>
|
||||
<string name="matching">übereinstimmend</string>
|
||||
<string name="loadWifiList">WLAN Liste laden</string>
|
||||
<string name="noKnownWifis">Es gibt keine bekannten WLANs auf Ihrem Gerät.</string>
|
||||
<string name="needLocationPermForWifiList">Die Liste von WLANs auf Ihrem Gerät könnte verwendet werden, um zu ermitteln, an welchen Orten Sie waren. Deshalb ist die Positions-Berechtigung nötig, um die Liste dieser WLANs zu laden. Wenn Sie eines aus der Liste auswählen möchten, müssen Sie diese Berechtigung gewähren. Wenn nicht, können Sie immer noch eines manuell eingeben.</string>
|
||||
<string name="urlToTriggerExplanation">Diese Funktion öffnet NICHT den Browser, sondern löst die HTTP Anfrage im Hintergrund aus. Sie können das z.B. benutzen, um Befehle an Ihre Heimautomatisierung zu schicken.</string>
|
||||
<string name="clone">Klonen</string>
|
||||
<string name="updateAvailable">Es gibt eine neue Version der Anwendung. Möchten Sie den Browser öffnen, um sie herunterzuladen?</string>
|
||||
<string name="automaticUpdateCheckSummary">Nur bei der APK Version.</string>
|
||||
<string name="automaticUpdateCheck">Nach Updates suchen</string>
|
||||
<string name="locationFound">Position gefunden. Der vorgeschlagene Mindestradius für Orte beträgt %1$d m.</string>
|
||||
<string name="locationFoundInaccurate">Es konnte nur eine ungenaue Position gefunden werden. Das funktioniert u.U. nicht zuverlässig. Der vorgeschlagene Mindestradius für Orte beträgt %1$d m.</string>
|
||||
<string name="pleaseGiveBgLocation">Gehen Sie auf dem nächsten Bildschirm bitte auf Berechtigungen, dann Position. Wählen Sie dort Immer erlauben aus, um Automation zu ermöglichen, die Position im Hintergrund zu ermitteln.</string>
|
||||
<string name="noLocationCouldBeFound">Leider konnte nach einem Limit von %1$s Sekunden keine Position gefunden werden.</string>
|
||||
<string name="vibrate">Vibrieren</string>
|
||||
<string name="test">Ausprobieren</string>
|
||||
<string name="VibrateExplanation">Geben Sie eine Vibrationsdauer, gefolgt von einem Komma ein, dann eine Pausendauer. Sie können so viele Vibrationen eingeben, wie sie möchten. Trennen Sie sie wieder mit Kommata.\nZ.B. wird das Muster 100,500,500,1000,100 100ms vibrieren, 500ms warten, 500ms vibrieren, 1000ms warten, 100ms vibrieren.\nWenn Sie denken, daß eine Vibration verschluckt wird, verlängern Sie die Pause vor ihr.</string>
|
||||
<string name="pleaseEnterValidVibrationPattern">Bitte geben Sie ein gültiges Vibrationsmuster ein.</string>
|
||||
<string name="tabsPlacement">Position der Tableiste</string>
|
||||
<string name="top">Oben</string>
|
||||
<string name="bottom">Unten</string>
|
||||
<string name="tabsPlacementSummary">Wol soll die Taskleiste angezeigt werden?</string>
|
||||
</resources>
|
@ -1,11 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:ns1="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="accelerometer">Accelerometro</string>
|
||||
<string name="ConfigurationExportError">C\'è stato un errore durante l\'esportazione della configurazione.</string>
|
||||
<string name="accelerometer">Accelerometro</string>
|
||||
<string name="accelerometerThreshold">Soglia accelerometro</string>
|
||||
<string name="accelerometerThresholdDescription">Soglia per i movimenti dell\'accelerometro</string>
|
||||
<string name="accelerometerTimer">Usa l\'accelerometro dopo x minuti senza lunghi cambiamento della cella radiomobile</string>
|
||||
<string name="accelerometerTimer">Usa l\'accelerometro dopo x minuti senza lunghi cambiamenti delripetitore</string>
|
||||
<string name="actionChangeSoundProfile">Cambia il profilo sonoro</string>
|
||||
<string name="actionDataConnection">Connessione di rete</string>
|
||||
<string name="actionDataConnection">Connessione dati mobile</string>
|
||||
<string name="actionDisableScreenRotation">disabilita la rotazione dello schermo</string>
|
||||
<string name="actionEnableScreenRotation">abilita la rotazione dello schermo</string>
|
||||
<string name="actionPlayMusic">Apri il lettore musicale</string>
|
||||
@ -16,42 +17,50 @@
|
||||
<string name="actionSetUsbTethering">Tethering USB</string>
|
||||
<string name="actionSetWifi">Wifi</string>
|
||||
<string name="actionSetWifiTethering">Wifi Tethering</string>
|
||||
<string name="actionSpeakText">Pronuncia</string>
|
||||
<string name="actionTriggerUrl">Apri URL</string>
|
||||
<string name="actionTurnAirplaneModeOff">termina la modalità aeroplano</string>
|
||||
<string name="actionTurnAirplaneModeOn">passa a modalità aeroplano</string>
|
||||
<string name="actionTurnBluetoothOff">attiva Bluetooth</string>
|
||||
<string name="actionTurnBluetoothOn">disattiva il Bluetooth</string>
|
||||
<string name="actionSpeakText">Pronuncia testo</string>
|
||||
<string name="actionTriggerUrl">Apri indirizzo</string>
|
||||
<string name="actionTurnAirplaneModeOff">termina la modalità aereo</string>
|
||||
<string name="actionTurnAirplaneModeOn">passa a modalità aereo</string>
|
||||
<string name="actionTurnBluetoothOff">disattiva Bluetooth</string>
|
||||
<string name="actionTurnBluetoothOn">attiva Bluetooth</string>
|
||||
<string name="actionTurnUsbTetheringOff">disattiva Tethering USB</string>
|
||||
<string name="actionTurnUsbTetheringOn">attiva Tethering USB</string>
|
||||
<string name="actionTurnWifiOff">disattiva Wifi</string>
|
||||
<string name="actionTurnWifiOn">attiva Wifi</string>
|
||||
<string name="actionTurnWifiTetheringOff">disattiva Tethering Wifi</string>
|
||||
<string name="actionTurnWifiTetheringOn">attiva Tethering Wifi</string>
|
||||
<string name="actions">Azioni(e)</string>
|
||||
<string name="actions">Azione(i)</string>
|
||||
<string name="actionsComment">(saranno eseguite in quest\'ordine)</string>
|
||||
<string name="activate">Attivazione</string>
|
||||
<string name="activate">Attiva</string>
|
||||
<string name="activated">attivo</string>
|
||||
<string name="activating">Sto attivando</string>
|
||||
<string name="activePoi">Posizione attiva:</string>
|
||||
<string name="activityDetection">Rilevamento di attività</string>
|
||||
<string name="activityDetectionFrequencySummary">Secondi tra i tentativi di rilevazione dell\'attività.</string>
|
||||
<string name="activityDetectionFrequencyTitle">Frequenza di rilevazione [sec]</string>
|
||||
<string name="activityDetectionRequiredProbabilitySummary">L\'attendibilità dell’esecuzione delle attività.</string>
|
||||
<string name="activityDetectionRequiredProbabilityTitle">Rilevazione di probabile attività</string>
|
||||
<string name="activityDetection">Rilevamento dell\'attività</string>
|
||||
<string name="activityDetectionFrequencySummary">Secondi tra i tentativi di rilevamento dell\'attività.</string>
|
||||
<string name="activityDetectionFrequencyTitle">Frequenza di rilevamento [sec]</string>
|
||||
<string name="activityDetectionRequiredProbabilitySummary">Attendibilità alla quale esecuzione delle attività è considerata corretta.</string>
|
||||
<string name="activityDetectionRequiredProbabilityTitle">Probabilità di rilevamento dell\'attività</string>
|
||||
<string name="activityOrActionName">Nome attività/azione</string>
|
||||
<string name="addAction">Aggiungi azione</string>
|
||||
<string name="addIntentValue">Aggiungi una coppia di Intent</string>
|
||||
<string name="addIntentValue">Aggiungi una coppia di intenzioni</string>
|
||||
<string name="addParameters">Aggiungi parametri</string>
|
||||
<string name="addPoi">Aggiungi posizione</string>
|
||||
<string name="addProfile">Aggiungi profilo</string>
|
||||
<string name="addRule">Aggiugni regola</string>
|
||||
<string name="addTrigger">Aggiungi evento</string>
|
||||
<string name="airplaneMode">Modalità aeroplano</string>
|
||||
<string name="airplaneModeSdk17Warning">A partire dalla versione Android 4.2 questa funzione è disponibile solo se il dispositivo è rootato.</string>
|
||||
<string name="addRule">Aggiungi regola</string>
|
||||
<string name="addTrigger">Aggiungi evento di attivazione</string>
|
||||
<string name="airplaneMode">Modalità aereo</string>
|
||||
<string name="airplaneModeSdk17Warning">A partire dalla versione Android 4.2 questa funzione è disponibile solo se il dispositivo ha accesso root.</string>
|
||||
<string name="alwaysPlay">riproduci sempre</string>
|
||||
<string name="alwaysPlayExplanation">Se questa impostazione è attiva, il suono sarà sempre riprodotto. Se questa è disattivata, la riproduzione avverrà quando il telefono non è nè in mute, nè in vibrazione. Comunque, quando attiva, non avrà effetto sul volume. Quindi, per esempio, se la il telefono ha la suoneria attivata, questa opzione non aumenterà il volume di riproduzione multimediale. E di conseguenza, se il volume del suono di riproduzione multimediale è in mute, non potrai ascoltare nulla.</string>
|
||||
<string name="android.permission.ACCESS_BACKGROUND_LOCATION">Leggi posizione in secondo piano.</string>
|
||||
<string name="android.permission.ACCESS_COARSE_LOCATION">Leggi posizione approssimativa</string>
|
||||
<string name="android.permission.ACCESS_FINE_LOCATION">Leggi posizione precisa</string>
|
||||
<string name="android.permission.ACCESS_NETWORK_STATE">Leggi lo stato della rete mobile</string>
|
||||
<string name="android.permission.ACCESS_NOTIFICATION_POLICY">Ignora la politica di "non disturbare"</string>
|
||||
<string name="android.permission.ACCESS_WIFI_STATE">Leggi lo stato della rete wifi</string>
|
||||
<string name="android.permission.ACTIVITY_RECOGNITION">Identificazione attività</string>
|
||||
<string name="android.permission.BATTERY_STATS">Leggere lo stato della batteria</string>
|
||||
<string name="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">Leggere le notifiche di sistema</string>
|
||||
<string name="android.permission.BLUETOOTH">Cambia le impostazioni Bluetooth</string>
|
||||
<string name="android.permission.BLUETOOTH_ADMIN">Cambia le impostazioni Bluetooth</string>
|
||||
<string name="android.permission.CHANGE_BACKGROUND_DATA_SETTING">Cambia la connessione dati</string>
|
||||
@ -60,184 +69,191 @@
|
||||
<string name="android.permission.MODIFY_AUDIO_SETTINGS">Cambia le impostazioni audio</string>
|
||||
<string name="android.permission.MODIFY_PHONE_STATE">Cambia le impostazioni del dispositivo</string>
|
||||
<string name="android.permission.NFC">Usa il modulo NFC</string>
|
||||
<string name="android.permission.PROCESS_OUTGOING_CALLS">Rileva chiamata in uscita</string>
|
||||
<string name="android.permission.READ_CALENDAR">Legge gli appuntamenti dal calendario</string>
|
||||
<string name="android.permission.READ_CALL_LOG">Legge il registro chiamate</string>
|
||||
<string name="android.permission.READ_EXTERNAL_STORAGE">Legge la memoria esterna</string>
|
||||
<string name="android.permission.PROCESS_OUTGOING_CALLS">Rileva chiamate in uscita</string>
|
||||
<string name="android.permission.READ_CALENDAR">Leggere gli appuntamenti dal calendario</string>
|
||||
<string name="android.permission.READ_CALL_LOG">Leggere il registro chiamate</string>
|
||||
<string name="android.permission.READ_CONTACTS">Leggere informazioni dai Contatti</string>
|
||||
<string name="android.permission.READ_EXTERNAL_STORAGE">Leggere la memoria esterna</string>
|
||||
<string name="android.permission.READ_PHONE_STATE">Rileva lo stato del telefono</string>
|
||||
<string name="android.permission.RECEIVE_BOOT_COMPLETED">Rileva che il dispositivo è stato riavviato</string>
|
||||
<string name="android.permission.RECORD_AUDIO">Registra l\'audio</string>
|
||||
<string name="android.permission.VIBRATE">Fa vibrare il telefono</string>
|
||||
<string name="android.permission.WAKE_LOCK">Mantiene attivo il dispositivo</string>
|
||||
<string name="android.permission.WRITE_EXTERNAL_STORAGE">Scrive su SD</string>
|
||||
<string name="android.permission.RECEIVE_BOOT_COMPLETED">Rileva riavvio del dispositivo</string>
|
||||
<string name="android.permission.RECORD_AUDIO">Registra audio</string>
|
||||
<string name="android.permission.SEND_SMS">Invia messaggio di testo</string>
|
||||
<string name="android.permission.VIBRATE">Attiva vibrazione</string>
|
||||
<string name="android.permission.WAKE_LOCK">Mantienere attivo il dispositivo</string>
|
||||
<string name="android.permission.WRITE_EXTERNAL_STORAGE">Scrive sulla SD</string>
|
||||
<string name="android.permission.WRITE_SECURE_SETTINGS">Cambia le impostazioni del dispositivo</string>
|
||||
<string name="android.permission.WRITE_SETTINGS">Cambia le impostazioni del dispositivo</string>
|
||||
<string name="android10WifiToggleNotice">Sfortunatamente, Google ha deciso di rimuovere questa funzione in Android 10. Applicazioni normali non hanno più accesso alla accensione o spegnimento della connessione wifi on. Questo significa che questa azione non avrà effetto su questo dispositivo.</string>
|
||||
<string name="android9RecordAudioNotice">Se si sta usando il livello di rumore come evento di attivazione: sfortunatamente, a partire da Android 9 (Pie), Google ha deciso di non permettere l\'accesso al microfono da parte di applicazioni attive in secondo piano. Pertanto questo evento non ha più effetto e non attiverà nessuna azione.</string>
|
||||
<string name="anotherAppIsRunning">Si è avviata/fermata un\'altra app</string>
|
||||
<string name="anotherPoiByThatName">Nome già usato per un\'altra posizione.</string>
|
||||
<string name="anotherProfileByThatName">Nome già usato per un altro profilo.</string>
|
||||
<string name="anotherRuleByThatName">Nome già usato per un\'altra regola.</string>
|
||||
<string name="any">qualsiaisi</string>
|
||||
<string name="anyApp">Qualsiasi applicazione</string>
|
||||
<string name="anyDevice">qualsiasi dispositivo</string>
|
||||
<string name="anyLocation">qualsiasi posizione</string>
|
||||
<string name="anyNumber">qualsiasi numero</string>
|
||||
<string name="anyWifi">qualsiasi wifi</string>
|
||||
<string name="appRequiresPermissiontoAccessExternalStorage">Automation richiede l’autorizzazione per archiviare e leggere le impostazioni e le regole.</string>
|
||||
<string name="featuresDisabled">L\'applicazione è in esecuzione in modalità limitata a causa di autorizzazioni mancanti.</string>
|
||||
<string name="appStarted">App avviata.</string>
|
||||
<string name="appStopped">App terminata.</string>
|
||||
<string name="app_name">Automation</string>
|
||||
<string name="appRequiresPermissiontoAccessExternalStorage">Automation richiede accesso alla memoria esterna per leggere le proprie impostazioni e regole.</string>
|
||||
<string name="application">Applicazione</string>
|
||||
<string name="applicationHasBeenUpdated">L\'applicazione è stata aggiornata.</string>
|
||||
<string name="applyingSettingsAndRules">Applicazione delle impostazioni, regole e posizioni.</string>
|
||||
<string name="areYouSure">Sicuro?</string>
|
||||
<string name="at">il</string>
|
||||
<string name="atLeastRuleXisUsingY">Almeno una regola ( \"%1$s\" ) sta usando una condizione di tipo \"%2$s\".</string>
|
||||
<string name="logAttemptingDownloadOf">Tentativo di dowload di</string>
|
||||
<string name="logAttemptingToBindToService">Tentativo di attivare il servizio... </string>
|
||||
<string name="logAttemptingToUnbindFromService">Tentativo di disattivare il servizio... </string>
|
||||
<string name="audibleSelection">Audio alla selezione di cambio schermo</string>
|
||||
<string name="apply">applica</string>
|
||||
<string name="areYouSure">Sei sicuro?</string>
|
||||
<string name="at">al</string>
|
||||
<string name="audibleSelection">Audio abilitato quando si seleziona lo schermo</string>
|
||||
<string name="autoBrightness">Abilitare luminosità automatica</string>
|
||||
<string name="autoBrightnessNotice">Se usi la luminosità automatica, il valore di luminosità scelto a seguito non sarà probabilmente in use per molto.</string>
|
||||
<string name="batteryLevel">livello della batteria</string>
|
||||
<string name="bluetoothConnection">Connessione Bluetooth</string>
|
||||
<string name="bluetoothConnectionTo">Connessione Bluetooth fra %1$s</string>
|
||||
<string name="bluetoothConnectionTo">Connessione Bluetooth con %1$s</string>
|
||||
<string name="bluetoothDeviceInRange">Dispositivo Bluetooth %1$s rilevato.</string>
|
||||
<string name="bluetoothDeviceOutOfRange">Dispositivo Bluetooth %1$s non raggiungibile.</string>
|
||||
<string name="bluetoothDisconnectFrom">Bluetooth connection to %1$s torn</string>
|
||||
<string name="bluetoothDisconnectFrom">Connessione Bluetooth con %1$s interrotta</string>
|
||||
<string name="bluetoothFailed">Impossibile attivare il Bluetooth. Questo dispositivo è dotato di Bluetooth?</string>
|
||||
<string name="logBoundToService">Servizio impegnato.</string>
|
||||
<string name="cancel">Abbandona</string>
|
||||
<string name="cantDownloadTooFewRequestsInSettings">Non è possibile scaricare nulla. La quantità di richieste HTTP è impostata inferiore a 1.</string>
|
||||
<string name="cantMoveDown">Non posso abbassare l\'item. E\' già l\'ultimo.</string>
|
||||
<string name="cantMoveUp">Non posso alzare l\'item. E\' già il primo.</string>
|
||||
<string name="cantRunRule">Queste regole non possono essere eseguite.</string>
|
||||
<string name="brightnessAuto">luminosità automatica</string>
|
||||
<string name="brightnessManual">luminosità manuale</string>
|
||||
<string name="cancel">Annulla</string>
|
||||
<string name="cantFindSoundFile">Impossibile trovate il file audio %1$s e riprodurlo.</string>
|
||||
<string name="cantMoveDown">Non posso spostare giù l\'elemento. E\' già l\'ultimo.</string>
|
||||
<string name="cantMoveUp">Non posso spostare su l\'elemento. E\' già il primo.</string>
|
||||
<string name="cantRunRule">Impossibile eseguire le regole.</string>
|
||||
<string name="cantStopIt">Non posso fermarla.</string>
|
||||
<string name="cellMastChanged">Devi cambiare la cella: %1$s</string>
|
||||
<string name="cellMastIdleTime">Massimo tempo di inattività della cella</string>
|
||||
<string name="change">Abilita modifiche</string>
|
||||
<string name="logClearingBothLocationListeners">Cancello la posizione sia come rete che come GPS</string>
|
||||
<string name="closeTo">chiuso in</string>
|
||||
<string name="closestPoi">Posizione precedente:</string>
|
||||
<string name="comparing">Ho la posizione sia dalla rete che dal GPS e le sto confrontando...</string>
|
||||
<string name="cellMastIdleTime">Massimo tempo di inattività del ripetitore</string>
|
||||
<string name="change">Modifica</string>
|
||||
<string name="chooseActivityHint">In questa ultima selezione dovrai selezionare una attività specifica. Praticamente, questa è come una finestra dell\'applicazione desiderata. Se non sai qual è, si raccomanda scegliere quella che ha \"main\" o \"launcher\" nel suo nome.</string>
|
||||
<string name="clickAndHoldForOptions">Clicca e mantieni premuto un elemento per vedere le opzioni.</string>
|
||||
<string name="closeTo">vicino a</string>
|
||||
<string name="closestPoi">Posizione più vicina:</string>
|
||||
<string name="com.wireguard.android.permission.CONTROL_TUNNELS">Controllare i tunnels dell\'applicazione wireguard</string>
|
||||
<string name="configurationExportedSuccessfully">Configurazione esportata con successo.</string>
|
||||
<string name="configurationImportedSuccessfully">Configurazione esportata con successo.</string>
|
||||
<string name="connected">connesso</string>
|
||||
<string name="connectedToWifi">connesso a wifi \"%1$s</string>
|
||||
<string name="connectedToWifi">connesso al wifi \"%1$s</string>
|
||||
<string name="connecting">connessione in corso</string>
|
||||
<string name="connectionToDevice">connessione al dispositivo</string>
|
||||
<string name="continueText">Continua</string>
|
||||
<string name="continueText">continua</string>
|
||||
<string name="currentId">ID corrente:</string>
|
||||
<string name="currentVolume">Volume attuale</string>
|
||||
<string name="dataConWithRootFail">Il dato non può essere cambiato usando i permessi superuser.</string>
|
||||
<string name="dataConWithRootSuccess">La connessione è stata cambiata usando i permessi superuser. </string>
|
||||
<string name="deactivate">Disattivazione</string>
|
||||
<string name="deactivated">non attivo</string>
|
||||
<string name="deactivating">Disattivazione in corso</string>
|
||||
<string name="defaultSettings">Ripristino impostazioni di default</string>
|
||||
<string name="delete">cancella</string>
|
||||
<string name="deleteCapital">Cancella</string>
|
||||
<string name="delete">rimuovi</string>
|
||||
<string name="deleteCapital">Rimuovi</string>
|
||||
<string name="deletePoi">Cancella posizione</string>
|
||||
<string name="detectedActivity">Cancella attività:</string>
|
||||
<string name="detectedActivity">Attività rilevata:</string>
|
||||
<string name="detectedActivityInVehicle">In un veicolo (auto, bus,...)</string>
|
||||
<string name="detectedActivityInvalidStatus">Attività non valida</string>
|
||||
<string name="detectedActivityOnBicycle">In bicicletta</string>
|
||||
<string name="detectedActivityOnFoot">A piedi</string>
|
||||
<string name="detectedActivityRunning">Di corsa</string>
|
||||
<string name="detectedActivityStill">Fermo</string>
|
||||
<string name="detectedActivityTilting">Pendenza</string>
|
||||
<string name="detectedActivityTilting">Ribaltando</string>
|
||||
<string name="detectedActivityUnknown">Sconosciuto</string>
|
||||
<string name="detectedActivityWalking">Passeggio</string>
|
||||
<string name="logDetectingTetherableUsbInterface">Individuata interfaccia USB con tethering.</string>
|
||||
<string name="deviceDoesNotHaveNfc">Sembra che il dispositivo non sia NFC.</string>
|
||||
<string name="detectedActivityWalking">Camminando</string>
|
||||
<string name="deviceDoesNotHaveBluetooth">Questo dispositivo non sembra avere bluetooth. Puoi comunque configurare questa opzione, ma non avrà probabilmente nessun effetto.</string>
|
||||
<string name="deviceDoesNotHaveNfc">Sembra che il dispositivo non abbia la funzione NFC.</string>
|
||||
<string name="deviceInRange">dispositivo visibile</string>
|
||||
<string name="deviceOutOfRange">dispositivo fuori portata</string>
|
||||
<string name="direction">Direzione</string>
|
||||
<string name="directionStringContains">contiene</string>
|
||||
<string name="directionStringEndsWith">finisce in</string>
|
||||
<string name="directionStringEquals">uguale a</string>
|
||||
<string name="directionStringNotEquals">non uguale a</string>
|
||||
<string name="directionStringStartsWith">comincia con</string>
|
||||
<string name="disabledFeatures">Funzioni disabilitate</string>
|
||||
<string name="disconnected">disconnesso</string>
|
||||
<string name="disconnectedFromWifi">disconnesso dal wifi \"%1$s</string>
|
||||
<string name="disconnectedFromWifi">disconnesso dalla rete wifi \"%1$s</string>
|
||||
<string name="disconnecting">disconnessione in corso</string>
|
||||
<string name="disconnectionFromDevice">disconnesso dal dispositivo</string>
|
||||
<string name="distanceBetween">La distanza tra la posizione GPS e la posizione di rete è</string>
|
||||
<string name="displayNewsOnMainScreen">Visualizza le novità dell\'applicazione sullo schermo principale</string>
|
||||
<string name="displayNewsOnMainScreenDescription">Novità relative solo a questa applicazione, stiamo parlando di un paio per anno, non di più.</string>
|
||||
<string name="distanceBetween">La distanza tra la posizione GPS e la posizione di rete è di %1$d metri. Il raggio minimo è +1 metro.</string>
|
||||
<string name="distanceForGpsUpdate">Distanza per l\'aggiornamento del GPS [m]</string>
|
||||
<string name="distanceForNetworkUpdate">Distanza per l\'aggiornamento della rete [m]</string>
|
||||
<string name="droppingBelow">inferiore a</string>
|
||||
<string name="droppingBelow">sta andando sotto</string>
|
||||
<string name="dropsBelow">inferiore</string>
|
||||
<string name="edit">Modifica</string>
|
||||
<string name="end">Fine</string>
|
||||
<string name="enforcingGps">Impedisce la localizzazione del provider e forza il GPS</string>
|
||||
<string name="enterAPositiveValidNonDecimalNumber">Inserire un numero intero positivo</string>
|
||||
<string name="enterAname">Inserisci un nome</string>
|
||||
<string name="enterNameForIntentPair">Definisci un nome per la coppia di Intent</string>
|
||||
<string name="enterPhoneNumber">Inserisci un numero di telefono. Lascia vuoto per qualsiasi numero.</string>
|
||||
<string name="enterValidReferenceValue">Inserire un valore di riferimento valido.</string>
|
||||
<string name="enterValueForIntentPair">Definisci un valore per la coppia di Intent.</string>
|
||||
<string name="enterWifiName">Inserire un nome per la wifi. Se vuoto varrà per qualsiasi wifi.</string>
|
||||
<string name="enterAPositiveValidNonDecimalNumber">Inserisci un numero intero positivo</string>
|
||||
<string name="enterAname">Inserisci un nome.</string>
|
||||
<string name="enterNameForIntentPair">Definisci un nome per la coppia di intenzioni</string>
|
||||
<string name="enterPackageName">Inserisci un nome di pacchetto che sia valido.</string>
|
||||
<string name="enterPhoneNumber">Inserisci un numero di telefono. Lascia vuoto per accettare qualsiasi numero.</string>
|
||||
<string name="enterValidAction">Inserisci una azione valida</string>
|
||||
<string name="enterValidReferenceValue">Inserisci un valore di riferimento valido.</string>
|
||||
<string name="enterValueForIntentPair">Definisci un valore per la coppia di Intenzioni.</string>
|
||||
<string name="enterWifiName">Inserire un nome per la wifi. Se vuoto sarà valido per qualsiasi wifi.</string>
|
||||
<string name="entering">entrando in</string>
|
||||
<string name="eraseSettings">Azzera le impostazioni</string>
|
||||
<string name="error">Errore</string>
|
||||
<string name="errorActivatingProfile">Errore nell\'attivazione del profilo:</string>
|
||||
<string name="errorActivatingWifiAp">Errore nell\'attivazione del wifi</string>
|
||||
<string name="errorChangingScreenRotation">Errore nella rotazione dello schermo</string>
|
||||
<string name="logErrorDeterminingCurrentUsbTetheringState">Errore nel riconsocimento di UsbTethering.</string>
|
||||
<string name="errorDeterminingWifiApState">Errore nel riconoscimento wifi</string>
|
||||
<string name="logErrorGettingConnectionManagerService">Errore del connectionManager. Il Tethering USB non risponde.</string>
|
||||
<string name="errorInitializingSettingsToPersistentMemory">Errore nello scrivere le impostazioni nella memoria di massa.</string>
|
||||
<string name="errorReadingPoisAndRulesFromFile">Errore nella lettura di regole e posizioni dal file.</string>
|
||||
<string name="errorReadingSettings">Errore nel leggere le impostazioni</string>
|
||||
<string name="errorRunningRule">C\'è stato un errore cercando di eseguire una regola.</string>
|
||||
<string name="errorStartingOtherActivity">Errore nel\'avvio dell\'altra attività</string>
|
||||
<string name="errorTriggeringUrl">Errore di indirizzamento</string>
|
||||
<string name="errorWritingConfig">Errore nello scrivere la configurazione. La memoria è accessibile?</string>
|
||||
<string name="errorWritingConfig">Errore nello scrivere la configurazione. È la memoria in sola lettura?</string>
|
||||
<string name="errorWritingFile">Errore nella scrittura delle impostazioni.</string>
|
||||
<string name="errorWritingSettingsToPersistentMemory">Errore nella memorizzazione delle impostazioni.</string>
|
||||
<string name="exceeding">superiore a</string>
|
||||
<string name="exceeds">superiore</string>
|
||||
<string name="exceeding">sta sorpassando</string>
|
||||
<string name="exceeds">è superiore</string>
|
||||
<string name="executeRulesAndProfilesWithSingleClickTitle">Esegui regole/profili con un singolo click.</string>
|
||||
<string name="exportConfiguration">Esporta la configurazione</string>
|
||||
<string name="failedToTriggerBluetooth">Non riesco ad attivare il Bluetooth. Questo dispositivo ha il Bluetooth?</string>
|
||||
<string name="forcedLocationUpdate">Aggiornamento forzato della posizione</string>
|
||||
<string name="forcedLocationUpdateLong">Essendo scaduto il timeout della misura sarà considerata valida l\'ultima posizione rilevata.</string>
|
||||
<string name="featureNotInFdroidVersion">Questa funzione sfrutta software non basato su codice aperto. Pertanto non è disponibile nella versione F-Droid.</string>
|
||||
<string name="featuresDisabled">L\'applicazione è in esecuzione in modalità limitata a causa di autorizzazioni mancanti.</string>
|
||||
<string name="fileDoesNotExist">Il file non esiste.</string>
|
||||
<string name="filesHaveBeenMovedTo">Automation usa adesso un percorso nuovo per salvare i tuoi files. Tutti i files di Automation sono stati mossi qui: \"%s\". I permessi di accesso alla memoria esterna non sono più necessari e si possono revocare. Questo verrà permanentemente rimosso in una versione futura.</string>
|
||||
<string name="filesStoredAt">I files di configurazione e log sono salvati nella cartella %1$s. Clicca su questo testo per aprire l\'esploratore di files. Sfortunatamente, questo solo funziona su un dispositivo con accesso root.\n\nPER TUTTI GLI ALTRI DISPOSITIVI: basta usare il bottone \'esporta\' per fare un backup.</string>
|
||||
<string name="friday">Venerdì</string>
|
||||
<string name="general">Descrizione della regola</string>
|
||||
<string name="from">da</string>
|
||||
<string name="general">Generale</string>
|
||||
<string name="generalSettings">Impostazioni globali</string>
|
||||
<string name="generalText">Per utilizzare questo programma è necessario impostare delle regole. Le regole contengono eventi, per esempio l\'arrivare in una determinata zona o essere in un intervallo temporale. Dopo che è stato fatto clic sul pulsante ON / OFF nella home-page.
|
||||
</string>
|
||||
<string name="generalText">Per utilizzare questo programma è necessario impostare delle regole. Le regole contengono eventi, per esempio l\'arrivare in una determinata zona o essere in un intervallo temporale. Dopo che è stato fatto, fare clic sul pulsante ON / OFF nella home-page.</string>
|
||||
<string name="getCurrentPosition">Rileva la posizione attuale</string>
|
||||
<string name="gettingListOfInstalledApplications">Sto cercando le applicazioni installate … </string>
|
||||
<string name="gettingPosition">Sto rilevando la posizione. Attendere prego ...</string>
|
||||
<string name="logGettingPositionWithProvider">Richiesta posizione dal provider:</string>
|
||||
<string name="google_app_id">id della tua app</string>
|
||||
<string name="logGotGpsUpdate">GPS aggiornato. Precisione:</string>
|
||||
<string name="logGotNetworkUpdate">Rete aggiornata. Precisione:</string>
|
||||
<string name="googleLocationChicanery">Questa applicazione accumula dati di localizzazione per abilitare regole basate sulla posizione insieme al rilevamento della velocità anche quando l\'applicazione è chiusa o non in uso.</string>
|
||||
<string name="googleLocationChicaneryOld">Questa applicazione accumula dati di localizzazione per determinare se sei attualmente ad una delle posizioni che hai creato. Inoltre, questa funzione è usata per determinare la tua velocità attuale se tale evento è stato attivato nelle regole. Questi rilevamenti sono effettuati anche quando l\'applicazione è chiusa o non in uso (ma solo se il servizio è attivato).</string>
|
||||
<string name="googleSarcasm">Grazie alla infinita sapienza di Google e continui sforzi per proteggere la nostra privacy, nelle regole che possano inviare SMS o coinvolgere lo stato del telefono, sono state rimossi eventi ed azioni rilevanti.</string>
|
||||
<string name="gpsAccuracy">Precisone del GPS [m]</string>
|
||||
<string name="gpsComparison">Confronto col GPS</string>
|
||||
<string name="gpsComparisonTimeoutStop">Fermata la comparazione col GPS per timeout.</string>
|
||||
<string name="gpsMeasurement">Misura GPS</string>
|
||||
<string name="gpsMeasurementTimeout">Misura GPS fermata per timeout.</string>
|
||||
<string name="hapticFeedback">Sensazione tattile(vibrazione al tocco)</string>
|
||||
<string name="gpsComparison">Comparazione GPS</string>
|
||||
<string name="hapticFeedback">Sensazione tattile (vibrazione al tocco)</string>
|
||||
<string name="headphoneAny">Oppure</string>
|
||||
<string name="headphoneMicrophone">Microfono</string>
|
||||
<string name="headphoneSelectType">Seleziona il tipo di auricolare</string>
|
||||
<string name="headphoneSimple">Auricolari</string>
|
||||
<string name="headsetConnected">Connesso auricolari (type: %1$s) </string>
|
||||
<string name="headsetDisconnected">Disconnesso auticolari (type: %1$s) </string>
|
||||
<string name="helpTextPoi">Una posizione è composta da una zona con un raggio intorno a un punto specificato dalle coordinate GPS. ll posizionamento è realizzato appoggianodosi alle coordinate dei ripetitori del tuo gestore. E\' leggermente impreciso, ma veloce e consuma poca batteria. Pertanto è bene non specificare un raggio troppo piccolo. L\'applicazione suggerisce un raggio minimo quando si crea una nuova posizione.</string>
|
||||
<string name="helpTextProcessMonitoring">Se si specifica una regola che controlli l\'esecuzione di un processo Automation eseguirà la verifica ogni x secondi (con x selezionabile nelle impostazioni). Va infatti considerato che un monitoraggio costante provocherebbe un rapido esaurimento della batteria e non esistono segnalazioni di questo tipo nel sistema operativo.</string>
|
||||
<string name="helpTextRules">Tutti gli eventi di una regola sono efficaci se si verificano nella loro totalità. Basta che un evento non sia verificato è la regola non si attiverà. Per avere invece una funzionalità alternativa bisogna creare più regole.</string>
|
||||
<string name="helpTextTimeFrame">Se si specifica una regola con un intervallo temporale si hanno due scelte. È possibile scegliere se si desidera attivare la regola all\'interno o all\'esterno dell\'intervallo di tempo. In entrambi i casi l\'azione verrà eseguita una sola volta.
|
||||
Quindi, se si crea una regola che imposta il profilo su vibrazione nell\'intervallo temporale xyz, il telefono, passato allo stato vibrazione, rimarrà definitivamente in tale stato anche dopo lo scadere dell\'intervallo di tempo. Se si desidera che ciò avvenga è necessario specificare un\'altra regola con un altro periodo di tempo.</string>
|
||||
<string name="helpTextToggable">Alcune regole hanno una bandiera chiamata "Reversibile". Ciò significa che, se una regola viene eseguita al verificarsi di un evento e poi quest\'ultimo si verifica una seconda volta, il comando della regola verrà eseguito una ulteriore volta in modalità inversa, se possibile. Attualmente questo avverrà solo in combinazione con i tag NFC. Se li si tocca due volte la regola associata invertirà la situazione attuale. Per esempio una regola “Reversibile” può disattivare il WiFi se attivo e viceversa attivarlo se non attivo.</string>
|
||||
<string name="headsetConnected">Connesso auricolare (tipo: %1$s) </string>
|
||||
<string name="headsetDisconnected">Disconnesso auticolari (tipo: %1$s) </string>
|
||||
<string name="helpTextActivityDetection">Questa funzione può identificare se sei attualmente in movimento e se sei a piedi o in che tipo di veicolo (almeno con una certa precisione). Questa funzione non è completamente integrata con Automation, ma viene fornita dai servizi di Google Play. In pratica, non fornisce un risultato si/no, ma provvede una percentuale del livello di sicurezza dello stato di movimento identificato. Puoi scegliere la percentuale raggiunta la quale Automation accetterà un resultato. Nota: 1) è possibile che più di uno stato sia identificato nello stesso momento. Per esempio, potresti star CAMMINANDO dentro a un bus in movimento; 2) Questo sensore ha bisogno di molte risorse di sistema. Se possibile, potresti considerare delle alternative, per esempio, potresti identificare che stai guidando, forzando una connessione con il vivavoce.</string>
|
||||
<string name="helpTextEnergySaving">Molti produttori di dispositive Android cercano di salvare energia limitando le attività di applicazioni eseguite in secondo piano. Sfortunatamente, questo spesso fa che tali applicazioni non funzionino correttamente e Automation è fra queste. Puoi leggere questa <a href="https://dontkillmyapp.com/">pagina web</a> per scoprire come escludere Automation da queste funzioni di risparmio energetico.</string>
|
||||
<string name="helpTextPoi">Una posizione è composta da cooridinate GPS ed un raggio d\'azione. Dato che il posizionamento realizzato tramite i ripetitori del tuo gestore è piuttosto impreciso (ma veloce e consuma poca batteria), è bene non specificare un raggio troppo piccolo. L\'applicazione suggerisce un raggio minimo quando si crea una nuova posizione.</string>
|
||||
<string name="helpTextProcessMonitoring">Se si specifica una regola che controlli l\'esecuzione di un processo, Automation eseguirà la verifica ogni x secondi (con x selezionabile nelle impostazioni). Bisogna considerare che un monitoraggio costante provocherebbe un rapido esaurimento della batteria e non esistono notifiche di questo tipo di attività proviste dal sistema operativo.</string>
|
||||
<string name="helpTextRules">Una regola sarà eseguita quando tutti i suoi eventi risultano veri. Basta che solo un evento non sia eseguito e la regola non si attiverà. Per eseguire una regola in base a diversi eventi individuali, è sufficiente creare regole specifiche per ogni set di eventi.</string>
|
||||
<string name="helpTextSound">Nello schermo principale puoi bloccare temporaneamente i cambi ai suoni per evitare l\'esecuzione di regole che facciano cambi alle attività sonore. Per esempio, potresti essere in una situatione o in un luogo dove normalmente ascoltare il suono di una suoneria è ok, ma in questa occasione bisognerebbe evitarlo. Questa funzione si disattiverà automaticamente non appena sia trascorso il tempo selezionato. Fai Click sul bottone + per raggiungere la quantità di tempo desiderata. Una volta attiva, questa si può disattivare nuovamente usando il pulsante di attivazione (e in questo modo, si riattiveranno le regole basate su cambi sonori).</string>
|
||||
<string name="helpTextTimeFrame">Se si specifica una regola con un intervallo temporale si hanno due scelte. È possibile scegliere se si desidera attivare la regola all\'interno o all\'esterno dell\'intervallo di tempo. In entrambi i casi l\'azione verrà eseguita una sola volta. Quindi, se si crea una regola che imposta il profilo su vibrazione nell\'intervallo temporale xyz, il telefono, passato allo stato vibrazione, rimarrà definitivamente in tale stato anche dopo lo scadere dell\'intervallo di tempo. Se si desidera che ciò avvenga è necessario specificare un\'altra regola con un altro periodo di tempo.</string>
|
||||
<string name="helpTextToggable">Le regole hanno un segno di spunta chiamato "Reversibile". Ciò significa che, se una regola viene eseguita al verificarsi di un evento e poi quest\'ultimo si verifica una seconda volta, il comando della regola verrà eseguito una ulteriore volta in modalità inversa, se possibile. Attualmente questo avverrà solo in combinazione con i tag NFC. Se li si tocca due volte la regola associata invertirà la situazione attuale. Per esempio una regola “Reversibile” può disattivare il WiFi se attivo e viceversa attivarlo se non attivo.</string>
|
||||
<string name="helpTitleEnergySaving">Risparmio energetico</string>
|
||||
<string name="hint">Suggerimento</string>
|
||||
<string name="httpAcceptAllCertificatesSummary">Salta il controllo dei certificate SSL (si consiglia di non attivarlo)</string>
|
||||
<string name="httpAcceptAllCertificatesTitle">Accetta tutti I certificati</string>
|
||||
<string name="httpAttemptGapSummary">Pausa prima del successive tentativo [secondi]</string>
|
||||
<string name="httpAcceptAllCertificatesSummary">Salta il controllo dei certificati SSL (si consiglia di non attivarlo)</string>
|
||||
<string name="httpAcceptAllCertificatesTitle">Accetta tutti i certificati</string>
|
||||
<string name="httpAttemptGapSummary">Pausa prima del tentativo successivo [secondi]</string>
|
||||
<string name="httpAttemptGapTitle">Pausa [sec]</string>
|
||||
<string name="httpAttemptsSummary">Numero di tentative ripetuti in caso di fallimento richiesta HTTP a causa della connessione </string>
|
||||
<string name="httpAttemptsSummary">Numero di tentativi in caso le richieste HTTP falliscano a causa di problemi di connessione </string>
|
||||
<string name="httpAttemptsTimeoutSummary">Timeout per richieste HTTP [secondi]</string>
|
||||
<string name="httpAttemptsTimeoutTitle">Timeout [sec]</string>
|
||||
<string name="httpAttemptsTitle">Numero di tentativi HTTP</string>
|
||||
<string name="ignoringActivityDetectionUpdateTooSoon">Nessuna risposta. Riprovo tra %1$s secondi.</string>
|
||||
<string name="incoming">ricevuta</string>
|
||||
<string name="incomingAdjective">ricevuta</string>
|
||||
<string name="importConfiguration">Importa configurazione</string>
|
||||
<string name="importExportExplanation">Quando si clicca su importa o esporta, stai scegliendo la direzione in cui i files vengono importati o esportati. Quando si procede alla esportazione, files esistenti potrebbero essere sovrascritti.</string>
|
||||
<string name="importNumberFromContacts">Importa numero dai contatti</string>
|
||||
<string name="incoming">in arrivo</string>
|
||||
<string name="incomingAdjective">in arrivo</string>
|
||||
<string name="incomingCallFrom">Chiamata in arrivo da %1$s.</string>
|
||||
<string name="incomingCallsRingtone">Suoneria per le chiamate in arrivo</string>
|
||||
<string name="initializingSettingsToPersistentMemory">Impostazioni iniziali in una memoria di massa.</string>
|
||||
<string name="insideOrOutsideTimeFrames">Dentro o fuori l\'intervallo?</string>
|
||||
<string name="insideOrOutsideTimeFrames">Dentro o fuori questi intervalli?</string>
|
||||
<string name="intentDataComment">Se il tuo parametro è di tipo Uri e usi \"IntentData\" come nome (in maiuscole o minuscole non importa), il parametro non verrà aggiunto come parametro normale con putExtra(), ma sarà aggiunto all\'intento con setData().</string>
|
||||
<string name="invalidDevice">Dispositivo non valido.</string>
|
||||
<string name="invalidPoiName">Nome posizione non valido.</string>
|
||||
<string name="invalidProfileName">Nome profilo non valido.</string>
|
||||
<string name="invalidStuffStoredInSettingsErasing">Impostazioni non tutte valide. Le sto cancellando ...</string>
|
||||
<string name="is">é</string>
|
||||
<string name="is">è</string>
|
||||
<string name="lastRule">Ultima regola:</string>
|
||||
<string name="latitude">Latitudine</string>
|
||||
<string name="leaving">uscendo da</string>
|
||||
@ -245,287 +261,283 @@ Quindi, se si crea una regola che imposta il profilo su vibrazione nell\'interva
|
||||
<string name="lengthOfNoiseLevelMeasurementsTitle">Durata di ogni misura di livello di rumore</string>
|
||||
<string name="listenToAccelerometerState">Rileva i movimenti del dispositivo dove non fosse disponibile il wifi</string>
|
||||
<string name="listenToWifiState">Rileva il cambiamento di stato del wifi se disponibile</string>
|
||||
<string name="loadWifiList">Carica lista wifi</string>
|
||||
<string name="locationDisabled">Localizzazione disattivata</string>
|
||||
<string name="locationEngineDisabledLong">Purtroppo la tua posizione non può più essere determinata. Un debito di gratitudine è dovuto a Google per la sua infinita saggezza e amabilità.\\n\\nVediamo di approfondire questo problema. A partire da Android 10 è stato introdotto un nuovo permesso che è necessario per determinare la vostra posizione in secondo piano (che naturalmente è necessario per un\'app come questa). Sebbene la consideri una buona idea in generale, i problemi che comporta per gli sviluppatori non lo sono.\\n\\nWQuando si sviluppa un\'app si può cercare di qualificarsi per questo permesso rispettando un catalogo di requisiti. Purtroppo le nuove versioni della mia app sono state rifiutate per un periodo di tre mesi. Ho soddisfatto tutti questi requisiti, mentre il merdoso supporto allo sviluppo di Google ha affermato che non l\'ho fatto. Dopo aver dato loro la prova che l\'ho fatto - ho ottenuto una risposta del tipo \"non posso più aiutarti\". Alla fine mi sono arreso. \\n\\nDi conseguenza, la versione di Google Play non può più usare la tua posizione come trigger. La mia unica opzione alternativa sarebbe stata quella di avere questa applicazione rimossa dal negozio interamente.\\n\\nNe sono molto dispiaciuto, ma ho fatto del mio meglio per discutere con un \"supporto\" che ripetutamente non ha superato il test di Turing.\n\\nInfine, c\'è una buona notizia: puoi ancora avere tutto!\\n\\nAutomation è adesso una applicazione di codice aperto e si può trovare su F-Droid. Questo è un app store che si preoccupa davvero della tua privacy - invece che fingere di farlo. Basta fare il backup del tuo file di configurazione, disinstallare questa app, installarla di nuovo da F-Droid e ripristinare il tuo file di configurazione - fatto.\\n\\nClicca qui per maggiori informazioni:</string>
|
||||
<string name="locationEngineDisabledShort">La localizzazione non può più essere determinata. Clicca qui per scoprirne il perché.</string>
|
||||
<string name="locationEngineNotActive">Ricerca posizione non attiva.</string>
|
||||
<string name="lockSoundChanges">Cambiamento dei suoni:</string>
|
||||
<string name="lockSoundChanges">Blocca il cambio dei suoni:</string>
|
||||
<string name="logFileMaxSizeSummary">Massima dimensione del file di log in Megabyte. Tronca quando la dimensione eccede.</string>
|
||||
<string name="logFileMaxSizeTitle">Massima dimensione del file di log [Mb]</string>
|
||||
<string name="logFileMaxSizeTitle">Massima dimensione del file di log [Mb]</string>
|
||||
<string name="logLevelSummary">Dettaglio del file di Log (1=minimo, 5=massimo)</string>
|
||||
<string name="logLevelTitle">Dettaglio del file di log</string>
|
||||
<string name="logServiceStopping">Arrestando il servizio.</string>
|
||||
<string name="longitude">Longitudine</string>
|
||||
<string name="mainScreenPermissionNote">Automation richiede ulteriori autorizzazioni. Clicca su questo testo per saperne di più e concederle.</string>
|
||||
<string name="menu_settings">Impostazioni</string>
|
||||
<string name="messageReceivedStatingProcessMonitoringIsComplete">Il messaggio ricevuto attesta che il monitoraggio del processo è completato.</string>
|
||||
<string name="minimumDistanceChangeForGpsLocationUpdates">Minimo intervallo (im metri) per l\'aggiornamento GPS </string>
|
||||
<string name="minimumDistanceChangeForNetworkLocationUpdates">Minima distanza percorsa per aggiornare la posizione della rete.</string>
|
||||
<string name="minimumTimeForLocationUpdates">Intervallo minimo in secondi per aggiornare la localizzazione</string>
|
||||
<string name="mainScreenPermissionNote">Automation richiede ulteriori autorizzazioni per funzionare correttamente. Clicca su questo testo per saperne di più e richiederle.</string>
|
||||
<string name="manageLocations">Creare o modificare posizioni</string>
|
||||
<string name="matching">abbinando</string>
|
||||
<string name="messageNotShownAgain">Questo messaggio non sarà mostrato più.</string>
|
||||
<string name="minimumDistanceChangeForGpsLocationUpdates">Minimo intervallo (in metri) per aggiornare le posizioni GPS </string>
|
||||
<string name="minimumDistanceChangeForNetworkLocationUpdates">Minimo cambio della distanza per aggiornare la posizione dalla rete.</string>
|
||||
<string name="minimumTimeForLocationUpdates">Intervallo minimo in millisecondi per aggiornare la localizzazione</string>
|
||||
<string name="monday">Lunedì</string>
|
||||
<string name="moreSettings">Altre impostazioni</string>
|
||||
<string name="moveDown">Sposta verso il basso</string>
|
||||
<string name="moveUp">Sposta versol\'alto</string>
|
||||
<string name="muteTextToSpeechDuringCallsSummary">Disabilitazione del TextToSpeach durante le chiamate</string>
|
||||
<string name="muteTextToSpeechDuringCallsTitle">Silenziato durante la chiamata</string>
|
||||
<string name="muteTextToSpeechDuringCallsTitle">Silenziare durante le chiamate</string>
|
||||
<string name="name">Nome</string>
|
||||
<string name="needLocationPermForWifiList">L\'elenco delle wifi a cui il tuo dispositivo è stato connesso potrebbe essere usato per determinare i luoghi in cui sei stato. Questo è il motivo per cui il permesso di localizzazione è richiesto per caricare l\'elenco delle wifi. Se vuoi essere in grado di sceglierne una dalla lista devi concedere questo permesso. Altrimenti puoi ancora inserire il nome della tua wifi manualmente.</string>
|
||||
<string name="networkAccuracy">Precisione della rete [m]</string>
|
||||
<string name="newId">Nuovo ID:</string>
|
||||
<string name="newNfcId">Scrivi un nuovo ID NFC</string>
|
||||
<string name="newThreadRules">Nuova discussione</string>
|
||||
<string name="newsOptIn">Vuoi ricevere delle notizie su questa app (solo quelle importanti) nella schermata principale? Queste vengono scaricate dal sito web dello sviluppatore. Non ci sarà nessuna notifica intrusiva, solo un testo nella schermata principale quando apri l\'app.</string>
|
||||
<string name="nfcApplyTagToRule">Applicazione del tag alla regola</string>
|
||||
<string name="nfcBringTagIntoRange">Portarsi nel campo d\'azione di un tag NFC.</string>
|
||||
<string name="nfcBringTagIntoRangeToRead">Ricerca di un TAG da leggere.</string>
|
||||
<string name="nfcEnterValidIdentifier">Inserire un nome valido per il tag (come "porta d\'ingresso di casa").</string>
|
||||
<string name="nfcNoNdefIntentBut">Nessun NFC NDEF intent, ma</string>
|
||||
<string name="nfcBringTagIntoRange">Portare un tag NFC nel campo d\'azione.</string>
|
||||
<string name="nfcBringTagIntoRangeToRead">Avvicina il TAG da leggere.</string>
|
||||
<string name="nfcEnterValidIdentifier">Inserire un nome valido per il tag (come "Porta d\'ingresso di casa").</string>
|
||||
<string name="nfcNoNdefIntentBut">Nessun intento NFC NDEF, ma</string>
|
||||
<string name="nfcNoTag">Nessun tag rilevato.</string>
|
||||
<string name="nfcNotSupportedInThisAndroidVersionYet">NFC non è ancora supportato in questa versione di Android.</string>
|
||||
<string name="nfcReadTag">Lettura ID da un tag</string>
|
||||
<string name="nfcNotSupportedInThisAndroidVersionYet">NFC non ancora supportato in questa versione di Android.</string>
|
||||
<string name="nfcReadTag">Lettura ID dal tag</string>
|
||||
<string name="nfcTag">Tag NFC</string>
|
||||
<string name="nfcTagDataNotUsable">Dato del tag inadatto, riscrivere.</string>
|
||||
<string name="nfcTagDataNotUsable">Dati del tag non leggibili, si prega di riscriverli.</string>
|
||||
<string name="nfcTagDiscovered">Tag rilevato</string>
|
||||
<string name="nfcTagFoundWithText">Trovatao Tag con scritto:</string>
|
||||
<string name="nfcTagReadSuccessfully">Tag letto.</string>
|
||||
<string name="nfcTagWriteError">Errore di scrittura sul tag. E\' in visibilità?</string>
|
||||
<string name="nfcTagWrittenSuccessfully">Scrittura Tag verificata.</string>
|
||||
<string name="nfcTagFoundWithText">Trovato Tag con testo:</string>
|
||||
<string name="nfcTagReadSuccessfully">Tag letto con successo.</string>
|
||||
<string name="nfcTagWriteError">Errore di scrittura sul tag. È sufficientemente vicino?</string>
|
||||
<string name="nfcTagWrittenSuccessfully">Scrittura Tag eseguita con successo.</string>
|
||||
<string name="nfcUnsupportedEncoding">Codifica non supportata:</string>
|
||||
<string name="nfcValueNotSuitable">Valore memorizzato non adatto.</string>
|
||||
<string name="nfcWriteTag">Scrittura tag</string>
|
||||
<string name="no">No</string>
|
||||
<string name="noApplicableFilesFoundInDirectory">Nessun file adatto è stato trovato in quella directory.</string>
|
||||
<string name="noChangeSelectedProfileDoesntMakeSense">Nessun cambiamento selezionato. Questo profilo non ha senso.</string>
|
||||
<string name="noDataChangedReadingAnyway">Sembra che non siano state salvate le modifiche. Tuttavia ci possono essere stati cambiamenti nella memoria che devono essere recuperati. Devo ricaricare il file.</string>
|
||||
<string name="noDataChangedReadingAnyway">Sembra che non siano state salvate le modifiche. Tuttavia ci possono essere stati cambiamenti in memoria che devono essere rimossi. Devo ricaricare il file.</string>
|
||||
<string name="noDevice">nessun dispositivo</string>
|
||||
<string name="noFileManageInstalled">Nessun esploratore di files installato.</string>
|
||||
<string name="noFilesImported">Non è stato possibile importare nessun file.</string>
|
||||
<string name="noKnownWifis">Non c\'è nessuna wifi conosciuta sul tuo dispositivo.</string>
|
||||
<string name="noMapsApplicationFound">Non trovo un navigatore installato.</string>
|
||||
<string name="noOverLap">Nessuna duplicazione di posizioni rilevata.</string>
|
||||
<string name="noPoiInRelevantRange">Nessuna posizione in un range significativo.</string>
|
||||
<string name="noPoisDefinedShort">Nessuna posizione inidcata.</string>
|
||||
<string name="noPoisSpecified">Non hai specificato nessuna posizione. E\' necessario.</string>
|
||||
<string name="noProfileChangeSoundLocked">Il profilo non può essere attivato. Rimane attivo l\'ultimo profilo attivato.</string>
|
||||
<string name="noProfilesCreateOneFirst">Non è specificato nessun profilo nella tua configurazione. Devi farlo prima.</string>
|
||||
<string name="logNoSuitableProvider">Non posso localizzare attraverso il provider.</string>
|
||||
<string name="noWifiNameSpecifiedAnyWillDo">Nessun SSID (nome della wifi) specificato; devi inserirne uno.</string>
|
||||
<string name="noWritableFolderFound">Nessun folder disponibile per salvare il file di configurazione.</string>
|
||||
<string name="noiseDetectionHint">Se pensi che la rilevazione del rumore non funzioni correttamente (in base al valore specificato) considera che ogni telefono è diverso. Quindi puoi tarare il "riferimento per la misurazione del rumore" nelle impostazioni. Consulta http://en.wikipedia.org/wiki/Decibel per maggiori informazioni. È possibile utilizzare la “Taratura audio” della schermata principale per calibrare il dispositivo.</string>
|
||||
<string name="noPoisDefinedShort">Nessuna posizione indicata.</string>
|
||||
<string name="noPoisSpecified">Non hai specificato nessuna posizione. È necessario.</string>
|
||||
<string name="noProfileChangeSoundLocked">Il profilo non può essere attivato. L\'ultimo profilo attivato è bloccato.</string>
|
||||
<string name="noProfilesCreateOneFirst">Non c\'è nessun profilo nella tua configurazione. Prima di tutto, creane uno.</string>
|
||||
<string name="noWritableFolderFound">Nessuna cartella scrivibile trovata che permetta salvare il file di configurazione.</string>
|
||||
<string name="noiseDetectionHint">Se pensi che la rilevazione del rumore non funzioni correttamente (in base al valore specificato) considera che ogni telefono è diverso. Quindi puoi tarare il "riferimento per la misurazione del rumore" nelle impostazioni. Consulta http://en.wikipedia.org/wiki/Decibel per maggiori informazioni. È possibile utilizzare la \"Taratura audio\" dalla schermata principale per calibrare il dispositivo.</string>
|
||||
<string name="none">nessuno</string>
|
||||
<string name="logNotAllMeasurings">P</string>
|
||||
<string name="notEnforcingGps">Permette la localizzazione da terzi e la normale ricerca del provider.</string>
|
||||
<string name="notRearmingProcessMonitoringMessageStopRequested">Messaggio di mancato avvio del monitoraggio, è riciesto l\’arresto.</string>
|
||||
<string name="logNotStartingServiceAfterAppUpdate">Nessun servizio attivo dopo l’aggiornamento dell’App.</string>
|
||||
<string name="logNotStartingServiceAtPhoneBoot">Nessun servizio attivo all’avvio del telefono.</string>
|
||||
<string name="notAllFilesImported">Non è stato possibile importare tutti i file rilevanti.</string>
|
||||
<string name="notification">Notifica</string>
|
||||
<string name="notificationAppears">La notifica appare</string>
|
||||
<string name="notificationDisappears">La notifica non appare</string>
|
||||
<string name="notificationRingtone">Tono di notifica</string>
|
||||
<string name="notificationTriggerExplanation">Questo evento risponderà ad altre applicazioni che aprono notifiche nell\'area apposita (o che vengono chiuse). Puoi specificare un\'altra applicazione da cui la notifica deve provenire. Se non lo fai, saranno incluse le notifiche da qualsiasi altra applicazione. Puoi anche specificare le stringhe che devono o non devono essere presenti nel titolo o nel corpo della notifica. Il confronto fatto non è sensibile alle maiuscole e alle minuscole.</string>
|
||||
<string name="number">numero</string>
|
||||
<string name="ok">Ok</string>
|
||||
<string name="onOff">On/Off</string>
|
||||
<string name="onOff">Acceso/Spento</string>
|
||||
<string name="openExamplesPage">Apri la pagina web con gli esempi</string>
|
||||
<string name="outgoing">effettuata</string>
|
||||
<string name="outgoingAdjective">effettuata</string>
|
||||
<string name="outgoingCallFrom">Ultima chiamata effettuata %1$s fa.</string>
|
||||
<string name="outgoingCallTo">Ultima chiamata effettuata %1$s fa.</string>
|
||||
<string name="overlapBetweenPois">Rilevata sovrapposizione della posizione %1$s. Ridurre il raggio almeno di %2$s metri.</string>
|
||||
<string name="overview">Panoramica</string>
|
||||
<string name="packageName">Nome del pacchetto</string>
|
||||
<string name="parameterName">Nome parametro</string>
|
||||
<string name="parameterType">Tipo parametro</string>
|
||||
<string name="parameterValue">Valore</string>
|
||||
<string name="password">Password</string>
|
||||
<string name="periodicProcessMonitoringIsAlreadyRunning">Non posso avviare il processo ciclico di monitoraggio perché é già attivo.</string>
|
||||
<string name="periodicProcessMonitoringIsNotActive">Non posso fermare il processo ciclico di monitoraggio perchè non è attivo.</string>
|
||||
<string name="periodicProcessMonitoringStarted">Processo ciclico di monitoraggio avviato.</string>
|
||||
<string name="periodicProcessMonitoringStopped">Processo ciclico di monitoraggio terminato.</string>
|
||||
<string name="permissionsExplanation">Spiegazione delle autorizzazioni richieste</string>
|
||||
<string name="permissionsExplanationGeneric">L\'applicazione è in esecuzione in modalità risparmio energetico ed ha pertanto disattivato alcune caratteristiche. Per funzionare appieno richiede ulteriori autorizzazioni. Se si desidera utilizzare tutte le funzionalità è necessario concedere le autorizzazioni indicate o alcune regole non potranno essere eseguite. Per ogni autorizzazione è esplicitato il motivo.
|
||||
Selezionare su “Continua” quando si è pronti a procedere.</string>
|
||||
<string name="permissionsExplanationSmall">Per attivare la funzione che hai tentato di utilizzare, necessitano ulteriori autorizzazioni. Seleziona “Continua” per richiederle.</string>
|
||||
<string name="permissionsTitle">Occorrono le autorizzazioni.</string>
|
||||
<string name="permissionsExplanationGeneric">L\'applicazione si sta eseguendo in modalità limitata ed ha pertanto disattivato alcune funzioni. Per funzionare appieno richiede ulteriori permessi. Se vuoi utilizzare tutte le funzionalità è necessario concedere i permessi nelle successive finestre o alcune regole non potranno essere eseguite. Di seguito ti viene data una spiegazione dei permessi richiesti. Clicca su \"Continua\" quando sei pronto a procedere.</string>
|
||||
<string name="permissionsExplanationSmall">Per attivare la funzione che hai appena tentato di utilizzare, sono necessari ulteriori permessi. Clicca \"Continua\" per richiederli.</string>
|
||||
<string name="permissionsTitle">Permessi necessari</string>
|
||||
<string name="phoneCall">Chiamata</string>
|
||||
<string name="phoneDirection">Seleziona se entrante o uscente</string>
|
||||
<string name="phoneIsNotRooted">Il telefono non è rootato.</string>
|
||||
<string name="phoneIsRooted">Il telefono è rootato.</string>
|
||||
<string name="phoneDirection">Seleziona se\nentrante o uscente</string>
|
||||
<string name="phoneNrReplacementError">Non ho l\'ultimo numero di telefono e quindi non posso inserirlo nella variabile.</string>
|
||||
<string name="phoneNumber">Numero di telefono</string>
|
||||
<string name="phoneNumberExplanation">È possibile inserire un numero di telefono specifico, ma non è necessario. Se vuoi specificarne uno, puoi sceglierlo dalla tua rubrica o inserirlo manualmente. Inoltre puoi usare espressioni regolari. Per testare un\'espressione regolare mi piace questa pagina:</string>
|
||||
<string name="playSound">Esegui suono</string>
|
||||
<string name="pleaseEnterValidLatitude">Inserisci una latitudine valida.</string>
|
||||
<string name="pleaseEnterValidLongitude">Inserisci una longitudine valida.</string>
|
||||
<string name="pleaseEnterValidName">Inserisci un nome valido.</string>
|
||||
<string name="pleaseEnterValidRadius">Inserisci un raggio positivo e valido.</string>
|
||||
<string name="pleaseSpecifiyAction">Indica almeno un\'azione.</string>
|
||||
<string name="pleaseSpecifiyTrigger">Indica almeno una consizione.</string>
|
||||
<string name="pleaseSpecifiyTrigger">Indica almeno un evento.</string>
|
||||
<string name="poi">Posizione</string>
|
||||
<string name="poiCouldBeInRange">Almeno la posizione %1$s potrebbe essere in zona, se non in sovrapposizione.</string>
|
||||
<string name="poiHasNoWifiNotStoppingCellLocationListener">La posizione non ha la connessione wifi. Continuo CellLocationListener.</string>
|
||||
<string name="poiHasWifiStoppingCellLocationListener">La posizione ha la connessione wifi. Termino CellLocationListener.</string>
|
||||
<string name="poiList">Elenco alfabetico delle posizioni:</string>
|
||||
<string name="poiStillReferenced">Ci sono ancora regole che fanno riferimento alla posizione (%1$s). Quindi non posso cancellare.</string>
|
||||
<string name="poiList">Elenco delle posizioni:</string>
|
||||
<string name="poiStillReferenced">Ci sono ancora regole che fanno riferimento a questa posizione (%1$s). Quindi non posso cancellarla ancora.</string>
|
||||
<string name="pois">Posizioni</string>
|
||||
<string name="positioningEngine">Modulo di posizionamento</string>
|
||||
<string name="positioningSettings">Impostazioni del posizionamento</string>
|
||||
<string name="positioningThresholds">Soglia del posizionamento</string>
|
||||
<string name="positioningWindowNotice">Se sei all\' interno di un edificio è fortemente consigliato accostarsi ad una finestra fino a quando è stata trovata una posizione. Diversamente la ricerca può richiedere molto tempo.</string>
|
||||
<string name="privacy">Info Privacy</string>
|
||||
<string name="positioningThresholds">Soglie del posizionamento</string>
|
||||
<string name="positioningWindowNotice">Se sei all\' interno di un edificio è fortemente consigliato avvicinarsi ad una finestra fino a quando è stata trovata una posizione. Diversamente la ricerca potrebbe richiedere molto tempo o non riuscire a trovare nulla.</string>
|
||||
<string name="postsNotification">%1$s notifica dei messaggi</string>
|
||||
<string name="prefsImportError">C\'è stato un errore nell\'importazione delle preferenze.</string>
|
||||
<string name="privacy">Informativa sulla Privacy</string>
|
||||
<string name="privacyConfirmationText">Sarai reindirizzato al sito dello sviluppatore per scaricare l\'informativa sulla privacy.</string>
|
||||
<string name="privacyLocationingSummary">Evita i metodi di localizzazione che possono inviare la tua posizione a un provider, ad esempio Google. Userà solo il GPS. Questo può provocare rallentamenti o non funzionare correttamente.</string>
|
||||
<string name="privacyLocationingTitle">Solo posizioni riservate</string>
|
||||
<string name="privacyLocationingSummary">Evita i metodi di localizzazione che possono inviare la tua posizione a un provider, ad esempio Google. Userà solo il GPS e pertanto potrebbe essere lento o non funzionare correttamente.</string>
|
||||
<string name="privacyLocationingTitle">Solo posizioni private</string>
|
||||
<string name="processMonitoring">Controllo di un processo</string>
|
||||
<string name="processes">Processi</string>
|
||||
<string name="profile">Profilo</string>
|
||||
<string name="profileActivate">Attivazione del profilo %1$s</string>
|
||||
<string name="profileList">Lista alfabetica dei profili</string>
|
||||
<string name="profiles">Profili</string>
|
||||
<string name="radiusHasToBePositive">Il raggio deve avere valore positivo.</string>
|
||||
<string name="radiusSuggestion">metri. Il raggio minimo è +1 ma puoi aumentare.</string>
|
||||
<string name="publishedOn">pubblicato il</string>
|
||||
<string name="radiusHasToBePositive">Il raggio deve essere un numero positivo.</string>
|
||||
<string name="radiusWithUnit">Raggio [m]</string>
|
||||
<string name="readLocation">Legge la posizione</string>
|
||||
<string name="rearmingProcessMonitoringMessage">Messaggio di riavvio del monitoraggio.</string>
|
||||
<string name="referenceValueForNoiseLevelMeasurementsSummary">Valore di riferimento fisico per la misura di rumore</string>
|
||||
<string name="referenceValueForNoiseLevelMeasurementsTitle">Riferimento per la misura di rumore</string>
|
||||
<string name="refreshingProcessList">Ricontrollo la lista dei processi.</string>
|
||||
<string name="refreshingSettingsFromFileToMemory">Riprisitna in memoria le impostzioni memorizzate in un file.</string>
|
||||
<string name="rememberLastActivePoiSummary">Se sei in una posizione, la memorizza in modo che al riavvio l\'applicazione eseguirà le regole associate al lasciare la posizione.</string>
|
||||
<string name="rememberLastActivePoiTitle">Ricorda la posizione dell\'ultima attività</string>
|
||||
<string name="rememberLastActivePoiSummary">Se sei in una posizione, riavvia il tuo dispositivo o l\'applicazione e lascia la posizione. L\'applicazione eseguirà le regole associate alla uscita dal luogo al suo prossimo avvio.</string>
|
||||
<string name="rememberLastActivePoiTitle">Ricorda la ultima posizione attiva</string>
|
||||
<string name="removedNotification">la notifica da %1$s rimossa</string>
|
||||
<string name="ringing">squillando</string>
|
||||
<string name="roaming">Roaming</string>
|
||||
<string name="rootExplanation">È necessario rootare il telefono per utilizzare questa funzione. Una volta rootato il telefono devi "eseguire la regola manualmente" per attivare la richiesta di autorizzazione come superuser. E\' necessario autorizzare l\'applicazione a utilizzare il profilo superuser sempre. In caso contrario, la regola non può funzionare quando il telefono è inattivo.</string>
|
||||
<string name="rootExplanation">È necessario avere permessi di root per utilizzare questa funzione. Una volta abilitato l\'accesso root, dovrai \"eseguire la regola manualmente\" per attivare la richiesta di autorizzazione come superuser. Quando la finestra di superuser appare, bisognerà autorizzare l\'applicazione a utilizzare superuser sempre. In caso contrario, la regola non potrà funzionare quando il telefono è inattivo.</string>
|
||||
<string name="rule">Regola</string>
|
||||
<string name="ruleActivate">Esecuzione di %1$s</string>
|
||||
<string name="ruleActivateToggle">Esecuzione di %1$s come Toggle</string>
|
||||
<string name="ruleActive">Attiva</string>
|
||||
<string name="ruleCheckOf">Controllo della regola %1$s</string>
|
||||
<string name="ruleDoesntApplyActivityGivenButTooLowProbability">Regola inapplicabile. Attività %1$s rilevata, ma con una probabilità insufficente (%2$s %%), occorre almeno il %3$s %%.</string>
|
||||
<string name="ruleDoesntApplyActivityNotPresent">Regola inapplicabile. Serve l\'attività %1$s non disponibile.</string>
|
||||
<string name="ruleDoesntApplyBatteryHigherThan">Regola inapplicabile: Livello della batteria superiore a</string>
|
||||
<string name="ruleDoesntApplyBatteryLowerThan">Regola inapplicabile: livello della batteria inferiore a</string>
|
||||
<string name="ruleDoesntApplyDeviceInRangeButShouldNotBe">Regola inapplicabile. Incoerente il range del dispositivo</string>
|
||||
<string name="ruleDoesntApplyItsLouderThan">Regola inapplicabile. E\' più forte di</string>
|
||||
<string name="ruleDoesntApplyItsQuieterThan">Regola inapplicabile. E\' inferiore a</string>
|
||||
<string name="ruleDoesntApplyNoTagLabel">Regola inapplicabile. Non vi è alcuna etichetta tag o nessun tag. </string>
|
||||
<string name="ruleDoesntApplyNotTheCorrectDeviceAddress">Regola inapplicabile. Indirizzo dispositivo bluetooth errato.</string>
|
||||
<string name="ruleDoesntApplyNotTheCorrectDeviceName">Regola inapplicabile. Nome dispositivo bluetooth errato.</string>
|
||||
<string name="ruleDoesntApplyNotTheCorrectSsid">Regola inapplicabile. SSID errato (demanded: \"%1$s\", given: \"%2$s\").</string>
|
||||
<string name="ruleDoesntApplyStateNotCorrect">Regola inapplicabile. Stato errato</string>
|
||||
<string name="ruleDoesntApplyWeAreFasterThan">Regola inapplicabile. Velocità superiore a</string>
|
||||
<string name="ruleDoesntApplyWeAreSlowerThan">Regola inapplicabile. Velocità inferiore a</string>
|
||||
<string name="ruleDoesntApplyWrongHeadphoneType">Regola inapplicabile. Tipo di auricolare errato.</string>
|
||||
<string name="ruleDoesntApplyWrongTagLabel">Regola inapplicabile. Etichetta Tag errata.</string>
|
||||
<string name="ruleActivate">Attivando la regola %1$s</string>
|
||||
<string name="ruleActivateToggle">Attivando la regola %1$s in modalità reversibile</string>
|
||||
<string name="ruleActive">Regola attiva</string>
|
||||
<string name="ruleHistory">Cronologia delle regole (dalla più recente):</string>
|
||||
<string name="ruleIsDeactivatedCantApply">La regola %1$s é disattiva e non posso applicarla.</string>
|
||||
<string name="ruleLegend">Verde = attiva, Rosso = inattiva, Giallo = necessita ulterori autorizzazioni Android.</string>
|
||||
<string name="ruleList">Elenco alfabetico delle regole:</string>
|
||||
<string name="ruleLegend">Verde = abilitata, Rosso = disabilitata, Giallo = necessita ulteriori permessi</string>
|
||||
<string name="ruleList">Elenco delle regole:</string>
|
||||
<string name="ruleName">Nome della regola</string>
|
||||
<string name="ruleNotToggable">La regola %1$s non è Reversibile.</string>
|
||||
<string name="ruleToggable">La regola %1$s é Reversibile.</string>
|
||||
<string name="ruleXrequiresThis">Lo richiede la regola \"%1$s\".</string>
|
||||
<string name="ruleToggable">La regola %1$s è adatta per essere Reversibile.</string>
|
||||
<string name="ruleXrequiresThis">La regola \"%1$s\" ne ha bisogno.</string>
|
||||
<string name="rules">Regole</string>
|
||||
<string name="rulesImportError">C\'è stato un errore nell\'importazione di regole e posizioni</string>
|
||||
<string name="rulesImportedSuccessfully">Le regole e le posizioni sono state importate con successo.</string>
|
||||
<string name="runManually">Esecuzione manuale</string>
|
||||
<string name="runningApp">App in esecuzione</string>
|
||||
<string name="satisfactoryAccuracyGps">precisione minima in metri quando la posizione è individuata via GPS</string>
|
||||
<string name="satisfactoryAccuracyNetwork">Precisione minima quando la localizzazione è effettuata in metri attraverso le celle radiomobile </string>
|
||||
<string name="satisfactoryAccuracyGps">Precisione minima in metri quando la posizione è individuata via GPS</string>
|
||||
<string name="satisfactoryAccuracyNetwork">Precisione minima quando la localizzazione è effettuata in metri attraverso i ripetitori</string>
|
||||
<string name="saturday">Sabato</string>
|
||||
<string name="save">Salva</string>
|
||||
<string name="savePoi">Salva posizione</string>
|
||||
<string name="saveRule">Conferma</string>
|
||||
<string name="saveRule">Salva Regola</string>
|
||||
<string name="screenLockSoundNotice">I suoni di blocco dello schermo non possono più essere modificati automaticamente sui dispositivi con Android versione 6.0 o superiore. Qualunque cosa tu abbia impostato qui, non funzionerà in nessuna direzione.</string>
|
||||
<string name="screenLockUnlockSound">Suono di blocco/sblocco schermo</string>
|
||||
<string name="screenRotationAlreadyDisabled">Rotazione schermo già disattiva.</string>
|
||||
<string name="screenRotationAlreadyDisabled">Rotazione schermo già disattivata.</string>
|
||||
<string name="screenRotationAlreadyEnabled">Rotazione schermo già attiva.</string>
|
||||
<string name="screenRotationDisabled">Rotazione schermo disabilitata.</string>
|
||||
<string name="screenRotationEnabled">Rotazione schermo attivata.</string>
|
||||
<string name="selectActivityToBeStarted">Seleziona l\'attività del pacchetto scelto</string>
|
||||
<string name="selectApplication">Aggiungi App</string>
|
||||
<string name="selectApplication">Scegli App</string>
|
||||
<string name="selectBattery">Seleziona il livello di batteria</string>
|
||||
<string name="selectConnectionOption">Seleziona una opzione di connessione.</string>
|
||||
<string name="selectDeviceFromList">uno della lista</string>
|
||||
<string name="selectDeviceOption">Seleziona una opzione del dispositivo</string>
|
||||
<string name="selectDeviceFromList">uno dalla lista</string>
|
||||
<string name="selectDeviceOption">Seleziona una opzione di dispositivo</string>
|
||||
<string name="selectNoiseLevel">Seleziona il livello di rumore</string>
|
||||
<string name="selectOneDay">Seleziona almeno un giorno</string>
|
||||
<string name="selectPackageOfApplication">Seleziona quale attività</string>
|
||||
<string name="selectPackageOfApplication">Seleziona il pacchetto dell\'applicazione</string>
|
||||
<string name="selectPoi">Seleziona la posizione</string>
|
||||
<string name="selectSoundFile">Select sound file</string>
|
||||
<string name="selectSoundProfile">Seleziona il profilo audio</string>
|
||||
<string name="selectSpeed">Seleziona la velocità</string>
|
||||
<string name="selectToggleDirection">Seleziona</string>
|
||||
<string name="selectToggleDirection">Seleziona acceso o spento?</string>
|
||||
<string name="selectTypeOfAction">Seleziona il tipo di azione</string>
|
||||
<string name="selectTypeOfActivity">Seleziona il tipo di attività</string>
|
||||
<string name="selectTypeOfIntentPair">Seleziona il tipo per la coppia di Intent</string>
|
||||
<string name="selectTypeOfIntentPair">Seleziona il tipo per la coppia di Intenzioni</string>
|
||||
<string name="selectTypeOfTrigger">Seleziona il tipo di evento</string>
|
||||
<string name="service">Stato:</string>
|
||||
<string name="logServiceAlreadyRunning">Richiesta di attivazione sul servizio già attivo.</string>
|
||||
<string name="sendTextMessage">Invia messaggio di testo</string>
|
||||
<string name="service">Servizio:</string>
|
||||
<string name="serviceHasToRunForThat">Devi attivare il servizio.</string>
|
||||
<string name="serviceNotRunning">Servizio non attivo.</string>
|
||||
<string name="serviceStarted">Automation attivata.</string>
|
||||
<string name="version">Versione %1$s.</string>
|
||||
<string name="logServiceStarting">Avvio del servizio</string>
|
||||
<string name="serviceStopped">Attività di Automation terminata.</string>
|
||||
<string name="logServiceStopping">Arresto attività.</string>
|
||||
<string name="serviceWontStart">Non c\'è nessuna regola. L\'attività non può iniziare.</string>
|
||||
<string name="serviceStarted">Il servizio di Automation è attivo.</string>
|
||||
<string name="serviceStopped">Il servizio di Automation è stato fermato.</string>
|
||||
<string name="serviceWontStart">Nessuna regola definita. Il servizio non può iniziare.</string>
|
||||
<string name="setScreenBrightness">Impostare la luminosità dello schermo</string>
|
||||
<string name="setScreenBrightnessEnterValue">Digitare la luminosità desiderata (da 0 a 100).</string>
|
||||
<string name="settings">Impostazioni</string>
|
||||
<string name="settingsCategoryHttp">Richieste HTTP(s)</string>
|
||||
<string name="settingsCategoryNoiseLevelMeasurements">Misura del livello di rumore</string>
|
||||
<string name="settingsCategoryProcessMonitoring">Controllo di processo</string>
|
||||
<string name="settingsCategoryProcessMonitoring">Monitoraggio del processo</string>
|
||||
<string name="settingsErased">Impostazioni cancellate.</string>
|
||||
<string name="settingsSetToDefault">Impostazioni di default ripristinate.</string>
|
||||
<string name="settingsWillTakeTime">Per rendere efficaci alcune impostazioni è necessario il riavvio o la modifica delle posizioni.</string>
|
||||
<string name="showHelp">Descrizione</string>
|
||||
<string name="settingsReferringToRestrictedFeatures">Le tue impostazioni e/o regole si riferiscono attualmente a funzioni non coperte da una licenza aperta e che pertanto non possono essere fornite nella versione F-Droid. Questo include il rilevamento della tua attuale attività fisica.</string>
|
||||
<string name="settingsSetToDefault">Impostazioni predefinite ripristinate.</string>
|
||||
<string name="settingsWillTakeTime">Alcune impostazioni non saranno applicate prima che alcune impostazioni contestuali cambino o che il servizio venga riavviato.</string>
|
||||
<string name="shareConfigAndLogExplanation">Questo creerà una email con la tua configurazione e i file di log allegati come file zip. Non sarà inviata automaticamente, dovrai premere \"invia\". Puoi anche cambiare il destinatario con te stesso, per esempio.</string>
|
||||
<string name="shareConfigAndLogFilesWithDev">Condividere i file di configurazione e di registro con lo sviluppatore (via e-mail).</string>
|
||||
<string name="showHelp">Mostra Aiuto</string>
|
||||
<string name="showIcon">Mostra icona</string>
|
||||
<string name="showIconWhenServiceIsRunning">Mostra una icona quando attiva (nascondere funziona solo sotto Android 7)</string>
|
||||
<string name="showIconWhenServiceIsRunning">Mostra una icona quando il servizio è attivo (nasconderla funziona solo in versioni inferiori ad Android 7)</string>
|
||||
<string name="showOnMap">Mostra sulla mappa</string>
|
||||
<string name="someOptionsNotAvailableYet">Alcune opzioni sono disabilitate in quanto non ancora implementate. Saranno introdotte in una versione successiva.</string>
|
||||
<string name="soundMode">Sonoro</string>
|
||||
<string name="soundMode">Modalità sonora</string>
|
||||
<string name="soundModeNormal">Normale</string>
|
||||
<string name="soundModeSilent">Silenziato</string>
|
||||
<string name="soundModeSilent">Silenziosa</string>
|
||||
<string name="soundModeVibrate">Vibrazione</string>
|
||||
<string name="soundSettings">Impostazioni del sonoro</string>
|
||||
<string name="soundSettings">Impostazioni del suono</string>
|
||||
<string name="speedMaximumTime">Tempo in minuti</string>
|
||||
<string name="speedMaximumTimeBetweenLocations">Tempo massimo tra la rilevazione di due posizioni per determinare la velocità.</string>
|
||||
<string name="speedMaximumTimeBetweenLocations">Tempo massimo tra la rilevazione di due posizioni per determinarne la velocità.</string>
|
||||
<string name="start">Inizio</string>
|
||||
<string name="startAtSystemBoot">Avvio automatic al boot</string>
|
||||
<string name="startNewThreadForRuleExecution">Nuovo tentativo di attivazione della regola.</string>
|
||||
<string name="startAppByAction">per azione</string>
|
||||
<string name="startAppByActivity">per attività</string>
|
||||
<string name="startAppBySendBroadcast">per sendBroadcast()</string>
|
||||
<string name="startAppByStartActivity">per startActivity()</string>
|
||||
<string name="startAppChoiceNote">Qui hai 2 opzioni generali:\n\n1. Puoi avviare un programma selezionando un\'attività. Immagina questo come la preselezione di una specifica schermata/finestra di un\'applicazione. Tieni a mente che questo potrebbe non funzionare sempre. Questo perché le finestre di un\'applicazione potrebbero interagire tra loro, ad esempio per passarsi dei parametri. Quando si avvia direttamente una schermata specifica la cui\n\ninterazione non è ancora avvenuta, la finestra potrebbe chiudersi istantaneamente (quindi non verrà mai mostrata). Ma puoi provare comunque! Inserisci un percorso di attività manualmente, ma si raccomanda di usare il pulsante \"Seleziona\". Se decidi di inserirlo manualmente, digita il nome del pacchetto dell\'applicazione nel campo superiore e il percorso completo dell\'attività in quello inferiore.\n\n2. Selezione per azione. Invece che selezionare una specifica finestra puoi anche avviare un programma per mezzo di un\'azione. Questo è come gridare "Vorrei xyz" e se c\'è un\'applicazione installata che è registrata con quella funzione, verrà avviata. Un buon esempio sarebbe avviare un navigatore - potresti anche averne più di uno installato (ma uno è di solito quello di default). Devi inserire questo manualmente, mentre PackageName è opzionale qui. Tieni a mente che nessuna variabile sarà risolta. Se vuoi avviare la fotocamera per esempio usando \"MediaStore.ACTION_IMAGE_CAPTURE\" non funzionerà. Devi dare un\'occhiata alla documentazione di Android e usare invece il valore effettivo di questa variabile che in questo esempio sarebbe \"android.media.action.IMAGE_CAPTURE\".</string>
|
||||
<string name="startAppSelectionType">Metodo per\nselezionare l\'applicazione</string>
|
||||
<string name="startAppStartType">Seleziona tipo di avvio</string>
|
||||
<string name="startAtSystemBoot">Avvio automatico al boot</string>
|
||||
<string name="startAutomationAsService">Avvia Automation come un servizio</string>
|
||||
<string name="startNewThreadForRuleExecution">Iniziata nuova esecuzione per l\'attivazione della regola.</string>
|
||||
<string name="startOtherActivity">Inizia una nuova app</string>
|
||||
<string name="startServiceAfterAppUpdate">Riavvia automaticamente l\'app dopo un aggiornamento se era già in esecuzione.</string>
|
||||
<string name="startServiceAfterAppUpdateShort">Riavvio dopo aggiornamento</string>
|
||||
<string name="started">avviando</string>
|
||||
<string name="starting">avvio</string>
|
||||
<string name="startingGpsTimeout">In attesa del GPS</string>
|
||||
<string name="startingPeriodicProcessMonitoringEngine">Avviare il processo ciclico di monitoraggio.</string>
|
||||
<string name="logStartingServiceAfterAppUpdate">Inizio attività dopo l\'aggiornamento.</string>
|
||||
<string name="logStartingServiceAtPhoneBoot">Starting service at phone boot.</string>
|
||||
<string name="status">Riepilogo</string>
|
||||
<string name="stillGettingPosition">In attesa</string>
|
||||
<string name="stopped">terminando</string>
|
||||
<string name="stopping">quando finisce</string>
|
||||
<string name="stoppingPeriodicProcessMonitoringEngine">Fermare il processo ciclico di monitoraggio engine.</string>
|
||||
<string name="storeSettings">Scrivere e/o leggere le impostazioni</string>
|
||||
<string name="startScreen">Schermo di Avvio</string>
|
||||
<string name="startScreenSummary">Seleziona la schermata con cui le applicazioni si aprono all\'inizio.</string>
|
||||
<string name="startServiceAfterAppUpdate">Riavvia automaticamente il servizio se era già in esecuzione, dopo che l\'applicazione venga aggiornata.</string>
|
||||
<string name="startServiceAfterAppUpdateShort">Riavvio del servizio dopo l\'aggiornamento</string>
|
||||
<string name="started">avviato</string>
|
||||
<string name="starting">avviando</string>
|
||||
<string name="status">Stato</string>
|
||||
<string name="stillGettingPosition">Ancora in attesa della posizione</string>
|
||||
<string name="stopped">terminatoo</string>
|
||||
<string name="stopping">terminando</string>
|
||||
<string name="storeSettings">Leggere e scrivere le impostazioni</string>
|
||||
<string name="stringNotAllowed">La stringa %1$s non è permessa.</string>
|
||||
<string name="sunday">Domenica</string>
|
||||
<string name="systemSettingsNote1">E\' necessaria l’abilitazione a modificare alcune impostazioni del sistema operativo (anche cose semplici come accendere il Bluetooth o ilm Wifi). Dopo aver selezionato "Continua" si aprirà un popup per abilitare Automation. Premi il tasto "back" per tornare.</string>
|
||||
<string name="systemSettingsNote1">Il permesso di cambiare alcune impostazioni del sistema operativo è necessario (anche per cose semplici come attivare il bluetooth o il wifi). Dopo aver cliccato su \"continua\" si aprirà una finestra dove dovrai abilitare questo per Automation. Poi premi il tasto \"indietro\".</string>
|
||||
<string name="systemSettingsNote2">Ulteriori autorizzazioni verranno richieste in una seconda finestra.</string>
|
||||
<string name="textToSpeak">Text to speak</string>
|
||||
<string name="text">Testo</string>
|
||||
<string name="textMessageAnnotations">Puoi inserire direttamente un numero di telefono. In alternativa usa l\'opzione contatti per sceglierne uno. Ma tieni presente che il numero verrà memorizzato qui, non nel contatto. Se cambi il numero di telefono di un contatto, dovrai aggiornarlo nella questa regola. Non si aggiorna da solo.</string>
|
||||
<string name="textToSend">Testo da inviare</string>
|
||||
<string name="textToSpeak">Testo da leggere</string>
|
||||
<string name="textTooShort">Il testo deve avere almeno 10 caratteri.</string>
|
||||
<string name="theFollowingPermissionsHaveBeenDenied">Sono state negate le seguenti autorizzazioni:</string>
|
||||
<string name="theseAreThePermissionsRequired">Necessitano le seguenti autorizzazioni:</string>
|
||||
<string name="theseAreThePermissionsRequired">Queste sono le autorizzazioni necessarie:</string>
|
||||
<string name="thursday">Giovedì</string>
|
||||
<string name="timeBetweenNoiseLevelMeasurementsSummary">Secondi tra misure di livello di rumore</string>
|
||||
<string name="timeBetweenNoiseLevelMeasurementsTitle">Secondi tra misure di livello di rumore</string>
|
||||
<string name="timeBetweenProcessMonitoringsSummary">Più è basso e più alto sarà il consume della batteria</string>
|
||||
<string name="timeBetweenProcessMonitoringsSummary">Più è basso e più sarà alto il consumo della batteria</string>
|
||||
<string name="timeBetweenProcessMonitoringsTitle">Secondi tra un monitoraggio e l\'altro</string>
|
||||
<string name="timeForUpdate">Intervallo di aggiornamento [millisecondi]</string>
|
||||
<string name="timeFrameWhichDays">Che giorno?</string>
|
||||
<string name="timeFrameWhichDays">In che giorni?</string>
|
||||
<string name="timeframes">Intervalli</string>
|
||||
<string name="timeoutForGpsComparisonsSummary">Massimo tempo in secondi per cercare di individuare la posizione GPS per confront. Allo scadere sarà assunta valida l\'ultima localizzazione rilevata.</string>
|
||||
<string name="timeoutForGpsComparisonsTitle">GPS timeout [sec]</string>
|
||||
<string name="title_activity_main">Automation</string>
|
||||
<string name="toggableRules">Regole “Reversibili”</string>
|
||||
<string name="toggle">toggle</string>
|
||||
<string name="toggleNotAllowed">La reversibilità al momento è disponibile solo per le regole che hanno come evento un tag NFC. Consulta l\'help per i dettagli.</string>
|
||||
<string name="toggleRule">Reversibile</string>
|
||||
<string name="toggling">Inversione</string>
|
||||
<string name="triggerCharging">Carica della Batteria</string>
|
||||
<string name="triggerHeadsetPlugged">Inserimento auricolari</string>
|
||||
<string name="timeoutForGpsComparisonsSummary">Massimo tempo in secondi per cercare di individuare la posizione GPS per la comparazione. Allo scadere sarà assunta valida l\'ultima localizzazione rilevata.</string>
|
||||
<string name="timeoutForGpsComparisonsTitle">Timeout del GPS [sec]</string>
|
||||
<string name="title">Titolo</string>
|
||||
<string name="to">a</string>
|
||||
<string name="toggableRules">Regole \"Reversibili\"</string>
|
||||
<string name="toggle">reversibile</string>
|
||||
<string name="toggleNotAllowed">La reversibilità al momento è disponibile solo per le regole che hanno come evento un tag NFC. Consulta l\'aiuto per i dettagli.</string>
|
||||
<string name="toggleRule">Regola Reversibile</string>
|
||||
<string name="toggling">Attivando</string>
|
||||
<string name="triggerCharging">Batteria sotto carica</string>
|
||||
<string name="triggerHeadsetPlugged">Connessione Auricolari</string>
|
||||
<string name="triggerNoiseLevel">Livello del rumore di fondo</string>
|
||||
<string name="triggerOnlyAvailableIfPlayServicesInstalled">Questa evento è valida solo se Google play service è installato.</string>
|
||||
<string name="triggerOnlyAvailableIfPlayServicesInstalled">Questa evento è valido solo se Google play service è installato.</string>
|
||||
<string name="triggerPointOfInterest">Posizione</string>
|
||||
<string name="triggerSpeed">Velocità</string>
|
||||
<string name="triggerTimeFrame">Intervallo</string>
|
||||
<string name="triggerUrlReplacementPositionError">Hai chiesto di aggiungere una posizione alla tua URL. Purtroppo non ho ancora alcuna posizione.</string>
|
||||
<string name="triggerUsb_host_connection">connessione al computer (USB)</string>
|
||||
<string name="triggers">evento(i)</string>
|
||||
<string name="triggersComment">(le attive saranno applicate in AND)</string>
|
||||
<string name="triggers">Evento(i)</string>
|
||||
<string name="triggersComment">(tutti gli eventi devono essere validi allo stesso tempo)</string>
|
||||
<string name="tuesday">Martedì</string>
|
||||
<string name="logUnboundFromService">Servizio disimpegnato.</string>
|
||||
<string name="unknownActionSpecified">Azione non riconosciuta.</string>
|
||||
<string name="unknownError">Errore indeterminato.</string>
|
||||
<string name="until">finchè</string>
|
||||
<string name="urlLegend">Variabili:\n È possibile utilizzare le seguenti variabili. All\'innesco saranno sostituite con il valore corrispondente sul dispositivo. Includi le parentesi nella tuo testo.\n\n[uniqueid] - L\'imei del tuo dispositivo\n[serialnr] - Il serial number del tuo dispositivio\n[latitude] - La latitudine del tuo dispositivo\n[longitude] - La longitudine del tuo dispositivo\n[phonenr] - Nr ultima chiamata (entrante o uscente)\n[d] - Il giorno del mese, sempre 2 cifre\n[m] - Mese in formato numerico, sempre 2 cifre\n[Y] - L’anno, sempre 4 cifre\n[h] - Ore in formato 12 ore, sempre 2 cifre con due punti\n[H] - Ore in formato 24 ore, sempre 2 cifre con due punti\n[i] - Minuti, sempre 2 cifre\n[s] - Secondi, sempre 2 cifre\n[ms] - millisecondi, sempre 3 cifre
|
||||
</string>
|
||||
<string name="urlLegend">Variabili:\n È possibile utilizzare le seguenti variabili. All\'attivazione saranno sostituite con il valore corrispondente sul dispositivo. Includi le parentesi nel tuo testo.\n\n[uniqueid] - Il numero di serie del tuo dispositivo\n[serialnr] - Il serial number del tuo dispositivio\n[latitude] - La latitudine del tuo dispositivo\n[longitude] - La longitudine del tuo dispositivo\n[phonenr] - Numero dell\'ultima chiamata (entrante o uscente)\n[d] - Il giorno del mese, sempre 2 cifre\n[m] - Mese in formato numerico, sempre 2 cifre\n[Y] - L\’anno, sempre 4 cifre\n[h] - Ore in formato 12 ore, sempre 2 cifre con due punti\n[H] - Ore in formato 24 ore, sempre 2 cifre con due punti\n[i] - Minuti, sempre 2 cifre\n[s] - Secondi, sempre 2 cifre\n[ms] - millisecondi, sempre 3 cifre [notificationTitle] - titolo dell\'ultima notifica [notificationText] - testo dell\'ultima notifica</string>
|
||||
<string name="urlToTrigger">URL da caricare:</string>
|
||||
<string name="urlTooShort">La url deve avere almeno 10 caratteri.</string>
|
||||
<string name="usbTetheringFailForAboveGingerbread">Questo molto probabilmente non funziona con versioni superiori ad Android 2.3. Tuttavia è possibile utilizzare la connessione wifi tethering per attivare la regola.</string>
|
||||
<string name="useAuthentication">Attiva Username e Password</string>
|
||||
<string name="urlTooShort">L\'url deve avere almeno 10 caratteri.</string>
|
||||
<string name="usbTetheringFailForAboveGingerbread">Questo molto probabilmente non funzionerà dato che sei su una versione superiore ad Android 2.3. Tuttavia è possibile utilizzare la connessione wifi tethering per attivare la regola.</string>
|
||||
<string name="useAuthentication">Usa l\'autenticazione</string>
|
||||
<string name="useExistingTag">Utilizzo di un tag NFC esistente</string>
|
||||
<string name="useTextToSpeechOnNormalSummary">Usa TextToSpeech nel modo normale</string>
|
||||
<string name="useTextToSpeechOnNormalTitle">TTS in modo normale</string>
|
||||
@ -533,19 +545,21 @@ Selezionare su “Continua” quando si è pronti a procedere.</string>
|
||||
<string name="useTextToSpeechOnSilentTitle">TTS in modo silenzioso</string>
|
||||
<string name="useTextToSpeechOnVibrateSummary">Usa TextToSpeech nel modo vibrazione</string>
|
||||
<string name="useTextToSpeechOnVibrateTitle">TTS in modo vibrazione</string>
|
||||
<string name="username">Username</string>
|
||||
<string name="usingNewThreadForRuleExecution">Nuovo tentativo di avvio della regola.</string>
|
||||
<string name="username">Nome utente</string>
|
||||
<string name="usingNewThreadForRuleExecution">Iniziata nuova esecuzione per l\'attivazione della regola.</string>
|
||||
<string name="version">Versione %1$s.</string>
|
||||
<string name="vibrateWhenRinging">Vibrazione alla chiamata</string>
|
||||
<string name="volumeAlarms">Allarmi sonori</string>
|
||||
<string name="volumeMusicVideoGameMedia">Multimedia (musica, video …)</string>
|
||||
<string name="volumeRingtoneNotifications">Toni e notifiche</string>
|
||||
<string name="volumeTest">Taratura audio</string>
|
||||
<string name="volumeTesterExplanation">Per calcolare il valore del rumore di fondo in dB è necessario specificare un valore di riferimento fisico (si prega di leggere Wikipedia per ulteriori informazioni). Questo valore è probabilmente diverso per ogni telefono. Trascinare il cursore per modificare il valore di riferimento fisico definito. Più alto è il valore di riferimento e più basso sarà il valore misurato in dB. Misurazioni costanti saranno effettuati ogni 3 secondi ed i risultati visualizzati sotto. Premere indietro quando si è trovato un valore adeguato.</string>
|
||||
<string name="volumes">Livelli sonori</string>
|
||||
<string name="volumeTesterExplanation">Per calcolare il valore del rumore di fondo in dB è necessario specificare un valore di riferimento fisico (si prega di leggere Wikipedia per ulteriori informazioni). Questo valore è probabilmente diverso per ogni telefono. Trascinare il cursore per modificare il valore di riferimento fisico definito. Più alto è il valore di riferimento e più basso sarà il valore misurato in dB. Misurazioni costanti saranno effettuate ogni %1$s secondi ed i risultati visualizzati sotto. Premere indietro quando hai trovato un valore adeguato.</string>
|
||||
<string name="volumes">Volumi</string>
|
||||
<string name="waitBeforeNextAction">Attesa prima della azione successiva</string>
|
||||
<string name="waitBeforeNextActionEnterValue">Inserisci il valore della pausa tra tra un\'azione e la successiva (millisecondi).</string>
|
||||
<string name="wakeupDevice">Sveglia del dispositivo</string>
|
||||
<string name="wakeupDeviceValue">Inserisci per quanto tempo il dispositivo deve rimanere attivo (millisecondi). In assenza si assume 0.</string>
|
||||
<string name="wakeupDevice">Sveglia il dispositivo</string>
|
||||
<string name="wakeupDeviceValue">Inserisci per quanto tempo il dispositivo deve rimanere attivo (millisecondi). Usa 0 per i valori standard.</string>
|
||||
<string name="warning">Attenzione</string>
|
||||
<string name="wednesday">Mercoledì</string>
|
||||
<string name="whatToDoWithAction">Cosa vuoi fare?</string>
|
||||
<string name="whatToDoWithIntentPair">Cosa fare con la coppia?</string>
|
||||
@ -557,13 +571,19 @@ Selezionare su “Continua” quando si è pronti a procedere.</string>
|
||||
<string name="wifi">wifi</string>
|
||||
<string name="wifiConnection">Connessione wifi</string>
|
||||
<string name="wifiName">Nome wifi</string>
|
||||
<string name="wifiNameMatchesRuleWillApply">Il nome della wifi combacia. La regola può è valida.</string>
|
||||
<string name="wifiNameSpecifiedCheckingThat">Verifica della wifi indicata.</string>
|
||||
<string name="wifiState">Stato Wifi</string>
|
||||
<string name="with">con</string>
|
||||
<string name="withLabel">con etichetta</string>
|
||||
<string name="writeLogFileToSd">Memorizza un file di log su SD card</string>
|
||||
<string name="writingSettingsToPersistentMemory">Scrivo le impostazioni nella memoria di massa.</string>
|
||||
<string name="writeLogFile">Memorizza un file di log</string>
|
||||
<string name="yes">Si</string>
|
||||
<string name="edit">Elaborare</string>
|
||||
</resources>
|
||||
<string name="clone">Clonare</string>
|
||||
<string name="state">Status</string>
|
||||
<string name="urlToTriggerExplanation">Questa funzione NON apre un navigatore, ma attiva un indirizzo URL in secondo piano. Puoi usarla per esempio per mandare dei comandi al tuo sistema di domotica.</string>
|
||||
<string name="automaticUpdateCheck">Controlla aggiornamenti</string>
|
||||
<string name="automaticUpdateCheckSummary">Applicabile solo alla versione APK.</string>
|
||||
<string name="updateAvailable">C\'è un nuovo aggiornamento disponibile. Vuoi aprire il navigatore per scaricarlo?</string>
|
||||
<string name="locationFound">Ubicazione trovata. Il raggio minimo per le ubicazioni è di %1$d m.</string>
|
||||
<string name="locationFoundInaccurate">È stato possibile solo trovare una ubicazione con una precisione limitata. Potrebbe non funzionare in maniera affidabile. Il raggio minimo per le ubicazioni è di %1$d m.</string>
|
||||
<string name="noLocationCouldBeFound">Nessuna posizione è stata trovata dopo un tempo di attesa di %1$s seconds.</string>
|
||||
<string name="pleaseGiveBgLocation">Nella schermata successiva vai su permessi, poi posizione. Lì seleziona \"Consenti sempre\" per permettere ad Automation di determinare la tua posizione in secondo piano.</string>
|
||||
</resources>
|
||||
|
@ -10,10 +10,10 @@
|
||||
</string-array>
|
||||
|
||||
<string-array name="startScreenOptions">
|
||||
<item name="0">Home</item>
|
||||
<item name="1">Locations</item>
|
||||
<item name="2">Rules</item>
|
||||
<item name="3">Profiles</item>
|
||||
<item name="0">@string/overview</item>
|
||||
<item name="1">@string/pois</item>
|
||||
<item name="2">@string/rules</item>
|
||||
<item name="3">@string/profiles</item>
|
||||
</string-array>
|
||||
<string-array name="startScreenOptionsValues">
|
||||
<item name="0">0</item>
|
||||
@ -21,4 +21,16 @@
|
||||
<item name="2">2</item>
|
||||
<item name="3">3</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="tabsPlacementOptions">
|
||||
<item name="0">@string/top</item>
|
||||
<item name="1">@string/bottom</item>
|
||||
</string-array>
|
||||
<string-array name="tabsPlacementOptionsValues">
|
||||
<item name="0">0</item>
|
||||
<item name="1">1</item>
|
||||
<item name="2">2</item>
|
||||
<item name="3">3</item>
|
||||
</string-array>
|
||||
|
||||
</resources>
|
@ -10,5 +10,9 @@
|
||||
<color name="teal_200">#008080</color>
|
||||
<color name="teal_700">#008080</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>
|
||||
|