Initial commit
150
.gitignore
vendored
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
|
||||||
|
# Created by https://www.toptal.com/developers/gitignore/api/androidstudio
|
||||||
|
# Edit at https://www.toptal.com/developers/gitignore?templates=androidstudio
|
||||||
|
|
||||||
|
### AndroidStudio ###
|
||||||
|
# Covers files to be ignored for android development using Android Studio.
|
||||||
|
|
||||||
|
# Built application files
|
||||||
|
*.apk
|
||||||
|
*.ap_
|
||||||
|
*.aab
|
||||||
|
|
||||||
|
# Files for the ART/Dalvik VM
|
||||||
|
*.dex
|
||||||
|
|
||||||
|
# Java class files
|
||||||
|
*.class
|
||||||
|
|
||||||
|
# Generated files
|
||||||
|
bin/
|
||||||
|
gen/
|
||||||
|
out/
|
||||||
|
|
||||||
|
# Gradle files
|
||||||
|
.gradle
|
||||||
|
.gradle/
|
||||||
|
build/
|
||||||
|
|
||||||
|
# Signing files
|
||||||
|
.signing/
|
||||||
|
|
||||||
|
# Local configuration file (sdk path, etc)
|
||||||
|
local.properties
|
||||||
|
|
||||||
|
# Proguard folder generated by Eclipse
|
||||||
|
proguard/
|
||||||
|
|
||||||
|
# Log Files
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Android Studio
|
||||||
|
/*/build/
|
||||||
|
/*/local.properties
|
||||||
|
/*/out
|
||||||
|
/*/*/build
|
||||||
|
/*/*/production
|
||||||
|
captures/
|
||||||
|
.navigation/
|
||||||
|
*.ipr
|
||||||
|
*~
|
||||||
|
*.swp
|
||||||
|
|
||||||
|
# Keystore files
|
||||||
|
*.jks
|
||||||
|
*.keystore
|
||||||
|
|
||||||
|
# Google Services (e.g. APIs or Firebase)
|
||||||
|
# google-services.json
|
||||||
|
|
||||||
|
# Android Patch
|
||||||
|
gen-external-apklibs
|
||||||
|
|
||||||
|
# External native build folder generated in Android Studio 2.2 and later
|
||||||
|
.externalNativeBuild
|
||||||
|
|
||||||
|
# NDK
|
||||||
|
obj/
|
||||||
|
|
||||||
|
# IntelliJ IDEA
|
||||||
|
*.iml
|
||||||
|
*.iws
|
||||||
|
/out/
|
||||||
|
|
||||||
|
# User-specific configurations
|
||||||
|
.idea/caches/
|
||||||
|
.idea/libraries/
|
||||||
|
.idea/shelf/
|
||||||
|
.idea/workspace.xml
|
||||||
|
.idea/tasks.xml
|
||||||
|
.idea/.name
|
||||||
|
.idea/compiler.xml
|
||||||
|
.idea/copyright/profiles_settings.xml
|
||||||
|
.idea/encodings.xml
|
||||||
|
.idea/misc.xml
|
||||||
|
.idea/modules.xml
|
||||||
|
.idea/scopes/scope_settings.xml
|
||||||
|
.idea/dictionaries
|
||||||
|
.idea/vcs.xml
|
||||||
|
.idea/jsLibraryMappings.xml
|
||||||
|
.idea/datasources.xml
|
||||||
|
.idea/dataSources.ids
|
||||||
|
.idea/sqlDataSources.xml
|
||||||
|
.idea/dynamic.xml
|
||||||
|
.idea/uiDesigner.xml
|
||||||
|
.idea/assetWizardSettings.xml
|
||||||
|
.idea/gradle.xml
|
||||||
|
.idea/jarRepositories.xml
|
||||||
|
.idea/navEditor.xml
|
||||||
|
|
||||||
|
# OS-specific files
|
||||||
|
.DS_Store
|
||||||
|
.DS_Store?
|
||||||
|
._*
|
||||||
|
.Spotlight-V100
|
||||||
|
.Trashes
|
||||||
|
ehthumbs.db
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Legacy Eclipse project files
|
||||||
|
.classpath
|
||||||
|
.project
|
||||||
|
.cproject
|
||||||
|
.settings/
|
||||||
|
|
||||||
|
# Mobile Tools for Java (J2ME)
|
||||||
|
.mtj.tmp/
|
||||||
|
|
||||||
|
# Package Files #
|
||||||
|
*.war
|
||||||
|
*.ear
|
||||||
|
|
||||||
|
# virtual machine crash logs (Reference: http://www.java.com/en/download/help/error_hotspot.xml)
|
||||||
|
hs_err_pid*
|
||||||
|
|
||||||
|
## Plugin-specific files:
|
||||||
|
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
# Mongo Explorer plugin
|
||||||
|
.idea/mongoSettings.xml
|
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
|
com_crashlytics_export_strings.xml
|
||||||
|
crashlytics.properties
|
||||||
|
crashlytics-build.properties
|
||||||
|
fabric.properties
|
||||||
|
|
||||||
|
### AndroidStudio Patch ###
|
||||||
|
|
||||||
|
!/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
# End of https://www.toptal.com/developers/gitignore/api/androidstudio
|
||||||
|
|
||||||
|
|
||||||
|
/app/app-release.apk
|
||||||
|
Automation_settings.xml
|
3
.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
150
app/.gitignore
vendored
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
|
||||||
|
# Created by https://www.toptal.com/developers/gitignore/api/androidstudio
|
||||||
|
# Edit at https://www.toptal.com/developers/gitignore?templates=androidstudio
|
||||||
|
|
||||||
|
### AndroidStudio ###
|
||||||
|
# Covers files to be ignored for android development using Android Studio.
|
||||||
|
|
||||||
|
# Built application files
|
||||||
|
*.apk
|
||||||
|
*.ap_
|
||||||
|
*.aab
|
||||||
|
|
||||||
|
# Files for the ART/Dalvik VM
|
||||||
|
*.dex
|
||||||
|
|
||||||
|
# Java class files
|
||||||
|
*.class
|
||||||
|
|
||||||
|
# Generated files
|
||||||
|
bin/
|
||||||
|
gen/
|
||||||
|
out/
|
||||||
|
|
||||||
|
# Gradle files
|
||||||
|
.gradle
|
||||||
|
.gradle/
|
||||||
|
build/
|
||||||
|
|
||||||
|
# Signing files
|
||||||
|
.signing/
|
||||||
|
|
||||||
|
# Local configuration file (sdk path, etc)
|
||||||
|
local.properties
|
||||||
|
|
||||||
|
# Proguard folder generated by Eclipse
|
||||||
|
proguard/
|
||||||
|
|
||||||
|
# Log Files
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Android Studio
|
||||||
|
/*/build/
|
||||||
|
/*/local.properties
|
||||||
|
/*/out
|
||||||
|
/*/*/build
|
||||||
|
/*/*/production
|
||||||
|
captures/
|
||||||
|
.navigation/
|
||||||
|
*.ipr
|
||||||
|
*~
|
||||||
|
*.swp
|
||||||
|
|
||||||
|
# Keystore files
|
||||||
|
*.jks
|
||||||
|
*.keystore
|
||||||
|
|
||||||
|
# Google Services (e.g. APIs or Firebase)
|
||||||
|
# google-services.json
|
||||||
|
|
||||||
|
# Android Patch
|
||||||
|
gen-external-apklibs
|
||||||
|
|
||||||
|
# External native build folder generated in Android Studio 2.2 and later
|
||||||
|
.externalNativeBuild
|
||||||
|
|
||||||
|
# NDK
|
||||||
|
obj/
|
||||||
|
|
||||||
|
# IntelliJ IDEA
|
||||||
|
*.iml
|
||||||
|
*.iws
|
||||||
|
/out/
|
||||||
|
|
||||||
|
# User-specific configurations
|
||||||
|
.idea/caches/
|
||||||
|
.idea/libraries/
|
||||||
|
.idea/shelf/
|
||||||
|
.idea/workspace.xml
|
||||||
|
.idea/tasks.xml
|
||||||
|
.idea/.name
|
||||||
|
.idea/compiler.xml
|
||||||
|
.idea/copyright/profiles_settings.xml
|
||||||
|
.idea/encodings.xml
|
||||||
|
.idea/misc.xml
|
||||||
|
.idea/modules.xml
|
||||||
|
.idea/scopes/scope_settings.xml
|
||||||
|
.idea/dictionaries
|
||||||
|
.idea/vcs.xml
|
||||||
|
.idea/jsLibraryMappings.xml
|
||||||
|
.idea/datasources.xml
|
||||||
|
.idea/dataSources.ids
|
||||||
|
.idea/sqlDataSources.xml
|
||||||
|
.idea/dynamic.xml
|
||||||
|
.idea/uiDesigner.xml
|
||||||
|
.idea/assetWizardSettings.xml
|
||||||
|
.idea/gradle.xml
|
||||||
|
.idea/jarRepositories.xml
|
||||||
|
.idea/navEditor.xml
|
||||||
|
|
||||||
|
# OS-specific files
|
||||||
|
.DS_Store
|
||||||
|
.DS_Store?
|
||||||
|
._*
|
||||||
|
.Spotlight-V100
|
||||||
|
.Trashes
|
||||||
|
ehthumbs.db
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Legacy Eclipse project files
|
||||||
|
.classpath
|
||||||
|
.project
|
||||||
|
.cproject
|
||||||
|
.settings/
|
||||||
|
|
||||||
|
# Mobile Tools for Java (J2ME)
|
||||||
|
.mtj.tmp/
|
||||||
|
|
||||||
|
# Package Files #
|
||||||
|
*.war
|
||||||
|
*.ear
|
||||||
|
|
||||||
|
# virtual machine crash logs (Reference: http://www.java.com/en/download/help/error_hotspot.xml)
|
||||||
|
hs_err_pid*
|
||||||
|
|
||||||
|
## Plugin-specific files:
|
||||||
|
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
# Mongo Explorer plugin
|
||||||
|
.idea/mongoSettings.xml
|
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
|
com_crashlytics_export_strings.xml
|
||||||
|
crashlytics.properties
|
||||||
|
crashlytics-build.properties
|
||||||
|
fabric.properties
|
||||||
|
|
||||||
|
### AndroidStudio Patch ###
|
||||||
|
|
||||||
|
!/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
# End of https://www.toptal.com/developers/gitignore/api/androidstudio
|
||||||
|
|
||||||
|
|
||||||
|
/app/app-release.apk
|
||||||
|
Automation_settings.xml
|
79
app/build.gradle
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
plugins {
|
||||||
|
id 'com.android.application'
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
compileSdkVersion 29
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
applicationId "com.jens.automation2"
|
||||||
|
minSdkVersion 14
|
||||||
|
compileSdkVersion 29
|
||||||
|
buildToolsVersion '29.0.2'
|
||||||
|
useLibrary 'org.apache.http.legacy'
|
||||||
|
versionCode 96
|
||||||
|
versionName "1.6.21"
|
||||||
|
|
||||||
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
minifyEnabled false
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
|
|
||||||
|
lintOptions {
|
||||||
|
checkReleaseBuilds false
|
||||||
|
abortOnError false
|
||||||
|
}
|
||||||
|
|
||||||
|
flavorDimensions "version"
|
||||||
|
|
||||||
|
productFlavors
|
||||||
|
{
|
||||||
|
googlePlayFlavor
|
||||||
|
{
|
||||||
|
dimension "version"
|
||||||
|
applicationIdSuffix ".googlePlay"
|
||||||
|
versionNameSuffix "-googlePlay"
|
||||||
|
targetSdkVersion 29
|
||||||
|
}
|
||||||
|
|
||||||
|
fdroidFlavor
|
||||||
|
{
|
||||||
|
dimension "version"
|
||||||
|
applicationIdSuffix ".fdroid"
|
||||||
|
versionNameSuffix "-fdroid"
|
||||||
|
targetSdkVersion 28
|
||||||
|
}
|
||||||
|
|
||||||
|
apkFlavor
|
||||||
|
{
|
||||||
|
dimension "version"
|
||||||
|
applicationIdSuffix ".apk"
|
||||||
|
versionNameSuffix "-apk"
|
||||||
|
targetSdkVersion 28
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
googlePlayFlavorImplementation 'com.google.firebase:firebase-appindexing:16.0.1'
|
||||||
|
googlePlayFlavorImplementation 'com.google.android.gms:play-services-location:15.0.1'
|
||||||
|
|
||||||
|
apkFlavorImplementation 'com.google.firebase:firebase-appindexing:16.0.1'
|
||||||
|
apkFlavorImplementation 'com.google.android.gms:play-services-location:15.0.1'
|
||||||
|
|
||||||
|
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||||
|
|
||||||
|
implementation 'com.google.android.material:material:1.1.0'
|
||||||
|
testImplementation 'junit:junit:4.+'
|
||||||
|
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||||
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||||
|
}
|
21
app/proguard-rules.pro
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Add project specific ProGuard rules here.
|
||||||
|
# You can control the set of applied configuration files using the
|
||||||
|
# proguardFiles setting in build.gradle.
|
||||||
|
#
|
||||||
|
# For more details, see
|
||||||
|
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||||
|
|
||||||
|
# If your project uses WebView with JS, uncomment the following
|
||||||
|
# and specify the fully qualified class name to the JavaScript interface
|
||||||
|
# class:
|
||||||
|
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||||
|
# public *;
|
||||||
|
#}
|
||||||
|
|
||||||
|
# Uncomment this to preserve the line number information for
|
||||||
|
# debugging stack traces.
|
||||||
|
#-keepattributes SourceFile,LineNumberTable
|
||||||
|
|
||||||
|
# If you keep the line number information, uncomment this to
|
||||||
|
# hide the original source file name.
|
||||||
|
#-renamesourcefileattribute SourceFile
|
@ -0,0 +1,28 @@
|
|||||||
|
package com.jens.automation2;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import androidx.test.platform.app.InstrumentationRegistry;
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instrumented test, which will execute on an Android device.
|
||||||
|
*
|
||||||
|
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||||
|
*/
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class ExampleInstrumentedTest
|
||||||
|
{
|
||||||
|
@Test
|
||||||
|
public void useAppContext()
|
||||||
|
{
|
||||||
|
// Context of the app under test.
|
||||||
|
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||||
|
assertEquals("com.jens.automation2", appContext.getPackageName());
|
||||||
|
}
|
||||||
|
}
|
203
app/src/apkFlavor/AndroidManifest.xml
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.jens.automation2">
|
||||||
|
|
||||||
|
<supports-screens
|
||||||
|
android:anyDensity="true"
|
||||||
|
android:largeScreens="true"
|
||||||
|
android:normalScreens="true"
|
||||||
|
android:smallScreens="true" />
|
||||||
|
<!-- android:xlargeScreens="true" -->
|
||||||
|
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.location"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.location.gps"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.location.network"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.bluetooth"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.microphone"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.wifi"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.touchscreen"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.nfc"
|
||||||
|
android:required="false" />
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
|
||||||
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
|
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
|
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
||||||
|
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||||
|
<uses-permission android:name="android.permission.BATTERY_STATS" />
|
||||||
|
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
|
||||||
|
<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.GET_TASKS" />
|
||||||
|
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.NFC" />
|
||||||
|
<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" />
|
||||||
|
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
|
||||||
|
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_SUPERUSER" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
|
||||||
|
<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-feature
|
||||||
|
android:name="android.hardware.telephony"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
|
||||||
|
<uses-permission android:name="android.permission.SEND_SMS"/>
|
||||||
|
|
||||||
|
|
||||||
|
<application
|
||||||
|
android:allowBackup="true"
|
||||||
|
android:allowClearUserData="true"
|
||||||
|
android:icon="@drawable/gears"
|
||||||
|
android:label="@string/title_activity_main"
|
||||||
|
android:theme="@style/AppTheme"
|
||||||
|
android:networkSecurityConfig="@xml/network_security_config">
|
||||||
|
|
||||||
|
<meta-data
|
||||||
|
android:name="firebase_analytics_collection_deactivated"
|
||||||
|
android:value="true" />
|
||||||
|
<meta-data
|
||||||
|
android:name="google_analytics_adid_collection_enabled"
|
||||||
|
android:value="false" />
|
||||||
|
<meta-data
|
||||||
|
android:name="google_analytics_ssaid_collection_enabled"
|
||||||
|
android:value="false" />
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".ActivityMainScreen"
|
||||||
|
android:label="@string/app_name"></activity>
|
||||||
|
<activity
|
||||||
|
android:name=".ActivityManageSpecificPoi"
|
||||||
|
android:label="@string/title_activity_main"></activity>
|
||||||
|
<activity
|
||||||
|
android:name=".ActivitySettings"
|
||||||
|
android:label="@string/title_activity_main"></activity>
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name=".AutomationService"
|
||||||
|
android:exported="false"
|
||||||
|
android:label="@string/title_activity_main" />
|
||||||
|
|
||||||
|
<receiver android:name=".receivers.StartupIntentReceiver" android:enabled="true" android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<!--<action android:name="android.intent.action.SCREEN_ON" />-->
|
||||||
|
<!--<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />-->
|
||||||
|
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
|
||||||
|
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
|
||||||
|
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||||
|
<action android:name="android.intent.action.REBOOT"/>
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
<receiver android:name=".receivers.PackageReplacedReceiver"
|
||||||
|
android:enabled="true">
|
||||||
|
<intent-filter>
|
||||||
|
<!--<action android:name="android.intent.action.PACKAGE_ADDED"/>
|
||||||
|
<action android:name="android.intent.action.PACKAGE_REPLACED" />
|
||||||
|
<action android:name="android.intent.action.PACKAGE_REMOVED"/>
|
||||||
|
<action android:name="android.intent.action.ACTION_PACKAGE_REPLACED" />-->
|
||||||
|
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
|
||||||
|
|
||||||
|
<!--<data
|
||||||
|
android:path="com.jens.automation2"
|
||||||
|
android:scheme="package" />-->
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
<receiver android:name=".receivers.AlarmListener" />
|
||||||
|
<receiver android:name=".receivers.ConnectivityReceiver" />
|
||||||
|
<receiver android:name=".receivers.TimeZoneListener" />
|
||||||
|
|
||||||
|
<activity android:name=".ActivityManageSpecificRule" />
|
||||||
|
<activity android:name=".ActivityEditTriggerUrl" />
|
||||||
|
<activity android:name=".ActivityEditSendTextMessage" />
|
||||||
|
<activity android:name=".ActivityManageTimeFrame" />
|
||||||
|
<activity android:name=".ActivityManageBrightnessSetting" />
|
||||||
|
<activity android:name=".ActivityHelp" />
|
||||||
|
<activity
|
||||||
|
android:name=".ActivityMainTabLayout"
|
||||||
|
android:launchMode="singleTask">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
|
||||||
|
<!-- <action android:name="android.nfc.action.TECH_DISCOVERED"/> -->
|
||||||
|
<!-- <action android:name="android.nfc.action.TAG_DISCOVERED"/> -->
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
|
||||||
|
<data android:mimeType="text/plain" />
|
||||||
|
<!-- <data android:mimeType="application/com.jens.automation2" /> -->
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<data android:mimeType="application/com.jens.automation2" />
|
||||||
|
</intent-filter>
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<meta-data
|
||||||
|
android:name="android.nfc.action.TECH_DISCOVERED"
|
||||||
|
android:resource="@xml/nfc_tech_filter" />
|
||||||
|
-->
|
||||||
|
</activity>
|
||||||
|
<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=".ActivityMainProfiles" />
|
||||||
|
<activity android:name=".ActivityManageSpecificProfile" />
|
||||||
|
<activity android:name=".ActivityVolumeTest" />
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name=".receivers.ActivityDetectionReceiver"
|
||||||
|
android:exported="false"
|
||||||
|
android:label="@string/app_name"></service>
|
||||||
|
|
||||||
|
<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"/>
|
||||||
|
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
187
app/src/fdroidFlavor/AndroidManifest.xml
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.jens.automation2">
|
||||||
|
|
||||||
|
<supports-screens
|
||||||
|
android:anyDensity="true"
|
||||||
|
android:largeScreens="true"
|
||||||
|
android:normalScreens="true"
|
||||||
|
android:smallScreens="true" />
|
||||||
|
<!-- android:xlargeScreens="true" -->
|
||||||
|
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.location"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.location.gps"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.location.network"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.bluetooth"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.microphone"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.wifi"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.touchscreen"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.nfc"
|
||||||
|
android:required="false" />
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
|
||||||
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
|
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
|
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
||||||
|
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||||
|
<uses-permission android:name="android.permission.BATTERY_STATS" />
|
||||||
|
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
|
||||||
|
<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.GET_TASKS" />
|
||||||
|
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.NFC" />
|
||||||
|
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_SUPERUSER" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
|
||||||
|
<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-feature
|
||||||
|
android:name="android.hardware.telephony"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
|
||||||
|
<uses-permission android:name="android.permission.SEND_SMS"/>
|
||||||
|
|
||||||
|
|
||||||
|
<application
|
||||||
|
android:allowBackup="true"
|
||||||
|
android:allowClearUserData="true"
|
||||||
|
android:icon="@drawable/gears"
|
||||||
|
android:label="@string/title_activity_main"
|
||||||
|
android:theme="@style/AppTheme"
|
||||||
|
android:networkSecurityConfig="@xml/network_security_config">
|
||||||
|
|
||||||
|
<meta-data
|
||||||
|
android:name="firebase_analytics_collection_deactivated"
|
||||||
|
android:value="true" />
|
||||||
|
<meta-data
|
||||||
|
android:name="google_analytics_adid_collection_enabled"
|
||||||
|
android:value="false" />
|
||||||
|
<meta-data
|
||||||
|
android:name="google_analytics_ssaid_collection_enabled"
|
||||||
|
android:value="false" />
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".ActivityMainScreen"
|
||||||
|
android:label="@string/app_name"></activity>
|
||||||
|
<activity
|
||||||
|
android:name=".ActivityManageSpecificPoi"
|
||||||
|
android:label="@string/title_activity_main"></activity>
|
||||||
|
<activity
|
||||||
|
android:name=".ActivitySettings"
|
||||||
|
android:label="@string/title_activity_main"></activity>
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name=".AutomationService"
|
||||||
|
android:exported="false"
|
||||||
|
android:label="@string/title_activity_main" />
|
||||||
|
|
||||||
|
<receiver android:name=".receivers.StartupIntentReceiver" android:enabled="true" android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<!--<action android:name="android.intent.action.SCREEN_ON" />-->
|
||||||
|
<!--<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />-->
|
||||||
|
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
|
||||||
|
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
|
||||||
|
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||||
|
<action android:name="android.intent.action.REBOOT"/>
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
<receiver android:name=".receivers.PackageReplacedReceiver"
|
||||||
|
android:enabled="true">
|
||||||
|
<intent-filter>
|
||||||
|
<!--<action android:name="android.intent.action.PACKAGE_ADDED"/>
|
||||||
|
<action android:name="android.intent.action.PACKAGE_REPLACED" />
|
||||||
|
<action android:name="android.intent.action.PACKAGE_REMOVED"/>
|
||||||
|
<action android:name="android.intent.action.ACTION_PACKAGE_REPLACED" />-->
|
||||||
|
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
|
||||||
|
|
||||||
|
<!--<data
|
||||||
|
android:path="com.jens.automation2"
|
||||||
|
android:scheme="package" />-->
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
<receiver android:name=".receivers.AlarmListener" />
|
||||||
|
<receiver android:name=".receivers.ConnectivityReceiver" />
|
||||||
|
<receiver android:name=".receivers.TimeZoneListener" />
|
||||||
|
|
||||||
|
<activity android:name=".ActivityManageSpecificRule" />
|
||||||
|
<activity android:name=".ActivityEditTriggerUrl" />
|
||||||
|
<activity android:name=".ActivityEditSendTextMessage" />
|
||||||
|
<activity android:name=".ActivityManageTimeFrame" />
|
||||||
|
<activity android:name=".ActivityManageBrightnessSetting" />
|
||||||
|
<activity android:name=".ActivityHelp" />
|
||||||
|
<activity
|
||||||
|
android:name=".ActivityMainTabLayout"
|
||||||
|
android:launchMode="singleTask">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
|
||||||
|
<!-- <action android:name="android.nfc.action.TECH_DISCOVERED"/> -->
|
||||||
|
<!-- <action android:name="android.nfc.action.TAG_DISCOVERED"/> -->
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
|
||||||
|
<data android:mimeType="text/plain" />
|
||||||
|
<!-- <data android:mimeType="application/com.jens.automation2" /> -->
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<data android:mimeType="application/com.jens.automation2" />
|
||||||
|
</intent-filter>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<meta-data
|
||||||
|
android:name="android.nfc.action.TECH_DISCOVERED"
|
||||||
|
android:resource="@xml/nfc_tech_filter" />
|
||||||
|
-->
|
||||||
|
</activity>
|
||||||
|
<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=".ActivityMainProfiles" />
|
||||||
|
<activity android:name=".ActivityManageSpecificProfile" />
|
||||||
|
<activity android:name=".ActivityVolumeTest" />
|
||||||
|
|
||||||
|
<activity android:name=".ActivityPermissions"></activity>
|
||||||
|
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
48
app/src/google-services.json
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
{
|
||||||
|
"project_info": {
|
||||||
|
"project_number": "977361397436",
|
||||||
|
"project_id": "automation-9bed6"
|
||||||
|
},
|
||||||
|
"client": [
|
||||||
|
{
|
||||||
|
"client_info": {
|
||||||
|
"mobilesdk_app_id": "1:977361397436:android:ee5ad5243b40934a",
|
||||||
|
"android_client_info": {
|
||||||
|
"package_name": "com.jens.automation2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"oauth_client": [
|
||||||
|
{
|
||||||
|
"client_id": "977361397436-86ebgevdi3ttfhcki5l1ldnquocos854.apps.googleusercontent.com",
|
||||||
|
"client_type": 1,
|
||||||
|
"android_info": {
|
||||||
|
"package_name": "com.jens.automation2",
|
||||||
|
"certificate_hash": "86ec434e30ed99ec9ee1f4e5c33166558a8442a9"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"client_id": "977361397436-1n1769oadmm31pckln04pjdkela9p3e4.apps.googleusercontent.com",
|
||||||
|
"client_type": 3
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"api_key": [
|
||||||
|
{
|
||||||
|
"current_key": "AIzaSyCeDEkuDmAr7b03auJKDrL1YAB-KlY7088"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"services": {
|
||||||
|
"analytics_service": {
|
||||||
|
"status": 1
|
||||||
|
},
|
||||||
|
"appinvite_service": {
|
||||||
|
"status": 1,
|
||||||
|
"other_platform_oauth_client": []
|
||||||
|
},
|
||||||
|
"ads_service": {
|
||||||
|
"status": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"configuration_version": "1"
|
||||||
|
}
|
203
app/src/googlePlayFlavor/AndroidManifest.xml
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.jens.automation2">
|
||||||
|
|
||||||
|
<supports-screens
|
||||||
|
android:anyDensity="true"
|
||||||
|
android:largeScreens="true"
|
||||||
|
android:normalScreens="true"
|
||||||
|
android:smallScreens="true" />
|
||||||
|
<!-- android:xlargeScreens="true" -->
|
||||||
|
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.location"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.location.gps"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.location.network"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.bluetooth"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.microphone"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.wifi"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.touchscreen"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.nfc"
|
||||||
|
android:required="false" />
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
|
||||||
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
|
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
|
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
||||||
|
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||||
|
<uses-permission android:name="android.permission.BATTERY_STATS" />
|
||||||
|
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
|
||||||
|
<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.GET_TASKS" />
|
||||||
|
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.NFC" />
|
||||||
|
<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" />
|
||||||
|
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
|
||||||
|
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_SUPERUSER" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
|
||||||
|
<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-feature
|
||||||
|
android:name="android.hardware.telephony"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
|
||||||
|
<uses-permission android:name="android.permission.SEND_SMS"/>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<application
|
||||||
|
android:allowBackup="true"
|
||||||
|
android:allowClearUserData="true"
|
||||||
|
android:icon="@drawable/gears"
|
||||||
|
android:label="@string/title_activity_main"
|
||||||
|
android:theme="@style/AppTheme"
|
||||||
|
android:networkSecurityConfig="@xml/network_security_config">
|
||||||
|
|
||||||
|
<meta-data
|
||||||
|
android:name="firebase_analytics_collection_deactivated"
|
||||||
|
android:value="true" />
|
||||||
|
<meta-data
|
||||||
|
android:name="google_analytics_adid_collection_enabled"
|
||||||
|
android:value="false" />
|
||||||
|
<meta-data
|
||||||
|
android:name="google_analytics_ssaid_collection_enabled"
|
||||||
|
android:value="false" />
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".ActivityMainScreen"
|
||||||
|
android:label="@string/app_name"></activity>
|
||||||
|
<activity
|
||||||
|
android:name=".ActivityManageSpecificPoi"
|
||||||
|
android:label="@string/title_activity_main"></activity>
|
||||||
|
<activity
|
||||||
|
android:name=".ActivitySettings"
|
||||||
|
android:label="@string/title_activity_main"></activity>
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name=".AutomationService"
|
||||||
|
android:exported="false"
|
||||||
|
android:label="@string/title_activity_main" />
|
||||||
|
|
||||||
|
<receiver android:name=".receivers.StartupIntentReceiver" android:enabled="true" android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<!--<action android:name="android.intent.action.SCREEN_ON" />-->
|
||||||
|
<!--<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />-->
|
||||||
|
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
|
||||||
|
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
|
||||||
|
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||||
|
<action android:name="android.intent.action.REBOOT"/>
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
<receiver android:name=".receivers.PackageReplacedReceiver"
|
||||||
|
android:enabled="true">
|
||||||
|
<intent-filter>
|
||||||
|
<!--<action android:name="android.intent.action.PACKAGE_ADDED"/>
|
||||||
|
<action android:name="android.intent.action.PACKAGE_REPLACED" />
|
||||||
|
<action android:name="android.intent.action.PACKAGE_REMOVED"/>
|
||||||
|
<action android:name="android.intent.action.ACTION_PACKAGE_REPLACED" />-->
|
||||||
|
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
|
||||||
|
|
||||||
|
<!--<data
|
||||||
|
android:path="com.jens.automation2"
|
||||||
|
android:scheme="package" />-->
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
<receiver android:name=".receivers.AlarmListener" />
|
||||||
|
<receiver android:name=".receivers.ConnectivityReceiver" />
|
||||||
|
<receiver android:name=".receivers.TimeZoneListener" />
|
||||||
|
|
||||||
|
<activity android:name=".ActivityManageSpecificRule" />
|
||||||
|
<activity android:name=".ActivityEditTriggerUrl" />
|
||||||
|
<activity android:name=".ActivityEditSendTextMessage" />
|
||||||
|
<activity android:name=".ActivityManageTimeFrame" />
|
||||||
|
<activity android:name=".ActivityManageBrightnessSetting" />
|
||||||
|
<activity android:name=".ActivityHelp" />
|
||||||
|
<activity
|
||||||
|
android:name=".ActivityMainTabLayout"
|
||||||
|
android:launchMode="singleTask">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
|
||||||
|
<!-- <action android:name="android.nfc.action.TECH_DISCOVERED"/> -->
|
||||||
|
<!-- <action android:name="android.nfc.action.TAG_DISCOVERED"/> -->
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
|
||||||
|
<data android:mimeType="text/plain" />
|
||||||
|
<!-- <data android:mimeType="application/com.jens.automation2" /> -->
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<data android:mimeType="application/com.jens.automation2" />
|
||||||
|
</intent-filter>
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<meta-data
|
||||||
|
android:name="android.nfc.action.TECH_DISCOVERED"
|
||||||
|
android:resource="@xml/nfc_tech_filter" />
|
||||||
|
-->
|
||||||
|
</activity>
|
||||||
|
<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=".ActivityMainProfiles" />
|
||||||
|
<activity android:name=".ActivityManageSpecificProfile" />
|
||||||
|
<activity android:name=".ActivityVolumeTest" />
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name=".receivers.ActivityDetectionReceiver"
|
||||||
|
android:exported="false"
|
||||||
|
android:label="@string/app_name"></service>
|
||||||
|
|
||||||
|
<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"/>
|
||||||
|
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
192
app/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.jens.automation2">
|
||||||
|
|
||||||
|
<supports-screens
|
||||||
|
android:anyDensity="true"
|
||||||
|
android:largeScreens="true"
|
||||||
|
android:normalScreens="true"
|
||||||
|
android:smallScreens="true" />
|
||||||
|
<!-- android:xlargeScreens="true" -->
|
||||||
|
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.location"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.location.gps"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.location.network"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.bluetooth"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.microphone"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.wifi"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.touchscreen"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.nfc"
|
||||||
|
android:required="false" />
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
|
||||||
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
|
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
|
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
||||||
|
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||||
|
<uses-permission android:name="android.permission.BATTERY_STATS" />
|
||||||
|
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
|
||||||
|
<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.GET_TASKS" />
|
||||||
|
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.NFC" />
|
||||||
|
<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" />
|
||||||
|
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
|
||||||
|
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_SUPERUSER" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
|
||||||
|
<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-feature
|
||||||
|
android:name="android.hardware.telephony"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
|
||||||
|
<uses-permission android:name="android.permission.SEND_SMS"/>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<application
|
||||||
|
android:allowBackup="true"
|
||||||
|
android:allowClearUserData="true"
|
||||||
|
android:icon="@drawable/gears"
|
||||||
|
android:label="@string/title_activity_main"
|
||||||
|
android:theme="@style/AppTheme"
|
||||||
|
android:networkSecurityConfig="@xml/network_security_config">
|
||||||
|
|
||||||
|
<meta-data
|
||||||
|
android:name="firebase_analytics_collection_deactivated"
|
||||||
|
android:value="true" />
|
||||||
|
<meta-data
|
||||||
|
android:name="google_analytics_adid_collection_enabled"
|
||||||
|
android:value="false" />
|
||||||
|
<meta-data
|
||||||
|
android:name="google_analytics_ssaid_collection_enabled"
|
||||||
|
android:value="false" />
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".ActivityMainScreen"
|
||||||
|
android:label="@string/app_name"></activity>
|
||||||
|
<activity
|
||||||
|
android:name=".ActivityManageSpecificPoi"
|
||||||
|
android:label="@string/title_activity_main"></activity>
|
||||||
|
<activity
|
||||||
|
android:name=".ActivitySettings"
|
||||||
|
android:label="@string/title_activity_main"></activity>
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name=".AutomationService"
|
||||||
|
android:exported="false"
|
||||||
|
android:label="@string/title_activity_main" />
|
||||||
|
|
||||||
|
<receiver android:name=".receivers.StartupIntentReceiver" android:enabled="true" android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<!--<action android:name="android.intent.action.SCREEN_ON" />-->
|
||||||
|
<!--<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />-->
|
||||||
|
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
|
||||||
|
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
|
||||||
|
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||||
|
<action android:name="android.intent.action.REBOOT"/>
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
<receiver android:name=".receivers.PackageReplacedReceiver"
|
||||||
|
android:enabled="true">
|
||||||
|
<intent-filter>
|
||||||
|
<!--<action android:name="android.intent.action.PACKAGE_ADDED"/>
|
||||||
|
<action android:name="android.intent.action.PACKAGE_REPLACED" />
|
||||||
|
<action android:name="android.intent.action.PACKAGE_REMOVED"/>
|
||||||
|
<action android:name="android.intent.action.ACTION_PACKAGE_REPLACED" />-->
|
||||||
|
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
|
||||||
|
|
||||||
|
<!--<data
|
||||||
|
android:path="com.jens.automation2"
|
||||||
|
android:scheme="package" />-->
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
<receiver android:name=".receivers.AlarmListener" />
|
||||||
|
<receiver android:name=".receivers.ConnectivityReceiver" />
|
||||||
|
<receiver android:name=".receivers.TimeZoneListener" />
|
||||||
|
|
||||||
|
<activity android:name=".ActivityManageSpecificRule" />
|
||||||
|
<activity android:name=".ActivityEditTriggerUrl" />
|
||||||
|
<activity android:name=".ActivityEditSendTextMessage" />
|
||||||
|
<activity android:name=".ActivityManageTimeFrame" />
|
||||||
|
<activity android:name=".ActivityManageBrightnessSetting" />
|
||||||
|
<activity android:name=".ActivityHelp" />
|
||||||
|
<activity
|
||||||
|
android:name=".ActivityMainTabLayout"
|
||||||
|
android:launchMode="singleTask">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
|
||||||
|
<!-- <action android:name="android.nfc.action.TECH_DISCOVERED"/> -->
|
||||||
|
<!-- <action android:name="android.nfc.action.TAG_DISCOVERED"/> -->
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
|
||||||
|
<data android:mimeType="text/plain" />
|
||||||
|
<!-- <data android:mimeType="application/com.jens.automation2" /> -->
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<data android:mimeType="application/com.jens.automation2" />
|
||||||
|
</intent-filter>
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<meta-data
|
||||||
|
android:name="android.nfc.action.TECH_DISCOVERED"
|
||||||
|
android:resource="@xml/nfc_tech_filter" />
|
||||||
|
-->
|
||||||
|
</activity>
|
||||||
|
<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=".ActivityMainProfiles" />
|
||||||
|
<activity android:name=".ActivityManageSpecificProfile" />
|
||||||
|
<activity android:name=".ActivityVolumeTest" />
|
||||||
|
|
||||||
|
<activity android:name=".ActivityPermissions"></activity>
|
||||||
|
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
200
app/src/main/java/com/jens/automation2/AESCrypt.java
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
package com.jens.automation2;
|
||||||
|
|
||||||
|
import android.util.Base64;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.spec.IvParameterSpec;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypt and decrypt messages using AES 256 bit encryption that are compatible with AESCrypt-ObjC and AESCrypt Ruby.
|
||||||
|
* <p/>
|
||||||
|
* Created by scottab on 04/10/2014.
|
||||||
|
*/
|
||||||
|
public final class AESCrypt
|
||||||
|
{
|
||||||
|
private static final String TAG = "AESCrypt";
|
||||||
|
|
||||||
|
//AESCrypt-ObjC uses CBC and PKCS7Padding
|
||||||
|
private static final String AES_MODE = "AES/CBC/PKCS7Padding";
|
||||||
|
// private static final String AES_MODE = "AES/ECB/NoPadding";
|
||||||
|
private static final String CHARSET = "UTF-8";
|
||||||
|
|
||||||
|
//AESCrypt-ObjC uses SHA-256 (and so a 256-bit key)
|
||||||
|
private static final String HASH_ALGORITHM = "SHA-256";
|
||||||
|
|
||||||
|
//AESCrypt-ObjC uses blank IV (not the best security, but the aim here is compatibility)
|
||||||
|
private static final byte[] ivBytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
|
||||||
|
//togglable log option (please turn off in live!)
|
||||||
|
public static boolean DEBUG_LOG_ENABLED = false;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates SHA256 hash of the password which is used as key
|
||||||
|
*
|
||||||
|
* @param password used to generated key
|
||||||
|
* @return SHA256 of the password
|
||||||
|
*/
|
||||||
|
private static SecretKeySpec generateKey(final String password) throws NoSuchAlgorithmException, UnsupportedEncodingException {
|
||||||
|
final MessageDigest digest = MessageDigest.getInstance(HASH_ALGORITHM);
|
||||||
|
byte[] bytes = password.getBytes("UTF-8");
|
||||||
|
digest.update(bytes, 0, bytes.length);
|
||||||
|
byte[] key = digest.digest();
|
||||||
|
|
||||||
|
log("SHA-256 key ", key);
|
||||||
|
|
||||||
|
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
|
||||||
|
return secretKeySpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypt and encode message using 256-bit AES with key generated from password.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param password used to generated key
|
||||||
|
* @param message the thing you want to encrypt assumed String UTF-8
|
||||||
|
* @return Base64 encoded CipherText
|
||||||
|
* @throws GeneralSecurityException if problems occur during encryption
|
||||||
|
*/
|
||||||
|
public static String encrypt(final String password, String message)
|
||||||
|
throws GeneralSecurityException {
|
||||||
|
|
||||||
|
try {
|
||||||
|
final SecretKeySpec key = generateKey(password);
|
||||||
|
|
||||||
|
log("message", message);
|
||||||
|
|
||||||
|
byte[] cipherText = encrypt(key, ivBytes, message.getBytes(CHARSET));
|
||||||
|
|
||||||
|
//NO_WRAP is important as was getting \n at the end
|
||||||
|
String encoded = Base64.encodeToString(cipherText, Base64.NO_WRAP);
|
||||||
|
log("Base64.NO_WRAP", encoded);
|
||||||
|
return encoded;
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
if (DEBUG_LOG_ENABLED)
|
||||||
|
Log.e(TAG, "UnsupportedEncodingException ", e);
|
||||||
|
throw new GeneralSecurityException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* More flexible AES encrypt that doesn't encode
|
||||||
|
* @param key AES key typically 128, 192 or 256 bit
|
||||||
|
* @param iv Initiation Vector
|
||||||
|
* @param message in bytes (assumed it's already been decoded)
|
||||||
|
* @return Encrypted cipher text (not encoded)
|
||||||
|
* @throws GeneralSecurityException if something goes wrong during encryption
|
||||||
|
*/
|
||||||
|
public static byte[] encrypt(final SecretKeySpec key, final byte[] iv, final byte[] message)
|
||||||
|
throws GeneralSecurityException {
|
||||||
|
final Cipher cipher = Cipher.getInstance(AES_MODE);
|
||||||
|
IvParameterSpec ivSpec = new IvParameterSpec(iv);
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
|
||||||
|
byte[] cipherText = cipher.doFinal(message);
|
||||||
|
|
||||||
|
log("cipherText", cipherText);
|
||||||
|
|
||||||
|
return cipherText;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypt and decode ciphertext using 256-bit AES with key generated from password
|
||||||
|
*
|
||||||
|
* @param password used to generated key
|
||||||
|
* @param base64EncodedCipherText the encrpyted message encoded with base64
|
||||||
|
* @return message in Plain text (String UTF-8)
|
||||||
|
* @throws GeneralSecurityException if there's an issue decrypting
|
||||||
|
*/
|
||||||
|
public static String decrypt(final String password, String base64EncodedCipherText)
|
||||||
|
throws GeneralSecurityException {
|
||||||
|
|
||||||
|
try {
|
||||||
|
final SecretKeySpec key = generateKey(password);
|
||||||
|
|
||||||
|
log("base64EncodedCipherText", base64EncodedCipherText);
|
||||||
|
byte[] decodedCipherText = Base64.decode(base64EncodedCipherText, Base64.NO_WRAP);
|
||||||
|
log("decodedCipherText", decodedCipherText);
|
||||||
|
|
||||||
|
byte[] decryptedBytes = decrypt(key, ivBytes, decodedCipherText);
|
||||||
|
|
||||||
|
log("decryptedBytes", decryptedBytes);
|
||||||
|
String message = new String(decryptedBytes, CHARSET);
|
||||||
|
log("message", message);
|
||||||
|
|
||||||
|
|
||||||
|
return message;
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
if (DEBUG_LOG_ENABLED)
|
||||||
|
Log.e(TAG, "UnsupportedEncodingException ", e);
|
||||||
|
|
||||||
|
throw new GeneralSecurityException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* More flexible AES decrypt that doesn't encode
|
||||||
|
*
|
||||||
|
* @param key AES key typically 128, 192 or 256 bit
|
||||||
|
* @param iv Initiation Vector
|
||||||
|
* @param decodedCipherText in bytes (assumed it's already been decoded)
|
||||||
|
* @return Decrypted message cipher text (not encoded)
|
||||||
|
* @throws GeneralSecurityException if something goes wrong during encryption
|
||||||
|
*/
|
||||||
|
public static byte[] decrypt(final SecretKeySpec key, final byte[] iv, final byte[] decodedCipherText)
|
||||||
|
throws GeneralSecurityException {
|
||||||
|
final Cipher cipher = Cipher.getInstance(AES_MODE);
|
||||||
|
IvParameterSpec ivSpec = new IvParameterSpec(iv);
|
||||||
|
cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
|
||||||
|
byte[] decryptedBytes = cipher.doFinal(decodedCipherText);
|
||||||
|
|
||||||
|
log("decryptedBytes", decryptedBytes);
|
||||||
|
|
||||||
|
return decryptedBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private static void log(String what, byte[] bytes) {
|
||||||
|
if (DEBUG_LOG_ENABLED)
|
||||||
|
Log.d(TAG, what + "[" + bytes.length + "] [" + bytesToHex(bytes) + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void log(String what, String value) {
|
||||||
|
if (DEBUG_LOG_ENABLED)
|
||||||
|
Log.d(TAG, what + "[" + value.length() + "] [" + value + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts byte array to hexidecimal useful for logging and fault finding
|
||||||
|
* @param bytes
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static String bytesToHex(byte[] bytes) {
|
||||||
|
final char[] hexArray = {'0', '1', '2', '3', '4', '5', '6', '7', '8',
|
||||||
|
'9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
||||||
|
char[] hexChars = new char[bytes.length * 2];
|
||||||
|
int v;
|
||||||
|
for (int j = 0; j < bytes.length; j++) {
|
||||||
|
v = bytes[j] & 0xFF;
|
||||||
|
hexChars[j * 2] = hexArray[v >>> 4];
|
||||||
|
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
|
||||||
|
}
|
||||||
|
return new String(hexChars);
|
||||||
|
}
|
||||||
|
|
||||||
|
private AESCrypt() {
|
||||||
|
}
|
||||||
|
}
|
537
app/src/main/java/com/jens/automation2/Action.java
Normal file
@ -0,0 +1,537 @@
|
|||||||
|
package com.jens.automation2;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import org.apache.http.client.methods.HttpGet;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
|
||||||
|
public class Action
|
||||||
|
{
|
||||||
|
public enum Action_Enum {
|
||||||
|
setWifi,
|
||||||
|
setBluetooth,
|
||||||
|
setUsbTethering,
|
||||||
|
setWifiTethering,
|
||||||
|
setDisplayRotation,
|
||||||
|
turnWifiOn,turnWifiOff,
|
||||||
|
turnBluetoothOn,turnBluetoothOff,
|
||||||
|
triggerUrl,
|
||||||
|
changeSoundProfile,
|
||||||
|
turnUsbTetheringOn,turnUsbTetheringOff,
|
||||||
|
turnWifiTetheringOn,turnWifiTetheringOff,
|
||||||
|
enableScreenRotation, disableScreenRotation,
|
||||||
|
startOtherActivity,
|
||||||
|
waitBeforeNextAction,
|
||||||
|
wakeupDevice,
|
||||||
|
setAirplaneMode,
|
||||||
|
setDataConnection,
|
||||||
|
speakText,
|
||||||
|
playMusic,
|
||||||
|
setScreenBrightness,
|
||||||
|
sendTextMessage;
|
||||||
|
|
||||||
|
public String getFullName(Context context)
|
||||||
|
{
|
||||||
|
switch(this)
|
||||||
|
{
|
||||||
|
case setWifi:
|
||||||
|
return context.getResources().getString(R.string.actionSetWifi);
|
||||||
|
case setBluetooth:
|
||||||
|
return context.getResources().getString(R.string.actionSetBluetooth);
|
||||||
|
case setWifiTethering:
|
||||||
|
return context.getResources().getString(R.string.actionSetWifiTethering);
|
||||||
|
case setUsbTethering:
|
||||||
|
return context.getResources().getString(R.string.actionSetUsbTethering);
|
||||||
|
case setDisplayRotation:
|
||||||
|
return context.getResources().getString(R.string.actionSetDisplayRotation);
|
||||||
|
case turnWifiOn:
|
||||||
|
return context.getResources().getString(R.string.actionTurnWifiOn);
|
||||||
|
case turnWifiOff:
|
||||||
|
return context.getResources().getString(R.string.actionTurnWifiOff);
|
||||||
|
case turnBluetoothOn:
|
||||||
|
return context.getResources().getString(R.string.actionTurnBluetoothOn);
|
||||||
|
case turnBluetoothOff:
|
||||||
|
return context.getResources().getString(R.string.actionTurnBluetoothOff);
|
||||||
|
case triggerUrl:
|
||||||
|
return context.getResources().getString(R.string.actionTriggerUrl);
|
||||||
|
case changeSoundProfile:
|
||||||
|
return context.getResources().getString(R.string.actionChangeSoundProfile);
|
||||||
|
case turnUsbTetheringOn:
|
||||||
|
return context.getResources().getString(R.string.actionTurnUsbTetheringOn);
|
||||||
|
case turnUsbTetheringOff:
|
||||||
|
return context.getResources().getString(R.string.actionTurnUsbTetheringOff);
|
||||||
|
case turnWifiTetheringOn:
|
||||||
|
return context.getResources().getString(R.string.actionTurnWifiTetheringOn);
|
||||||
|
case turnWifiTetheringOff:
|
||||||
|
return context.getResources().getString(R.string.actionTurnWifiTetheringOff);
|
||||||
|
case enableScreenRotation:
|
||||||
|
return context.getResources().getString(R.string.actionEnableScreenRotation);
|
||||||
|
case disableScreenRotation:
|
||||||
|
return context.getResources().getString(R.string.actionDisableScreenRotation);
|
||||||
|
case startOtherActivity:
|
||||||
|
return context.getResources().getString(R.string.startOtherActivity);
|
||||||
|
case waitBeforeNextAction:
|
||||||
|
return context.getResources().getString(R.string.waitBeforeNextAction);
|
||||||
|
case wakeupDevice:
|
||||||
|
return context.getResources().getString(R.string.wakeupDevice);
|
||||||
|
case setAirplaneMode:
|
||||||
|
return context.getResources().getString(R.string.airplaneMode);
|
||||||
|
case setDataConnection:
|
||||||
|
return context.getResources().getString(R.string.actionDataConnection);
|
||||||
|
case speakText:
|
||||||
|
return context.getResources().getString(R.string.actionSpeakText);
|
||||||
|
case playMusic:
|
||||||
|
return context.getResources().getString(R.string.actionPlayMusic);
|
||||||
|
case sendTextMessage:
|
||||||
|
return context.getResources().getString(R.string.sendTextMessage);
|
||||||
|
case setScreenBrightness:
|
||||||
|
return context.getResources().getString(R.string.setScreenBrightness);
|
||||||
|
default:
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private Action_Enum action;
|
||||||
|
private boolean parameter1 = false;
|
||||||
|
private String parameter2 = "";
|
||||||
|
|
||||||
|
public Action_Enum getAction()
|
||||||
|
{
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
public void setAction(Action_Enum action)
|
||||||
|
{
|
||||||
|
this.action = action;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getParameter1()
|
||||||
|
{
|
||||||
|
return parameter1;
|
||||||
|
}
|
||||||
|
public void setParameter1(boolean parameter1)
|
||||||
|
{
|
||||||
|
this.parameter1 = parameter1;
|
||||||
|
}
|
||||||
|
public String getParameter2()
|
||||||
|
{
|
||||||
|
return parameter2;
|
||||||
|
}
|
||||||
|
public void setParameter2(String parameter)
|
||||||
|
{
|
||||||
|
this.parameter2 = parameter;
|
||||||
|
}
|
||||||
|
public String toStringShort()
|
||||||
|
{
|
||||||
|
String returnString = action.toString();
|
||||||
|
|
||||||
|
return returnString;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
StringBuilder returnString = new StringBuilder();
|
||||||
|
|
||||||
|
if(this.getAction().equals(Action_Enum.setWifi))
|
||||||
|
{
|
||||||
|
if(this.getParameter1())
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.actionTurnWifiOn));
|
||||||
|
else
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.actionTurnWifiOff));
|
||||||
|
}
|
||||||
|
else if(this.getAction().equals(Action_Enum.setBluetooth))
|
||||||
|
{
|
||||||
|
if(this.getParameter1())
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.actionTurnBluetoothOn));
|
||||||
|
else
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.actionTurnBluetoothOff));
|
||||||
|
}
|
||||||
|
else if(this.getAction().equals(Action_Enum.setUsbTethering))
|
||||||
|
{
|
||||||
|
if(this.getParameter1())
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.actionTurnUsbTetheringOn));
|
||||||
|
else
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.actionTurnUsbTetheringOff));
|
||||||
|
}
|
||||||
|
else if(this.getAction().equals(Action_Enum.setWifiTethering))
|
||||||
|
{
|
||||||
|
if(this.getParameter1())
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.actionTurnWifiTetheringOn));
|
||||||
|
else
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.actionTurnWifiTetheringOff));
|
||||||
|
}
|
||||||
|
else if(this.getAction().equals(Action_Enum.setDisplayRotation))
|
||||||
|
{
|
||||||
|
if(this.getParameter1())
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.actionEnableScreenRotation));
|
||||||
|
else
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.actionDisableScreenRotation));
|
||||||
|
}
|
||||||
|
else if(this.getAction().equals(Action_Enum.setAirplaneMode))
|
||||||
|
{
|
||||||
|
if(this.getParameter1())
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.actionTurnAirplaneModeOn));
|
||||||
|
else
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.actionTurnAirplaneModeOff));
|
||||||
|
}
|
||||||
|
else if(this.getAction().equals(Action_Enum.setDataConnection))
|
||||||
|
{
|
||||||
|
if(this.getParameter1())
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.actionSetDataConnectionOn));
|
||||||
|
else
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.actionSetDataConnectionOff));
|
||||||
|
}
|
||||||
|
else if(this.getAction().equals(Action_Enum.startOtherActivity))
|
||||||
|
{
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.startOtherActivity));
|
||||||
|
}
|
||||||
|
else if(this.getAction().equals(Action_Enum.triggerUrl))
|
||||||
|
{
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.actionTriggerUrl));
|
||||||
|
}
|
||||||
|
else if(this.getAction().equals(Action_Enum.speakText))
|
||||||
|
{
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.actionSpeakText));
|
||||||
|
}
|
||||||
|
else if(this.getAction().equals(Action_Enum.playMusic))
|
||||||
|
{
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.actionPlayMusic));
|
||||||
|
}
|
||||||
|
else if(this.getAction().equals(Action_Enum.sendTextMessage))
|
||||||
|
{
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.sendTextMessage));
|
||||||
|
}
|
||||||
|
else if(this.getAction().equals(Action_Enum.wakeupDevice))
|
||||||
|
{
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.wakeupDevice));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
returnString.append(action.toString());
|
||||||
|
|
||||||
|
if(this.getAction().equals(Action_Enum.triggerUrl))
|
||||||
|
{
|
||||||
|
String[] components = parameter2.split(";");
|
||||||
|
if(components.length >= 3)
|
||||||
|
{
|
||||||
|
returnString.append(": " + components[2]);
|
||||||
|
|
||||||
|
if(parameter1)
|
||||||
|
returnString.append(" using authentication.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
returnString.append(": " + components[0]);
|
||||||
|
}
|
||||||
|
else if(this.getAction().equals(Action_Enum.sendTextMessage))
|
||||||
|
{
|
||||||
|
String[] components = parameter2.split(Actions.smsSeparator);
|
||||||
|
if(components.length >= 2)
|
||||||
|
{
|
||||||
|
returnString.append(" to number " + components[0]);
|
||||||
|
|
||||||
|
returnString.append(". Message: " + components[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(this.getAction().equals(Action_Enum.setScreenBrightness))
|
||||||
|
{
|
||||||
|
returnString.append(" to ");
|
||||||
|
|
||||||
|
if(parameter1)
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.brightnessAuto));
|
||||||
|
else
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.brightnessManual));
|
||||||
|
|
||||||
|
returnString.append(" / " + Integer.parseInt(parameter2) + "%");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (parameter2 != null && parameter2.length() > 0)
|
||||||
|
returnString.append(": " + parameter2);
|
||||||
|
|
||||||
|
return returnString.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CharSequence[] getActionTypesAsArray()
|
||||||
|
{
|
||||||
|
ArrayList<String> actionTypesList = new ArrayList<String>();
|
||||||
|
|
||||||
|
for(Action_Enum action : Action_Enum.values())
|
||||||
|
{
|
||||||
|
if( // exclusion for deprecated types
|
||||||
|
!action.toString().equals("turnWifiOn")
|
||||||
|
&&
|
||||||
|
!action.toString().equals("turnWifiOff")
|
||||||
|
&&
|
||||||
|
!action.toString().equals("turnBluetoothOn")
|
||||||
|
&&
|
||||||
|
!action.toString().equals("turnBluetoothOff")
|
||||||
|
&&
|
||||||
|
!action.toString().equals("turnUsbTetheringOn")
|
||||||
|
&&
|
||||||
|
!action.toString().equals("turnUsbTetheringOff")
|
||||||
|
&&
|
||||||
|
!action.toString().equals("turnWifiTetheringOn")
|
||||||
|
&&
|
||||||
|
!action.toString().equals("turnWifiTetheringOff")
|
||||||
|
&&
|
||||||
|
!action.toString().equals("enableScreenRotation")
|
||||||
|
&&
|
||||||
|
!action.toString().equals("disableScreenRotation")
|
||||||
|
) // exclusion for deprecated types
|
||||||
|
actionTypesList.add(action.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return (String[])actionTypesList.toArray(new String[actionTypesList.size()]);
|
||||||
|
}
|
||||||
|
public static CharSequence[] getActionTypesFullNameStringAsArray(Context context)
|
||||||
|
{
|
||||||
|
ArrayList<String> actionTypesList = new ArrayList<String>();
|
||||||
|
|
||||||
|
for(Action_Enum action : Action_Enum.values())
|
||||||
|
{
|
||||||
|
if( // exclusion for deprecated types
|
||||||
|
!action.toString().equals("turnWifiOn")
|
||||||
|
&&
|
||||||
|
!action.toString().equals("turnWifiOff")
|
||||||
|
&&
|
||||||
|
!action.toString().equals("turnBluetoothOn")
|
||||||
|
&&
|
||||||
|
!action.toString().equals("turnBluetoothOff")
|
||||||
|
&&
|
||||||
|
!action.toString().equals("turnUsbTetheringOn")
|
||||||
|
&&
|
||||||
|
!action.toString().equals("turnUsbTetheringOff")
|
||||||
|
&&
|
||||||
|
!action.toString().equals("turnWifiTetheringOn")
|
||||||
|
&&
|
||||||
|
!action.toString().equals("turnWifiTetheringOff")
|
||||||
|
&&
|
||||||
|
!action.toString().equals("enableScreenRotation")
|
||||||
|
&&
|
||||||
|
!action.toString().equals("disableScreenRotation")
|
||||||
|
) // exclusion for deprecated types
|
||||||
|
actionTypesList.add(action.getFullName(context));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (String[])actionTypesList.toArray(new String[actionTypesList.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run(Context context, boolean toggleActionIfPossible)
|
||||||
|
{
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
// 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
|
||||||
|
// {
|
||||||
|
Profile p = Profile.getByName(this.getParameter2());
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void triggerUrl(Context context)
|
||||||
|
{
|
||||||
|
String username = null;
|
||||||
|
String password = null;
|
||||||
|
String url;
|
||||||
|
|
||||||
|
String[] components = getParameter2().split(";");
|
||||||
|
|
||||||
|
if(components.length >= 3)
|
||||||
|
{
|
||||||
|
username = components[0];
|
||||||
|
password = components[1];
|
||||||
|
url = components[2];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
url = components[0];
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
url = Miscellaneous.replaceVariablesInText(url, context);
|
||||||
|
|
||||||
|
Actions myAction = new Actions();
|
||||||
|
|
||||||
|
Miscellaneous.logEvent("i", "HTTP", "Attempting download of " + url, 4); //getResources().getString("attemptingDownloadOf");
|
||||||
|
|
||||||
|
if(this.getParameter1()) // use authentication
|
||||||
|
new DownloadTask().execute(url, username, password);
|
||||||
|
else
|
||||||
|
new DownloadTask().execute(url, null, null);
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "triggerUrl", context.getResources().getString(R.string.errorTriggeringUrl) + ": " + e.getMessage() + ", detailed: " + Log.getStackTraceString(e), 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DownloadTask extends AsyncTask<String, Void, String>
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public String doInBackground(String... parameters)
|
||||||
|
{
|
||||||
|
Thread.setDefaultUncaughtExceptionHandler(Miscellaneous.uncaughtExceptionHandler);
|
||||||
|
|
||||||
|
int attempts=1;
|
||||||
|
String urlString=parameters[0];
|
||||||
|
|
||||||
|
String urlUsername = null;
|
||||||
|
String urlPassword = null;
|
||||||
|
if(parameters.length >= 3)
|
||||||
|
{
|
||||||
|
urlUsername=parameters[1];
|
||||||
|
urlPassword=parameters[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
String response = "httpError";
|
||||||
|
HttpGet post;
|
||||||
|
|
||||||
|
if(Settings.httpAttempts < 1)
|
||||||
|
Miscellaneous.logEvent("w", "HTTP Request", Miscellaneous.getAnyContext().getResources().getString(R.string.cantDownloadTooFewRequestsInSettings), 3);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Miscellaneous.logEvent("i", "HTTPS RESULT", response, 3);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPostExecute(String result)
|
||||||
|
{
|
||||||
|
//Do something with result
|
||||||
|
//Toast.makeText(context, text, duration) result;
|
||||||
|
Miscellaneous.logEvent("i", "HTTP RESULT", result, 3);
|
||||||
|
Actions myAction=new Actions();
|
||||||
|
myAction.useDownloadedWebpage(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1192
app/src/main/java/com/jens/automation2/Actions.java
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
package com.jens.automation2;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
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.view.View.OnClickListener;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import com.jens.automation2.Action.Action_Enum;
|
||||||
|
|
||||||
|
|
||||||
|
public class ActivityEditSendTextMessage extends Activity
|
||||||
|
{
|
||||||
|
Button bSaveSendTextMessage, bImportNumberFromContacts;
|
||||||
|
EditText etPhoneNumber, etSendTextMessage;
|
||||||
|
|
||||||
|
protected final static int requestCodeForContactsPermissions = 9876;
|
||||||
|
|
||||||
|
// private String existingUrl = "";
|
||||||
|
|
||||||
|
public static boolean edit = false;
|
||||||
|
public static Action resultingAction = null;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState)
|
||||||
|
{
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
this.setContentView(R.layout.send_textmessage_editor);
|
||||||
|
|
||||||
|
etSendTextMessage = (EditText)findViewById(R.id.etSendTextMessage);
|
||||||
|
etPhoneNumber = (EditText)findViewById(R.id.etPhoneNumber);
|
||||||
|
bSaveSendTextMessage = (Button)findViewById(R.id.bSaveSendTextMessage);
|
||||||
|
bImportNumberFromContacts = (Button)findViewById(R.id.bImportNumberFromContacts);
|
||||||
|
|
||||||
|
bSaveSendTextMessage.setOnClickListener(new OnClickListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onClick(View v)
|
||||||
|
{
|
||||||
|
if(etSendTextMessage.getText().toString().length() > 0 && etPhoneNumber.getText().toString().length() > 0)
|
||||||
|
{
|
||||||
|
if(resultingAction == null)
|
||||||
|
{
|
||||||
|
resultingAction = new Action();
|
||||||
|
resultingAction.setAction(Action_Enum.sendTextMessage);
|
||||||
|
resultingAction.setParameter2(etPhoneNumber.getText().toString() + Actions.smsSeparator + etSendTextMessage.getText().toString());
|
||||||
|
}
|
||||||
|
backToRuleManager();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Toast.makeText(getBaseContext(), getResources().getString(R.string.textTooShort), Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
bImportNumberFromContacts.setOnClickListener(new OnClickListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onClick(View view)
|
||||||
|
{
|
||||||
|
if(!ActivityPermissions.havePermission("android.permission.READ_CONTACTS", ActivityEditSendTextMessage.this))
|
||||||
|
{
|
||||||
|
requestPermissions("android.permission.READ_CONTACTS");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
openContactsDialogue();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ActivityEditSendTextMessage.edit = getIntent().getBooleanExtra("edit", false);
|
||||||
|
if(edit)
|
||||||
|
{
|
||||||
|
String[] parameters = ActivityEditSendTextMessage.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());
|
||||||
|
}
|
||||||
|
|
||||||
|
setResult(RESULT_OK);
|
||||||
|
|
||||||
|
this.finish();
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onActivityResult(int requestCode, int resultCode, Intent data)
|
||||||
|
{
|
||||||
|
if(requestCode == 1000)
|
||||||
|
{
|
||||||
|
if(resultCode == Activity.RESULT_OK)
|
||||||
|
{
|
||||||
|
String phoneNo = null;
|
||||||
|
String name = null;
|
||||||
|
|
||||||
|
Uri uri = data.getData();
|
||||||
|
Cursor cursor = ActivityEditSendTextMessage.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);
|
||||||
|
|
||||||
|
etPhoneNumber.setText(phoneNo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,76 @@
|
|||||||
|
package com.jens.automation2;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.View.OnClickListener;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.jens.automation2.Action.Action_Enum;
|
||||||
|
|
||||||
|
public class ActivityEditSpeakText extends Activity
|
||||||
|
{
|
||||||
|
private Button bSaveSpeakText;
|
||||||
|
private EditText etSpeakText;
|
||||||
|
|
||||||
|
// private String existingUrl = "";
|
||||||
|
|
||||||
|
public static boolean edit = false;
|
||||||
|
public static Action resultingAction = null;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState)
|
||||||
|
{
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
this.setContentView(R.layout.speak_text_editor);
|
||||||
|
|
||||||
|
etSpeakText = (EditText)findViewById(R.id.etTextToSpeak);
|
||||||
|
bSaveSpeakText = (Button)findViewById(R.id.bSaveTriggerUrl);
|
||||||
|
bSaveSpeakText.setOnClickListener(new OnClickListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onClick(View v)
|
||||||
|
{
|
||||||
|
if(etSpeakText.getText().toString().length()>0)
|
||||||
|
{
|
||||||
|
if(resultingAction == null)
|
||||||
|
{
|
||||||
|
resultingAction = new Action();
|
||||||
|
resultingAction.setAction(Action_Enum.speakText);
|
||||||
|
resultingAction.setParameter2(etSpeakText.getText().toString());
|
||||||
|
}
|
||||||
|
backToRuleManager();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Toast.makeText(getBaseContext(), getResources().getString(R.string.textTooShort), Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ActivityEditSpeakText.edit = getIntent().getBooleanExtra("edit", false);
|
||||||
|
if(edit)
|
||||||
|
etSpeakText.setText(ActivityEditSpeakText.resultingAction.getParameter2());
|
||||||
|
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
ActivityEditSpeakText.resultingAction.setParameter2(etSpeakText.getText().toString());
|
||||||
|
|
||||||
|
setResult(RESULT_OK);
|
||||||
|
|
||||||
|
this.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,171 @@
|
|||||||
|
package com.jens.automation2;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.View.OnClickListener;
|
||||||
|
import android.widget.AdapterView;
|
||||||
|
import android.widget.AdapterView.OnItemLongClickListener;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.CheckBox;
|
||||||
|
import android.widget.CompoundButton;
|
||||||
|
import android.widget.CompoundButton.OnCheckedChangeListener;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.ListView;
|
||||||
|
import android.widget.TableLayout;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.jens.automation2.Action.Action_Enum;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class ActivityEditTriggerUrl extends Activity
|
||||||
|
{
|
||||||
|
Button bSaveTriggerUrl;
|
||||||
|
EditText etTriggerUrl, etTriggerUrlUsername, etTriggerUrlPassword;
|
||||||
|
ListView lvTriggerUrlPostParameters;
|
||||||
|
CheckBox chkTriggerUrlUseAuthentication;
|
||||||
|
TableLayout tlTriggerUrlAuthentication;
|
||||||
|
|
||||||
|
ArrayAdapter<Map<String,String>> lvTriggerUrlPostParametersAdapter;
|
||||||
|
|
||||||
|
// private String existingUrl = "";
|
||||||
|
|
||||||
|
public static boolean edit = false;
|
||||||
|
public static Action resultingAction = null;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState)
|
||||||
|
{
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
this.setContentView(R.layout.trigger_url_editor);
|
||||||
|
|
||||||
|
etTriggerUrl = (EditText)findViewById(R.id.etTriggerUrl);
|
||||||
|
etTriggerUrlUsername = (EditText)findViewById(R.id.etTriggerUrlUsername);
|
||||||
|
etTriggerUrlPassword = (EditText)findViewById(R.id.etTriggerUrlPassword);
|
||||||
|
chkTriggerUrlUseAuthentication = (CheckBox)findViewById(R.id.chkTriggerUrlUseAuthentication);
|
||||||
|
lvTriggerUrlPostParameters = (ListView)findViewById(R.id.lvTriggerUrlPostParameters);
|
||||||
|
tlTriggerUrlAuthentication = (TableLayout)findViewById(R.id.tlTriggerUrlAuthentication);
|
||||||
|
bSaveTriggerUrl = (Button)findViewById(R.id.bSaveTriggerUrl);
|
||||||
|
bSaveTriggerUrl.setOnClickListener(new OnClickListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onClick(View v)
|
||||||
|
{
|
||||||
|
if(etTriggerUrl.getText().toString().length() > 0)
|
||||||
|
{
|
||||||
|
if(resultingAction == null)
|
||||||
|
{
|
||||||
|
resultingAction = new Action();
|
||||||
|
resultingAction.setAction(Action_Enum.triggerUrl);
|
||||||
|
resultingAction.setParameter1(chkTriggerUrlUseAuthentication.isChecked());
|
||||||
|
|
||||||
|
String username = etTriggerUrlUsername.getText().toString();
|
||||||
|
String password = etTriggerUrlPassword.getText().toString();
|
||||||
|
|
||||||
|
if(username == null)
|
||||||
|
username = "";
|
||||||
|
|
||||||
|
if(password == null)
|
||||||
|
password = "";
|
||||||
|
|
||||||
|
ActivityEditTriggerUrl.resultingAction.setParameter2(
|
||||||
|
username + ";" +
|
||||||
|
password + ";" +
|
||||||
|
etTriggerUrl.getText().toString().trim()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
backToRuleManager();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Toast.makeText(getBaseContext(), getResources().getString(R.string.urlTooShort), Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
chkTriggerUrlUseAuthentication.setOnCheckedChangeListener(new OnCheckedChangeListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
|
||||||
|
{
|
||||||
|
if(isChecked)
|
||||||
|
tlTriggerUrlAuthentication.setVisibility(View.VISIBLE);
|
||||||
|
else
|
||||||
|
tlTriggerUrlAuthentication.setVisibility(View.GONE);
|
||||||
|
|
||||||
|
etTriggerUrlUsername.setEnabled(isChecked);
|
||||||
|
etTriggerUrlPassword.setEnabled(isChecked);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
lvTriggerUrlPostParameters.setOnItemLongClickListener(new OnItemLongClickListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int arg2, long arg3)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
updateListView();
|
||||||
|
|
||||||
|
|
||||||
|
ActivityEditTriggerUrl.edit = getIntent().getBooleanExtra("edit", false);
|
||||||
|
if(edit)
|
||||||
|
{
|
||||||
|
// username,password,URL
|
||||||
|
String[] components = ActivityEditTriggerUrl.resultingAction.getParameter2().split(";");
|
||||||
|
|
||||||
|
if(components.length >= 3)
|
||||||
|
{
|
||||||
|
etTriggerUrl.setText(components[2]);
|
||||||
|
chkTriggerUrlUseAuthentication.setChecked(ActivityEditTriggerUrl.resultingAction.getParameter1());
|
||||||
|
etTriggerUrlUsername.setText(components[0]);
|
||||||
|
etTriggerUrlPassword.setText(components[1]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
etTriggerUrl.setText(components[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void backToRuleManager()
|
||||||
|
{
|
||||||
|
if(edit && resultingAction != null)
|
||||||
|
{
|
||||||
|
String username = etTriggerUrlUsername.getText().toString();
|
||||||
|
String password = etTriggerUrlPassword.getText().toString();
|
||||||
|
|
||||||
|
if(username == null)
|
||||||
|
username = "";
|
||||||
|
|
||||||
|
if(password == null)
|
||||||
|
password = "";
|
||||||
|
|
||||||
|
ActivityEditTriggerUrl.resultingAction.setParameter1(chkTriggerUrlUseAuthentication.isChecked());
|
||||||
|
|
||||||
|
ActivityEditTriggerUrl.resultingAction.setParameter2(
|
||||||
|
username + ";" +
|
||||||
|
password + ";" +
|
||||||
|
etTriggerUrl.getText().toString()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
setResult(RESULT_OK);
|
||||||
|
|
||||||
|
this.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateListView()
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "ListView", "Attempting to update lvTriggerUrlPostParameters", 4);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(lvTriggerUrlPostParameters.getAdapter() == null)
|
||||||
|
lvTriggerUrlPostParameters.setAdapter(lvTriggerUrlPostParametersAdapter);
|
||||||
|
|
||||||
|
lvTriggerUrlPostParametersAdapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
catch(NullPointerException e)
|
||||||
|
{}
|
||||||
|
}
|
||||||
|
}
|
67
app/src/main/java/com/jens/automation2/ActivityGeneric.java
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
package com.jens.automation2;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.ServiceConnection;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.jens.automation2.AutomationService.LocalBinder;
|
||||||
|
|
||||||
|
public class ActivityGeneric extends Activity
|
||||||
|
{
|
||||||
|
public static Intent myServiceIntent = null;
|
||||||
|
AutomationService myAutomationService = null;
|
||||||
|
boolean boundToService = false;
|
||||||
|
|
||||||
|
public void storeServiceReferenceInVariable()
|
||||||
|
{
|
||||||
|
if(AutomationService.isMyServiceRunning(getApplicationContext()) && myAutomationService == null)
|
||||||
|
{
|
||||||
|
bindToService();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void bindToService()
|
||||||
|
{
|
||||||
|
Log.i("service", "binding to service");
|
||||||
|
if(!boundToService)
|
||||||
|
{
|
||||||
|
// if(myServiceIntent == null)
|
||||||
|
myServiceIntent = new Intent(this, AutomationService.class);
|
||||||
|
|
||||||
|
Miscellaneous.logEvent("i", "Service", getResources().getString(R.string.logAttemptingToBindToService) + String.valueOf(bindService(myServiceIntent, myServiceConnection, Context.BIND_AUTO_CREATE)), 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void unBindFromService()
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "Service", getResources().getString(R.string.logAttemptingToUnbindFromService), 5);
|
||||||
|
if(boundToService)
|
||||||
|
{
|
||||||
|
unbindService(myServiceConnection);
|
||||||
|
boundToService = false;
|
||||||
|
Miscellaneous.logEvent("i", "Service", getResources().getString(R.string.logUnboundFromService), 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ServiceConnection myServiceConnection = new ServiceConnection()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onServiceConnected(ComponentName name, IBinder service)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "Service", getResources().getString(R.string.logBoundToService), 5);
|
||||||
|
LocalBinder binder = (LocalBinder)service;
|
||||||
|
myAutomationService = binder.getService();
|
||||||
|
boundToService = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onServiceDisconnected(ComponentName name)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "Service", getResources().getString(R.string.logUnboundFromService), 5);
|
||||||
|
boundToService = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
23
app/src/main/java/com/jens/automation2/ActivityHelp.java
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package com.jens.automation2;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.text.method.LinkMovementMethod;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.jens.automation2.R.layout;
|
||||||
|
|
||||||
|
public class ActivityHelp extends Activity
|
||||||
|
{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState)
|
||||||
|
{
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(layout.help_text);
|
||||||
|
|
||||||
|
TextView tvHelpTextEnergySaving = (TextView) findViewById(R.id.tvHelpTextEnergySaving);
|
||||||
|
tvHelpTextEnergySaving.setMovementMethod(LinkMovementMethod.getInstance());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
201
app/src/main/java/com/jens/automation2/ActivityMainPoi.java
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
package com.jens.automation2;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.View.OnClickListener;
|
||||||
|
import android.widget.AdapterView;
|
||||||
|
import android.widget.AdapterView.OnItemLongClickListener;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.ListView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.jens.automation2.AutomationService.serviceCommands;
|
||||||
|
|
||||||
|
public class ActivityMainPoi extends ActivityGeneric
|
||||||
|
{
|
||||||
|
private Button bAddPoi;
|
||||||
|
ListView poiListView;
|
||||||
|
|
||||||
|
ArrayAdapter<PointOfInterest> poiListViewAdapter;
|
||||||
|
|
||||||
|
AutomationService myAutomationService;
|
||||||
|
boolean boundToService = false;
|
||||||
|
|
||||||
|
protected static ActivityMainPoi instance = null;
|
||||||
|
|
||||||
|
public static PointOfInterest poiToEdit;
|
||||||
|
|
||||||
|
protected final static int requestCodeForPermission = 1002;
|
||||||
|
|
||||||
|
public static ActivityMainPoi getInstance()
|
||||||
|
{
|
||||||
|
if(instance == null)
|
||||||
|
instance = new ActivityMainPoi();
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState)
|
||||||
|
{
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.main_poi_layout);
|
||||||
|
|
||||||
|
instance = this;
|
||||||
|
|
||||||
|
bAddPoi = (Button)findViewById(R.id.bAddPoi);
|
||||||
|
bAddPoi.setOnClickListener(new OnClickListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onClick(View v)
|
||||||
|
{
|
||||||
|
if(!ActivityPermissions.havePermission(ActivityPermissions.writeExternalStoragePermissionName, ActivityMainPoi.this))
|
||||||
|
{
|
||||||
|
Toast.makeText(ActivityMainPoi.this, getResources().getString(R.string.appRequiresPermissiontoAccessExternalStorage), Toast.LENGTH_LONG).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!ActivityPermissions.havePermission(ActivityPermissions.permissionNameLocationCoarse, ActivityMainPoi.this) || !ActivityPermissions.havePermission(ActivityPermissions.permissionNameLocationFine, ActivityMainPoi.this))
|
||||||
|
{
|
||||||
|
Intent permissionIntent = new Intent(ActivityMainPoi.this, ActivityPermissions.class);
|
||||||
|
|
||||||
|
permissionIntent.putExtra(ActivityPermissions.intentExtraName, new String[] { ActivityPermissions.permissionNameLocationCoarse, ActivityPermissions.permissionNameLocationFine });
|
||||||
|
|
||||||
|
startActivityForResult(permissionIntent, requestCodeForPermission);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buttonAddPoi();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
poiListView = (ListView)findViewById(R.id.lvPoiList);
|
||||||
|
|
||||||
|
poiListViewAdapter = new ArrayAdapter<PointOfInterest>(this, R.layout.text_view_for_poi_listview_mediumtextsize, PointOfInterest.getPointOfInterestCollection());
|
||||||
|
poiListView.setClickable(true);
|
||||||
|
/*poiListView.setOnItemClickListener(new AdapterView.OnItemClickListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3)
|
||||||
|
{
|
||||||
|
poiToEdit = (PointOfInterest)poiListViewAdapter.getItem(arg2);
|
||||||
|
Intent manageSpecificPoiIntent = new Intent (ActivityMainPoi.this, ActivityManageSpecificPoi.class);
|
||||||
|
manageSpecificPoiIntent.putExtra("action", "change");
|
||||||
|
startActivityForResult(manageSpecificPoiIntent, 2000);
|
||||||
|
}
|
||||||
|
});*/
|
||||||
|
poiListView.setOnItemLongClickListener(new OnItemLongClickListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int arg2, long arg3)
|
||||||
|
{
|
||||||
|
getPoiOptionsDialog((PointOfInterest)poiListView.getItemAtPosition(arg2)).show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
updateListView();
|
||||||
|
|
||||||
|
this.storeServiceReferenceInVariable();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void buttonAddPoi()
|
||||||
|
{
|
||||||
|
poiToEdit = null;
|
||||||
|
Intent manageSpecificPoiIntent = new Intent(ActivityMainPoi.this, ActivityManageSpecificPoi.class);
|
||||||
|
manageSpecificPoiIntent.putExtra("action", "create");
|
||||||
|
startActivityForResult(manageSpecificPoiIntent, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateListView()
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "ListView", "Attempting to update PoiListView", 5);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(poiListView.getAdapter() == null)
|
||||||
|
poiListView.setAdapter(poiListViewAdapter);
|
||||||
|
|
||||||
|
poiListViewAdapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
catch(NullPointerException e)
|
||||||
|
{}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onActivityResult(int requestCode, int resultCode, Intent data)
|
||||||
|
{
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
|
||||||
|
if(AutomationService.isMyServiceRunning(this))
|
||||||
|
bindToService();
|
||||||
|
|
||||||
|
switch(requestCode)
|
||||||
|
{
|
||||||
|
case 1000: //add Poi
|
||||||
|
// poiToEdit = null; //clear cache
|
||||||
|
updateListView();
|
||||||
|
break;
|
||||||
|
case 2000://edit Poi
|
||||||
|
poiToEdit = null; //clear cache
|
||||||
|
updateListView();
|
||||||
|
break;
|
||||||
|
case requestCodeForPermission:
|
||||||
|
if(resultCode == RESULT_OK)
|
||||||
|
buttonAddPoi();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(boundToService && AutomationService.isMyServiceRunning(this))
|
||||||
|
{
|
||||||
|
myAutomationService.serviceInterface(serviceCommands.updateNotification); //in case names got changed.
|
||||||
|
unBindFromService();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private AlertDialog getPoiOptionsDialog(final PointOfInterest pointOfInterest)
|
||||||
|
{
|
||||||
|
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
|
||||||
|
alertDialogBuilder.setTitle(getResources().getString(R.string.whatToDoWithPoi));
|
||||||
|
alertDialogBuilder.setItems(new String[]{ getResources().getString(R.string.edit), getResources().getString(R.string.deleteCapital) }, new DialogInterface.OnClickListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which)
|
||||||
|
{
|
||||||
|
switch(which)
|
||||||
|
{
|
||||||
|
/*case 0:
|
||||||
|
if(AutomationService.isMyServiceRunning(ActivityMainPoi.this))
|
||||||
|
{
|
||||||
|
AutomationService runContext = AutomationService.getInstance();
|
||||||
|
if(runContext != null)
|
||||||
|
{
|
||||||
|
pointOfInterest.activate(runContext);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Toast.makeText(ActivityMainPoi.this, getResources().getString(R.string.serviceHasToRunForThat), Toast.LENGTH_LONG).show();
|
||||||
|
break;*/
|
||||||
|
case 0:
|
||||||
|
poiToEdit = pointOfInterest;
|
||||||
|
Intent manageSpecificPoiIntent = new Intent (ActivityMainPoi.this, ActivityManageSpecificPoi.class);
|
||||||
|
manageSpecificPoiIntent.putExtra("action", "change");
|
||||||
|
startActivityForResult(manageSpecificPoiIntent, 2000);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if(pointOfInterest.delete(Miscellaneous.getAnyContext()))
|
||||||
|
updateListView();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
AlertDialog alertDialog = alertDialogBuilder.create();
|
||||||
|
|
||||||
|
return alertDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
198
app/src/main/java/com/jens/automation2/ActivityMainProfiles.java
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
package com.jens.automation2;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.View.OnClickListener;
|
||||||
|
import android.widget.AdapterView;
|
||||||
|
import android.widget.AdapterView.OnItemLongClickListener;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.ListView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.jens.automation2.AutomationService.serviceCommands;
|
||||||
|
|
||||||
|
public class ActivityMainProfiles extends ActivityGeneric
|
||||||
|
{
|
||||||
|
private Button bAddProfile;
|
||||||
|
ListView profileListView;
|
||||||
|
|
||||||
|
ArrayAdapter<Profile> profileListViewAdapter;
|
||||||
|
|
||||||
|
AutomationService myAutomationService;
|
||||||
|
|
||||||
|
public static Profile profileToEdit;
|
||||||
|
|
||||||
|
protected static ActivityMainProfiles instance = null;
|
||||||
|
|
||||||
|
public static ActivityMainProfiles getInstance()
|
||||||
|
{
|
||||||
|
if(instance == null)
|
||||||
|
instance = new ActivityMainProfiles();
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState)
|
||||||
|
{
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.main_profile_layout);
|
||||||
|
|
||||||
|
instance = this;
|
||||||
|
|
||||||
|
bAddProfile = (Button)findViewById(R.id.bAddProfile);
|
||||||
|
bAddProfile.setOnClickListener(new OnClickListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onClick(View v)
|
||||||
|
{
|
||||||
|
if(!ActivityPermissions.havePermission(ActivityPermissions.writeExternalStoragePermissionName, ActivityMainProfiles.this))
|
||||||
|
{
|
||||||
|
Toast.makeText(ActivityMainProfiles.this, getResources().getString(R.string.appRequiresPermissiontoAccessExternalStorage), Toast.LENGTH_LONG).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
profileToEdit = null;
|
||||||
|
Intent manageSpecificProfileIntent = new Intent (ActivityMainProfiles.this, ActivityManageSpecificProfile.class);
|
||||||
|
manageSpecificProfileIntent.putExtra("action", "create");
|
||||||
|
startActivityForResult(manageSpecificProfileIntent, 1000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
profileListView = (ListView)findViewById(R.id.lvProfilesList);
|
||||||
|
|
||||||
|
profileListViewAdapter = new ArrayAdapter<Profile>(this, R.layout.text_view_for_poi_listview_mediumtextsize, Profile.getProfileCollection());
|
||||||
|
profileListView.setClickable(true);
|
||||||
|
/*profileListView.setOnItemClickListener(new AdapterView.OnItemClickListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3)
|
||||||
|
{
|
||||||
|
profileToEdit = (Profile)profileListViewAdapter.getItem(arg2);
|
||||||
|
Intent manageSpecificProfileIntent = new Intent (ActivityMainProfiles.this, ActivityManageSpecificProfile.class);
|
||||||
|
manageSpecificProfileIntent.putExtra("action", "change");
|
||||||
|
startActivityForResult(manageSpecificProfileIntent, 2000);
|
||||||
|
}
|
||||||
|
});*/
|
||||||
|
profileListView.setOnItemLongClickListener(new OnItemLongClickListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int arg2, long arg3)
|
||||||
|
{
|
||||||
|
getProfileDialog((Profile)profileListView.getItemAtPosition(arg2)).show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if(Settings.executeRulesAndProfilesWithSingleClick)
|
||||||
|
{
|
||||||
|
profileListView.setOnItemClickListener(new AdapterView.OnItemClickListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
|
||||||
|
{
|
||||||
|
if(AutomationService.isMyServiceRunning(ActivityMainProfiles.this))
|
||||||
|
{
|
||||||
|
AutomationService runContext = AutomationService.getInstance();
|
||||||
|
if(runContext != null)
|
||||||
|
{
|
||||||
|
Profile profile = (Profile)profileListView.getItemAtPosition(position);
|
||||||
|
profile.activate(runContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
updateListView();
|
||||||
|
|
||||||
|
this.storeServiceReferenceInVariable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateListView()
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "ListView", "Attempting to update ProfileListView", 5);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(profileListView.getAdapter() == null)
|
||||||
|
profileListView.setAdapter(profileListViewAdapter);
|
||||||
|
|
||||||
|
profileListViewAdapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
catch(NullPointerException e)
|
||||||
|
{}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onActivityResult(int requestCode, int resultCode, Intent data)
|
||||||
|
{
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
|
||||||
|
if(AutomationService.isMyServiceRunning(this))
|
||||||
|
bindToService();
|
||||||
|
|
||||||
|
if(requestCode == 1000) //add Profile
|
||||||
|
{
|
||||||
|
// profileToEdit = null; //clear cache
|
||||||
|
updateListView();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(requestCode == 2000) //edit Profile
|
||||||
|
{
|
||||||
|
profileToEdit = null; //clear cache
|
||||||
|
updateListView();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(boundToService && AutomationService.isMyServiceRunning(this))
|
||||||
|
{
|
||||||
|
myAutomationService.serviceInterface(serviceCommands.updateNotification); // in case names got changed.
|
||||||
|
unBindFromService();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private AlertDialog getProfileDialog(final Profile profile)
|
||||||
|
{
|
||||||
|
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
|
||||||
|
alertDialogBuilder.setTitle(getResources().getString(R.string.whatToDoWithProfile));
|
||||||
|
alertDialogBuilder.setItems(new String[]{ getResources().getString(R.string.runManually), getResources().getString(R.string.edit), getResources().getString(R.string.deleteCapital) }, new DialogInterface.OnClickListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which)
|
||||||
|
{
|
||||||
|
switch(which)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
if(AutomationService.isMyServiceRunning(ActivityMainProfiles.this))
|
||||||
|
{
|
||||||
|
AutomationService runContext = AutomationService.getInstance();
|
||||||
|
if(runContext != null)
|
||||||
|
{
|
||||||
|
profile.activate(runContext);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Toast.makeText(ActivityMainProfiles.this, getResources().getString(R.string.serviceHasToRunForThat), Toast.LENGTH_LONG).show();
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
profileToEdit = profile;
|
||||||
|
Intent manageSpecificProfileIntent = new Intent (ActivityMainProfiles.this, ActivityManageSpecificProfile.class);
|
||||||
|
manageSpecificProfileIntent.putExtra("action", "change");
|
||||||
|
startActivityForResult(manageSpecificProfileIntent, 2000);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if(profile.delete(myAutomationService))
|
||||||
|
updateListView();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
AlertDialog alertDialog = alertDialogBuilder.create();
|
||||||
|
|
||||||
|
return alertDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
252
app/src/main/java/com/jens/automation2/ActivityMainRules.java
Normal file
@ -0,0 +1,252 @@
|
|||||||
|
package com.jens.automation2;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.View.OnClickListener;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.AdapterView;
|
||||||
|
import android.widget.AdapterView.OnItemLongClickListener;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.ListView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.jens.automation2.AutomationService.serviceCommands;
|
||||||
|
import com.jens.automation2.receivers.AlarmListener;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class ActivityMainRules extends ActivityGeneric
|
||||||
|
{
|
||||||
|
private ListView ruleListView;
|
||||||
|
private ArrayAdapter<Rule> ruleListViewAdapter;
|
||||||
|
public static Rule ruleToEdit;
|
||||||
|
protected static ActivityMainRules instance = null;
|
||||||
|
|
||||||
|
public static ActivityMainRules getInstance()
|
||||||
|
{
|
||||||
|
if(instance == null)
|
||||||
|
instance = new ActivityMainRules();
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState)
|
||||||
|
{
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.main_rule_layout);
|
||||||
|
|
||||||
|
instance = this;
|
||||||
|
|
||||||
|
Button bAddRule = (Button)findViewById(R.id.bAddRule);
|
||||||
|
bAddRule.setOnClickListener(new OnClickListener()
|
||||||
|
{
|
||||||
|
@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, ActivityManageSpecificRule.class);
|
||||||
|
startActivityForResult(startAddRuleIntent, 3000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int arg2, long arg3)
|
||||||
|
{
|
||||||
|
getRuleDialog((Rule)ruleListView.getItemAtPosition(arg2)).show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if(Settings.executeRulesAndProfilesWithSingleClick)
|
||||||
|
{
|
||||||
|
ruleListView.setOnItemClickListener(new AdapterView.OnItemClickListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
|
||||||
|
{
|
||||||
|
if(AutomationService.isMyServiceRunning(ActivityMainRules.this))
|
||||||
|
{
|
||||||
|
AutomationService runContext = AutomationService.getInstance();
|
||||||
|
if(runContext != null)
|
||||||
|
{
|
||||||
|
Rule rule = (Rule)ruleListView.getItemAtPosition(position);
|
||||||
|
rule.activate(runContext, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
updateListView();
|
||||||
|
|
||||||
|
this.storeServiceReferenceInVariable();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class RuleHolder
|
||||||
|
{
|
||||||
|
public ImageView ivActiveInactive;
|
||||||
|
public TextView tvRuleName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class RuleArrayAdapter extends ArrayAdapter<Rule>
|
||||||
|
{
|
||||||
|
|
||||||
|
public RuleArrayAdapter(Context context, int resource, ArrayList<Rule> objects)
|
||||||
|
{
|
||||||
|
super(context, resource, objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View getView(int position, View convertView, ViewGroup parent)
|
||||||
|
{
|
||||||
|
View v = convertView;
|
||||||
|
RuleHolder holder = new RuleHolder();
|
||||||
|
// First let's verify the convertView is not null
|
||||||
|
if (convertView == null)
|
||||||
|
{
|
||||||
|
// This a new view we inflate the new layout
|
||||||
|
LayoutInflater inflater = (LayoutInflater) this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
|
v = inflater.inflate(R.layout.view_for_rule_listview, null);
|
||||||
|
// Now we can fill the layout with the right values
|
||||||
|
TextView tv = (TextView) v.findViewById(R.id.tvRuleName);
|
||||||
|
ImageView img = (ImageView) v.findViewById(R.id.ivActiveInactive);
|
||||||
|
holder.tvRuleName = tv;
|
||||||
|
holder.ivActiveInactive = img;
|
||||||
|
v.setTag(holder);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
holder = (RuleHolder) v.getTag();
|
||||||
|
|
||||||
|
System.out.println("Position ["+position+"]");
|
||||||
|
Rule r = Rule.getRuleCollection().get(position);
|
||||||
|
holder.tvRuleName.setText(r.getName());
|
||||||
|
if(r.isRuleActive())
|
||||||
|
{
|
||||||
|
if (r.haveEnoughPermissions())
|
||||||
|
holder.ivActiveInactive.setImageResource(R.drawable.status_active);
|
||||||
|
else
|
||||||
|
holder.ivActiveInactive.setImageResource(R.drawable.status_unable);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
holder.ivActiveInactive.setImageResource(R.drawable.status_inactive);
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onActivityResult(int requestCode, int resultCode, Intent data)
|
||||||
|
{
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
if(AutomationService.isMyServiceRunning(this))
|
||||||
|
bindToService();
|
||||||
|
|
||||||
|
if(requestCode == 3000) //add Rule
|
||||||
|
{
|
||||||
|
ruleToEdit = null; //clear cache
|
||||||
|
updateListView();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(requestCode == 4000) //editRule
|
||||||
|
{
|
||||||
|
ruleToEdit = null; //clear cache
|
||||||
|
updateListView();
|
||||||
|
}
|
||||||
|
|
||||||
|
AutomationService service = AutomationService.getInstance();
|
||||||
|
if(service != null)
|
||||||
|
service.applySettingsAndRules();
|
||||||
|
|
||||||
|
if(boundToService && AutomationService.isMyServiceRunning(this))
|
||||||
|
{
|
||||||
|
myAutomationService.serviceInterface(serviceCommands.updateNotification); //in case names got changed.
|
||||||
|
unBindFromService();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private AlertDialog getRuleDialog(final Rule ruleThisIsAbout)
|
||||||
|
{
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which)
|
||||||
|
{
|
||||||
|
switch(which)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
if(AutomationService.isMyServiceRunning(ActivityMainRules.this))
|
||||||
|
{
|
||||||
|
AutomationService runContext = AutomationService.getInstance();
|
||||||
|
if(runContext != null)
|
||||||
|
{
|
||||||
|
ruleThisIsAbout.activate(runContext, true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Toast.makeText(ActivityMainRules.this, getResources().getString(R.string.serviceHasToRunForThat), Toast.LENGTH_LONG).show();
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
ruleToEdit = ruleThisIsAbout;
|
||||||
|
Intent manageSpecificRuleIntent = new Intent (ActivityMainRules.this, ActivityManageSpecificRule.class);
|
||||||
|
startActivityForResult(manageSpecificRuleIntent, 4000);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if(ruleThisIsAbout.delete())
|
||||||
|
updateListView();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
AlertDialog alertDialog = alertDialogBuilder.create();
|
||||||
|
|
||||||
|
return alertDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateListView()
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "ListView", "Attempting to update RuleListView", 4);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(ruleListView.getAdapter() == null)
|
||||||
|
ruleListView.setAdapter(ruleListViewAdapter);
|
||||||
|
|
||||||
|
ruleListViewAdapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
catch(NullPointerException e)
|
||||||
|
{}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(AutomationService.isMyServiceRunning(this))
|
||||||
|
AlarmListener.reloadAlarms();
|
||||||
|
}
|
||||||
|
catch(NullPointerException e)
|
||||||
|
{
|
||||||
|
// AlarmManager instance not prepared, yet.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
600
app/src/main/java/com/jens/automation2/ActivityMainScreen.java
Normal file
@ -0,0 +1,600 @@
|
|||||||
|
package com.jens.automation2;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.View.OnClickListener;
|
||||||
|
import android.view.View.OnTouchListener;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.CompoundButton;
|
||||||
|
import android.widget.CompoundButton.OnCheckedChangeListener;
|
||||||
|
import android.widget.ListView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
import android.widget.ToggleButton;
|
||||||
|
|
||||||
|
import com.google.android.gms.appindexing.AppIndex;
|
||||||
|
import com.google.android.gms.appindexing.Thing;
|
||||||
|
import com.google.android.gms.common.api.GoogleApiClient;
|
||||||
|
import com.jens.automation2.AutomationService.serviceCommands;
|
||||||
|
import com.jens.automation2.Trigger.Trigger_Enum;
|
||||||
|
import com.jens.automation2.location.LocationProvider;
|
||||||
|
|
||||||
|
import java.util.Calendar;
|
||||||
|
|
||||||
|
@SuppressLint("NewApi")
|
||||||
|
public class ActivityMainScreen extends ActivityGeneric
|
||||||
|
{
|
||||||
|
private static boolean guiChangeInProgress = false;
|
||||||
|
|
||||||
|
private static ActivityMainScreen activityMainScreenInstance = null;
|
||||||
|
private ToggleButton toggleService, tbLockSound;
|
||||||
|
private Button bShowHelp, bPrivacy, bSettingsErase, bSettingsSetToDefault, bVolumeTest, bAddSoundLockTIme;
|
||||||
|
private TextView tvActivePoi, tvClosestPoi, tvLastRule, tvMainScreenNote, tvlockSoundDuration;
|
||||||
|
|
||||||
|
private ListView lvRuleHistory;
|
||||||
|
private ArrayAdapter<Rule> ruleHistoryListViewAdapter;
|
||||||
|
|
||||||
|
private static boolean uiUpdateRunning = false;
|
||||||
|
/**
|
||||||
|
* ATTENTION: This was auto-generated to implement the App Indexing API.
|
||||||
|
* See https://g.co/AppIndexing/AndroidStudio for more information.
|
||||||
|
*/
|
||||||
|
private GoogleApiClient client;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState)
|
||||||
|
{
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.main_overview_layout);
|
||||||
|
|
||||||
|
activityMainScreenInstance = this;
|
||||||
|
|
||||||
|
if(ActivityPermissions.needMorePermissions(ActivityMainScreen.this))
|
||||||
|
{
|
||||||
|
Intent permissionsIntent = new Intent(ActivityMainScreen.this, ActivityPermissions.class);
|
||||||
|
startActivityForResult(permissionsIntent, 7000);
|
||||||
|
}
|
||||||
|
|
||||||
|
Settings.readFromPersistentStorage(this);
|
||||||
|
|
||||||
|
guiChangeInProgress = true;
|
||||||
|
|
||||||
|
tvActivePoi = (TextView) findViewById(R.id.tvActivePoi);
|
||||||
|
tvClosestPoi = (TextView) findViewById(R.id.tvClosestPoi);
|
||||||
|
lvRuleHistory = (ListView) findViewById(R.id.lvRuleHistory);
|
||||||
|
tvLastRule = (TextView) findViewById(R.id.tvTimeFrameHelpText);
|
||||||
|
tvMainScreenNote = (TextView) findViewById(R.id.tvMainScreenNote);
|
||||||
|
tvlockSoundDuration = (TextView)findViewById(R.id.tvlockSoundDuration);
|
||||||
|
tbLockSound = (ToggleButton) findViewById(R.id.tbLockSound);
|
||||||
|
toggleService = (ToggleButton) findViewById(R.id.tbArmMastListener);
|
||||||
|
toggleService.setChecked(AutomationService.isMyServiceRunning(this));
|
||||||
|
toggleService.setOnCheckedChangeListener(new OnCheckedChangeListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
|
||||||
|
{
|
||||||
|
if (!ActivityMainScreen.this.uiUpdateRunning)
|
||||||
|
{
|
||||||
|
if (toggleService.isChecked())
|
||||||
|
{
|
||||||
|
startAutomationService(getBaseContext(), false);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
stopAutomationService();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
tvMainScreenNote.setOnClickListener(new OnClickListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onClick(View v)
|
||||||
|
{
|
||||||
|
Intent intent = new Intent(ActivityMainScreen.this, ActivityPermissions.class);
|
||||||
|
startActivityForResult(intent, ActivityPermissions.requestCodeForPermissions);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
tbLockSound.setOnCheckedChangeListener(new OnCheckedChangeListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
|
||||||
|
{
|
||||||
|
Settings.lockSoundChanges = isChecked;
|
||||||
|
|
||||||
|
if(!isChecked)
|
||||||
|
{
|
||||||
|
AutomationService.getInstance().nullLockSoundChangesEnd();
|
||||||
|
updateMainScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!guiChangeInProgress)
|
||||||
|
Settings.writeSettings(ActivityMainScreen.this);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Button bSettings = (Button) findViewById(R.id.bSettings);
|
||||||
|
bSettings.setOnClickListener(new OnClickListener()
|
||||||
|
{
|
||||||
|
@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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
bShowHelp = (Button) findViewById(R.id.bShowHelp);
|
||||||
|
bShowHelp.setOnClickListener(new OnClickListener()
|
||||||
|
{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(View v)
|
||||||
|
{
|
||||||
|
Intent showHelpIntent = new Intent(ActivityMainScreen.this, ActivityHelp.class);
|
||||||
|
startActivity(showHelpIntent);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
bPrivacy = (Button) findViewById(R.id.bPrivacy);
|
||||||
|
bPrivacy.setOnClickListener(new OnClickListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onClick(View v)
|
||||||
|
{
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(ActivityMainScreen.this);
|
||||||
|
builder.setMessage(getResources().getString(R.string.privacyConfirmationText));
|
||||||
|
builder.setPositiveButton(getResources().getString(R.string.yes), new DialogInterface.OnClickListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which)
|
||||||
|
{
|
||||||
|
openPrivacyPolicy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
builder.setNegativeButton(getResources().getString(R.string.no), null);
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public boolean onTouch(View v, MotionEvent event)
|
||||||
|
{
|
||||||
|
v.getParent().requestDisallowInterceptTouchEvent(true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
bAddSoundLockTIme = (Button)findViewById(R.id.bAddSoundLockTIme);
|
||||||
|
bAddSoundLockTIme.setText("+" + Settings.lockSoundChangesInterval + " min");
|
||||||
|
bAddSoundLockTIme.setOnClickListener(new OnClickListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onClick(View view)
|
||||||
|
{
|
||||||
|
if(AutomationService.isMyServiceRunning(ActivityMainScreen.this))
|
||||||
|
{
|
||||||
|
AutomationService.getInstance().lockSoundChangesEndAddTime();
|
||||||
|
ActivityMainScreen.updateMainScreen();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Toast.makeText(ActivityMainScreen.this, getResources().getString(R.string.serviceNotRunning), Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ruleHistoryListViewAdapter = new ArrayAdapter<Rule>(this, R.layout.text_view_for_poi_listview_mediumtextsize, Rule.getRuleRunHistory());
|
||||||
|
|
||||||
|
if (PointOfInterest.getPointOfInterestCollection() == null | PointOfInterest.getPointOfInterestCollection().size() == 0)
|
||||||
|
PointOfInterest.loadPoisFromFile();
|
||||||
|
if (Rule.getRuleCollection() == null | Rule.getRuleCollection().size() == 0)
|
||||||
|
Rule.readFromFile();
|
||||||
|
|
||||||
|
ActivityMainScreen.updateMainScreen();
|
||||||
|
|
||||||
|
this.storeServiceReferenceInVariable();
|
||||||
|
|
||||||
|
guiChangeInProgress = false;
|
||||||
|
// ATTENTION: This was auto-generated to implement the App Indexing API.
|
||||||
|
// See https://g.co/AppIndexing/AndroidStudio for more information.
|
||||||
|
client = new GoogleApiClient.Builder(this).addApi(AppIndex.API).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AlertDialog getEraseSettingsDialog(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.eraseSettings(context))
|
||||||
|
Toast.makeText(context, context.getResources().getString(R.string.settingsErased), Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
alertDialogBuilder.setNegativeButton(context.getResources().getString(R.string.no), null);
|
||||||
|
AlertDialog alertDialog = alertDialogBuilder.create();
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void updateMainScreen()
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "MainScreen", "Request to update notification.", 5);
|
||||||
|
|
||||||
|
if (activityMainScreenInstance != null)
|
||||||
|
{
|
||||||
|
if(ActivityPermissions.needMorePermissions(activityMainScreenInstance))
|
||||||
|
{
|
||||||
|
activityMainScreenInstance.tvMainScreenNote.setText(R.string.mainScreenPermissionNote);
|
||||||
|
activityMainScreenInstance.tvMainScreenNote.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
activityMainScreenInstance.tvMainScreenNote.setText("");
|
||||||
|
activityMainScreenInstance.tvMainScreenNote.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AutomationService.isMyServiceRunning(activityMainScreenInstance))
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "MainScreen", "Service is running. Updating mainscreen with this info.", 5);
|
||||||
|
uiUpdateRunning = true;
|
||||||
|
activityMainScreenInstance.toggleService.setChecked(true);
|
||||||
|
uiUpdateRunning = false;
|
||||||
|
// if(activityMainScreenInstance.hasWindowFocus())
|
||||||
|
// {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PointOfInterest activePoi = PointOfInterest.getActivePoi();
|
||||||
|
if (activePoi == null)
|
||||||
|
{
|
||||||
|
PointOfInterest closestPoi = PointOfInterest.getClosestPOI(LocationProvider.getInstance().getCurrentLocation());
|
||||||
|
activityMainScreenInstance.tvActivePoi.setText("none");
|
||||||
|
activityMainScreenInstance.tvClosestPoi.setText(closestPoi.getName());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
activityMainScreenInstance.tvActivePoi.setText(activePoi.getName());
|
||||||
|
activityMainScreenInstance.tvClosestPoi.setText("n./a.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (NullPointerException e)
|
||||||
|
{
|
||||||
|
if (PointOfInterest.getPointOfInterestCollection().size() > 0)
|
||||||
|
{
|
||||||
|
if(
|
||||||
|
Rule.isAnyRuleUsing(Trigger_Enum.pointOfInterest)
|
||||||
|
&&
|
||||||
|
ActivityPermissions.havePermission(ActivityPermissions.permissionNameLocationCoarse, AutomationService.getInstance())
|
||||||
|
&&
|
||||||
|
ActivityPermissions.havePermission(ActivityPermissions.permissionNameLocationFine, AutomationService.getInstance())
|
||||||
|
)
|
||||||
|
activityMainScreenInstance.tvActivePoi.setText(activityMainScreenInstance.getResources().getString(R.string.stillGettingPosition));
|
||||||
|
else
|
||||||
|
activityMainScreenInstance.tvActivePoi.setText(activityMainScreenInstance.getResources().getString(R.string.locationEngineNotActive));
|
||||||
|
|
||||||
|
activityMainScreenInstance.tvClosestPoi.setText("n./a.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
activityMainScreenInstance.tvActivePoi.setText(activityMainScreenInstance.getResources().getString(R.string.noPoisDefinedShort));
|
||||||
|
activityMainScreenInstance.tvClosestPoi.setText("n./a.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
activityMainScreenInstance.tvLastRule.setText(Rule.getLastActivatedRule().getName() + " " + activityMainScreenInstance.getResources().getString(R.string.at) + " " + Rule.getLastActivatedRuleActivationTime().toLocaleString());
|
||||||
|
activityMainScreenInstance.updateListView();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
activityMainScreenInstance.tvLastRule.setText("n./a.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "MainScreen", "Service not running. Updating mainscreen with this info.", 5);
|
||||||
|
activityMainScreenInstance.toggleService.setChecked(false);
|
||||||
|
activityMainScreenInstance.tvActivePoi.setText(activityMainScreenInstance.getResources().getString(R.string.serviceNotRunning));
|
||||||
|
activityMainScreenInstance.tvClosestPoi.setText("");
|
||||||
|
activityMainScreenInstance.tvLastRule.setText("");
|
||||||
|
}
|
||||||
|
|
||||||
|
// uiUpdateRunning = true;
|
||||||
|
if(AutomationService.isMyServiceRunning(ActivityMainScreen.getActivityMainScreenInstance()) && AutomationService.getInstance() != null)
|
||||||
|
{
|
||||||
|
AutomationService.getInstance().checkLockSoundChangesTimeElapsed();
|
||||||
|
|
||||||
|
Calendar end = AutomationService.getInstance().getLockSoundChangesEnd();
|
||||||
|
activityMainScreenInstance.tbLockSound.setChecked(end != null);
|
||||||
|
activityMainScreenInstance.tbLockSound.setEnabled(end != null);
|
||||||
|
|
||||||
|
if(end != null)
|
||||||
|
{
|
||||||
|
Calendar now = Calendar.getInstance();
|
||||||
|
long millis = end.getTimeInMillis() - now.getTimeInMillis();
|
||||||
|
long minutes = millis/1000/60;
|
||||||
|
if(minutes < 60)
|
||||||
|
activityMainScreenInstance.tvlockSoundDuration.setText(String.valueOf(minutes + " min..."));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
double hours = (double)minutes / 60.0;
|
||||||
|
activityMainScreenInstance.tvlockSoundDuration.setText(String.valueOf(Math.round(hours * 100.0) / 100.0) + " h...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
activityMainScreenInstance.tvlockSoundDuration.setText(String.valueOf(""));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
activityMainScreenInstance.tbLockSound.setChecked(false);
|
||||||
|
activityMainScreenInstance.tbLockSound.setEnabled(false);
|
||||||
|
activityMainScreenInstance.tvlockSoundDuration.setText("");
|
||||||
|
}
|
||||||
|
Settings.writeSettings(activityMainScreenInstance);
|
||||||
|
// uiUpdateRunning = false;
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// Miscellaneous.logEvent("i", "ActivityMainScreen", "Window doesn't have focus. We're not updating anything.", 5);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Miscellaneous.logEvent("i", "ActivityMainScreen", "Activity not running. No need to update.", 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onActivityResult(int requestCode, int resultCode, Intent data)
|
||||||
|
{
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
|
||||||
|
// Miscellaneous.logEvent("i", "ListView", "Notifying ListViewAdapter", 4);
|
||||||
|
|
||||||
|
if (AutomationService.isMyServiceRunning(this))
|
||||||
|
bindToService();
|
||||||
|
|
||||||
|
switch (requestCode)
|
||||||
|
{
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
// Let service reload via binding interface.
|
||||||
|
if (boundToService)
|
||||||
|
{
|
||||||
|
myAutomationService.serviceInterface(serviceCommands.updateNotification); //in case names got changed.
|
||||||
|
unBindFromService();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Let service reload classically.
|
||||||
|
AutomationService service = AutomationService.getInstance();
|
||||||
|
if (service != null)
|
||||||
|
service.applySettingsAndRules();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void startAutomationService(Context context, boolean startAtBoot)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (Rule.getRuleCollection().size() > 0)
|
||||||
|
{
|
||||||
|
if (!AutomationService.isMyServiceRunning(context))
|
||||||
|
{
|
||||||
|
// if(myServiceIntent == null) //do we need that line?????
|
||||||
|
myServiceIntent = new Intent(context, AutomationService.class);
|
||||||
|
myServiceIntent.putExtra("startAtBoot", startAtBoot);
|
||||||
|
context.startService(myServiceIntent);
|
||||||
|
} else
|
||||||
|
Miscellaneous.logEvent("w", "Service", context.getResources().getString(R.string.logServiceAlreadyRunning), 3);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
Toast.makeText(context, context.getResources().getString(R.string.serviceWontStart), Toast.LENGTH_LONG).show();
|
||||||
|
activityMainScreenInstance.toggleService.setChecked(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (NullPointerException ne)
|
||||||
|
{
|
||||||
|
Toast.makeText(context, context.getResources().getString(R.string.serviceWontStart), Toast.LENGTH_LONG).show();
|
||||||
|
activityMainScreenInstance.toggleService.setChecked(false);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Toast.makeText(context, "Error: " + e.getMessage(), Toast.LENGTH_LONG).show();
|
||||||
|
activityMainScreenInstance.toggleService.setChecked(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopAutomationService()
|
||||||
|
{
|
||||||
|
if (myServiceIntent == null)
|
||||||
|
myServiceIntent = new Intent(this, AutomationService.class);
|
||||||
|
stopService(myServiceIntent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onRestart()
|
||||||
|
{
|
||||||
|
super.onRestart();
|
||||||
|
toggleService.setChecked(AutomationService.isMyServiceRunning(this));
|
||||||
|
ActivityMainScreen.updateMainScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onStart()
|
||||||
|
{
|
||||||
|
super.onStart();// ATTENTION: This was auto-generated to implement the App Indexing API.
|
||||||
|
// See https://g.co/AppIndexing/AndroidStudio for more information.
|
||||||
|
client.connect();
|
||||||
|
toggleService.setChecked(AutomationService.isMyServiceRunning(this));
|
||||||
|
ActivityMainScreen.updateMainScreen();
|
||||||
|
// ATTENTION: This was auto-generated to implement the App Indexing API.
|
||||||
|
// See https://g.co/AppIndexing/AndroidStudio for more information.
|
||||||
|
AppIndex.AppIndexApi.start(client, getIndexApiAction());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume()
|
||||||
|
{
|
||||||
|
super.onResume();
|
||||||
|
toggleService.setChecked(AutomationService.isMyServiceRunning(this));
|
||||||
|
ActivityMainScreen.updateMainScreen();
|
||||||
|
|
||||||
|
if(Build.VERSION.SDK_INT >= 28 && !Settings.noticeAndroid9MicrophoneShown && Rule.isAnyRuleUsing(Trigger_Enum.noiseLevel))
|
||||||
|
{
|
||||||
|
Settings.noticeAndroid9MicrophoneShown = true;
|
||||||
|
Settings.writeSettings(ActivityMainScreen.this);
|
||||||
|
Miscellaneous.messageBox(getResources().getString(R.string.app_name), getResources().getString(R.string.android9RecordAudioNotice) + " " + getResources().getString(R.string.messageNotShownAgain), ActivityMainScreen.this).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Build.VERSION.SDK_INT >= 29 && !Settings.noticeAndroid10WifiShown && Rule.isAnyRuleUsing(Action.Action_Enum.setWifi))
|
||||||
|
{
|
||||||
|
Settings.noticeAndroid10WifiShown = true;
|
||||||
|
Settings.writeSettings(ActivityMainScreen.this);
|
||||||
|
Miscellaneous.messageBox(getResources().getString(R.string.app_name), getResources().getString(R.string.android10WifiToggleNotice) + " " + getResources().getString(R.string.messageNotShownAgain), ActivityMainScreen.this).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy()
|
||||||
|
{
|
||||||
|
super.onDestroy();
|
||||||
|
activityMainScreenInstance = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void openPrivacyPolicy()
|
||||||
|
{
|
||||||
|
String privacyPolicyUrl = "http://server47.de/automation/privacy.html";
|
||||||
|
|
||||||
|
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(privacyPolicyUrl));
|
||||||
|
startActivity(browserIntent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateListView()
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "ListView", "Attempting to update lvRuleHistory", 4);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (lvRuleHistory.getAdapter() == null)
|
||||||
|
lvRuleHistory.setAdapter(ruleHistoryListViewAdapter);
|
||||||
|
|
||||||
|
ruleHistoryListViewAdapter.notifyDataSetChanged();
|
||||||
|
} catch (NullPointerException e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ATTENTION: This was auto-generated to implement the App Indexing API.
|
||||||
|
* See https://g.co/AppIndexing/AndroidStudio for more information.
|
||||||
|
*/
|
||||||
|
public com.google.android.gms.appindexing.Action getIndexApiAction()
|
||||||
|
{
|
||||||
|
Thing object = new Thing.Builder()
|
||||||
|
.setName("ActivityMainScreen Page") // TODO: Define a title for the content shown.
|
||||||
|
// TODO: Make sure this auto-generated URL is correct.
|
||||||
|
.setUrl(Uri.parse("http://[ENTER-YOUR-URL-HERE]"))
|
||||||
|
.build();
|
||||||
|
return new com.google.android.gms.appindexing.Action.Builder(com.google.android.gms.appindexing.Action.TYPE_VIEW)
|
||||||
|
.setObject(object)
|
||||||
|
.setActionStatus(com.google.android.gms.appindexing.Action.STATUS_TYPE_COMPLETED)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStop()
|
||||||
|
{
|
||||||
|
super.onStop();
|
||||||
|
|
||||||
|
// ATTENTION: This was auto-generated to implement the App Indexing API.
|
||||||
|
// See https://g.co/AppIndexing/AndroidStudio for more information.
|
||||||
|
AppIndex.AppIndexApi.end(client, getIndexApiAction());
|
||||||
|
client.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void showMessageBox(String title, String text)
|
||||||
|
{
|
||||||
|
Miscellaneous.messageBox(title, text, ActivityMainScreen.getActivityMainScreenInstance());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
package com.jens.automation2;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.app.TabActivity;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.widget.TabHost;
|
||||||
|
import android.widget.TabHost.TabSpec;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
TabHost tabHost = getTabHost();
|
||||||
|
|
||||||
|
TabSpec specOverview = tabHost.newTabSpec("overview");
|
||||||
|
specOverview.setIndicator(getResources().getString(R.string.overview), getResources().getDrawable(R.drawable.icon_overview_tab));
|
||||||
|
Intent overviewIntent = new Intent(this, ActivityMainScreen.class);
|
||||||
|
specOverview.setContent(overviewIntent);
|
||||||
|
|
||||||
|
TabSpec specPoi = tabHost.newTabSpec("pois");
|
||||||
|
specPoi.setIndicator(getResources().getString(R.string.pois), getResources().getDrawable(R.drawable.map));
|
||||||
|
Intent mainPoiIntent = new Intent(this, ActivityMainPoi.class);
|
||||||
|
specPoi.setContent(mainPoiIntent);
|
||||||
|
|
||||||
|
TabSpec specRules = tabHost.newTabSpec("rules");
|
||||||
|
specRules.setIndicator(getResources().getString(R.string.rules), getResources().getDrawable(R.drawable.gear));
|
||||||
|
Intent mainRulesIntent = new Intent(this, ActivityMainRules.class);
|
||||||
|
specRules.setContent(mainRulesIntent);
|
||||||
|
|
||||||
|
TabSpec specProfiles = tabHost.newTabSpec("profiles");
|
||||||
|
specProfiles.setIndicator(getResources().getString(R.string.profiles), getResources().getDrawable(R.drawable.sound));
|
||||||
|
Intent mainProfilesIntent = new Intent(this, ActivityMainProfiles.class);
|
||||||
|
specProfiles.setContent(mainProfilesIntent);
|
||||||
|
|
||||||
|
tabHost.addTab(specOverview);
|
||||||
|
tabHost.addTab(specPoi);
|
||||||
|
tabHost.addTab(specRules);
|
||||||
|
tabHost.addTab(specProfiles);
|
||||||
|
|
||||||
|
tabHost.setCurrentTab(Settings.startScreen);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume()
|
||||||
|
{
|
||||||
|
super.onResume();
|
||||||
|
// Miscellaneous.logEvent("i", "NFC", "ActivityMainTabLayout.onResume().", 5);
|
||||||
|
NfcReceiver.checkIntentForNFC(this, getIntent());
|
||||||
|
// NfcReceiver.checkIntentForNFC(this, new Intent(this.getApplicationContext(), this.getClass()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onNewIntent(Intent intent)
|
||||||
|
{
|
||||||
|
// Miscellaneous.logEvent("i", "NFC", "ActivityMainTabLayout.onNewIntent().", 5);
|
||||||
|
// setIntent(intent);
|
||||||
|
NfcReceiver.checkIntentForNFC(this, intent);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,187 @@
|
|||||||
|
package com.jens.automation2;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.bluetooth.BluetoothDevice;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.View.OnClickListener;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.CompoundButton;
|
||||||
|
import android.widget.CompoundButton.OnCheckedChangeListener;
|
||||||
|
import android.widget.RadioButton;
|
||||||
|
import android.widget.Spinner;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.jens.automation2.receivers.BluetoothReceiver;
|
||||||
|
|
||||||
|
public class ActivityManageBluetoothTrigger extends Activity
|
||||||
|
{
|
||||||
|
protected static Trigger editedBluetoothTrigger;
|
||||||
|
RadioButton radioAnyBluetoothDevice, radioNoDevice, radioDeviceFromList, radioBluetoothConnected, radioBluetoothDisconnected, radioBluetoothInRange, radioBluetoothOutRange;
|
||||||
|
Button bSaveBluetoothTrigger;
|
||||||
|
Spinner spinnerBluetoothDevices;
|
||||||
|
|
||||||
|
ArrayAdapter<String> bluetoothDevicesSpinnerAdapter;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState)
|
||||||
|
{
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_bluetooth_trigger);
|
||||||
|
|
||||||
|
radioAnyBluetoothDevice = (RadioButton)findViewById(R.id.radioAnyBluetoothDevice);
|
||||||
|
radioNoDevice = (RadioButton)findViewById(R.id.radioNoDevice);
|
||||||
|
radioDeviceFromList = (RadioButton)findViewById(R.id.radioDeviceFromList);
|
||||||
|
radioBluetoothConnected = (RadioButton)findViewById(R.id.radioBluetoothConnected);
|
||||||
|
radioBluetoothDisconnected = (RadioButton)findViewById(R.id.radioBluetoothDisconnected);
|
||||||
|
radioBluetoothInRange = (RadioButton)findViewById(R.id.radioBluetoothInRange);
|
||||||
|
radioBluetoothOutRange = (RadioButton)findViewById(R.id.radioBluetoothOutRange);
|
||||||
|
bSaveBluetoothTrigger = (Button)findViewById(R.id.bSaveBluetoothTrigger);
|
||||||
|
spinnerBluetoothDevices = (Spinner)findViewById(R.id.spinnerBluetoothDevices);
|
||||||
|
|
||||||
|
bluetoothDevicesSpinnerAdapter = new ArrayAdapter<String>(this, R.layout.text_view_for_poi_listview_mediumtextsize, BluetoothReceiver.getAllPairedBluetoothDevicesStrings());
|
||||||
|
|
||||||
|
radioDeviceFromList.setOnCheckedChangeListener(new OnCheckedChangeListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
|
||||||
|
{
|
||||||
|
spinnerBluetoothDevices.setEnabled(isChecked);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
bSaveBluetoothTrigger.setOnClickListener(new OnClickListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onClick(View v)
|
||||||
|
{
|
||||||
|
if(saveTrigger())
|
||||||
|
{
|
||||||
|
setResult(RESULT_OK);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
refreshBluetoothDeviceSpinner();
|
||||||
|
spinnerBluetoothDevices.setEnabled(false);
|
||||||
|
|
||||||
|
if(editedBluetoothTrigger.getBluetoothDeviceAddress() != null && editedBluetoothTrigger.getBluetoothDeviceAddress().length() > 0)
|
||||||
|
loadVariableIntoGui();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void refreshBluetoothDeviceSpinner()
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "Spinner", "Attempting to update spinnerBluetoothDevices", 4);
|
||||||
|
if(spinnerBluetoothDevices.getAdapter() == null)
|
||||||
|
{
|
||||||
|
spinnerBluetoothDevices.setAdapter(bluetoothDevicesSpinnerAdapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
bluetoothDevicesSpinnerAdapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean saveTrigger()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// DEVICE
|
||||||
|
|
||||||
|
if(radioAnyBluetoothDevice.isChecked())
|
||||||
|
{
|
||||||
|
editedBluetoothTrigger.setBluetoothDeviceAddress("<any>");
|
||||||
|
}
|
||||||
|
else if(radioNoDevice.isChecked())
|
||||||
|
{
|
||||||
|
editedBluetoothTrigger.setBluetoothDeviceAddress("<none>");
|
||||||
|
}
|
||||||
|
else if(radioDeviceFromList.isChecked())
|
||||||
|
{
|
||||||
|
BluetoothDevice selectedDevice = BluetoothReceiver.getAllPairedBluetoothDevices()[spinnerBluetoothDevices.getSelectedItemPosition()];
|
||||||
|
if(selectedDevice != null)
|
||||||
|
{
|
||||||
|
editedBluetoothTrigger.setBluetoothDeviceAddress(selectedDevice.getAddress());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Miscellaneous.logEvent("w", "ActivityManageBluetoothTrigger", "Device not found.", 3);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Toast.makeText(ActivityManageBluetoothTrigger.this, getResources().getString(R.string.selectDeviceOption), Toast.LENGTH_LONG).show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// EVENT
|
||||||
|
|
||||||
|
if(radioBluetoothConnected.isChecked())
|
||||||
|
{
|
||||||
|
editedBluetoothTrigger.setTriggerParameter(true);
|
||||||
|
editedBluetoothTrigger.setBluetoothEvent(BluetoothDevice.ACTION_ACL_CONNECTED);
|
||||||
|
}
|
||||||
|
else if(radioBluetoothDisconnected.isChecked())
|
||||||
|
{
|
||||||
|
editedBluetoothTrigger.setTriggerParameter(false);
|
||||||
|
editedBluetoothTrigger.setBluetoothEvent(BluetoothDevice.ACTION_ACL_DISCONNECTED);
|
||||||
|
}
|
||||||
|
else if(radioBluetoothInRange.isChecked())
|
||||||
|
{
|
||||||
|
editedBluetoothTrigger.setTriggerParameter(true);
|
||||||
|
editedBluetoothTrigger.setBluetoothEvent(BluetoothDevice.ACTION_FOUND);
|
||||||
|
}
|
||||||
|
else if(radioBluetoothOutRange.isChecked())
|
||||||
|
{
|
||||||
|
editedBluetoothTrigger.setTriggerParameter(false);
|
||||||
|
editedBluetoothTrigger.setBluetoothEvent(BluetoothDevice.ACTION_FOUND);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Toast.makeText(ActivityManageBluetoothTrigger.this, getResources().getString(R.string.selectConnectionOption), Toast.LENGTH_LONG).show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("w", "ActivityManageBluetoothTrigger", "Error during trigger create/change: " + Log.getStackTraceString(e), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void loadVariableIntoGui()
|
||||||
|
{
|
||||||
|
if(editedBluetoothTrigger != null)
|
||||||
|
{
|
||||||
|
if(editedBluetoothTrigger.getBluetoothDeviceAddress().equals("<any>"))
|
||||||
|
{
|
||||||
|
radioAnyBluetoothDevice.setChecked(true);
|
||||||
|
}
|
||||||
|
else if(editedBluetoothTrigger.getBluetoothDeviceAddress().equals("<none>"))
|
||||||
|
{
|
||||||
|
radioNoDevice.setChecked(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
radioDeviceFromList.setChecked(true);
|
||||||
|
spinnerBluetoothDevices.setSelection(BluetoothReceiver.getDevicePositionByAddress(editedBluetoothTrigger.getBluetoothDeviceAddress()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(editedBluetoothTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED))
|
||||||
|
{
|
||||||
|
radioBluetoothConnected.setChecked(true);
|
||||||
|
}
|
||||||
|
else if(editedBluetoothTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_DISCONNECTED))
|
||||||
|
{
|
||||||
|
radioBluetoothDisconnected.setChecked(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
radioBluetoothInRange.setChecked(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
package com.jens.automation2;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.CheckBox;
|
||||||
|
import android.widget.CompoundButton;
|
||||||
|
import android.widget.SeekBar;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
public class ActivityManageBrightnessSetting extends Activity
|
||||||
|
{
|
||||||
|
CheckBox chkAutoBrightness;
|
||||||
|
SeekBar sbBrightness;
|
||||||
|
Button bApplyBrightness;
|
||||||
|
TextView tvAutoBrightnessNotice;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(@Nullable Bundle savedInstanceState)
|
||||||
|
{
|
||||||
|
setContentView(R.layout.activity_manage_brightness_setting);
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
chkAutoBrightness = (CheckBox)findViewById(R.id.chkAutoBrightness);
|
||||||
|
sbBrightness = (SeekBar)findViewById(R.id.sbBrightness);
|
||||||
|
bApplyBrightness = (Button)findViewById(R.id.bApplyBrightness);
|
||||||
|
tvAutoBrightnessNotice = (TextView)findViewById(R.id.tvAutoBrightnessNotice);
|
||||||
|
|
||||||
|
Intent input = getIntent();
|
||||||
|
|
||||||
|
if(input.hasExtra("autoBrightness"))
|
||||||
|
chkAutoBrightness.setChecked(input.getBooleanExtra("autoBrightness", false));
|
||||||
|
|
||||||
|
if(input.hasExtra("brightnessValue"))
|
||||||
|
sbBrightness.setProgress(input.getIntExtra("brightnessValue", 0));
|
||||||
|
|
||||||
|
bApplyBrightness.setOnClickListener(new View.OnClickListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onClick(View view)
|
||||||
|
{
|
||||||
|
Intent answer = new Intent();
|
||||||
|
answer.putExtra("autoBrightness", chkAutoBrightness.isChecked());
|
||||||
|
answer.putExtra("brightnessValue", sbBrightness.getProgress());
|
||||||
|
setResult(RESULT_OK, answer);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
chkAutoBrightness.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
|
||||||
|
{
|
||||||
|
if(isChecked)
|
||||||
|
tvAutoBrightnessNotice.setText(R.string.autoBrightnessNotice);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
306
app/src/main/java/com/jens/automation2/ActivityManageNfc.java
Normal file
@ -0,0 +1,306 @@
|
|||||||
|
package com.jens.automation2;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.PendingIntent;
|
||||||
|
import android.app.ProgressDialog;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.DialogInterface.OnCancelListener;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
import android.nfc.NfcAdapter;
|
||||||
|
import android.nfc.Tag;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.View.OnClickListener;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.jens.automation2.receivers.NfcReceiver;
|
||||||
|
|
||||||
|
@SuppressLint("NewApi")
|
||||||
|
public class ActivityManageNfc extends Activity
|
||||||
|
{
|
||||||
|
public static String generatedId = null;
|
||||||
|
private static Tag discoveredTag = null;
|
||||||
|
|
||||||
|
EditText etNewNfcIdValue;
|
||||||
|
Button bReadNfcTag, bUseValueCurrentlyStored, bWriteNfcTag;
|
||||||
|
TextView tvCurrentNfcId;
|
||||||
|
|
||||||
|
private static int currentStatus = 0;
|
||||||
|
private static ProgressDialog progressDialog = null;
|
||||||
|
|
||||||
|
// Check if NFC is activated
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState)
|
||||||
|
{
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.manage_nfc);
|
||||||
|
|
||||||
|
etNewNfcIdValue = (EditText)findViewById(R.id.etNewNfcIdValue);
|
||||||
|
bReadNfcTag = (Button)findViewById(R.id.bReadNfcTag);
|
||||||
|
bUseValueCurrentlyStored = (Button)findViewById(R.id.bUseValueCurrentlyStored);
|
||||||
|
bWriteNfcTag = (Button)findViewById(R.id.bWriteNfcTag);
|
||||||
|
tvCurrentNfcId = (TextView)findViewById(R.id.tvCurrentNfcId);
|
||||||
|
|
||||||
|
bReadNfcTag.setOnClickListener(new OnClickListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onClick(View v)
|
||||||
|
{
|
||||||
|
if(discoveredTag != null)
|
||||||
|
{
|
||||||
|
generatedId = NfcReceiver.readTag(discoveredTag);
|
||||||
|
tvCurrentNfcId.setText(generatedId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
progressDialog = ProgressDialog.show(ActivityManageNfc.this, null, getResources().getString(R.string.nfcBringTagIntoRange), false, true, new OnCancelListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onCancel(DialogInterface dialog)
|
||||||
|
{
|
||||||
|
progressDialog.dismiss();
|
||||||
|
progressDialog = null;
|
||||||
|
currentStatus = 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
bUseValueCurrentlyStored.setOnClickListener(new OnClickListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onClick(View v)
|
||||||
|
{
|
||||||
|
if(discoveredTag != null)
|
||||||
|
{
|
||||||
|
if(checkEnteredText(false))
|
||||||
|
{
|
||||||
|
setResult(RESULT_OK);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
progressDialog = ProgressDialog.show(ActivityManageNfc.this, null, getResources().getString(R.string.nfcBringTagIntoRange), false, true, new OnCancelListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onCancel(DialogInterface dialog)
|
||||||
|
{
|
||||||
|
progressDialog.dismiss();
|
||||||
|
progressDialog = null;
|
||||||
|
currentStatus = 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
currentStatus = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
bWriteNfcTag.setOnClickListener(new OnClickListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onClick(View v)
|
||||||
|
{
|
||||||
|
if(checkEnteredText(true))
|
||||||
|
{
|
||||||
|
// ActivityPermissions.requestSpecificPermission("android.permission.NFC");
|
||||||
|
if(discoveredTag != null)
|
||||||
|
{
|
||||||
|
tryWrite();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
progressDialog = ProgressDialog.show(ActivityManageNfc.this, null, getResources().getString(R.string.nfcBringTagIntoRange), false, true, new OnCancelListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onCancel(DialogInterface dialog)
|
||||||
|
{
|
||||||
|
progressDialog.dismiss();
|
||||||
|
progressDialog = null;
|
||||||
|
currentStatus = 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
currentStatus = 2;
|
||||||
|
|
||||||
|
// Toast.makeText(ActivityManageNfc.this, "No tag.", Toast.LENGTH_LONG).show();
|
||||||
|
// Miscellaneous.logEvent("w", "NFC", "No tag.", 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if(generatedId != null)
|
||||||
|
etNewNfcIdValue.setText(generatedId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void enableForegroundDispatch(final Activity activity)
|
||||||
|
{
|
||||||
|
NfcAdapter nfcAdapter = NfcReceiver.getNfcAdapter(activity);
|
||||||
|
|
||||||
|
final Intent intent = new Intent(activity.getApplicationContext(), activity.getClass());
|
||||||
|
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||||
|
|
||||||
|
final PendingIntent pendingIntent = PendingIntent.getActivity(activity.getApplicationContext(), 0, intent, 0);
|
||||||
|
|
||||||
|
IntentFilter[] filters = new IntentFilter[1];
|
||||||
|
String[][] techList = new String[][]{};
|
||||||
|
|
||||||
|
// Notice that this is the same filter as in our manifest.
|
||||||
|
filters[0] = new IntentFilter();
|
||||||
|
filters[0].addAction(NfcAdapter.ACTION_NDEF_DISCOVERED);
|
||||||
|
filters[0].addAction(NfcAdapter.ACTION_TAG_DISCOVERED);
|
||||||
|
filters[0].addAction(NfcAdapter.ACTION_TECH_DISCOVERED);
|
||||||
|
filters[0].addCategory(Intent.CATEGORY_DEFAULT);
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// filters[0].addDataType(NfcReceiver.MIME_TEXT_PLAIN);
|
||||||
|
// }
|
||||||
|
// catch (MalformedMimeTypeException e)
|
||||||
|
// {
|
||||||
|
// throw new RuntimeException("Check your mime type.");
|
||||||
|
// }
|
||||||
|
|
||||||
|
nfcAdapter.enableForegroundDispatch(activity, pendingIntent, filters, techList);
|
||||||
|
|
||||||
|
Miscellaneous.logEvent("i", "NFC", "Enabled foreground dispatch.", 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void disableForegroundDispatch(final Activity activity)
|
||||||
|
{
|
||||||
|
NfcAdapter nfcAdapter = NfcReceiver.getNfcAdapter(activity);
|
||||||
|
nfcAdapter.disableForegroundDispatch(activity);
|
||||||
|
Miscellaneous.logEvent("i", "NFC", "Disabled foreground dispatch.", 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPause()
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Call this before onPause, otherwise an IllegalArgumentException is thrown as well.
|
||||||
|
*/
|
||||||
|
disableForegroundDispatch(this);
|
||||||
|
|
||||||
|
super.onPause();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume()
|
||||||
|
{
|
||||||
|
super.onResume();
|
||||||
|
/**
|
||||||
|
* It's important, that the activity is in the foreground (resumed). Otherwise
|
||||||
|
* an IllegalStateException is thrown.
|
||||||
|
*/
|
||||||
|
enableForegroundDispatch(this);
|
||||||
|
|
||||||
|
// NfcReceiver.checkIntentForNFC(this, new Intent(this.getApplicationContext(), this.getClass()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onNewIntent(Intent intent)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "NFC", "ActivityManageNfc->onNewIntent().", 5);
|
||||||
|
|
||||||
|
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
|
||||||
|
|
||||||
|
if(tag == null)
|
||||||
|
{
|
||||||
|
tvCurrentNfcId.setText(getResources().getString(R.string.nfcNoTag));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "NFC", getResources().getString(R.string.nfcTagDiscovered), 4);
|
||||||
|
Toast.makeText(this, getResources().getString(R.string.nfcTagDiscovered), Toast.LENGTH_LONG).show();
|
||||||
|
discoveredTag = tag;
|
||||||
|
if(progressDialog != null)
|
||||||
|
{
|
||||||
|
progressDialog.dismiss();
|
||||||
|
progressDialog = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(currentStatus == 0)
|
||||||
|
{
|
||||||
|
generatedId = NfcReceiver.readTag(discoveredTag);
|
||||||
|
if(generatedId != null && generatedId.length() > 0)
|
||||||
|
tvCurrentNfcId.setText(generatedId);
|
||||||
|
else
|
||||||
|
tvCurrentNfcId.setText(getResources().getString(R.string.nfcTagDataNotUsable));
|
||||||
|
}
|
||||||
|
else if(currentStatus == 1)
|
||||||
|
{
|
||||||
|
tryRead();
|
||||||
|
}
|
||||||
|
else if(currentStatus == 2)
|
||||||
|
if(checkEnteredText(true))
|
||||||
|
tryWrite();
|
||||||
|
}
|
||||||
|
|
||||||
|
// NfcReceiver.checkIntentForNFC(this, intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkEnteredText(boolean checkGuiValue)
|
||||||
|
{
|
||||||
|
if(checkGuiValue)
|
||||||
|
generatedId = etNewNfcIdValue.getText().toString();
|
||||||
|
|
||||||
|
if(generatedId.length() == 0)
|
||||||
|
{
|
||||||
|
generatedId = null;
|
||||||
|
Toast.makeText(ActivityManageNfc.this, getResources().getString(R.string.nfcEnterValidIdentifier), Toast.LENGTH_LONG).show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tryWrite()
|
||||||
|
{
|
||||||
|
if(NfcReceiver.writeTag(generatedId, discoveredTag))
|
||||||
|
{
|
||||||
|
currentStatus = 0;
|
||||||
|
Toast.makeText(ActivityManageNfc.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();
|
||||||
|
Miscellaneous.logEvent("e", "NFC", getResources().getString(R.string.nfcTagWriteError), 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tryRead()
|
||||||
|
{
|
||||||
|
generatedId = NfcReceiver.readTag(discoveredTag);
|
||||||
|
if(checkEnteredText(false))
|
||||||
|
{
|
||||||
|
currentStatus = 0;
|
||||||
|
Toast.makeText(ActivityManageNfc.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();
|
||||||
|
generatedId = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy()
|
||||||
|
{
|
||||||
|
super.onDestroy();
|
||||||
|
discoveredTag = null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,476 @@
|
|||||||
|
package com.jens.automation2;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.ProgressDialog;
|
||||||
|
import android.content.ActivityNotFoundException;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.location.Criteria;
|
||||||
|
import android.location.Location;
|
||||||
|
import android.location.LocationListener;
|
||||||
|
import android.location.LocationManager;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.View.OnClickListener;
|
||||||
|
import android.view.inputmethod.InputMethodManager;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.ImageButton;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
public class ActivityManageSpecificPoi extends Activity
|
||||||
|
{
|
||||||
|
public LocationManager myLocationManager;
|
||||||
|
MyLocationListenerGps myLocationListenerGps = new MyLocationListenerGps();
|
||||||
|
Location locationGps = null, locationNetwork = null;
|
||||||
|
// Location locationWifi = null;
|
||||||
|
MyLocationListenerNetwork myLocationListenerNetwork = new MyLocationListenerNetwork();
|
||||||
|
Button bGetPosition, bSavePoi;
|
||||||
|
ImageButton ibShowOnMap;
|
||||||
|
EditText guiPoiName, guiPoiLatitude, guiPoiLongitude, guiPoiRadius;
|
||||||
|
|
||||||
|
private static ProgressDialog progressDialog;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPause()
|
||||||
|
{
|
||||||
|
super.onPause();
|
||||||
|
Miscellaneous.logEvent("i", "ActivityManageSpecificPoi", getResources().getString(R.string.logClearingBothLocationListeners) , 5);
|
||||||
|
myLocationManager.removeUpdates(myLocationListenerGps);
|
||||||
|
myLocationManager.removeUpdates(myLocationListenerNetwork);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState)
|
||||||
|
{
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
this.setContentView(R.layout.manage_specific_poi);
|
||||||
|
|
||||||
|
myLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
|
||||||
|
bGetPosition = (Button)findViewById(R.id.bGetPosition);
|
||||||
|
ibShowOnMap = (ImageButton)findViewById(R.id.ibShowOnMap);
|
||||||
|
|
||||||
|
guiPoiName = (EditText)findViewById(R.id.etPoiName);
|
||||||
|
guiPoiLatitude = (EditText)findViewById(R.id.etPoiLatitude);
|
||||||
|
guiPoiLongitude = (EditText)findViewById(R.id.etPoiLongitude);
|
||||||
|
guiPoiRadius = (EditText)findViewById(R.id.etPoiRadius);
|
||||||
|
|
||||||
|
bGetPosition.setOnClickListener(new OnClickListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onClick(View v)
|
||||||
|
{
|
||||||
|
hideKeyboard();
|
||||||
|
getNotificationDialog(getResources().getString(R.string.positioningWindowNotice)).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
bSavePoi = (Button)findViewById(R.id.bSavePoi);
|
||||||
|
bSavePoi.setOnClickListener(new OnClickListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onClick(View v)
|
||||||
|
{
|
||||||
|
hideKeyboard();
|
||||||
|
|
||||||
|
if(ActivityMainPoi.poiToEdit == null)
|
||||||
|
createPoi();
|
||||||
|
else
|
||||||
|
changePoi();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ibShowOnMap.setOnClickListener(new OnClickListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onClick(View v)
|
||||||
|
{
|
||||||
|
hideKeyboard();
|
||||||
|
showOnMap();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if(ActivityMainPoi.poiToEdit != null)
|
||||||
|
editPoi(ActivityMainPoi.poiToEdit);
|
||||||
|
//else
|
||||||
|
// new Poi to be created
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createPoi()
|
||||||
|
{
|
||||||
|
myLocationManager.removeUpdates(myLocationListenerGps);
|
||||||
|
ActivityMainPoi.poiToEdit = new PointOfInterest();
|
||||||
|
ActivityMainPoi.poiToEdit.setLocation(new Location("POINT_LOCATION"));
|
||||||
|
if(loadFormValuesToVariable())
|
||||||
|
if(ActivityMainPoi.poiToEdit.create(this))
|
||||||
|
{
|
||||||
|
this.setResult(RESULT_OK);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void changePoi()
|
||||||
|
{
|
||||||
|
myLocationManager.removeUpdates(myLocationListenerGps);
|
||||||
|
if(loadFormValuesToVariable())
|
||||||
|
if(ActivityMainPoi.poiToEdit.change(this))
|
||||||
|
{
|
||||||
|
this.setResult(RESULT_OK);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void getLocation()
|
||||||
|
{
|
||||||
|
Criteria critNetwork = new Criteria();
|
||||||
|
critNetwork.setPowerRequirement(Criteria.POWER_LOW);
|
||||||
|
critNetwork.setAltitudeRequired(false);
|
||||||
|
critNetwork.setSpeedRequired(false);
|
||||||
|
critNetwork.setBearingRequired(false);
|
||||||
|
critNetwork.setCostAllowed(false);
|
||||||
|
critNetwork.setAccuracy(Criteria.ACCURACY_COARSE);
|
||||||
|
|
||||||
|
Criteria critGps = new Criteria();
|
||||||
|
critGps.setAltitudeRequired(false);
|
||||||
|
critGps.setSpeedRequired(false);
|
||||||
|
critGps.setBearingRequired(false);
|
||||||
|
critGps.setCostAllowed(true);
|
||||||
|
critGps.setAccuracy(Criteria.ACCURACY_FINE);
|
||||||
|
|
||||||
|
String provider1 = myLocationManager.getBestProvider(critNetwork, true);
|
||||||
|
String provider2 = myLocationManager.getBestProvider(critGps, true);
|
||||||
|
// String provider3 = myLocationManager.getProvider("wifi");
|
||||||
|
|
||||||
|
if(provider1 == null | provider2 == null)
|
||||||
|
{
|
||||||
|
Toast.makeText(this, getResources().getString(R.string.logNoSuitableProvider), Toast.LENGTH_LONG).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "POI Manager", getResources().getString(R.string.logGettingPositionWithProvider) + " " + provider1, 3);
|
||||||
|
myLocationManager.requestLocationUpdates(provider1, 500, Settings.satisfactoryAccuracyNetwork, myLocationListenerNetwork);
|
||||||
|
|
||||||
|
Miscellaneous.logEvent("i", "POI Manager", getResources().getString(R.string.logGettingPositionWithProvider) + " " + provider2, 3);
|
||||||
|
myLocationManager.requestLocationUpdates(provider2, 500, Settings.satisfactoryAccuracyGps, myLocationListenerGps);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void compareLocations()
|
||||||
|
{
|
||||||
|
if(locationGps != null)
|
||||||
|
{
|
||||||
|
guiPoiLatitude.setText(String.valueOf(locationGps.getLatitude()));
|
||||||
|
guiPoiLongitude.setText(String.valueOf(locationGps.getLongitude()));
|
||||||
|
|
||||||
|
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();
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
progressDialog.dismiss();
|
||||||
|
myLocationManager.removeUpdates(myLocationListenerNetwork);
|
||||||
|
guiPoiRadius.setText("250");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Miscellaneous.logEvent("i", "POI Manager", getResources().getString(R.string.logNotAllMeasurings), 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
private AlertDialog getNotificationDialog(String text)
|
||||||
|
{
|
||||||
|
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
|
||||||
|
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener()
|
||||||
|
{
|
||||||
|
|
||||||
|
@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(ActivityManageSpecificPoi.this, "", getResources().getString(R.string.gettingPosition), true, true);
|
||||||
|
getLocation();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
alertDialogBuilder.setMessage(text).setPositiveButton("Ok", dialogClickListener);
|
||||||
|
//.setNegativeButton("No", dialogClickListener);
|
||||||
|
AlertDialog alertDialog = alertDialogBuilder.create();
|
||||||
|
|
||||||
|
return alertDialog;
|
||||||
|
}
|
||||||
|
private AlertDialog getDialog(String text, final double value)
|
||||||
|
{
|
||||||
|
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
|
||||||
|
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener()
|
||||||
|
{
|
||||||
|
@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.dismiss();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
alertDialogBuilder.setMessage(text).setPositiveButton(getResources().getString(R.string.yes), dialogClickListener)
|
||||||
|
.setNegativeButton(getResources().getString(R.string.no), dialogClickListener);
|
||||||
|
AlertDialog alertDialog = alertDialogBuilder.create();
|
||||||
|
|
||||||
|
return alertDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MyLocationListenerGps implements LocationListener
|
||||||
|
{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLocationChanged(Location location)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "POI Manager", getResources().getString(R.string.logGotGpsUpdate) + " " + String.valueOf(location.getAccuracy()), 3);
|
||||||
|
// 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 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);
|
||||||
|
// 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();
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
@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 void editPoi(PointOfInterest poi)
|
||||||
|
{
|
||||||
|
guiPoiName.setText(poi.getName());
|
||||||
|
guiPoiLatitude.setText(String.valueOf(poi.getLocation().getLatitude()));
|
||||||
|
guiPoiLongitude.setText(String.valueOf(poi.getLocation().getLongitude()));
|
||||||
|
guiPoiRadius.setText(String.valueOf(poi.getRadius()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean loadFormValuesToVariable()
|
||||||
|
{
|
||||||
|
if(ActivityMainPoi.poiToEdit == null)
|
||||||
|
ActivityMainPoi.poiToEdit = new PointOfInterest();
|
||||||
|
|
||||||
|
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());
|
||||||
|
|
||||||
|
if(ActivityMainPoi.poiToEdit.getLocation() == null)
|
||||||
|
ActivityMainPoi.poiToEdit.setLocation(new Location("POINT_LOCATION"));
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ActivityMainPoi.poiToEdit.getLocation().setLatitude(Double.parseDouble(guiPoiLatitude.getText().toString()));
|
||||||
|
}
|
||||||
|
catch(NumberFormatException e)
|
||||||
|
{
|
||||||
|
Toast.makeText(this, getResources().getString(R.string.pleaseEnterValidLatitude), Toast.LENGTH_LONG).show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ActivityMainPoi.poiToEdit.getLocation().setLongitude(Double.parseDouble(guiPoiLongitude.getText().toString()));
|
||||||
|
}
|
||||||
|
catch(NumberFormatException e)
|
||||||
|
{
|
||||||
|
Toast.makeText(this, getResources().getString(R.string.pleaseEnterValidLongitude), Toast.LENGTH_LONG).show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showOnMap()
|
||||||
|
{
|
||||||
|
if(loadFormValuesToVariable())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String uri = "geo:" + guiPoiLatitude.getText().toString() + "," + guiPoiLongitude.getText().toString();
|
||||||
|
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(uri)));
|
||||||
|
|
||||||
|
// You can also choose to place a point like so:
|
||||||
|
// String uri = "geo:"+ latitude + "," + longitude + "?q=my+street+address";
|
||||||
|
// startActivity(new Intent(android.content.Intent.ACTION_VIEW, Uri.parse(uri)));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The Possible Query params options are the following:
|
||||||
|
*
|
||||||
|
* Show map at location: geo:latitude,longitude
|
||||||
|
* Show zoomed map at location: geo:latitude,longitude?z=zoom
|
||||||
|
* Show map at locaiton with point: geo:0,0?q=my+street+address
|
||||||
|
* Show map of businesses in area: geo:0,0?q=business+near+city
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
catch(ActivityNotFoundException e)
|
||||||
|
{
|
||||||
|
Toast.makeText(this, getResources().getString(R.string.noMapsApplicationFound), Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void hideKeyboard()
|
||||||
|
{
|
||||||
|
View view = this.getCurrentFocus();
|
||||||
|
if (view != null)
|
||||||
|
{
|
||||||
|
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||||
|
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,487 @@
|
|||||||
|
package com.jens.automation2;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.ProgressDialog;
|
||||||
|
import android.content.ActivityNotFoundException;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.media.AudioManager;
|
||||||
|
import android.media.RingtoneManager;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.provider.MediaStore;
|
||||||
|
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.CompoundButton.OnCheckedChangeListener;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.SeekBar;
|
||||||
|
import android.widget.Spinner;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.annotation.RequiresApi;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
public class ActivityManageSpecificProfile extends Activity
|
||||||
|
{
|
||||||
|
private static ProgressDialog progressDialog;
|
||||||
|
final static int intentCodeRingtonePickerCallsFile = 9010;
|
||||||
|
final static int intentCodeRingtonePickerCallsRingtone = 9011;
|
||||||
|
final static int intentCodeRingtonePickerNotificationsFile = 9020;
|
||||||
|
final static int intentCodeRingtonePickerNotificationsRingtone = 9021;
|
||||||
|
|
||||||
|
CheckBox checkBoxChangeSoundMode, checkBoxChangeVolumeMusicVideoGameMedia, checkBoxChangeVolumeNotifications, checkBoxChangeVolumeAlarms, checkBoxChangeIncomingCallsRingtone, checkBoxChangeNotificationRingtone, checkBoxChangeAudibleSelection, checkBoxChangeScreenLockUnlockSound, checkBoxChangeHapticFeedback, checkBoxChangeVibrateWhenRinging, checkBoxVibrateWhenRinging, checkBoxAudibleSelection, checkBoxScreenLockUnlockSound, checkBoxHapticFeedback;
|
||||||
|
Spinner spinnerSoundMode;
|
||||||
|
SeekBar seekBarVolumeMusic, seekBarVolumeNotifications, seekBarVolumeAlarms;
|
||||||
|
Button bChangeSoundIncomingCalls, bChangeSoundNotifications, bSaveProfile;
|
||||||
|
TextView tvIncomingCallsRingtone, tvNotificationsRingtone;
|
||||||
|
EditText etName;
|
||||||
|
|
||||||
|
File incomingCallsRingtone = null, notificationsRingtone = null;
|
||||||
|
|
||||||
|
ArrayAdapter<String> soundModeAdapter;
|
||||||
|
|
||||||
|
public void setIncomingCallsRingtone(File incomingCallsRingtone)
|
||||||
|
{
|
||||||
|
this.incomingCallsRingtone = incomingCallsRingtone;
|
||||||
|
|
||||||
|
if(incomingCallsRingtone != null)
|
||||||
|
tvIncomingCallsRingtone.setText(this.incomingCallsRingtone.getAbsolutePath());
|
||||||
|
else
|
||||||
|
tvIncomingCallsRingtone.setText(getResources().getString(R.string.none));
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getIncomingCallsRingtone()
|
||||||
|
{
|
||||||
|
return incomingCallsRingtone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNotificationsRingtone(File notificationsRingtone)
|
||||||
|
{
|
||||||
|
this.notificationsRingtone = notificationsRingtone;
|
||||||
|
|
||||||
|
if(this.notificationsRingtone != null)
|
||||||
|
tvNotificationsRingtone.setText(this.notificationsRingtone.getAbsolutePath());
|
||||||
|
else
|
||||||
|
tvNotificationsRingtone.setText(getResources().getString(R.string.none));
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getNotificationsRingtone()
|
||||||
|
{
|
||||||
|
return notificationsRingtone;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState)
|
||||||
|
{
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
this.setContentView(R.layout.manage_specific_profile);
|
||||||
|
|
||||||
|
checkBoxChangeSoundMode = (CheckBox)findViewById(R.id.checkBoxChangeSoundMode);
|
||||||
|
checkBoxChangeVolumeMusicVideoGameMedia = (CheckBox)findViewById(R.id.checkBoxChangeVolumeMusicVideoGameMedia);
|
||||||
|
checkBoxChangeVolumeNotifications = (CheckBox)findViewById(R.id.checkBoxChangeVolumeNotifications);
|
||||||
|
checkBoxChangeVolumeAlarms = (CheckBox)findViewById(R.id.checkBoxChangeVolumeAlarms);
|
||||||
|
checkBoxChangeIncomingCallsRingtone = (CheckBox)findViewById(R.id.checkBoxChangeIncomingCallsRingtone);
|
||||||
|
checkBoxChangeNotificationRingtone = (CheckBox)findViewById(R.id.checkBoxChangeNotificationRingtone);
|
||||||
|
checkBoxChangeAudibleSelection = (CheckBox)findViewById(R.id.checkBoxChangeAudibleSelection);
|
||||||
|
checkBoxChangeScreenLockUnlockSound = (CheckBox)findViewById(R.id.checkBoxChangeScreenLockUnlockSound);
|
||||||
|
checkBoxChangeHapticFeedback = (CheckBox)findViewById(R.id.checkBoxChangeHapticFeedback);
|
||||||
|
checkBoxChangeVibrateWhenRinging = (CheckBox)findViewById(R.id.checkBoxChangeVibrateWhenRinging);
|
||||||
|
checkBoxAudibleSelection = (CheckBox)findViewById(R.id.checkBoxAudibleSelection);
|
||||||
|
checkBoxScreenLockUnlockSound = (CheckBox)findViewById(R.id.checkBoxScreenLockUnlockSound);
|
||||||
|
checkBoxHapticFeedback = (CheckBox)findViewById(R.id.checkBoxHapticFeedback);
|
||||||
|
checkBoxVibrateWhenRinging = (CheckBox)findViewById(R.id.checkBoxVibrateWhenRinging);
|
||||||
|
spinnerSoundMode = (Spinner)findViewById(R.id.spinnerSoundMode);
|
||||||
|
seekBarVolumeMusic = (SeekBar)findViewById(R.id.seekBarVolumeMusic);
|
||||||
|
seekBarVolumeNotifications = (SeekBar)findViewById(R.id.seekBarVolumeNotifications);
|
||||||
|
seekBarVolumeAlarms = (SeekBar)findViewById(R.id.seekBarVolumeAlarms);
|
||||||
|
bChangeSoundIncomingCalls = (Button)findViewById(R.id.bChangeSoundIncomingCalls);
|
||||||
|
bChangeSoundNotifications = (Button)findViewById(R.id.bChangeSoundNotifications);
|
||||||
|
tvIncomingCallsRingtone = (TextView)findViewById(R.id.tvIncomingCallsRingtone);
|
||||||
|
tvNotificationsRingtone = (TextView)findViewById(R.id.tvNotificationsRingtone);
|
||||||
|
bSaveProfile = (Button)findViewById(R.id.bSaveProfile);
|
||||||
|
etName = (EditText)findViewById(R.id.etName);
|
||||||
|
|
||||||
|
checkBoxVibrateWhenRinging.setEnabled(false);
|
||||||
|
checkBoxAudibleSelection.setEnabled(false);
|
||||||
|
checkBoxScreenLockUnlockSound.setEnabled(false);
|
||||||
|
checkBoxHapticFeedback.setEnabled(false);
|
||||||
|
spinnerSoundMode.setEnabled(false);
|
||||||
|
seekBarVolumeMusic.setEnabled(false);
|
||||||
|
seekBarVolumeNotifications.setEnabled(false);
|
||||||
|
seekBarVolumeAlarms.setEnabled(false);
|
||||||
|
bChangeSoundIncomingCalls.setEnabled(false);
|
||||||
|
bChangeSoundNotifications.setEnabled(false);
|
||||||
|
|
||||||
|
spinnerSoundMode.setSelection(0);
|
||||||
|
|
||||||
|
// Scale SeekBars to the system's maximum volume values
|
||||||
|
AudioManager am = (AudioManager) Miscellaneous.getAnyContext().getSystemService(Context.AUDIO_SERVICE);
|
||||||
|
seekBarVolumeMusic.setMax(am.getStreamMaxVolume(AudioManager.STREAM_MUSIC));
|
||||||
|
seekBarVolumeNotifications.setMax(am.getStreamMaxVolume(AudioManager.STREAM_NOTIFICATION));
|
||||||
|
seekBarVolumeAlarms.setMax(am.getStreamMaxVolume(AudioManager.STREAM_ALARM));
|
||||||
|
|
||||||
|
soundModeAdapter = new ArrayAdapter<String>(this, R.layout.text_view_for_poi_listview_mediumtextsize, new String[] { getResources().getString(R.string.soundModeSilent), getResources().getString(R.string.soundModeVibrate), getResources().getString(R.string.soundModeNormal) });
|
||||||
|
spinnerSoundMode.setAdapter(soundModeAdapter);
|
||||||
|
|
||||||
|
checkBoxChangeSoundMode.setOnCheckedChangeListener(new OnCheckedChangeListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
|
||||||
|
{
|
||||||
|
spinnerSoundMode.setEnabled(isChecked);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
checkBoxChangeVolumeMusicVideoGameMedia.setOnCheckedChangeListener(new OnCheckedChangeListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
|
||||||
|
{
|
||||||
|
seekBarVolumeMusic.setEnabled(isChecked);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
checkBoxChangeVolumeNotifications.setOnCheckedChangeListener(new OnCheckedChangeListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
|
||||||
|
{
|
||||||
|
seekBarVolumeNotifications.setEnabled(isChecked);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
checkBoxChangeVolumeAlarms.setOnCheckedChangeListener(new OnCheckedChangeListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
|
||||||
|
{
|
||||||
|
seekBarVolumeAlarms.setEnabled(isChecked);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
checkBoxChangeIncomingCallsRingtone.setOnCheckedChangeListener(new OnCheckedChangeListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
|
||||||
|
{
|
||||||
|
bChangeSoundIncomingCalls.setEnabled(isChecked);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
checkBoxChangeNotificationRingtone.setOnCheckedChangeListener(new OnCheckedChangeListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
|
||||||
|
{
|
||||||
|
bChangeSoundNotifications.setEnabled(isChecked);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
checkBoxChangeAudibleSelection.setOnCheckedChangeListener(new OnCheckedChangeListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
|
||||||
|
{
|
||||||
|
checkBoxAudibleSelection.setEnabled(isChecked);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
checkBoxChangeScreenLockUnlockSound.setOnCheckedChangeListener(new OnCheckedChangeListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
|
||||||
|
{
|
||||||
|
checkBoxScreenLockUnlockSound.setEnabled(isChecked);
|
||||||
|
|
||||||
|
if(isChecked && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
|
||||||
|
Miscellaneous.messageBox("Info", getResources().getString(R.string.screenLockSoundNotice), ActivityManageSpecificProfile.this).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
checkBoxChangeHapticFeedback.setOnCheckedChangeListener(new OnCheckedChangeListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
|
||||||
|
{
|
||||||
|
checkBoxHapticFeedback.setEnabled(isChecked);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
checkBoxChangeVibrateWhenRinging.setOnCheckedChangeListener(new OnCheckedChangeListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
|
||||||
|
{
|
||||||
|
checkBoxVibrateWhenRinging.setEnabled(isChecked);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
bSaveProfile.setOnClickListener(new OnClickListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onClick(View v)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(ActivityMainProfiles.profileToEdit == null)
|
||||||
|
createProfile(ActivityManageSpecificProfile.this);
|
||||||
|
else
|
||||||
|
changeProfile();
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
Toast.makeText(ActivityManageSpecificProfile.this, getResources().getString(R.string.errorWritingFile) + " " + ex.getMessage(), Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
bChangeSoundIncomingCalls.setOnClickListener(new OnClickListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onClick(View v)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Intent fileIntent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||||
|
fileIntent.setType("audio/*");
|
||||||
|
startActivityForResult(Intent.createChooser(fileIntent, "Select a ringtone"), intentCodeRingtonePickerCallsFile);
|
||||||
|
}
|
||||||
|
catch(ActivityNotFoundException e)
|
||||||
|
{
|
||||||
|
// Use media browser instead
|
||||||
|
Intent fileSelectionIntent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
|
||||||
|
|
||||||
|
if(ActivityMainProfiles.profileToEdit != null)
|
||||||
|
{
|
||||||
|
Uri currenturi = Uri.parse(ActivityMainProfiles.profileToEdit.incomingCallsRingtone.getAbsolutePath());
|
||||||
|
if(ActivityMainProfiles.profileToEdit.changeIncomingCallsRingtone)
|
||||||
|
fileSelectionIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, currenturi);
|
||||||
|
}
|
||||||
|
|
||||||
|
startActivityForResult(fileSelectionIntent, intentCodeRingtonePickerCallsRingtone);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
bChangeSoundNotifications.setOnClickListener(new OnClickListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onClick(View v)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Intent fileIntent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||||
|
fileIntent.setType("audio/*");
|
||||||
|
startActivityForResult(Intent.createChooser(fileIntent, "Select a ringtone"), intentCodeRingtonePickerNotificationsFile);
|
||||||
|
}
|
||||||
|
catch(ActivityNotFoundException e)
|
||||||
|
{
|
||||||
|
// Use media browser instead
|
||||||
|
Intent fileSelectionIntent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
|
||||||
|
|
||||||
|
if(ActivityMainProfiles.profileToEdit != null)
|
||||||
|
{
|
||||||
|
Uri currenturi = Uri.parse(ActivityMainProfiles.profileToEdit.notificationRingtone.getAbsolutePath());
|
||||||
|
if(ActivityMainProfiles.profileToEdit.changeNotificationRingtone)
|
||||||
|
fileSelectionIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, currenturi);
|
||||||
|
}
|
||||||
|
|
||||||
|
startActivityForResult(fileSelectionIntent, intentCodeRingtonePickerNotificationsRingtone);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if(ActivityMainProfiles.profileToEdit != null)
|
||||||
|
editProfile(ActivityMainProfiles.profileToEdit);
|
||||||
|
//else
|
||||||
|
// new Profile to be created
|
||||||
|
|
||||||
|
// Toast.makeText(this, getResources().getString(R.string.someOptionsNotAvailableYet), Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createProfile(Context context)
|
||||||
|
{
|
||||||
|
if(plausibilityCheck())
|
||||||
|
{
|
||||||
|
if(loadFormValuesToVariable())
|
||||||
|
if(ActivityMainProfiles.profileToEdit.create(context, true))
|
||||||
|
{
|
||||||
|
this.setResult(RESULT_OK);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void changeProfile()
|
||||||
|
{
|
||||||
|
if(plausibilityCheck())
|
||||||
|
{
|
||||||
|
loadFormValuesToVariable();
|
||||||
|
|
||||||
|
if(ActivityMainProfiles.profileToEdit.change(this))
|
||||||
|
{
|
||||||
|
this.setResult(RESULT_OK);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void editProfile(Profile profileToEdit)
|
||||||
|
{
|
||||||
|
etName.setText(ActivityMainProfiles.profileToEdit.getName());
|
||||||
|
checkBoxChangeSoundMode.setChecked(ActivityMainProfiles.profileToEdit.getChangeSoundMode());
|
||||||
|
checkBoxChangeVolumeMusicVideoGameMedia.setChecked(ActivityMainProfiles.profileToEdit.getChangeVolumeMusicVideoGameMedia());
|
||||||
|
checkBoxChangeVolumeNotifications.setChecked(ActivityMainProfiles.profileToEdit.getChangeVolumeNotifications());
|
||||||
|
checkBoxChangeVolumeAlarms.setChecked(ActivityMainProfiles.profileToEdit.getChangeVolumeAlarms());
|
||||||
|
checkBoxChangeIncomingCallsRingtone.setChecked(ActivityMainProfiles.profileToEdit.getChangeIncomingCallsRingtone());
|
||||||
|
checkBoxChangeNotificationRingtone.setChecked(ActivityMainProfiles.profileToEdit.getChangeNotificationRingtone());
|
||||||
|
checkBoxChangeAudibleSelection.setChecked(ActivityMainProfiles.profileToEdit.getChangeAudibleSelection());
|
||||||
|
checkBoxChangeScreenLockUnlockSound.setChecked(ActivityMainProfiles.profileToEdit.getChangeScreenLockUnlockSound());
|
||||||
|
checkBoxChangeHapticFeedback.setChecked(ActivityMainProfiles.profileToEdit.getChangeHapticFeedback());
|
||||||
|
checkBoxChangeVibrateWhenRinging.setChecked(ActivityMainProfiles.profileToEdit.getChangeVibrateWhenRinging());
|
||||||
|
|
||||||
|
spinnerSoundMode.setSelection(ActivityMainProfiles.profileToEdit.getSoundMode());
|
||||||
|
seekBarVolumeMusic.setProgress(ActivityMainProfiles.profileToEdit.getVolumeMusic());
|
||||||
|
seekBarVolumeNotifications.setProgress(ActivityMainProfiles.profileToEdit.getVolumeNotifications());
|
||||||
|
seekBarVolumeAlarms.setProgress(ActivityMainProfiles.profileToEdit.getVolumeAlarms());
|
||||||
|
checkBoxAudibleSelection.setChecked(ActivityMainProfiles.profileToEdit.audibleSelection);
|
||||||
|
checkBoxScreenLockUnlockSound.setChecked(ActivityMainProfiles.profileToEdit.screenLockUnlockSound);
|
||||||
|
checkBoxHapticFeedback.setChecked(ActivityMainProfiles.profileToEdit.hapticFeedback);
|
||||||
|
checkBoxVibrateWhenRinging.setChecked(ActivityMainProfiles.profileToEdit.vibrateWhenRinging);
|
||||||
|
|
||||||
|
setIncomingCallsRingtone(ActivityMainProfiles.profileToEdit.getIncomingCallsRingtone());
|
||||||
|
setNotificationsRingtone(ActivityMainProfiles.profileToEdit.getNotificationRingtone());
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean loadFormValuesToVariable()
|
||||||
|
{
|
||||||
|
if(plausibilityCheck())
|
||||||
|
{
|
||||||
|
if(ActivityMainProfiles.profileToEdit == null)
|
||||||
|
ActivityMainProfiles.profileToEdit = new Profile();
|
||||||
|
|
||||||
|
ActivityMainProfiles.profileToEdit.setName(etName.getText().toString());
|
||||||
|
ActivityMainProfiles.profileToEdit.setChangeSoundMode(checkBoxChangeSoundMode.isChecked());
|
||||||
|
ActivityMainProfiles.profileToEdit.setChangeVolumeMusicVideoGameMedia(checkBoxChangeVolumeMusicVideoGameMedia.isChecked());
|
||||||
|
ActivityMainProfiles.profileToEdit.setChangeVolumeNotifications(checkBoxChangeVolumeNotifications.isChecked());
|
||||||
|
ActivityMainProfiles.profileToEdit.setChangeVolumeAlarms(checkBoxChangeVolumeAlarms.isChecked());
|
||||||
|
ActivityMainProfiles.profileToEdit.setChangeIncomingCallsRingtone(checkBoxChangeIncomingCallsRingtone.isChecked());
|
||||||
|
ActivityMainProfiles.profileToEdit.setChangeNotificationRingtone(checkBoxChangeNotificationRingtone.isChecked());
|
||||||
|
ActivityMainProfiles.profileToEdit.setChangeAudibleSelection(checkBoxChangeAudibleSelection.isChecked());
|
||||||
|
ActivityMainProfiles.profileToEdit.setChangeScreenLockUnlockSound(checkBoxChangeScreenLockUnlockSound.isChecked());
|
||||||
|
ActivityMainProfiles.profileToEdit.setChangeHapticFeedback(checkBoxChangeHapticFeedback.isChecked());
|
||||||
|
ActivityMainProfiles.profileToEdit.setChangeVibrateWhenRinging(checkBoxChangeVibrateWhenRinging.isChecked());
|
||||||
|
|
||||||
|
ActivityMainProfiles.profileToEdit.setAudibleSelection(checkBoxAudibleSelection.isChecked());
|
||||||
|
ActivityMainProfiles.profileToEdit.setScreenLockUnlockSound(checkBoxScreenLockUnlockSound.isChecked());
|
||||||
|
ActivityMainProfiles.profileToEdit.setHapticFeedback(checkBoxHapticFeedback.isChecked());
|
||||||
|
ActivityMainProfiles.profileToEdit.setVibrateWhenRinging(checkBoxVibrateWhenRinging.isChecked());
|
||||||
|
ActivityMainProfiles.profileToEdit.setSoundMode(spinnerSoundMode.getSelectedItemPosition());
|
||||||
|
ActivityMainProfiles.profileToEdit.setVolumeMusic(seekBarVolumeMusic.getProgress());
|
||||||
|
ActivityMainProfiles.profileToEdit.setVolumeNotifications(seekBarVolumeNotifications.getProgress());
|
||||||
|
ActivityMainProfiles.profileToEdit.setVolumeAlarms(seekBarVolumeAlarms.getProgress());
|
||||||
|
ActivityMainProfiles.profileToEdit.setIncomingCallsRingtone(incomingCallsRingtone);
|
||||||
|
ActivityMainProfiles.profileToEdit.setNotificationRingtone(notificationsRingtone);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean plausibilityCheck()
|
||||||
|
{
|
||||||
|
if(etName.getText().toString().length() > 0)
|
||||||
|
{
|
||||||
|
// Check for duplicates
|
||||||
|
// for(Profile.)
|
||||||
|
// if(etName.getText().toString()
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Toast.makeText(this, getResources().getString(R.string.enterAname), Toast.LENGTH_LONG).show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!checkBoxChangeSoundMode.isChecked()
|
||||||
|
&
|
||||||
|
!checkBoxChangeVolumeMusicVideoGameMedia.isChecked()
|
||||||
|
&
|
||||||
|
!checkBoxChangeVolumeNotifications.isChecked()
|
||||||
|
&
|
||||||
|
!checkBoxChangeVolumeAlarms.isChecked()
|
||||||
|
&
|
||||||
|
!checkBoxChangeIncomingCallsRingtone.isChecked()
|
||||||
|
&
|
||||||
|
!checkBoxChangeNotificationRingtone.isChecked()
|
||||||
|
&
|
||||||
|
!checkBoxChangeAudibleSelection.isChecked()
|
||||||
|
&
|
||||||
|
!checkBoxChangeScreenLockUnlockSound.isChecked()
|
||||||
|
&
|
||||||
|
!checkBoxChangeHapticFeedback.isChecked()
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Toast.makeText(this, getResources().getString(R.string.noChangeSelectedProfileDoesntMakeSense), Toast.LENGTH_LONG).show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
||||||
|
@Override
|
||||||
|
protected void onActivityResult(int requestCode, int resultCode, Intent data)
|
||||||
|
{
|
||||||
|
if(resultCode == RESULT_OK)
|
||||||
|
{
|
||||||
|
switch (requestCode)
|
||||||
|
{
|
||||||
|
case intentCodeRingtonePickerCallsRingtone: // incoming calls
|
||||||
|
{
|
||||||
|
// Method for ringtone selection
|
||||||
|
Uri uri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
|
||||||
|
if (uri != null)
|
||||||
|
{
|
||||||
|
String ringTonePath = CompensateCrappyAndroidPaths.getPath(ActivityManageSpecificProfile.this, uri);
|
||||||
|
setIncomingCallsRingtone(new File(ringTonePath));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case intentCodeRingtonePickerCallsFile:
|
||||||
|
{
|
||||||
|
String ringTonePath = CompensateCrappyAndroidPaths.getPath(ActivityManageSpecificProfile.this, data.getData());
|
||||||
|
setIncomingCallsRingtone(new File(ringTonePath));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case intentCodeRingtonePickerNotificationsRingtone: // notifications
|
||||||
|
{
|
||||||
|
Uri uri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
|
||||||
|
if (uri != null)
|
||||||
|
{
|
||||||
|
String ringTonePath = CompensateCrappyAndroidPaths.getPath(ActivityManageSpecificProfile.this, data.getData());
|
||||||
|
setNotificationsRingtone(new File(ringTonePath));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case intentCodeRingtonePickerNotificationsFile:
|
||||||
|
{
|
||||||
|
String ringTonePath = CompensateCrappyAndroidPaths.getPath(ActivityManageSpecificProfile.this, data.getData());
|
||||||
|
setNotificationsRingtone(new File(ringTonePath));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRealPathFromURI(Uri uri)
|
||||||
|
{
|
||||||
|
String[] projection = { MediaStore.Images.Media.DATA };
|
||||||
|
Cursor cursor = getContentResolver().query(uri, projection, null, null, null);
|
||||||
|
if (cursor == null) return null;
|
||||||
|
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
|
||||||
|
cursor.moveToFirst();
|
||||||
|
String s=cursor.getString(column_index);
|
||||||
|
cursor.close();
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,500 @@
|
|||||||
|
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.text.InputType;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.View.OnClickListener;
|
||||||
|
import android.view.View.OnTouchListener;
|
||||||
|
import android.widget.AdapterView;
|
||||||
|
import android.widget.AdapterView.OnItemLongClickListener;
|
||||||
|
import android.widget.AdapterView.OnItemSelectedListener;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.ListView;
|
||||||
|
import android.widget.Spinner;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.jens.automation2.Action.Action_Enum;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ActivityManageStartActivity extends Activity
|
||||||
|
{
|
||||||
|
ListView lvIntentPairs;
|
||||||
|
EditText etParameterName, etParameterValue;
|
||||||
|
Button bSelectApp, bAddIntentPair, bSaveActionStartOtherActivity;
|
||||||
|
Spinner spinnerParameterType;
|
||||||
|
TextView tvSelectedActivity;
|
||||||
|
boolean edit = false;
|
||||||
|
ProgressDialog progressDialog = null;
|
||||||
|
|
||||||
|
private class CustomPackageInfo extends PackageInfo implements Comparable<CustomPackageInfo>
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public int compareTo(CustomPackageInfo another)
|
||||||
|
{
|
||||||
|
String name1 = "";
|
||||||
|
String name2 = "";
|
||||||
|
|
||||||
|
ApplicationInfo aInfo1 = this.applicationInfo;
|
||||||
|
if (aInfo1 != null)
|
||||||
|
{
|
||||||
|
name1 = (String) ActivityManageStartActivity.this.getPackageManager().getApplicationLabel(aInfo1);
|
||||||
|
}
|
||||||
|
ApplicationInfo aInfo2 = another.applicationInfo;
|
||||||
|
if (aInfo2 != null)
|
||||||
|
{
|
||||||
|
name2 = (String) ActivityManageStartActivity.this.getPackageManager().getApplicationLabel(aInfo2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return name1.compareTo(name2);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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 ArrayList<String> intentPairList = new ArrayList<String>();
|
||||||
|
|
||||||
|
ArrayAdapter<String> intentTypeSpinnerAdapter, intentPairAdapter;
|
||||||
|
|
||||||
|
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 = ActivityManageStartActivity.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 = ActivityManageStartActivity.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();
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
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[] = ActivityManageStartActivity.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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
AlertDialog alertDialog = alertDialogBuilder.create();
|
||||||
|
|
||||||
|
return alertDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState)
|
||||||
|
{
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.action_start_activity);
|
||||||
|
|
||||||
|
lvIntentPairs = (ListView)findViewById(R.id.lvIntentPairs);
|
||||||
|
etParameterName = (EditText)findViewById(R.id.etParameterName);
|
||||||
|
etParameterValue = (EditText)findViewById(R.id.etParameterValue);
|
||||||
|
bSelectApp = (Button)findViewById(R.id.bSelectApp);
|
||||||
|
bAddIntentPair = (Button)findViewById(R.id.bAddIntentPair);
|
||||||
|
bSaveActionStartOtherActivity = (Button)findViewById(R.id.bSaveActionStartOtherActivity);
|
||||||
|
spinnerParameterType = (Spinner)findViewById(R.id.spinnerParameterType);
|
||||||
|
tvSelectedActivity = (TextView)findViewById(R.id.tvSelectedActivity);
|
||||||
|
|
||||||
|
intentTypeSpinnerAdapter = new ArrayAdapter<String>(this, R.layout.text_view_for_poi_listview_mediumtextsize, ActivityManageStartActivity.supportedIntentTypes);
|
||||||
|
spinnerParameterType.setAdapter(intentTypeSpinnerAdapter);
|
||||||
|
intentTypeSpinnerAdapter.notifyDataSetChanged();
|
||||||
|
|
||||||
|
intentPairAdapter = new ArrayAdapter<String>(this, R.layout.text_view_for_poi_listview_smalltextsize, intentPairList);
|
||||||
|
|
||||||
|
bSelectApp.setOnClickListener(new OnClickListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onClick(View v)
|
||||||
|
{
|
||||||
|
GetActivityListTask getActivityListTask = new GetActivityListTask();
|
||||||
|
getActivityListTask.execute();
|
||||||
|
progressDialog = ProgressDialog.show(ActivityManageStartActivity.this, "", ActivityManageStartActivity.this.getResources().getString(R.string.gettingListOfInstalledApplications));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
bAddIntentPair.setOnClickListener(new OnClickListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onClick(View v)
|
||||||
|
{
|
||||||
|
// type;name;value
|
||||||
|
if(spinnerParameterType.getSelectedItem().toString().length() == 0)
|
||||||
|
{
|
||||||
|
Toast.makeText(ActivityManageStartActivity.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();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(etParameterValue.getText().toString().length() == 0)
|
||||||
|
{
|
||||||
|
Toast.makeText(ActivityManageStartActivity.this, getResources().getString(R.string.enterValueForIntentPair), Toast.LENGTH_LONG).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String param = supportedIntentTypes[spinnerParameterType.getSelectedItemPosition()] + "/" + etParameterName.getText().toString() + "/" + etParameterValue.getText().toString();
|
||||||
|
intentPairList.add(param);
|
||||||
|
|
||||||
|
spinnerParameterType.setSelection(0);
|
||||||
|
etParameterName.setText("");
|
||||||
|
etParameterValue.setText("");
|
||||||
|
|
||||||
|
updateIntentPairList();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
lvIntentPairs.setOnItemLongClickListener(new OnItemLongClickListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int arg2, long arg3)
|
||||||
|
{
|
||||||
|
getIntentPairDialog(arg2).show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
bSaveActionStartOtherActivity.setOnClickListener(new OnClickListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onClick(View v)
|
||||||
|
{
|
||||||
|
if(saveAction())
|
||||||
|
{
|
||||||
|
ActivityManageStartActivity.this.setResult(RESULT_OK);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
lvIntentPairs.setOnTouchListener(new OnTouchListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public boolean onTouch(View v, MotionEvent event)
|
||||||
|
{
|
||||||
|
v.getParent().requestDisallowInterceptTouchEvent(true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
spinnerParameterType.setOnItemSelectedListener(new OnItemSelectedListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
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);
|
||||||
|
else
|
||||||
|
ActivityManageStartActivity.this.etParameterValue.setInputType(InputType.TYPE_CLASS_TEXT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNothingSelected(AdapterView<?> arg0)
|
||||||
|
{
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Intent i = getIntent();
|
||||||
|
if(i.getBooleanExtra("edit", false) == true)
|
||||||
|
{
|
||||||
|
edit = true;
|
||||||
|
loadValuesIntoGui();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadValuesIntoGui()
|
||||||
|
{
|
||||||
|
String[] params = resultingAction.getParameter2().split(";");
|
||||||
|
if(params.length >= 2)
|
||||||
|
{
|
||||||
|
tvSelectedActivity.setText(params[0] + ";" + params[1]);
|
||||||
|
|
||||||
|
if(params.length > 2)
|
||||||
|
{
|
||||||
|
intentPairList.clear();
|
||||||
|
|
||||||
|
for(int i=2; i<params.length; i++)
|
||||||
|
{
|
||||||
|
intentPairList.add(params[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateIntentPairList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateIntentPairList()
|
||||||
|
{
|
||||||
|
if(lvIntentPairs.getAdapter() == null)
|
||||||
|
lvIntentPairs.setAdapter(intentPairAdapter);
|
||||||
|
|
||||||
|
intentPairAdapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean saveAction()
|
||||||
|
{
|
||||||
|
if(tvSelectedActivity.getText().toString().length() == 0)
|
||||||
|
{
|
||||||
|
Toast.makeText(ActivityManageStartActivity.this, getResources().getString(R.string.selectApplication), Toast.LENGTH_LONG).show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(tvSelectedActivity.getText().toString().equals(getResources().getString(R.string.selectApplication)))
|
||||||
|
{
|
||||||
|
Toast.makeText(this, getResources().getString(R.string.selectApplication), Toast.LENGTH_LONG).show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(resultingAction == null)
|
||||||
|
resultingAction = new Action();
|
||||||
|
|
||||||
|
resultingAction.setAction(Action_Enum.startOtherActivity);
|
||||||
|
|
||||||
|
String parameter2 = tvSelectedActivity.getText().toString();
|
||||||
|
for(String s : intentPairList)
|
||||||
|
parameter2 += ";" + s;
|
||||||
|
|
||||||
|
resultingAction.setParameter2(parameter2);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private AlertDialog getIntentPairDialog(final int itemPosition)
|
||||||
|
{
|
||||||
|
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(ActivityManageStartActivity.this);
|
||||||
|
alertDialogBuilder.setTitle(getResources().getString(R.string.whatToDoWithIntentPair));
|
||||||
|
alertDialogBuilder.setItems(new String[]{getResources().getString(R.string.delete)}, new DialogInterface.OnClickListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which)
|
||||||
|
{
|
||||||
|
// Only 1 choice at the moment, no need to check
|
||||||
|
ActivityManageStartActivity.this.intentPairList.remove(itemPosition);
|
||||||
|
updateIntentPairList();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
AlertDialog alertDialog = alertDialogBuilder.create();
|
||||||
|
|
||||||
|
return alertDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class GetActivityListTask extends AsyncTask<Void, Void, Void>
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
protected Void doInBackground(Void... params)
|
||||||
|
{
|
||||||
|
getActivityList(ActivityManageStartActivity.this);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Void result)
|
||||||
|
{
|
||||||
|
progressDialog.dismiss();
|
||||||
|
getActionStartActivityDialog1().show();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,163 @@
|
|||||||
|
package com.jens.automation2;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.View.OnClickListener;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.CheckBox;
|
||||||
|
import android.widget.RadioButton;
|
||||||
|
import android.widget.TimePicker;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import java.sql.Time;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Calendar;
|
||||||
|
|
||||||
|
public class ActivityManageTimeFrame extends Activity
|
||||||
|
{
|
||||||
|
Button bSaveTimeFrame;
|
||||||
|
TimePicker startPicker, stopPicker;
|
||||||
|
CheckBox checkMonday, checkTuesday, checkWednesday, checkThursday, checkFriday, checkSaturday, checkSunday;
|
||||||
|
RadioButton radioTimeFrameEntering, radioTimeFrameLeaving;
|
||||||
|
|
||||||
|
public static Trigger editedTimeFrameTrigger = null;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState)
|
||||||
|
{
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.trigger_timeframe_editor);
|
||||||
|
|
||||||
|
startPicker = (TimePicker)findViewById(R.id.tpTimeFrameStart);
|
||||||
|
stopPicker = (TimePicker)findViewById(R.id.tpTimeFrameStop);
|
||||||
|
startPicker.setIs24HourView(true);
|
||||||
|
stopPicker.setIs24HourView(true);
|
||||||
|
|
||||||
|
bSaveTimeFrame = (Button)findViewById(R.id.bSaveTimeFrame);
|
||||||
|
checkMonday = (CheckBox)findViewById(R.id.checkMonday);
|
||||||
|
checkTuesday = (CheckBox)findViewById(R.id.checkTuesday);
|
||||||
|
checkWednesday = (CheckBox)findViewById(R.id.checkWednesday);
|
||||||
|
checkThursday = (CheckBox)findViewById(R.id.checkThursday);
|
||||||
|
checkFriday = (CheckBox)findViewById(R.id.checkFriday);
|
||||||
|
checkSaturday = (CheckBox)findViewById(R.id.checkSaturday);
|
||||||
|
checkSunday = (CheckBox)findViewById(R.id.checkSunday);
|
||||||
|
radioTimeFrameEntering = (RadioButton)findViewById(R.id.radioTimeFrameEntering);
|
||||||
|
radioTimeFrameLeaving = (RadioButton)findViewById(R.id.radioTimeFrameLeaving);
|
||||||
|
|
||||||
|
bSaveTimeFrame.setOnClickListener(new OnClickListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onClick(View v)
|
||||||
|
{
|
||||||
|
Time startTime = new Time(0);
|
||||||
|
startTime.setHours(startPicker.getCurrentHour());
|
||||||
|
startTime.setMinutes(startPicker.getCurrentMinute());
|
||||||
|
|
||||||
|
Time stopTime = new Time(0);
|
||||||
|
stopTime.setHours(stopPicker.getCurrentHour());
|
||||||
|
stopTime.setMinutes(stopPicker.getCurrentMinute());
|
||||||
|
|
||||||
|
ArrayList<Integer> dayList = new ArrayList<Integer>();
|
||||||
|
if(checkMonday.isChecked())
|
||||||
|
dayList.add(Calendar.MONDAY);
|
||||||
|
if(checkTuesday.isChecked())
|
||||||
|
dayList.add(Calendar.TUESDAY);
|
||||||
|
if(checkWednesday.isChecked())
|
||||||
|
dayList.add(Calendar.WEDNESDAY);
|
||||||
|
if(checkThursday.isChecked())
|
||||||
|
dayList.add(Calendar.THURSDAY);
|
||||||
|
if(checkFriday.isChecked())
|
||||||
|
dayList.add(Calendar.FRIDAY);
|
||||||
|
if(checkSaturday.isChecked())
|
||||||
|
dayList.add(Calendar.SATURDAY);
|
||||||
|
if(checkSunday.isChecked())
|
||||||
|
dayList.add(Calendar.SUNDAY);
|
||||||
|
|
||||||
|
if(
|
||||||
|
!checkMonday.isChecked()
|
||||||
|
&&
|
||||||
|
!checkTuesday.isChecked()
|
||||||
|
&&
|
||||||
|
!checkWednesday.isChecked()
|
||||||
|
&&
|
||||||
|
!checkThursday.isChecked()
|
||||||
|
&&
|
||||||
|
!checkFriday.isChecked()
|
||||||
|
&&
|
||||||
|
!checkSaturday.isChecked()
|
||||||
|
&&
|
||||||
|
!checkSunday.isChecked()
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Toast.makeText(getBaseContext(), getResources().getString(R.string.selectOneDay), Toast.LENGTH_LONG).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(editedTimeFrameTrigger.getTimeFrame() == null)
|
||||||
|
// add new one
|
||||||
|
editedTimeFrameTrigger.setTimeFrame(new TimeFrame(startTime, stopTime, dayList));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// edit one
|
||||||
|
editedTimeFrameTrigger.getTimeFrame().setTriggerTimeStart(startTime);
|
||||||
|
editedTimeFrameTrigger.getTimeFrame().setTriggerTimeStop(stopTime);
|
||||||
|
editedTimeFrameTrigger.getTimeFrame().getDayList().clear();
|
||||||
|
editedTimeFrameTrigger.getTimeFrame().setDayList(dayList);
|
||||||
|
}
|
||||||
|
|
||||||
|
editedTimeFrameTrigger.setTriggerParameter(radioTimeFrameEntering.isChecked());
|
||||||
|
|
||||||
|
setResult(RESULT_OK);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if(editedTimeFrameTrigger.getTimeFrame() != null)
|
||||||
|
loadVariableIntoGui();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadVariableIntoGui()
|
||||||
|
{
|
||||||
|
startPicker.setCurrentHour(editedTimeFrameTrigger.getTimeFrame().getTriggerTimeStart().getHours());
|
||||||
|
startPicker.setCurrentMinute(editedTimeFrameTrigger.getTimeFrame().getTriggerTimeStart().getMinutes());
|
||||||
|
|
||||||
|
stopPicker.setCurrentHour(editedTimeFrameTrigger.getTimeFrame().getTriggerTimeStop().getHours());
|
||||||
|
stopPicker.setCurrentMinute(editedTimeFrameTrigger.getTimeFrame().getTriggerTimeStop().getMinutes());
|
||||||
|
|
||||||
|
radioTimeFrameEntering.setChecked(editedTimeFrameTrigger.getTriggerParameter());
|
||||||
|
radioTimeFrameLeaving.setChecked(!editedTimeFrameTrigger.getTriggerParameter());
|
||||||
|
|
||||||
|
for(int day : editedTimeFrameTrigger.getTimeFrame().getDayList())
|
||||||
|
{
|
||||||
|
switch(day)
|
||||||
|
{
|
||||||
|
case Calendar.MONDAY:
|
||||||
|
checkMonday.setChecked(true);
|
||||||
|
break;
|
||||||
|
case Calendar.TUESDAY:
|
||||||
|
checkTuesday.setChecked(true);
|
||||||
|
break;
|
||||||
|
case Calendar.WEDNESDAY:
|
||||||
|
checkWednesday.setChecked(true);
|
||||||
|
break;
|
||||||
|
case Calendar.THURSDAY:
|
||||||
|
checkThursday.setChecked(true);
|
||||||
|
break;
|
||||||
|
case Calendar.FRIDAY:
|
||||||
|
checkFriday.setChecked(true);
|
||||||
|
break;
|
||||||
|
case Calendar.SATURDAY:
|
||||||
|
checkSaturday.setChecked(true);
|
||||||
|
break;
|
||||||
|
case Calendar.SUNDAY:
|
||||||
|
checkSunday.setChecked(true);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Miscellaneous.logEvent("w", "TimeFrame", "Daylist contains invalid day: " + String.valueOf(day), 4);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
1370
app/src/main/java/com/jens/automation2/ActivityPermissions.java
Normal file
19
app/src/main/java/com/jens/automation2/ActivitySettings.java
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package com.jens.automation2;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.preference.ListPreference;
|
||||||
|
import android.preference.PreferenceActivity;
|
||||||
|
|
||||||
|
import com.jens.automation2.R.layout;
|
||||||
|
|
||||||
|
public class ActivitySettings extends PreferenceActivity
|
||||||
|
{
|
||||||
|
ListPreference lpStartScreenOptionsValues;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState)
|
||||||
|
{
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
addPreferencesFromResource(layout.settings);
|
||||||
|
}
|
||||||
|
}
|
210
app/src/main/java/com/jens/automation2/ActivityVolumeTest.java
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
package com.jens.automation2;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.media.MediaRecorder;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.SeekBar;
|
||||||
|
import android.widget.SeekBar.OnSeekBarChangeListener;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
@SuppressLint("NewApi")
|
||||||
|
public class ActivityVolumeTest extends Activity
|
||||||
|
{
|
||||||
|
TextView tvCurrentVolume, tvVolumeTestExplanation;
|
||||||
|
EditText etReferenceValue;
|
||||||
|
SeekBar sbReferenceValue;
|
||||||
|
|
||||||
|
final int volumeRefreshInterval = 3;
|
||||||
|
|
||||||
|
static ActivityVolumeTest instance = null;
|
||||||
|
|
||||||
|
AsyncTask<Integer, Long, Void> volumeTask = null;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState)
|
||||||
|
{
|
||||||
|
instance = this;
|
||||||
|
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_volume_test);
|
||||||
|
|
||||||
|
tvCurrentVolume = (TextView)findViewById(R.id.tvCurrentVolume);
|
||||||
|
etReferenceValue = (EditText)findViewById(R.id.etReferenceValue);
|
||||||
|
sbReferenceValue = (SeekBar)findViewById(R.id.sbReferenceValue);
|
||||||
|
tvVolumeTestExplanation = (TextView)findViewById(R.id.tvVolumeTestExplanation);
|
||||||
|
|
||||||
|
tvVolumeTestExplanation.setText(String.format(getResources().getString(R.string.volumeTesterExplanation), String.valueOf(volumeRefreshInterval)));
|
||||||
|
|
||||||
|
etReferenceValue.setText(String.valueOf(Settings.referenceValueForNoiseLevelMeasurements));
|
||||||
|
|
||||||
|
sbReferenceValue.setMax(500);
|
||||||
|
sbReferenceValue.setProgress((int) Settings.referenceValueForNoiseLevelMeasurements);
|
||||||
|
sbReferenceValue.setOnSeekBarChangeListener(new OnSeekBarChangeListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onStopTrackingTouch(SeekBar seekBar)
|
||||||
|
{
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStartTrackingTouch(SeekBar seekBar)
|
||||||
|
{
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onProgressChanged(SeekBar seekBar, int progress,
|
||||||
|
boolean fromUser)
|
||||||
|
{
|
||||||
|
etReferenceValue.setText(String.valueOf(sbReferenceValue.getProgress()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume()
|
||||||
|
{
|
||||||
|
super.onResume();
|
||||||
|
|
||||||
|
startVolumeMonitoring();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPause()
|
||||||
|
{
|
||||||
|
super.onPause();
|
||||||
|
stopVolumeMonitoring();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ActivityVolumeTest getInstance()
|
||||||
|
{
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBackPressed()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
stopVolumeMonitoring();
|
||||||
|
Settings.referenceValueForNoiseLevelMeasurements = Long.parseLong(etReferenceValue.getText().toString());
|
||||||
|
Settings.writeSettings(ActivityVolumeTest.this);
|
||||||
|
super.onBackPressed();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Toast.makeText(ActivityVolumeTest.this, ActivityVolumeTest.this.getResources().getString(R.string.enterValidReferenceValue), Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized private void startVolumeMonitoring()
|
||||||
|
{
|
||||||
|
volumeTask = new NoiseListenerMeasuring();
|
||||||
|
|
||||||
|
// if(!(volumeTask.getStatus() == AsyncTask.Status.PENDING | volumeTask.getStatus() != AsyncTask.Status.RUNNING))
|
||||||
|
volumeTask.execute(volumeRefreshInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized private void stopVolumeMonitoring()
|
||||||
|
{
|
||||||
|
// if(volumeTask != null && (volumeTask.getStatus() == Status.PENDING | volumeTask.getStatus() == Status.RUNNING))
|
||||||
|
volumeTask.cancel(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized void updateDisplayedNoiseLevel(long noise)
|
||||||
|
{
|
||||||
|
tvCurrentVolume.setText(String.valueOf(noise) + " dB");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class NoiseListenerMeasuring extends AsyncTask<Integer, Long, Void>
|
||||||
|
{
|
||||||
|
static boolean isNoiseMonitoringActive;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Void doInBackground(Integer... interval)
|
||||||
|
{
|
||||||
|
if(!isNoiseMonitoringActive)
|
||||||
|
{
|
||||||
|
isNoiseMonitoringActive = true;
|
||||||
|
|
||||||
|
Miscellaneous.logEvent("i", "Noise level", "Periodic noise level measurement started.", 5);
|
||||||
|
|
||||||
|
while(!isCancelled())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Start recording but don't store data
|
||||||
|
MediaRecorder mediaRecorder = new MediaRecorder();
|
||||||
|
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
|
||||||
|
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
|
||||||
|
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
|
||||||
|
mediaRecorder.setOutputFile("/dev/null");
|
||||||
|
// Date myDate = new Date();
|
||||||
|
// mediaRecorder.setOutputFile("/sdcard/temp/" + String.valueOf(myDate.getTime()) + ".3gpp");
|
||||||
|
|
||||||
|
mediaRecorder.prepare();
|
||||||
|
mediaRecorder.getMaxAmplitude();
|
||||||
|
mediaRecorder.start();
|
||||||
|
mediaRecorder.getMaxAmplitude();
|
||||||
|
|
||||||
|
long noiseLevel;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(interval[0] * 1000);
|
||||||
|
// Obtain maximum amplitude since last call of getMaxAmplitude()
|
||||||
|
noiseLevel = mediaRecorder.getMaxAmplitude();
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
noiseLevel = -1;
|
||||||
|
Miscellaneous.logEvent("e", "Noise level", "Error getting noise level: " + e.getMessage(), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
double currentReferenceValue = Double.parseDouble(ActivityVolumeTest.getInstance().etReferenceValue.getText().toString());
|
||||||
|
double db = 20 * Math.log(noiseLevel / currentReferenceValue);
|
||||||
|
long noiseLevelDb = Math.round(db);
|
||||||
|
|
||||||
|
publishProgress(noiseLevelDb);
|
||||||
|
|
||||||
|
// Message answer = new Message();
|
||||||
|
// Bundle answerBundle = new Bundle();
|
||||||
|
// answerBundle.putLong("noiseLevelDb", noiseLevelDb);
|
||||||
|
// answer.setData(answerBundle);
|
||||||
|
// volumeHandler.sendMessage(answer);
|
||||||
|
|
||||||
|
// Don't forget to release
|
||||||
|
mediaRecorder.reset();
|
||||||
|
mediaRecorder.release();
|
||||||
|
|
||||||
|
Miscellaneous.logEvent("i", "Noise level", "Measured noise level: " + String.valueOf(noiseLevel) + " / converted to db: " + String.valueOf(db), 3);
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{}
|
||||||
|
}
|
||||||
|
|
||||||
|
isNoiseMonitoringActive = false;
|
||||||
|
|
||||||
|
Miscellaneous.logEvent("i", "Noise level", "Periodic noise level measurement stopped.", 5);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onProgressUpdate(Long... values)
|
||||||
|
{
|
||||||
|
ActivityVolumeTest.getInstance().updateDisplayedNoiseLevel(values[0]);
|
||||||
|
|
||||||
|
// super.onProgressUpdate(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
713
app/src/main/java/com/jens/automation2/AutomationService.java
Normal file
@ -0,0 +1,713 @@
|
|||||||
|
package com.jens.automation2;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.app.ActivityManager;
|
||||||
|
import android.app.ActivityManager.RunningServiceInfo;
|
||||||
|
import android.app.Notification;
|
||||||
|
import android.app.Notification.Builder;
|
||||||
|
import android.app.NotificationChannel;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.app.PendingIntent;
|
||||||
|
import android.app.Service;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.media.AudioManager;
|
||||||
|
import android.os.Binder;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Environment;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.speech.tts.TextToSpeech;
|
||||||
|
import android.speech.tts.TextToSpeech.OnInitListener;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.core.app.NotificationCompat;
|
||||||
|
|
||||||
|
import com.jens.automation2.Trigger.Trigger_Enum;
|
||||||
|
import com.jens.automation2.location.LocationProvider;
|
||||||
|
import com.jens.automation2.receivers.PackageReplacedReceiver;
|
||||||
|
import com.jens.automation2.receivers.PhoneStatusListener;
|
||||||
|
|
||||||
|
import java.util.Calendar;
|
||||||
|
|
||||||
|
@SuppressLint("NewApi")
|
||||||
|
public class AutomationService extends Service implements OnInitListener
|
||||||
|
{
|
||||||
|
protected TextToSpeech ttsEngine = null;
|
||||||
|
protected final static int notificationId = 1000;
|
||||||
|
|
||||||
|
final static String NOTIFICATION_CHANNEL_ID = "com.jens.automation2";
|
||||||
|
final static String channelName = "Automation notifications";
|
||||||
|
|
||||||
|
protected static Notification myNotification;
|
||||||
|
protected static NotificationCompat.Builder notificationBuilder = null;
|
||||||
|
protected static PendingIntent myPendingIntent;
|
||||||
|
|
||||||
|
protected Calendar lockSoundChangesEnd = null;
|
||||||
|
protected boolean isRunning;
|
||||||
|
|
||||||
|
public void nullLockSoundChangesEnd()
|
||||||
|
{
|
||||||
|
lockSoundChangesEnd = null;
|
||||||
|
}
|
||||||
|
public Calendar getLockSoundChangesEnd()
|
||||||
|
{
|
||||||
|
return lockSoundChangesEnd;
|
||||||
|
}
|
||||||
|
public void lockSoundChangesEndAddTime()
|
||||||
|
{
|
||||||
|
if(lockSoundChangesEnd == null)
|
||||||
|
lockSoundChangesEnd = Calendar.getInstance();
|
||||||
|
|
||||||
|
lockSoundChangesEnd.add(Calendar.MINUTE, Settings.lockSoundChangesInterval);
|
||||||
|
// ActivityMainScreen.getActivityMainScreenInstance().updateMainScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkLockSoundChangesTimeElapsed()
|
||||||
|
{
|
||||||
|
Calendar now = Calendar.getInstance();
|
||||||
|
if(getLockSoundChangesEnd() != null && getLockSoundChangesEnd().getTimeInMillis() <= now.getTimeInMillis())
|
||||||
|
lockSoundChangesEnd = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLockSoundChangesEnd(Calendar lockSoundChangesEnd)
|
||||||
|
{
|
||||||
|
this.lockSoundChangesEnd = lockSoundChangesEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final IBinder myBinder = new LocalBinder();
|
||||||
|
|
||||||
|
protected LocationProvider myLocationProvider;
|
||||||
|
|
||||||
|
public LocationProvider getLocationProvider()
|
||||||
|
{
|
||||||
|
return myLocationProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static AutomationService centralInstance = null;
|
||||||
|
|
||||||
|
public static AutomationService getInstance()
|
||||||
|
{
|
||||||
|
return centralInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate()
|
||||||
|
{
|
||||||
|
super.onCreate();
|
||||||
|
|
||||||
|
Thread.setDefaultUncaughtExceptionHandler(Miscellaneous.uncaughtExceptionHandler);
|
||||||
|
|
||||||
|
// Store a reference to myself. Other classes often need a context or something, this can provide that.
|
||||||
|
centralInstance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean checkStartupRequirements(Context context, boolean startAtBoot)
|
||||||
|
{
|
||||||
|
if (!ActivityPermissions.havePermission(ActivityPermissions.writeExternalStoragePermissionName, AutomationService.this))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Don't have permission to access external storage. This is a show stopper as
|
||||||
|
the configuration file is stored on external storage.
|
||||||
|
*/
|
||||||
|
Miscellaneous.logEvent("e", "Permission", "Don't have permission to access external storage. Will request it now.", 4);
|
||||||
|
// Toast.makeText(AutomationService.this, getResources().getString(R.string.appRequiresPermissiontoAccessExternalStorage), Toast.LENGTH_LONG).show();
|
||||||
|
ActivityPermissions.requestSpecificPermission(ActivityPermissions.writeExternalStoragePermissionName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Build.VERSION.SDK_INT >= 28)
|
||||||
|
{
|
||||||
|
if (!ActivityPermissions.havePermission(ActivityPermissions.permissionNameStartService, 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);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PointOfInterest.getPointOfInterestCollection() == null | PointOfInterest.getPointOfInterestCollection().size() == 0
|
||||||
|
|
|
||||||
|
Rule.getRuleCollection() == null | Rule.getRuleCollection().size() == 0
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (startAtBoot)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* In case we start at boot the sd card may not have been mounted, yet.
|
||||||
|
* We will wait 3 seconds and check and do this 3 times.
|
||||||
|
*/
|
||||||
|
if (!XmlFileInterface.settingsFile.exists())
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
String state = Environment.getExternalStorageState();
|
||||||
|
if (!state.equals(Environment.MEDIA_MOUNTED))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("w", "AutoStart", "Service is started via boot. Settingsfile not available because storage is not mounted, yet. Waiting for 3 seconds.", 4);
|
||||||
|
Thread.sleep(3000);
|
||||||
|
} catch (InterruptedException e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (XmlFileInterface.settingsFile.exists())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PointOfInterest.loadPoisFromFile();
|
||||||
|
Rule.readFromFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
//if still no POIs...
|
||||||
|
if (//PointOfInterest.getPointOfInterestCollection() == null | PointOfInterest.getPointOfInterestCollection().size() == 0
|
||||||
|
// &&
|
||||||
|
Rule.getRuleCollection() == null | Rule.getRuleCollection().size() == 0
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("w", "AutomationService", context.getResources().getString(R.string.serviceWontStart), 1);
|
||||||
|
Toast.makeText(context, context.getResources().getString(R.string.serviceWontStart), Toast.LENGTH_LONG).show();
|
||||||
|
return false;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int onStartCommand(Intent intent, int flags, int startId)
|
||||||
|
{
|
||||||
|
boolean startAtBoot = false;
|
||||||
|
|
||||||
|
if (intent != null)
|
||||||
|
{
|
||||||
|
Bundle b = intent.getExtras();
|
||||||
|
startAtBoot = b.getBoolean("startAtBoot", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checkStartupRequirements(this, startAtBoot))
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "Service", this.getResources().getString(R.string.logServiceStarting), 1);
|
||||||
|
|
||||||
|
startUpRoutine();
|
||||||
|
|
||||||
|
Intent myIntent = new Intent(this, ActivityMainTabLayout.class);
|
||||||
|
myPendingIntent = PendingIntent.getActivity(this, 0, myIntent, 0);
|
||||||
|
notificationBuilder = createDefaultNotificationBuilder();
|
||||||
|
|
||||||
|
updateNotification();
|
||||||
|
|
||||||
|
if (isMainActivityRunning(this))
|
||||||
|
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);
|
||||||
|
Toast.makeText(this, this.getResources().getString(R.string.serviceStarted), Toast.LENGTH_LONG).show();
|
||||||
|
// ********** Test area **********
|
||||||
|
// Miscellaneous.logEvent("i", "setNetworkType", "bin hier.", 3);
|
||||||
|
// Actions.setData(true);
|
||||||
|
// ********** Test area **********
|
||||||
|
|
||||||
|
return START_STICKY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "Service", "checkStartupRequirements() delivered false. Stopping service...", 1);
|
||||||
|
this.stopSelf();
|
||||||
|
return START_NOT_STICKY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBinder onBind(Intent arg0)
|
||||||
|
{
|
||||||
|
return myBinder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum serviceCommands
|
||||||
|
{
|
||||||
|
reloadSettings, reloadPointsOfInterest, reloadRules, updateNotification
|
||||||
|
}
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
public void serviceInterface(serviceCommands command)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "Bind", "Ahhhh, customers... How can I help you?", 5);
|
||||||
|
|
||||||
|
Miscellaneous.logEvent("i", "ServiceBind", "Request to " + command.toString(), 5);
|
||||||
|
|
||||||
|
switch (command)
|
||||||
|
{
|
||||||
|
case reloadPointsOfInterest:
|
||||||
|
PointOfInterest.loadPoisFromFile();
|
||||||
|
break;
|
||||||
|
case reloadRules:
|
||||||
|
Rule.readFromFile();
|
||||||
|
break;
|
||||||
|
case reloadSettings:
|
||||||
|
Settings.readFromPersistentStorage(this);
|
||||||
|
applySettingsAndRules();
|
||||||
|
myLocationProvider.applySettingsAndRules();
|
||||||
|
break;
|
||||||
|
case updateNotification:
|
||||||
|
this.updateNotification();
|
||||||
|
ActivityMainScreen.updateMainScreen();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void applySettingsAndRules()
|
||||||
|
{
|
||||||
|
if (Settings.useTextToSpeechOnNormal | Settings.useTextToSpeechOnSilent | Settings.useTextToSpeechOnVibrate)
|
||||||
|
{
|
||||||
|
if (ttsEngine == null)
|
||||||
|
ttsEngine = new TextToSpeech(this, this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (ttsEngine != null)
|
||||||
|
ttsEngine.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
startLocationProvider();
|
||||||
|
ReceiverCoordinator.startAllReceivers();
|
||||||
|
if(myLocationProvider != null) // This condition can be met if the user has no locations defined.
|
||||||
|
myLocationProvider.applySettingsAndRules();
|
||||||
|
|
||||||
|
ReceiverCoordinator.applySettingsAndRules();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy()
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "Service", getResources().getString(R.string.logServiceStopping), 1);
|
||||||
|
|
||||||
|
stopRoutine();
|
||||||
|
this.isRunning = false;
|
||||||
|
Toast.makeText(this, getResources().getString(R.string.serviceStopped), Toast.LENGTH_LONG).show();
|
||||||
|
Miscellaneous.logEvent("i", "Service", getResources().getString(R.string.serviceStopped), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkForTtsEngine()
|
||||||
|
{
|
||||||
|
if (Settings.useTextToSpeechOnNormal | Settings.useTextToSpeechOnSilent | Settings.useTextToSpeechOnVibrate | Rule.isAnyRuleUsing(Action.Action_Enum.speakText))
|
||||||
|
{
|
||||||
|
if (ttsEngine == null)
|
||||||
|
ttsEngine = new TextToSpeech(this, this);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
if (ttsEngine != null)
|
||||||
|
ttsEngine.shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startUpRoutine()
|
||||||
|
{
|
||||||
|
checkForTtsEngine();
|
||||||
|
checkForPermissions();
|
||||||
|
|
||||||
|
Actions.context = this;
|
||||||
|
Actions.autoMationServerRef = this;
|
||||||
|
|
||||||
|
startLocationProvider();
|
||||||
|
ReceiverCoordinator.startAllReceivers();
|
||||||
|
|
||||||
|
PackageReplacedReceiver.setHasServiceBeenRunning(true, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void startLocationProvider()
|
||||||
|
{
|
||||||
|
if(ActivityPermissions.havePermission("android.permission.ACCESS_COARSE_LOCATION", AutomationService.this))
|
||||||
|
myLocationProvider = new LocationProvider(this); //autostart with this (only) constructor
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void checkForPermissions()
|
||||||
|
{
|
||||||
|
if(ActivityPermissions.needMorePermissions(AutomationService.this))
|
||||||
|
{
|
||||||
|
boolean displayNotification = false;
|
||||||
|
|
||||||
|
for(Rule r : Rule.getRuleCollection())
|
||||||
|
{
|
||||||
|
if(r.isRuleActive())
|
||||||
|
{
|
||||||
|
if(!r.haveEnoughPermissions())
|
||||||
|
// for (String permission : ActivityPermissions.getPermissionsForRule(r))
|
||||||
|
{
|
||||||
|
// if (!ActivityPermissions.havePermission(permission, AutomationService.this))
|
||||||
|
{
|
||||||
|
// r.setRuleActive(false);
|
||||||
|
// r.change(AutomationService.this);
|
||||||
|
if(!displayNotification)
|
||||||
|
displayNotification = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.createDismissableNotification(getResources().getString(R.string.appRunningInLimitedMode), ActivityPermissions.notificationIdPermissions, pi);
|
||||||
|
}
|
||||||
|
// else
|
||||||
|
// Toast.makeText(Miscellaneous.getAnyContext(), "Have all required permissions.", Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void startAutomationService(Context context, boolean startAtBoot)
|
||||||
|
{
|
||||||
|
if(!(isMyServiceRunning(context)))
|
||||||
|
{
|
||||||
|
Intent myServiceIntent = new Intent(context, AutomationService.class);
|
||||||
|
myServiceIntent.putExtra("startAtBoot", startAtBoot);
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
|
||||||
|
context.startForegroundService(myServiceIntent);
|
||||||
|
else
|
||||||
|
context.startService(myServiceIntent);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Miscellaneous.logEvent("i", "Service", "Service is already running.", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopRoutine()
|
||||||
|
{
|
||||||
|
Log.i("STOP", "Stopping");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
myLocationProvider.stopLocationService();
|
||||||
|
ReceiverCoordinator.stopAllReceivers();
|
||||||
|
}
|
||||||
|
catch(NullPointerException e)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", getResources().getString(R.string.serviceNotRunning), getResources().getString(R.string.serviceNotRunning) + ". " + getResources().getString(R.string.cantStopIt), 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ttsEngine != null)
|
||||||
|
ttsEngine.shutdown();
|
||||||
|
|
||||||
|
PackageReplacedReceiver.setHasServiceBeenRunning(false, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static Builder createDefaultNotificationBuilderOld()
|
||||||
|
{
|
||||||
|
Builder builder = new Builder(AutomationService.getInstance());
|
||||||
|
builder.setContentTitle("Automation");
|
||||||
|
|
||||||
|
if(Settings.showIconWhenServiceIsRunning)
|
||||||
|
builder.setSmallIcon(R.drawable.ic_launcher);
|
||||||
|
|
||||||
|
builder.setCategory(Notification.CATEGORY_SERVICE);
|
||||||
|
builder.setWhen(System.currentTimeMillis());
|
||||||
|
builder.setContentIntent(myPendingIntent);
|
||||||
|
|
||||||
|
// Notification defaultNotification = new Notification();
|
||||||
|
Notification defaultNotification = builder.build();
|
||||||
|
|
||||||
|
defaultNotification.icon = R.drawable.ic_launcher;
|
||||||
|
defaultNotification.when = System.currentTimeMillis();
|
||||||
|
|
||||||
|
// defaultNotification.defaults |= Notification.DEFAULT_VIBRATE;
|
||||||
|
// defaultNotification.defaults |= Notification.DEFAULT_LIGHTS;
|
||||||
|
|
||||||
|
defaultNotification.flags |= Notification.FLAG_AUTO_CANCEL;
|
||||||
|
// defaultNotification.flags |= Notification.FLAG_SHOW_LIGHTS;
|
||||||
|
defaultNotification.flags |= Notification.FLAG_ONLY_ALERT_ONCE;
|
||||||
|
|
||||||
|
// defaultNotification.ledARGB = Color.YELLOW;
|
||||||
|
// defaultNotification.ledOnMS = 1500;
|
||||||
|
// defaultNotification.ledOffMS = 1500;
|
||||||
|
|
||||||
|
return builder;
|
||||||
|
|
||||||
|
/*NotificationManager mNotificationManager = (NotificationManager) AutomationService.getInstance().getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
|
|
||||||
|
NotificationCompat.Builder builder;
|
||||||
|
builder = new NotificationCompat.Builder(AutomationService.getInstance());
|
||||||
|
|
||||||
|
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
|
||||||
|
builder.setCategory(Notification.CATEGORY_EVENT);
|
||||||
|
|
||||||
|
builder.setWhen(System.currentTimeMillis());
|
||||||
|
|
||||||
|
builder.setContentTitle("Automation");
|
||||||
|
builder.setSmallIcon(R.drawable.ic_launcher);
|
||||||
|
// builder.setContentText(textToDisplay);
|
||||||
|
// builder.setSmallIcon(icon);
|
||||||
|
// builder.setContentIntent(pendingIntent);
|
||||||
|
// builder.setStyle(new NotificationCompat.BigTextStyle().bigText(textToDisplay));
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
|
||||||
|
{
|
||||||
|
NotificationChannel channel = new NotificationChannel("notify_001", "Channel human readable title", NotificationManager.IMPORTANCE_DEFAULT);
|
||||||
|
mNotificationManager.createNotificationChannel(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static NotificationCompat.Builder createDefaultNotificationBuilder()
|
||||||
|
{
|
||||||
|
NotificationManager mNotificationManager = (NotificationManager) AutomationService.getInstance().getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
|
|
||||||
|
NotificationCompat.Builder builder;
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
|
||||||
|
{
|
||||||
|
NotificationChannel chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_LOW);
|
||||||
|
// chan.setLightColor(Color.BLUE);
|
||||||
|
chan.enableVibration(false);
|
||||||
|
chan.setSound(null, null);
|
||||||
|
chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
|
||||||
|
mNotificationManager.createNotificationChannel(chan);
|
||||||
|
|
||||||
|
builder = new NotificationCompat.Builder(AutomationService.getInstance(), NOTIFICATION_CHANNEL_ID);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
builder = new NotificationCompat.Builder(AutomationService.getInstance());
|
||||||
|
|
||||||
|
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
|
||||||
|
builder.setCategory(Notification.CATEGORY_SERVICE);
|
||||||
|
|
||||||
|
builder.setWhen(System.currentTimeMillis());
|
||||||
|
builder.setContentIntent(myPendingIntent);
|
||||||
|
|
||||||
|
builder.setContentTitle(AutomationService.getInstance().getResources().getString(R.string.app_name));
|
||||||
|
builder.setOnlyAlertOnce(true);
|
||||||
|
|
||||||
|
if(Settings.showIconWhenServiceIsRunning)
|
||||||
|
builder.setSmallIcon(R.drawable.ic_launcher);
|
||||||
|
|
||||||
|
// builder.setContentText(textToDisplay);
|
||||||
|
// builder.setSmallIcon(icon);
|
||||||
|
// builder.setStyle(new NotificationCompat.BigTextStyle().bigText(textToDisplay));
|
||||||
|
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("NewApi")
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public static void updateNotification()
|
||||||
|
{
|
||||||
|
AutomationService instance = getInstance();
|
||||||
|
|
||||||
|
if(instance != null)
|
||||||
|
{
|
||||||
|
// if(Settings.showIconWhenServiceIsRunning)
|
||||||
|
// {
|
||||||
|
Miscellaneous.logEvent("i", "Notification", "Request to update notification.", 4);
|
||||||
|
|
||||||
|
String bodyText="";
|
||||||
|
String lastRuleString = "";
|
||||||
|
|
||||||
|
if(PointOfInterest.getPointOfInterestCollection() != null && PointOfInterest.getPointOfInterestCollection().size() > 0)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PointOfInterest activePoi = PointOfInterest.getActivePoi();
|
||||||
|
if(activePoi == null)
|
||||||
|
{
|
||||||
|
PointOfInterest closestPoi = PointOfInterest.getClosestPOI(instance.getLocationProvider().getCurrentLocation());
|
||||||
|
bodyText = "Active POI: none" + "\n" + "Closest POI: " + closestPoi.getName() + lastRuleString;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bodyText = "Active POI: " + activePoi.getName() + lastRuleString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(NullPointerException e)
|
||||||
|
{
|
||||||
|
if(
|
||||||
|
Rule.isAnyRuleUsing(Trigger_Enum.pointOfInterest)
|
||||||
|
&&
|
||||||
|
ActivityPermissions.havePermission(ActivityPermissions.permissionNameLocationCoarse, AutomationService.getInstance())
|
||||||
|
&&
|
||||||
|
ActivityPermissions.havePermission(ActivityPermissions.permissionNameLocationFine, AutomationService.getInstance())
|
||||||
|
)
|
||||||
|
bodyText = instance.getResources().getString(R.string.stillGettingPosition);
|
||||||
|
else
|
||||||
|
bodyText = instance.getResources().getString(R.string.locationEngineNotActive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
lastRuleString = instance.getResources().getString(R.string.lastRule) + " " + Rule.getLastActivatedRule().getName() + " " + instance.getResources().getString(R.string.at) + " " + Rule.getLastActivatedRuleActivationTime().toLocaleString();
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
lastRuleString = instance.getResources().getString(R.string.lastRule) + " n./a.";
|
||||||
|
}
|
||||||
|
|
||||||
|
String textToDisplay = bodyText + " " + lastRuleString;
|
||||||
|
// if(Build.VERSION.SDK_INT < 11)
|
||||||
|
// {
|
||||||
|
// myNotification.setLatestEventInfo(instance, "Automation", textToDisplay, myPendingIntent);
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
notificationBuilder.setContentText(textToDisplay);
|
||||||
|
notificationBuilder.setStyle(new NotificationCompat.BigTextStyle().bigText(textToDisplay));
|
||||||
|
|
||||||
|
myNotification = notificationBuilder.build();
|
||||||
|
myNotification.defaults = 0;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// NotificationManager notificationManager = (NotificationManager) instance.getSystemService(NOTIFICATION_SERVICE);
|
||||||
|
// hide the notification after its selected
|
||||||
|
// myNotification.flags |= Notification.FLAG_AUTO_CANCEL;
|
||||||
|
myNotification.flags |= Notification.FLAG_NO_CLEAR;
|
||||||
|
// notificationManager.notify(notificationId, myNotification);
|
||||||
|
|
||||||
|
instance.startForeground(notificationId, myNotification);
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// instance.startForeground(notificationId, null); // do not show icon in task bar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LocalBinder extends Binder
|
||||||
|
{
|
||||||
|
public AutomationService getService()
|
||||||
|
{
|
||||||
|
return AutomationService.this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInit(int status)
|
||||||
|
{
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* force will skip volume settings and stuff
|
||||||
|
**/
|
||||||
|
public void speak(String text, boolean force)
|
||||||
|
{
|
||||||
|
if(text.length() > 0 && (force | Settings.useTextToSpeechOnNormal | Settings.useTextToSpeechOnSilent | Settings.useTextToSpeechOnVibrate))
|
||||||
|
{
|
||||||
|
AudioManager myAudioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
|
||||||
|
int mode = myAudioManager.getRingerMode();
|
||||||
|
|
||||||
|
if(
|
||||||
|
(mode == AudioManager.RINGER_MODE_NORMAL && Settings.useTextToSpeechOnNormal)
|
||||||
|
|
|
||||||
|
(mode == AudioManager.RINGER_MODE_VIBRATE && Settings.useTextToSpeechOnVibrate)
|
||||||
|
|
|
||||||
|
(mode == AudioManager.RINGER_MODE_SILENT && Settings.useTextToSpeechOnSilent)
|
||||||
|
|
|
||||||
|
force
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if(Settings.muteTextToSpeechDuringCalls && PhoneStatusListener.isInACall() && !force)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "TextToSpeech", "Currently in a call. Not speaking as requested.", 4);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
for(int i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
if(ttsEngine != null)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "TTS", "Waiting for a moment to give the TTS service time to load...", 4);
|
||||||
|
Thread.sleep(1000); // give the tts engine time to load
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.ttsEngine.speak(text, TextToSpeech.QUEUE_ADD, null);
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "TextToSpeech", Log.getStackTraceString(e), 3);
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isMainActivityRunning(Context context)
|
||||||
|
{
|
||||||
|
if(ActivityMainScreen.getActivityMainScreenInstance() == null)
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// boolean isActivityFound = false;
|
||||||
|
// ActivityManager activityManager = (ActivityManager)context.getSystemService (Context.ACTIVITY_SERVICE);
|
||||||
|
// List<RunningTaskInfo> activitys = activityManager.getRunningTasks(Integer.MAX_VALUE);
|
||||||
|
// isActivityFound = false;
|
||||||
|
// for (int i = 0; i < activitys.size(); i++)
|
||||||
|
// {
|
||||||
|
// if (activitys.get(i).topActivity.toString().equalsIgnoreCase("ComponentInfo{com.jens.automation/com.jens.automation.ActivityMainScreen}"))
|
||||||
|
// {
|
||||||
|
// isActivityFound = true;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// Miscellaneous.logEvent("i", "ActivityMainScreen", "Activity running status: " + String.valueOf(isActivityFound), 5);
|
||||||
|
// return isActivityFound;
|
||||||
|
|
||||||
|
// ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
||||||
|
// List<RunningTaskInfo> tasks = activityManager.getRunningTasks(Integer.MAX_VALUE);
|
||||||
|
//
|
||||||
|
// for (RunningTaskInfo task : tasks)
|
||||||
|
// {
|
||||||
|
// if (context.getPackageName().equalsIgnoreCase(task.baseActivity.getPackageName()))
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isMyServiceRunning(Context context)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
||||||
|
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE))
|
||||||
|
{
|
||||||
|
if(AutomationService.class.getName().equals(service.service.getClassName()))
|
||||||
|
{
|
||||||
|
// return AutomationService.getInstance() != null && AutomationService.getInstance().isRunning;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(NullPointerException e)
|
||||||
|
{
|
||||||
|
if(Log.getStackTraceString(e).contains("activate")) // Means that a poi has been activated/deactivated. Service is running.
|
||||||
|
return true;
|
||||||
|
// return AutomationService.getInstance() != null && AutomationService.getInstance().isRunning;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,371 @@
|
|||||||
|
package com.jens.automation2;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.content.ContentUris;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Environment;
|
||||||
|
import android.provider.DocumentsContract;
|
||||||
|
import android.provider.MediaStore;
|
||||||
|
import android.provider.OpenableColumns;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
public class CompensateCrappyAndroidPaths
|
||||||
|
{
|
||||||
|
private static Uri contentUri = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a file path from a Uri. This will get the the path for Storage Access
|
||||||
|
* Framework Documents, as well as the _data field for the MediaStore and
|
||||||
|
* other file-based ContentProviders.<br>
|
||||||
|
* <br>
|
||||||
|
* Callers should check whether the path is local before assuming it
|
||||||
|
* represents a local file.
|
||||||
|
*
|
||||||
|
* @param context The context.
|
||||||
|
* @param uri The Uri to query.
|
||||||
|
*/
|
||||||
|
@SuppressLint("NewApi")
|
||||||
|
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;
|
||||||
|
String[] selectionArgs = null;
|
||||||
|
// DocumentProvider
|
||||||
|
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
|
||||||
|
// ExternalStorageProvider
|
||||||
|
if (isExternalStorageDocument(uri)) {
|
||||||
|
final String docId = DocumentsContract.getDocumentId(uri);
|
||||||
|
final String[] split = docId.split(":");
|
||||||
|
final String type = split[0];
|
||||||
|
|
||||||
|
String fullPath = getPathFromExtSD(split);
|
||||||
|
if (fullPath != "") {
|
||||||
|
return fullPath;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DownloadsProvider
|
||||||
|
else if (isDownloadsDocument(uri)) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
|
final String id;
|
||||||
|
Cursor cursor = null;
|
||||||
|
try {
|
||||||
|
cursor = context.getContentResolver().query(uri, new String[]{MediaStore.MediaColumns.DISPLAY_NAME}, null, null, null);
|
||||||
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
|
String fileName = cursor.getString(0);
|
||||||
|
String path = Environment.getExternalStorageDirectory().toString() + "/Download/" + fileName;
|
||||||
|
if (!TextUtils.isEmpty(path)) {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (cursor != null)
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
id = DocumentsContract.getDocumentId(uri);
|
||||||
|
if (!TextUtils.isEmpty(id)) {
|
||||||
|
if (id.startsWith("raw:")) {
|
||||||
|
return id.replaceFirst("raw:", "");
|
||||||
|
}
|
||||||
|
String[] contentUriPrefixesToTry = new String[]{
|
||||||
|
"content://downloads/public_downloads",
|
||||||
|
"content://downloads/my_downloads"
|
||||||
|
};
|
||||||
|
for (String contentUriPrefix : contentUriPrefixesToTry) {
|
||||||
|
try {
|
||||||
|
final Uri contentUri = ContentUris.withAppendedId(Uri.parse(contentUriPrefix), Long.valueOf(id));
|
||||||
|
|
||||||
|
/* final Uri contentUri = ContentUris.withAppendedId(
|
||||||
|
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));*/
|
||||||
|
|
||||||
|
return getDataColumn(context, contentUri, null, null);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
//In Android 8 and Android P the id is not a number
|
||||||
|
return uri.getPath().replaceFirst("^/document/raw:", "").replaceFirst("^raw:", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
final String id = DocumentsContract.getDocumentId(uri);
|
||||||
|
final boolean isOreo = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
|
||||||
|
if (id.startsWith("raw:")) {
|
||||||
|
return id.replaceFirst("raw:", "");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
contentUri = ContentUris.withAppendedId(
|
||||||
|
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
|
||||||
|
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
if (contentUri != null) {
|
||||||
|
return getDataColumn(context, contentUri, null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
// MediaProvider
|
||||||
|
else if (isMediaDocument(uri)) {
|
||||||
|
final String docId = DocumentsContract.getDocumentId(uri);
|
||||||
|
final String[] split = docId.split(":");
|
||||||
|
final String type = split[0];
|
||||||
|
|
||||||
|
Uri contentUri = null;
|
||||||
|
|
||||||
|
if ("image".equals(type)) {
|
||||||
|
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
|
||||||
|
} else if ("video".equals(type)) {
|
||||||
|
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
|
||||||
|
} else if ("audio".equals(type)) {
|
||||||
|
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
|
||||||
|
}
|
||||||
|
selection = "_id=?";
|
||||||
|
selectionArgs = new String[]{split[1]};
|
||||||
|
|
||||||
|
|
||||||
|
return getDataColumn(context, contentUri, selection,
|
||||||
|
selectionArgs);
|
||||||
|
} else if (isGoogleDriveUri(uri)) {
|
||||||
|
return getDriveFilePath(uri, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MediaStore (and general)
|
||||||
|
else if ("content".equalsIgnoreCase(uri.getScheme())) {
|
||||||
|
|
||||||
|
if (isGooglePhotosUri(uri)) {
|
||||||
|
return uri.getLastPathSegment();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isGoogleDriveUri(uri)) {
|
||||||
|
return getDriveFilePath(uri, context);
|
||||||
|
}
|
||||||
|
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N) {
|
||||||
|
// return getFilePathFromURI(context,uri);
|
||||||
|
return getMediaFilePathForN(uri, context);
|
||||||
|
// return getRealPathFromURI(context,uri);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
return getDataColumn(context, uri, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
// File
|
||||||
|
else if ("file".equalsIgnoreCase(uri.getScheme())) {
|
||||||
|
return uri.getPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a file exists on device
|
||||||
|
*
|
||||||
|
* @param filePath The absolute file path
|
||||||
|
*/
|
||||||
|
private static boolean fileExists(String filePath) {
|
||||||
|
File file = new File(filePath);
|
||||||
|
|
||||||
|
return file.exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get full file path from external storage
|
||||||
|
*
|
||||||
|
* @param pathData The storage type and the relative path
|
||||||
|
*/
|
||||||
|
private static String getPathFromExtSD(String[] pathData) {
|
||||||
|
final String type = pathData[0];
|
||||||
|
final String relativePath = "/" + pathData[1];
|
||||||
|
String fullPath = "";
|
||||||
|
|
||||||
|
// on my Sony devices (4.4.4 & 5.1.1), `type` is a dynamic string
|
||||||
|
// something like "71F8-2C0A", some kind of unique id per storage
|
||||||
|
// don't know any API that can get the root path of that storage based on its id.
|
||||||
|
//
|
||||||
|
// so no "primary" type, but let the check here for other devices
|
||||||
|
if ("primary".equalsIgnoreCase(type)) {
|
||||||
|
fullPath = Environment.getExternalStorageDirectory() + relativePath;
|
||||||
|
if (fileExists(fullPath)) {
|
||||||
|
return fullPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Environment.isExternalStorageRemovable() is `true` for external and internal storage
|
||||||
|
// so we cannot relay on it.
|
||||||
|
//
|
||||||
|
// instead, for each possible path, check if file exists
|
||||||
|
// we'll start with secondary storage as this could be our (physically) removable sd card
|
||||||
|
fullPath = System.getenv("SECONDARY_STORAGE") + relativePath;
|
||||||
|
if (fileExists(fullPath)) {
|
||||||
|
return fullPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
fullPath = System.getenv("EXTERNAL_STORAGE") + relativePath;
|
||||||
|
if (fileExists(fullPath)) {
|
||||||
|
return fullPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fullPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getDriveFilePath(Uri uri, Context context) {
|
||||||
|
Uri returnUri = uri;
|
||||||
|
Cursor returnCursor = context.getContentResolver().query(returnUri, null, null, null, null);
|
||||||
|
/*
|
||||||
|
* Get the column indexes of the data in the Cursor,
|
||||||
|
* * move to the first row in the Cursor, get the data,
|
||||||
|
* * and display it.
|
||||||
|
* */
|
||||||
|
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
|
||||||
|
int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
|
||||||
|
returnCursor.moveToFirst();
|
||||||
|
String name = (returnCursor.getString(nameIndex));
|
||||||
|
String size = (Long.toString(returnCursor.getLong(sizeIndex)));
|
||||||
|
File file = new File(context.getCacheDir(), name);
|
||||||
|
try {
|
||||||
|
InputStream inputStream = context.getContentResolver().openInputStream(uri);
|
||||||
|
FileOutputStream outputStream = new FileOutputStream(file);
|
||||||
|
int read = 0;
|
||||||
|
int maxBufferSize = 1 * 1024 * 1024;
|
||||||
|
int bytesAvailable = inputStream.available();
|
||||||
|
|
||||||
|
//int bufferSize = 1024;
|
||||||
|
int bufferSize = Math.min(bytesAvailable, maxBufferSize);
|
||||||
|
|
||||||
|
final byte[] buffers = new byte[bufferSize];
|
||||||
|
while ((read = inputStream.read(buffers)) != -1) {
|
||||||
|
outputStream.write(buffers, 0, read);
|
||||||
|
}
|
||||||
|
Log.e("File Size", "Size " + file.length());
|
||||||
|
inputStream.close();
|
||||||
|
outputStream.close();
|
||||||
|
Log.e("File Path", "Path " + file.getPath());
|
||||||
|
Log.e("File Size", "Size " + file.length());
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e("Exception", e.getMessage());
|
||||||
|
}
|
||||||
|
return file.getPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getMediaFilePathForN(Uri uri, Context context) {
|
||||||
|
Uri returnUri = uri;
|
||||||
|
Cursor returnCursor = context.getContentResolver().query(returnUri, null, null, null, null);
|
||||||
|
/*
|
||||||
|
* Get the column indexes of the data in the Cursor,
|
||||||
|
* * move to the first row in the Cursor, get the data,
|
||||||
|
* * and display it.
|
||||||
|
* */
|
||||||
|
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
|
||||||
|
int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
|
||||||
|
returnCursor.moveToFirst();
|
||||||
|
String name = (returnCursor.getString(nameIndex));
|
||||||
|
String size = (Long.toString(returnCursor.getLong(sizeIndex)));
|
||||||
|
File file = new File(context.getFilesDir(), name);
|
||||||
|
try {
|
||||||
|
InputStream inputStream = context.getContentResolver().openInputStream(uri);
|
||||||
|
FileOutputStream outputStream = new FileOutputStream(file);
|
||||||
|
int read = 0;
|
||||||
|
int maxBufferSize = 1 * 1024 * 1024;
|
||||||
|
int bytesAvailable = inputStream.available();
|
||||||
|
|
||||||
|
//int bufferSize = 1024;
|
||||||
|
int bufferSize = Math.min(bytesAvailable, maxBufferSize);
|
||||||
|
|
||||||
|
final byte[] buffers = new byte[bufferSize];
|
||||||
|
while ((read = inputStream.read(buffers)) != -1) {
|
||||||
|
outputStream.write(buffers, 0, read);
|
||||||
|
}
|
||||||
|
Log.e("File Size", "Size " + file.length());
|
||||||
|
inputStream.close();
|
||||||
|
outputStream.close();
|
||||||
|
Log.e("File Path", "Path " + file.getPath());
|
||||||
|
Log.e("File Size", "Size " + file.length());
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e("Exception", e.getMessage());
|
||||||
|
}
|
||||||
|
return file.getPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static String getDataColumn(Context context, Uri uri,
|
||||||
|
String selection, String[] selectionArgs) {
|
||||||
|
Cursor cursor = null;
|
||||||
|
final String column = "_data";
|
||||||
|
final String[] projection = {column};
|
||||||
|
|
||||||
|
try {
|
||||||
|
cursor = context.getContentResolver().query(uri, projection,
|
||||||
|
selection, selectionArgs, null);
|
||||||
|
|
||||||
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
|
final int index = cursor.getColumnIndexOrThrow(column);
|
||||||
|
return cursor.getString(index);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (cursor != null)
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param uri - The Uri to check.
|
||||||
|
* @return - Whether the Uri authority is ExternalStorageProvider.
|
||||||
|
*/
|
||||||
|
private static boolean isExternalStorageDocument(Uri uri) {
|
||||||
|
return "com.android.externalstorage.documents".equals(uri.getAuthority());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param uri - The Uri to check.
|
||||||
|
* @return - Whether the Uri authority is DownloadsProvider.
|
||||||
|
*/
|
||||||
|
private static boolean isDownloadsDocument(Uri uri) {
|
||||||
|
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param uri - The Uri to check.
|
||||||
|
* @return - Whether the Uri authority is MediaProvider.
|
||||||
|
*/
|
||||||
|
private static boolean isMediaDocument(Uri uri) {
|
||||||
|
return "com.android.providers.media.documents".equals(uri.getAuthority());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param uri - The Uri to check.
|
||||||
|
* @return - Whether the Uri authority is Google Photos.
|
||||||
|
*/
|
||||||
|
private static boolean isGooglePhotosUri(Uri uri) {
|
||||||
|
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param uri The Uri to check.
|
||||||
|
* @return Whether the Uri authority is Google Drive.
|
||||||
|
*/
|
||||||
|
private static boolean isGoogleDriveUri(Uri uri) {
|
||||||
|
return "com.google.android.apps.docs.storage".equals(uri.getAuthority()) || "com.google.android.apps.docs.storage.legacy".equals(uri.getAuthority());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
887
app/src/main/java/com/jens/automation2/Miscellaneous.java
Normal file
@ -0,0 +1,887 @@
|
|||||||
|
package com.jens.automation2;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.Notification;
|
||||||
|
import android.app.NotificationChannel;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.app.PendingIntent;
|
||||||
|
import android.app.Service;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Environment;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.provider.MediaStore;
|
||||||
|
import android.provider.Settings.Secure;
|
||||||
|
import android.util.Base64;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.core.app.NotificationCompat;
|
||||||
|
|
||||||
|
import com.jens.automation2.location.LocationProvider;
|
||||||
|
import com.jens.automation2.receivers.PhoneStatusListener;
|
||||||
|
|
||||||
|
import org.apache.http.HttpEntity;
|
||||||
|
import org.apache.http.HttpResponse;
|
||||||
|
import org.apache.http.HttpVersion;
|
||||||
|
import org.apache.http.client.HttpClient;
|
||||||
|
import org.apache.http.client.methods.HttpPost;
|
||||||
|
import org.apache.http.conn.ssl.SSLSocketFactory;
|
||||||
|
import org.apache.http.impl.client.DefaultHttpClient;
|
||||||
|
import org.apache.http.params.BasicHttpParams;
|
||||||
|
import org.apache.http.params.HttpParams;
|
||||||
|
import org.apache.http.params.HttpProtocolParams;
|
||||||
|
import org.apache.http.util.EntityUtils;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.lang.Thread.UncaughtExceptionHandler;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.security.KeyManagementException;
|
||||||
|
import java.security.KeyStore;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.sql.Time;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import javax.net.ssl.HostnameVerifier;
|
||||||
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
import javax.net.ssl.SSLSession;
|
||||||
|
import javax.net.ssl.TrustManager;
|
||||||
|
import javax.net.ssl.X509TrustManager;
|
||||||
|
|
||||||
|
import static com.jens.automation2.AutomationService.NOTIFICATION_CHANNEL_ID;
|
||||||
|
import static com.jens.automation2.AutomationService.channelName;
|
||||||
|
|
||||||
|
//import android.R.string;
|
||||||
|
//import android.util.Log;
|
||||||
|
|
||||||
|
public class Miscellaneous extends Service
|
||||||
|
{
|
||||||
|
private static String writeableFolderStringCache = null;
|
||||||
|
public static final String lineSeparator = System.getProperty("line.separator");
|
||||||
|
|
||||||
|
public static String downloadURL(String url, String username, String password)
|
||||||
|
{
|
||||||
|
HttpClient httpclient = new DefaultHttpClient();
|
||||||
|
StringBuilder responseBody = new StringBuilder();
|
||||||
|
boolean errorFound = false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
URL urlObject = new URL(url);
|
||||||
|
HttpURLConnection connection;
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
// Add http simple authentication if specified
|
||||||
|
if(username != null && password != null)
|
||||||
|
{
|
||||||
|
String encodedCredentials = Base64.encodeToString(new String(username + ":" + password).getBytes(), Base64.DEFAULT);
|
||||||
|
connection.setRequestMethod("POST");
|
||||||
|
connection.setDoOutput(true);
|
||||||
|
connection.setRequestProperty ("Authorization", "Basic " + encodedCredentials);
|
||||||
|
}
|
||||||
|
|
||||||
|
InputStream content = (InputStream)connection.getInputStream();
|
||||||
|
BufferedReader in = new BufferedReader (new InputStreamReader (content));
|
||||||
|
String line;
|
||||||
|
while ((line = in.readLine()) != null)
|
||||||
|
responseBody.append(line + Miscellaneous.lineSeparator);
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "HTTP error", Log.getStackTraceString(e), 3);
|
||||||
|
errorFound = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// When HttpClient instance is no longer needed,
|
||||||
|
// shut down the connection manager to ensure
|
||||||
|
// immediate deallocation of all system resources
|
||||||
|
httpclient.getConnectionManager().shutdown();
|
||||||
|
if(errorFound)
|
||||||
|
return "httpError";
|
||||||
|
else
|
||||||
|
return responseBody.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String downloadURLwithoutCertificateChecking(String url, String username, String password)
|
||||||
|
{
|
||||||
|
// HttpClient httpclient = new DefaultHttpClient();
|
||||||
|
// StringBuilder responseBody = new StringBuilder();
|
||||||
|
boolean errorFound = false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
HttpParams params = new BasicHttpParams();
|
||||||
|
params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false);
|
||||||
|
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
|
||||||
|
HttpClient httpclient = new DefaultHttpClient(params);
|
||||||
|
httpclient = Actions.getInsecureSslClient(httpclient);
|
||||||
|
|
||||||
|
HttpPost httppost = new HttpPost(url);
|
||||||
|
|
||||||
|
// Add http simple authentication if specified
|
||||||
|
if(username != null && password != null)
|
||||||
|
{
|
||||||
|
String encodedCredentials = Base64.encodeToString(new String(username + ":" + password).getBytes(), Base64.DEFAULT);
|
||||||
|
// List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(1);
|
||||||
|
httppost.addHeader("Authorization", "Basic " + encodedCredentials);
|
||||||
|
// nameValuePairs.add(new BasicNameValuePair("Authorization", "Basic " + encodedCredentials));
|
||||||
|
// httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs, "UTF-8"));
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpResponse response = httpclient.execute(httppost);
|
||||||
|
HttpEntity entity = response.getEntity();
|
||||||
|
if (entity != null)
|
||||||
|
{
|
||||||
|
// System.out.println(EntityUtils.toString(entity));
|
||||||
|
return EntityUtils.toString(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "HTTP error", Log.getStackTraceString(e), 3);
|
||||||
|
errorFound = true;
|
||||||
|
return "httpError";
|
||||||
|
}
|
||||||
|
// finally
|
||||||
|
// {
|
||||||
|
// // When HttpClient instance is no longer needed,
|
||||||
|
// // shut down the connection manager to ensure
|
||||||
|
// // immediate deallocation of all system resources
|
||||||
|
// httpclient.getConnectionManager().shutdown();
|
||||||
|
// return responseBody.toString();
|
||||||
|
// }
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBinder onBind(Intent arg0)
|
||||||
|
{
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// public static void logEvent(String type, String header, String description)
|
||||||
|
// {
|
||||||
|
// if(type.equals("e"))
|
||||||
|
// Log.e(header, description);
|
||||||
|
//
|
||||||
|
// if(type.equals("w"))
|
||||||
|
// Log.w(header, description);
|
||||||
|
//
|
||||||
|
// if(type.equals("i"))
|
||||||
|
// Log.i(header, description);
|
||||||
|
//
|
||||||
|
// if(Settings.writeLogFile)
|
||||||
|
// writeToLogFile(type, header, description);
|
||||||
|
// }
|
||||||
|
|
||||||
|
public static void logEvent(String type, String header, String description, int logLevel)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
header = getAnyContext().getResources().getString(R.string.app_name);
|
||||||
|
}
|
||||||
|
catch(NullPointerException e)
|
||||||
|
{
|
||||||
|
header = "Automation";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(type.equals("e"))
|
||||||
|
Log.e(header, description);
|
||||||
|
|
||||||
|
if(type.equals("w"))
|
||||||
|
Log.w(header, description);
|
||||||
|
|
||||||
|
if(type.equals("i"))
|
||||||
|
Log.i(header, description);
|
||||||
|
|
||||||
|
if(Settings.writeLogFile && Settings.logLevel >= logLevel)
|
||||||
|
{
|
||||||
|
writeToLogFile(type, header, description);
|
||||||
|
|
||||||
|
if(!logCleanerRunning && Math.random() < 0.1) // tidy up with 10% probability
|
||||||
|
{
|
||||||
|
rotateLogFile(getLogFile());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static boolean logCleanerRunning = false;
|
||||||
|
protected static void rotateLogFile(File logFile)
|
||||||
|
{
|
||||||
|
logCleanerRunning = true;
|
||||||
|
|
||||||
|
|
||||||
|
long maxSizeInBytes = (long)Settings.logFileMaxSize * 1024 * 1024;
|
||||||
|
|
||||||
|
if(logFile.exists() && logFile.length() > (maxSizeInBytes))
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "Logfile", "Cleaning up log file.", 3);
|
||||||
|
File archivedLogFile = new File(getWriteableFolder() + "/" + logFileName + "-old");
|
||||||
|
logFile.renameTo(archivedLogFile);
|
||||||
|
Miscellaneous.logEvent("i", "Logfile", "Cleaning up log file finished. Old log renamed to " + archivedLogFile.getAbsolutePath(), 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
logCleanerRunning = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static boolean testFolder(String folderPath)
|
||||||
|
{
|
||||||
|
File folder = new File(folderPath + "/" + Settings.folderName);
|
||||||
|
final String testFileName = "AutomationTestFile.txt";
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(folder.exists() || folder.mkdirs())
|
||||||
|
{
|
||||||
|
XmlFileInterface.migrateFilesFromRootToFolder(folderPath, folder.getAbsolutePath());
|
||||||
|
|
||||||
|
File testFile = new File(folder + "/" + testFileName);
|
||||||
|
if(!testFile.exists())
|
||||||
|
testFile.createNewFile();
|
||||||
|
|
||||||
|
if(testFile.canRead() && testFile.canWrite())
|
||||||
|
{
|
||||||
|
testFile.delete();
|
||||||
|
writeableFolderStringCache = testFile.getParent();
|
||||||
|
Miscellaneous.logEvent("i", "File", "Test of " + folder.getAbsolutePath() + " succeeded.", 3);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
Miscellaneous.logEvent("w", "File", "Test of " + folder.getAbsolutePath() + " failed.", 3);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getWriteableFolder()
|
||||||
|
{
|
||||||
|
if(writeableFolderStringCache == null)
|
||||||
|
{
|
||||||
|
String testPath = null;
|
||||||
|
File folder = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String[] foldersToTestArray = new String[]
|
||||||
|
{
|
||||||
|
Environment.getExternalStorageDirectory().getAbsolutePath(),
|
||||||
|
"/storage/emulated/0",
|
||||||
|
"/HWUserData",
|
||||||
|
"/mnt/sdcard"
|
||||||
|
};
|
||||||
|
|
||||||
|
for(String f : foldersToTestArray)
|
||||||
|
{
|
||||||
|
if (testFolder(f))
|
||||||
|
{
|
||||||
|
String pathToUse = f + "/" + Settings.folderName;
|
||||||
|
Miscellaneous.logEvent("i", "Path", "Using " + pathToUse + " to store settings and log.", 2);
|
||||||
|
// Toast.makeText(getAnyContext(), "Using " + pathToUse + " to store settings and log.", Toast.LENGTH_LONG).show();
|
||||||
|
return pathToUse;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Miscellaneous.logEvent("e", "getWritableFolder", folder.getAbsolutePath() + " does not exist and could not be created.", 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
Log.w("getWritableFolder", folder + " not writable.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// do not change to logEvent() - we can't write
|
||||||
|
Toast.makeText(getAnyContext(), "No writable folder could be found.", Toast.LENGTH_LONG).show();
|
||||||
|
Log.e("getWritableFolder", "No writable folder could be found.");
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return writeableFolderStringCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final static String logFileName = "Automation_logfile.txt";
|
||||||
|
protected static File getLogFile()
|
||||||
|
{
|
||||||
|
File logFile = null;
|
||||||
|
logFile = new File(getWriteableFolder() + "/" + logFileName);
|
||||||
|
if(!logFile.exists())
|
||||||
|
{
|
||||||
|
Log.i("LogFile", "Creating new logfile: " + logFile.getAbsolutePath());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
logFile.createNewFile();
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
Log.e("LogFile", "Error writing logs to file: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return logFile;
|
||||||
|
}
|
||||||
|
private static void writeToLogFile(String type, String header, String description)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
FileWriter fileWriter = new FileWriter(getLogFile(), true);
|
||||||
|
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
|
||||||
|
Date date = new Date();
|
||||||
|
|
||||||
|
bufferedWriter.write("\n" + date + ": " + type + " / " + header + " / " + description);
|
||||||
|
bufferedWriter.close();
|
||||||
|
|
||||||
|
// Log.i("LogFile", "Log entry written.");
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
Log.e("LogFile", "Error writing logs to file: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isAndroidEmulator()
|
||||||
|
{
|
||||||
|
String TAG = "EmulatorTest";
|
||||||
|
String model = Build.MODEL;
|
||||||
|
// Miscellaneous.logEvent("i", TAG, "model=" + model);
|
||||||
|
String product = Build.PRODUCT;
|
||||||
|
// Miscellaneous.logEvent("i", TAG, "product=" + product);
|
||||||
|
boolean isEmulator = false;
|
||||||
|
if (product != null)
|
||||||
|
{
|
||||||
|
isEmulator = product.equals("sdk") || product.contains("_sdk") || product.contains("sdk_");
|
||||||
|
}
|
||||||
|
// Miscellaneous.logEvent("i", TAG, "isEmulator=" + isEmulator);
|
||||||
|
return isEmulator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int compareTimes(Time time1, Time time2)
|
||||||
|
{
|
||||||
|
// Miscellaneous.logEvent("i", "TimeCompare", "To compare: " + time1.toString() + " / " + time2.toString());
|
||||||
|
|
||||||
|
if(time1.getHours() == time2.getHours() && time1.getMinutes() == time2.getMinutes())
|
||||||
|
{
|
||||||
|
// Miscellaneous.logEvent("i", "TimeCompare", "Times are equal.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(time1.getHours() > time2.getHours())
|
||||||
|
{
|
||||||
|
// Miscellaneous.logEvent("i", "TimeCompare", "Time1 is bigger/later by hours.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(time1.getHours() < time2.getHours())
|
||||||
|
{
|
||||||
|
// Miscellaneous.logEvent("i", "TimeCompare", "Time2 is bigger/later by hours.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(time1.getHours() == time2.getHours())
|
||||||
|
{
|
||||||
|
if(time1.getMinutes() < time2.getMinutes())
|
||||||
|
{
|
||||||
|
// Miscellaneous.logEvent("i", "TimeCompare", "Hours are equal. Time2 is bigger/later by minutes.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(time1.getMinutes() > time2.getMinutes())
|
||||||
|
{
|
||||||
|
// Miscellaneous.logEvent("i", "TimeCompare", "Hours are equal. Time1 is bigger/later by minutes.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Miscellaneous.logEvent("i", "TimeCompare", "Default return code. Shouldn't be here.", 5);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String convertStreamToString(InputStream is)
|
||||||
|
{
|
||||||
|
java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
|
||||||
|
return s.hasNext() ? s.next() : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Context getAnyContext()
|
||||||
|
{
|
||||||
|
Context returnContext;
|
||||||
|
|
||||||
|
returnContext = AutomationService.getInstance();
|
||||||
|
if(returnContext != null)
|
||||||
|
return returnContext;
|
||||||
|
|
||||||
|
returnContext = ActivityMainScreen.getActivityMainScreenInstance();
|
||||||
|
if(returnContext != null)
|
||||||
|
return returnContext;
|
||||||
|
|
||||||
|
returnContext = ActivityPermissions.getInstance().getApplicationContext();
|
||||||
|
if(returnContext != null)
|
||||||
|
return returnContext;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("NewApi")
|
||||||
|
public static String replaceVariablesInText(String source, Context context) throws Exception
|
||||||
|
{
|
||||||
|
// Replace variable with actual content
|
||||||
|
// Miscellaneous.logEvent("i", "Raw source", source);
|
||||||
|
if(source.contains("[uniqueid]"))
|
||||||
|
source = source.replace("[uniqueid]", Secure.getString(context.getContentResolver(), Secure.ANDROID_ID));
|
||||||
|
|
||||||
|
if(source.contains("[latitude]") | source.contains("[longitude]"))
|
||||||
|
{
|
||||||
|
if(LocationProvider.getLastKnownLocation() != null)
|
||||||
|
{
|
||||||
|
source = source.replace("[latitude]", String.valueOf(LocationProvider.getLastKnownLocation().getLatitude()));
|
||||||
|
source = source.replace("[longitude]", String.valueOf(LocationProvider.getLastKnownLocation().getLongitude()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("w", "TriggerURL", context.getResources().getString(R.string.triggerUrlReplacementPositionError), 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(source.contains("[phonenr]"))
|
||||||
|
{
|
||||||
|
String lastPhoneNr = PhoneStatusListener.getLastPhoneNumber();
|
||||||
|
|
||||||
|
if(lastPhoneNr != null && lastPhoneNr.length() > 0)
|
||||||
|
source = source.replace("[phonenr]", PhoneStatusListener.getLastPhoneNumber());
|
||||||
|
else
|
||||||
|
Miscellaneous.logEvent("w", "TriggerURL", context.getResources().getString(R.string.triggerUrlReplacementPositionError), 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(source.contains("[serialnr]"))
|
||||||
|
if(Build.VERSION.SDK_INT > 8)
|
||||||
|
source = source.replace("[serialnr]", Secure.getString(context.getContentResolver(), Build.SERIAL));
|
||||||
|
else
|
||||||
|
source = source.replace("[serialnr]", "serialUnknown");
|
||||||
|
|
||||||
|
if(
|
||||||
|
source.contains("[d]") |
|
||||||
|
source.contains("[m]") |
|
||||||
|
source.contains("[Y]") |
|
||||||
|
source.contains("[h]") |
|
||||||
|
source.contains("[H]") |
|
||||||
|
source.contains("[i]") |
|
||||||
|
source.contains("[s]") |
|
||||||
|
source.contains("[ms]")
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Calendar cal = Calendar.getInstance();
|
||||||
|
|
||||||
|
source = source.replace("[d]", String.valueOf(cal.get(Calendar.DAY_OF_MONTH)));
|
||||||
|
source = source.replace("[m]", String.valueOf(cal.get(Calendar.MONTH)));
|
||||||
|
source = source.replace("[Y]", String.valueOf(cal.get(Calendar.YEAR)));
|
||||||
|
source = source.replace("[h]", String.valueOf(cal.get(Calendar.HOUR)));
|
||||||
|
source = source.replace("[H]", String.valueOf(cal.get(Calendar.HOUR_OF_DAY)));
|
||||||
|
source = source.replace("[i]", String.valueOf(cal.get(Calendar.MINUTE)));
|
||||||
|
source = source.replace("[s]", String.valueOf(cal.get(Calendar.SECOND)));
|
||||||
|
source = source.replace("[ms]", String.valueOf(cal.get(Calendar.MILLISECOND)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Miscellaneous.logEvent("i", "URL after replace", source);
|
||||||
|
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write a log entry and exit the application, so the crash is actually visible.
|
||||||
|
* Might even cause the activity to be automatically restarted by the OS.
|
||||||
|
*/
|
||||||
|
public static UncaughtExceptionHandler uncaughtExceptionHandler = new UncaughtExceptionHandler()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void uncaughtException(Thread thread, Throwable ex)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "UncaughtException", Log.getStackTraceString(ex), 1);
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static AlertDialog messageBox(String title, String message, Context context)
|
||||||
|
{
|
||||||
|
AlertDialog.Builder alertDialog = new AlertDialog.Builder(context);
|
||||||
|
|
||||||
|
alertDialog.setTitle(title);
|
||||||
|
alertDialog.setMessage(message);
|
||||||
|
|
||||||
|
alertDialog.setPositiveButton("Ok", new DialogInterface.OnClickListener()
|
||||||
|
{
|
||||||
|
public void onClick(DialogInterface dialog, int whichButton)
|
||||||
|
{
|
||||||
|
dialog.dismiss();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// alertDialog.setNegativeButton(context.getResources().getString(R.string.cancel), new DialogInterface.OnClickListener()
|
||||||
|
// {
|
||||||
|
// public void onClick(DialogInterface dialog, int whichButton)
|
||||||
|
// {
|
||||||
|
// // Canceled.
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
|
return alertDialog.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the device is rooted.
|
||||||
|
*
|
||||||
|
* @return <code>true</code> if the device is rooted, <code>false</code> otherwise.
|
||||||
|
*/
|
||||||
|
public static boolean isPhoneRooted()
|
||||||
|
{
|
||||||
|
// get from build info
|
||||||
|
String buildTags = Build.TAGS;
|
||||||
|
if (buildTags != null && buildTags.contains("test-keys")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if /system/app/Superuser.apk is present
|
||||||
|
try
|
||||||
|
{
|
||||||
|
File file = new File("/system/app/Superuser.apk");
|
||||||
|
if (file.exists())
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e1)
|
||||||
|
{
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
// try executing commands
|
||||||
|
return canExecuteCommand("/system/xbin/which su")
|
||||||
|
||
|
||||||
|
canExecuteCommand("/system/bin/which su")
|
||||||
|
||
|
||||||
|
canExecuteCommand("which su");
|
||||||
|
}
|
||||||
|
|
||||||
|
// executes a command on the system
|
||||||
|
private static boolean canExecuteCommand(String command)
|
||||||
|
{
|
||||||
|
boolean executedSuccesfully;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Runtime.getRuntime().exec(command);
|
||||||
|
executedSuccesfully = true;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
executedSuccesfully = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return executedSuccesfully;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isNumeric(String str)
|
||||||
|
{
|
||||||
|
return str.matches("-?\\d+(\\.\\d+)?"); //match a number with optional '-' and decimal.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disables the SSL certificate checking for new instances of {@link HttpsURLConnection} This has been created to
|
||||||
|
* aid testing on a local box, not for use on production.
|
||||||
|
*/
|
||||||
|
private static void disableSSLCertificateChecking()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
SSLSocketFactory ssf = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
SSLContext ctx = SSLContext.getInstance("TLS");
|
||||||
|
|
||||||
|
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||||
|
trustStore.load(null, null);
|
||||||
|
ssf = new MySSLSocketFactoryInsecure(trustStore);
|
||||||
|
ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
|
||||||
|
ctx.init(null, null, null);
|
||||||
|
|
||||||
|
// return new DefaultHttpClient(ccm, client.getParams());
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
ex.printStackTrace();
|
||||||
|
// return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Install the all-trusting trust manager
|
||||||
|
SSLContext sc = SSLContext.getInstance("TLS");
|
||||||
|
sc.init(null, getInsecureTrustManager(), new java.security.SecureRandom());
|
||||||
|
// HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
|
||||||
|
// HttpsURLConnection.setDefaultSSLSocketFactory(ssf);
|
||||||
|
|
||||||
|
// Install the all-trusting host verifier
|
||||||
|
HttpsURLConnection.setDefaultHostnameVerifier(getInsecureHostnameVerifier());
|
||||||
|
HttpsURLConnection.setDefaultHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
|
||||||
|
}
|
||||||
|
catch (KeyManagementException e)
|
||||||
|
{
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
catch (NoSuchAlgorithmException e)
|
||||||
|
{
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TrustManager[] getInsecureTrustManager()
|
||||||
|
{
|
||||||
|
TrustManager[] trustAllCerts =
|
||||||
|
new TrustManager[]
|
||||||
|
{
|
||||||
|
new X509TrustManager()
|
||||||
|
{
|
||||||
|
public X509Certificate[] getAcceptedIssuers()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException
|
||||||
|
{
|
||||||
|
// Not implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException
|
||||||
|
{
|
||||||
|
// Not implemented
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return trustAllCerts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HostnameVerifier getInsecureHostnameVerifier()
|
||||||
|
{
|
||||||
|
HostnameVerifier allHostsValid = new HostnameVerifier()
|
||||||
|
{
|
||||||
|
public boolean verify(String hostname, SSLSession session)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return allHostsValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("NewApi")
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public static void createDismissableNotification(String textToDisplay, int notificationId, PendingIntent pendingIntent)
|
||||||
|
{
|
||||||
|
NotificationManager mNotificationManager = (NotificationManager) Miscellaneous.getAnyContext().getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
|
|
||||||
|
NotificationCompat.Builder dismissableNotificationBuilder = createDismissableNotificationBuilder(pendingIntent);
|
||||||
|
dismissableNotificationBuilder.setContentText(textToDisplay);
|
||||||
|
dismissableNotificationBuilder.setContentIntent(pendingIntent);
|
||||||
|
dismissableNotificationBuilder.setStyle(new NotificationCompat.BigTextStyle().bigText(textToDisplay));
|
||||||
|
|
||||||
|
Notification dismissableNotification = dismissableNotificationBuilder.build();
|
||||||
|
|
||||||
|
mNotificationManager.notify(notificationId, dismissableNotification);
|
||||||
|
|
||||||
|
/*NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
|
||||||
|
.setSmallIcon(R.drawable.ic_launcher) // notification icon
|
||||||
|
.setContentTitle("Notification!") // title for notification
|
||||||
|
.setContentText("Hello word") // message for notification
|
||||||
|
.setAutoCancel(true); // clear notification after click
|
||||||
|
Intent intent = new Intent(this, MainActivity.class);
|
||||||
|
PendingIntent pi = PendingIntent.getActivity(this,0,intent,Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
mBuilder.setContentIntent(pi);
|
||||||
|
NotificationManager mNotificationManager =
|
||||||
|
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
|
mNotificationManager.notify(0, dismissableNotification);*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/*protected static Notification.Builder createDismissableNotificationBuilder()
|
||||||
|
{
|
||||||
|
Notification.Builder builder = new Notification.Builder(AutomationService.getInstance());
|
||||||
|
builder.setContentTitle("Automation");
|
||||||
|
builder.setSmallIcon(R.drawable.ic_launcher);
|
||||||
|
builder.setCategory(Notification.CATEGORY_EVENT);
|
||||||
|
builder.setWhen(System.currentTimeMillis());
|
||||||
|
|
||||||
|
//static PendingIntent myPendingIntent = PendingIntent.getActivity(this, 0, myIntent, 0);
|
||||||
|
|
||||||
|
//builder.setContentIntent(myPendingIntent);
|
||||||
|
|
||||||
|
// Notification defaultNotification = new Notification();
|
||||||
|
*//* Notification defaultNotification = builder.build();
|
||||||
|
|
||||||
|
defaultNotification.icon = R.drawable.ic_launcher;
|
||||||
|
defaultNotification.when = System.currentTimeMillis();
|
||||||
|
|
||||||
|
// defaultNotification.defaults |= Notification.DEFAULT_VIBRATE;
|
||||||
|
// defaultNotification.defaults |= Notification.DEFAULT_LIGHTS;
|
||||||
|
|
||||||
|
defaultNotification.flags |= Notification.FLAG_AUTO_CANCEL;
|
||||||
|
// defaultNotification.flags |= Notification.FLAG_SHOW_LIGHTS;
|
||||||
|
defaultNotification.flags |= Notification.FLAG_ONLY_ALERT_ONCE;
|
||||||
|
|
||||||
|
// defaultNotification.ledARGB = Color.YELLOW;
|
||||||
|
// defaultNotification.ledOnMS = 1500;
|
||||||
|
// defaultNotification.ledOffMS = 1500;
|
||||||
|
*//*
|
||||||
|
return builder;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
protected static NotificationCompat.Builder createDismissableNotificationBuilder(PendingIntent myPendingIntent)
|
||||||
|
{
|
||||||
|
NotificationManager mNotificationManager = (NotificationManager) AutomationService.getInstance().getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
|
|
||||||
|
NotificationCompat.Builder builder;
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
|
||||||
|
{
|
||||||
|
NotificationChannel chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_LOW);
|
||||||
|
// chan.setLightColor(Color.BLUE);
|
||||||
|
// chan.enableVibration(false);
|
||||||
|
// chan.setSound(null, null);
|
||||||
|
chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
|
||||||
|
mNotificationManager.createNotificationChannel(chan);
|
||||||
|
|
||||||
|
builder = new NotificationCompat.Builder(AutomationService.getInstance(), NOTIFICATION_CHANNEL_ID);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
builder = new NotificationCompat.Builder(AutomationService.getInstance());
|
||||||
|
|
||||||
|
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
|
||||||
|
builder.setCategory(Notification.CATEGORY_SERVICE);
|
||||||
|
|
||||||
|
builder.setWhen(System.currentTimeMillis());
|
||||||
|
builder.setContentIntent(myPendingIntent);
|
||||||
|
|
||||||
|
builder.setContentTitle(AutomationService.getInstance().getResources().getString(R.string.app_name));
|
||||||
|
// builder.setOnlyAlertOnce(true);
|
||||||
|
|
||||||
|
builder.setSmallIcon(R.drawable.priority);
|
||||||
|
|
||||||
|
// builder.setContentText(textToDisplay);
|
||||||
|
// builder.setSmallIcon(icon);
|
||||||
|
// builder.setStyle(new NotificationCompat.BigTextStyle().bigText(textToDisplay));
|
||||||
|
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String explode(ArrayList<String> arrayList)
|
||||||
|
{
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
for(String s : arrayList)
|
||||||
|
builder.append(s);
|
||||||
|
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isGooglePlayInstalled(Context context)
|
||||||
|
{
|
||||||
|
// return false;
|
||||||
|
PackageManager pm = context.getPackageManager();
|
||||||
|
boolean app_installed = false;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PackageInfo info = pm.getPackageInfo("com.android.vending", PackageManager.GET_ACTIVITIES);
|
||||||
|
String label = (String) info.applicationInfo.loadLabel(pm);
|
||||||
|
app_installed = (label != null && !label.equals("Market"));
|
||||||
|
}
|
||||||
|
catch (PackageManager.NameNotFoundException e)
|
||||||
|
{
|
||||||
|
app_installed = false;
|
||||||
|
}
|
||||||
|
return app_installed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double round(double value, int places)
|
||||||
|
{
|
||||||
|
if (places < 0) throw new IllegalArgumentException();
|
||||||
|
|
||||||
|
BigDecimal bd = new BigDecimal(Double.toString(value));
|
||||||
|
bd = bd.setScale(places, RoundingMode.HALF_UP);
|
||||||
|
return bd.doubleValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getRealPathFromURI(Context context, Uri contentUri)
|
||||||
|
{
|
||||||
|
Cursor cursor = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String[] proj = { MediaStore.Images.Media.DATA };
|
||||||
|
cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
|
||||||
|
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
|
||||||
|
cursor.moveToFirst();
|
||||||
|
return cursor.getString(column_index);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "Uri", "getRealPathFromURI Exception : " + Log.getStackTraceString(e), 1);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (cursor != null)
|
||||||
|
{
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
57
app/src/main/java/com/jens/automation2/MyHttpClient.java
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package com.jens.automation2;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import org.apache.http.conn.ClientConnectionManager;
|
||||||
|
import org.apache.http.conn.scheme.PlainSocketFactory;
|
||||||
|
import org.apache.http.conn.scheme.Scheme;
|
||||||
|
import org.apache.http.conn.scheme.SchemeRegistry;
|
||||||
|
import org.apache.http.conn.ssl.SSLSocketFactory;
|
||||||
|
import org.apache.http.impl.client.DefaultHttpClient;
|
||||||
|
import org.apache.http.impl.conn.SingleClientConnManager;
|
||||||
|
|
||||||
|
import java.security.KeyStore;
|
||||||
|
|
||||||
|
public class MyHttpClient extends DefaultHttpClient
|
||||||
|
{
|
||||||
|
|
||||||
|
final Context context;
|
||||||
|
|
||||||
|
public MyHttpClient(Context context)
|
||||||
|
{
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ClientConnectionManager createClientConnectionManager()
|
||||||
|
{
|
||||||
|
SchemeRegistry registry = new SchemeRegistry();
|
||||||
|
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
|
||||||
|
// Register for port 443 our SSLSocketFactory with our keystore
|
||||||
|
// to the ConnectionManager
|
||||||
|
registry.register(new Scheme("https", newSslSocketFactory(), 443));
|
||||||
|
return new SingleClientConnManager(getParams(), registry);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SSLSocketFactory newSslSocketFactory()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Get an instance of the Bouncy Castle KeyStore format
|
||||||
|
KeyStore trusted = KeyStore.getInstance("BKS");
|
||||||
|
// Get the raw resource, which contains the keystore with
|
||||||
|
// your trusted certificates (root and any intermediate certs)
|
||||||
|
// Pass the keystore to the SSLSocketFactory. The factory is responsible
|
||||||
|
// for the verification of the server certificate.
|
||||||
|
SSLSocketFactory sf = new SSLSocketFactory(trusted);
|
||||||
|
// Hostname verification from certificate
|
||||||
|
// http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506
|
||||||
|
sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
|
||||||
|
return sf;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
package com.jens.automation2;
|
||||||
|
|
||||||
|
import org.apache.http.conn.ssl.SSLSocketFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.security.KeyManagementException;
|
||||||
|
import java.security.KeyStore;
|
||||||
|
import java.security.KeyStoreException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.UnrecoverableKeyException;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
import javax.net.ssl.TrustManager;
|
||||||
|
import javax.net.ssl.X509TrustManager;
|
||||||
|
|
||||||
|
public class MySSLSocketFactoryInsecure extends SSLSocketFactory
|
||||||
|
{
|
||||||
|
SSLContext sslContext = SSLContext.getInstance("TLS");
|
||||||
|
|
||||||
|
public MySSLSocketFactoryInsecure(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
|
||||||
|
super(truststore);
|
||||||
|
|
||||||
|
TrustManager tm = new X509TrustManager()
|
||||||
|
{
|
||||||
|
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public X509Certificate[] getAcceptedIssuers()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
sslContext.init(null, new TrustManager[] { tm }, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException
|
||||||
|
{
|
||||||
|
return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Socket createSocket() throws IOException
|
||||||
|
{
|
||||||
|
return sslContext.getSocketFactory().createSocket();
|
||||||
|
}
|
||||||
|
}
|
825
app/src/main/java/com/jens/automation2/PointOfInterest.java
Normal file
@ -0,0 +1,825 @@
|
|||||||
|
package com.jens.automation2;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.location.Criteria;
|
||||||
|
import android.location.Location;
|
||||||
|
import android.location.LocationListener;
|
||||||
|
import android.location.LocationManager;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Message;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.jens.automation2.Trigger.Trigger_Enum;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
public class PointOfInterest implements Comparable<PointOfInterest>
|
||||||
|
{
|
||||||
|
// The array containing all POIs
|
||||||
|
private static ArrayList<PointOfInterest> pointOfInterestCollection = new ArrayList<PointOfInterest>();
|
||||||
|
|
||||||
|
public static ArrayList<PointOfInterest> getPointOfInterestCollection()
|
||||||
|
{
|
||||||
|
Collections.sort(pointOfInterestCollection);
|
||||||
|
return pointOfInterestCollection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setPointOfInterestCollection(ArrayList<PointOfInterest> pointOfInterestCollection)
|
||||||
|
{
|
||||||
|
Collections.sort(pointOfInterestCollection);
|
||||||
|
PointOfInterest.pointOfInterestCollection = pointOfInterestCollection;
|
||||||
|
}
|
||||||
|
|
||||||
|
// name and location
|
||||||
|
private String name;
|
||||||
|
private Location location;
|
||||||
|
private double radius;
|
||||||
|
|
||||||
|
private String oldName;
|
||||||
|
private boolean activated=false;
|
||||||
|
|
||||||
|
private static Location[] locationRingBuffer = new Location[Settings.locationRingBufferSize];
|
||||||
|
private static int locationRingBufferLastPosition = -1;
|
||||||
|
|
||||||
|
private static boolean gpsLocationListenerArmed = false;
|
||||||
|
private static LocationManager gpsComparisonLocationManager;
|
||||||
|
private static GpsComparisonLocationListener gpsComparisonLocationListener;
|
||||||
|
private static TimeoutHandler timeoutHandler = new TimeoutHandler();
|
||||||
|
private static boolean timeoutHandlerActive = false;
|
||||||
|
public String getName()
|
||||||
|
{
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void stopRoutine()
|
||||||
|
{
|
||||||
|
if(gpsLocationListenerArmed)
|
||||||
|
stopGpsMeasurement();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String desiredName)
|
||||||
|
{
|
||||||
|
this.oldName = this.name;
|
||||||
|
this.name = desiredName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Location getLocation()
|
||||||
|
{
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLocation(Location location)
|
||||||
|
{
|
||||||
|
this.location = location;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getRadius()
|
||||||
|
{
|
||||||
|
return radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRadius(double radius, Context context) throws Exception
|
||||||
|
{
|
||||||
|
if(radius <= 0)
|
||||||
|
throw new Exception(context.getResources().getString(R.string.radiusHasToBePositive));
|
||||||
|
|
||||||
|
this.radius = radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setActivated(boolean value)
|
||||||
|
{
|
||||||
|
this.activated = value;
|
||||||
|
}
|
||||||
|
public boolean isActivated()
|
||||||
|
{
|
||||||
|
return activated;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void positionUpdate(Location newLocation, AutomationService parentService, boolean forceApply, boolean skipVerfication)
|
||||||
|
{
|
||||||
|
// StackTraceElement[] trace = Thread.currentThread().getStackTrace();
|
||||||
|
// for(StackTraceElement element : trace)
|
||||||
|
// {
|
||||||
|
// Log.i("Trace", Arrays.toString(trace));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Assumption "active POI = closest POI" is wrong!
|
||||||
|
|
||||||
|
if(newLocation != null)
|
||||||
|
{
|
||||||
|
String accuracyString = "n./a.";
|
||||||
|
if(newLocation.hasAccuracy())
|
||||||
|
accuracyString = String.valueOf(newLocation.getAccuracy() + " m");
|
||||||
|
Miscellaneous.logEvent("i", "POI", "Got position update (" + String.valueOf(newLocation.getLatitude()) + " / " + String.valueOf(newLocation.getLongitude()) + " / provider: " + newLocation.getProvider() + " / Accuracy: " + accuracyString + "), checking rules.", 2);
|
||||||
|
|
||||||
|
PointOfInterest closestPoi = PointOfInterest.getClosestPOI(newLocation);
|
||||||
|
|
||||||
|
if(getActivePoi() != null)
|
||||||
|
Miscellaneous.logEvent("i", "POI", "Active POI: " + getActivePoi().getName() + ", distance : " + String.valueOf(newLocation.distanceTo(getActivePoi().getLocation())), 4);
|
||||||
|
|
||||||
|
if(closestPoi == null)
|
||||||
|
{
|
||||||
|
// There are no POIs defined. Not much we can do.
|
||||||
|
// Miscellaneous.logEvent("i", "POI", "Closest POI: n/a, distance : n/a", 4);
|
||||||
|
Miscellaneous.logEvent("i", "POI", "Got position update, but there are no POIs defined. Can't trigger a rule.", 3);
|
||||||
|
// return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Miscellaneous.logEvent("i", "POI", "Closest POI: " + closestPoi.getName() + ", distance : " + String.valueOf(newLocation.distanceTo(closestPoi.getLocation())), 4);
|
||||||
|
|
||||||
|
if(
|
||||||
|
(getActivePoi() != null && getActivePoi().isActivated() && !getActivePoi().reachedPoiArea(newLocation))
|
||||||
|
|
|
||||||
|
(closestPoi != null && !closestPoi.isActivated() && closestPoi.reachedPoiArea(newLocation))
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// only an active POI can be left while only a closestPOI can be entered, hence the complex if/else
|
||||||
|
if(getActivePoi() != null && getActivePoi().isActivated() && !getActivePoi().reachedPoiArea(newLocation))
|
||||||
|
Miscellaneous.logEvent("i", "POI", "May have left POI " + getActivePoi().getName() + ", checking location accuracy...", 4);
|
||||||
|
if(closestPoi != null && !closestPoi.isActivated() && closestPoi.reachedPoiArea(newLocation))
|
||||||
|
Miscellaneous.logEvent("i", "POI", "May have entered POI " + closestPoi.getName() + ", checking location accuracy...", 4);
|
||||||
|
|
||||||
|
if(forceApply)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", parentService.getResources().getString(R.string.forcedLocationUpdate), parentService.getResources().getString(R.string.forcedLocationUpdateLong), 4);
|
||||||
|
|
||||||
|
// only an active POI can be left while only a closestPOI can be entered, hence the complex if/else
|
||||||
|
if(getActivePoi() != null && getActivePoi().isActivated() && !getActivePoi().reachedPoiArea(newLocation))
|
||||||
|
{
|
||||||
|
addPositionToRingBuffer(newLocation);
|
||||||
|
getActivePoi().deactivate(parentService);
|
||||||
|
}
|
||||||
|
if(closestPoi != null && !closestPoi.isActivated() && closestPoi.reachedPoiArea(newLocation))
|
||||||
|
{
|
||||||
|
addPositionToRingBuffer(newLocation);
|
||||||
|
closestPoi.activate(parentService);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(newLocation.hasAccuracy() && newLocation.getAccuracy() > Settings.satisfactoryAccuracyNetwork && !newLocation.getProvider().equals(LocationManager.GPS_PROVIDER))
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "POI", "Location update with unsatisfactory accuracy: " + String.valueOf(newLocation.getAccuracy()) + ", demanded: " + String.valueOf(Settings.satisfactoryAccuracyNetwork), 4);
|
||||||
|
if(!skipVerfication)
|
||||||
|
{
|
||||||
|
if(PointOfInterest.isPoiInRelevantRange(newLocation))
|
||||||
|
startGpsMeasurement(parentService);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "POI", "Applying update with unsatisfactory accuracy because no defined location is in a relevant range.", 4);
|
||||||
|
positionUpdate(newLocation, parentService, true, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "POI", "Location update with unsatisfactory accuracy, but skipping verfication as requested. Effectively ignoring this update. It's probably from a passive source. Verifying it would cost battery.", 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "POI", "Location update with acceptable accuracy.", 4);
|
||||||
|
/* It may be that a previous location wasn't accurate enough, we now got a better location via network,
|
||||||
|
* but the GPS listener is still active and trying to find out a precise location. We need to deactivate
|
||||||
|
* it if we are here
|
||||||
|
*/
|
||||||
|
if(gpsLocationListenerArmed)
|
||||||
|
stopGpsMeasurement();
|
||||||
|
|
||||||
|
// only an active POI can be left while only a closestPOI can be entered, hence the complex if/else
|
||||||
|
if(getActivePoi() != null && getActivePoi().isActivated() && !getActivePoi().reachedPoiArea(newLocation))
|
||||||
|
{
|
||||||
|
addPositionToRingBuffer(newLocation);
|
||||||
|
getActivePoi().deactivate(parentService);
|
||||||
|
}
|
||||||
|
if(closestPoi != null && !closestPoi.isActivated() && closestPoi.reachedPoiArea(newLocation))
|
||||||
|
{
|
||||||
|
addPositionToRingBuffer(newLocation);
|
||||||
|
closestPoi.activate(parentService);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Miscellaneous.logEvent("e", "POI", "Given location is null. Aborting.", 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean reachedPoiArea(Location currentLocation)
|
||||||
|
{
|
||||||
|
float distance = this.location.distanceTo(currentLocation);
|
||||||
|
|
||||||
|
if(distance < this.radius)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void activate(AutomationService parentService)
|
||||||
|
{
|
||||||
|
if(!this.isActivated())
|
||||||
|
{
|
||||||
|
// Deactivate all others in case nobody deactivated them
|
||||||
|
for(int i = 0; i < pointOfInterestCollection.size(); i++)
|
||||||
|
pointOfInterestCollection.get(i).deactivate(parentService);
|
||||||
|
|
||||||
|
/*
|
||||||
|
ConcurrentModificationErrors have been seen when using this method: for(PointOfInterest onePoi : pointOfInterestCollection)
|
||||||
|
|
||||||
|
Tue Nov 20 19:21:50 GMT+01:00 2018: e / Automation / java.util.ConcurrentModificationException
|
||||||
|
at java.util.ArrayList$Itr.next(ArrayList.java:860)
|
||||||
|
at com.jens.automation2.PointOfInterest.activate(PointOfInterest.java:227)
|
||||||
|
at com.jens.automation2.PointOfInterest.positionUpdate(PointOfInterest.java:199)
|
||||||
|
at com.jens.automation2.location.LocationProvider.setCurrentLocation(LocationProvider.java:126)
|
||||||
|
at com.jens.automation2.location.LocationProvider$MyPassiveLocationListener.onLocationChanged(LocationProvider.java:289)
|
||||||
|
at android.location.LocationManager$ListenerTransport._handleMessage(LocationManager.java:291)
|
||||||
|
at android.location.LocationManager$ListenerTransport.-wrap0(Unknown Source:0)
|
||||||
|
at android.location.LocationManager$ListenerTransport$1.handleMessage(LocationManager.java:236)
|
||||||
|
at android.os.Handler.dispatchMessage(Handler.java:105)
|
||||||
|
at android.os.Looper.loop(Looper.java:164)
|
||||||
|
at android.app.ActivityThread.main(ActivityThread.java:6944)
|
||||||
|
at java.lang.reflect.Method.invoke(Native Method)
|
||||||
|
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
|
||||||
|
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)
|
||||||
|
*/
|
||||||
|
|
||||||
|
this.activated = true;
|
||||||
|
Settings.lastActivePoi = this;
|
||||||
|
Settings.writeSettings(parentService);
|
||||||
|
|
||||||
|
Miscellaneous.logEvent("i", "POI", "Reached POI " + this.getName() + ". Checking if there's a rule that applies to that.", 2);
|
||||||
|
|
||||||
|
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByPoi(this, true);
|
||||||
|
if(ruleCandidates.size()==0)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "POI", "POI " + this.getName() + " not found in ANY rule.", 2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "POI", "POI " + this.getName() + " found in " + ruleCandidates.size() + " rule(s).", 2);
|
||||||
|
|
||||||
|
for(int i=0; i<ruleCandidates.size(); i++)
|
||||||
|
{
|
||||||
|
if(ruleCandidates.get(i).applies(parentService) && ruleCandidates.get(i).haveEnoughPermissions())
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "POI", "Rule " + ruleCandidates.get(i).getName() + " applies for entering POI " + this.getName() + ".", 2);
|
||||||
|
ruleCandidates.get(i).activate(parentService, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parentService.updateNotification();
|
||||||
|
ActivityMainScreen.updateMainScreen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void deactivate(AutomationService parentService)
|
||||||
|
{
|
||||||
|
if(this.isActivated())
|
||||||
|
{
|
||||||
|
this.activated=false; //has to stay before Rule.applies()
|
||||||
|
Settings.lastActivePoi = null;
|
||||||
|
Settings.writeSettings(parentService);
|
||||||
|
|
||||||
|
Miscellaneous.logEvent("i", "POI", "Left POI " + this.getName() + ". Checking if there's a rule that applies to that.", 2);
|
||||||
|
|
||||||
|
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByPoi(this, false);
|
||||||
|
if(ruleCandidates.size()==0)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "POI", "POI " + this.getName() + " not found in ANY rule.", 2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "POI", "POI " + this.getName() + " found in " + ruleCandidates.size() + " rule(s).", 2);
|
||||||
|
for(int i=0; i<ruleCandidates.size(); i++)
|
||||||
|
{
|
||||||
|
if(ruleCandidates.get(i).applies(parentService))
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "POI", "Rule " + ruleCandidates.get(i).getName() + " applies for leaving POI " + this.getName() + ".", 2);
|
||||||
|
ruleCandidates.get(i).activate(parentService, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parentService.updateNotification();
|
||||||
|
ActivityMainScreen.updateMainScreen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PointOfInterest getClosestPOI(Location currentLocation)// throws Exception
|
||||||
|
{
|
||||||
|
// return the currently closed one of all saved points of interest
|
||||||
|
|
||||||
|
if(pointOfInterestCollection.size() == 0)
|
||||||
|
{
|
||||||
|
//throw new Exception("No points of interest defined.");
|
||||||
|
//Toast.makeText(context, "No points of interest defined.", Toast.LENGTH_LONG).show();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else if(pointOfInterestCollection.size() == 1)
|
||||||
|
return pointOfInterestCollection.get(0);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
double distance = pointOfInterestCollection.get(0).location.distanceTo(currentLocation);
|
||||||
|
PointOfInterest closestPoi = pointOfInterestCollection.get(0);
|
||||||
|
|
||||||
|
distance = (int) currentLocation.distanceTo(pointOfInterestCollection.get(0).location);
|
||||||
|
|
||||||
|
for(int i=1; i<pointOfInterestCollection.size(); i++)
|
||||||
|
{
|
||||||
|
if(currentLocation.distanceTo(pointOfInterestCollection.get(i).location) < distance)
|
||||||
|
{
|
||||||
|
distance = currentLocation.distanceTo(pointOfInterestCollection.get(i).location);
|
||||||
|
closestPoi = pointOfInterestCollection.get(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return closestPoi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Determines if a POI is in any relevant range. Doesn't say if one is
|
||||||
|
* reached, but can help decide if it's worth activating GPS to be sure.
|
||||||
|
* @param currentLocation
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static boolean isPoiInRelevantRange(Location currentLocation)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Radius
|
||||||
|
* + Precision
|
||||||
|
* + Self defined value
|
||||||
|
*/
|
||||||
|
|
||||||
|
double distance;
|
||||||
|
double minimumDistance;
|
||||||
|
|
||||||
|
for(PointOfInterest poi : PointOfInterest.getPointOfInterestCollection())
|
||||||
|
{
|
||||||
|
distance = poi.getLocation().distanceTo(currentLocation);
|
||||||
|
if(currentLocation.hasAccuracy())
|
||||||
|
minimumDistance = currentLocation.getAccuracy();
|
||||||
|
else
|
||||||
|
minimumDistance = 0;
|
||||||
|
|
||||||
|
minimumDistance += poi.getRadius();
|
||||||
|
|
||||||
|
if(distance < minimumDistance)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "POI", String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.poiCouldBeInRange), poi.getName()), 4);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void loadPoisFromFile()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(XmlFileInterface.settingsFile.exists())
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "POI", "SettingsFile " + XmlFileInterface.settingsFile.getPath() + " exists. Loading POIs from File.", 4);
|
||||||
|
XmlFileInterface.readFile();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("w", "POI", "SettingsFile " + XmlFileInterface.settingsFile.getPath() + " doesn't exist.", 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static boolean writePoisToFile()
|
||||||
|
{
|
||||||
|
return XmlFileInterface.writeFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return this.getName();
|
||||||
|
}
|
||||||
|
public String toStringLong()
|
||||||
|
{
|
||||||
|
return this.name + ": " + String.valueOf(this.radius) + " meters around " + String.valueOf(this.location.getLatitude() + " / " + String.valueOf(this.location.getLongitude()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean create(Context context)
|
||||||
|
{
|
||||||
|
for(PointOfInterest poi : PointOfInterest.pointOfInterestCollection)
|
||||||
|
if(poi.getName().equals(this.getName()))
|
||||||
|
{
|
||||||
|
Toast.makeText(context, context.getResources().getString(R.string.anotherPoiByThatName), Toast.LENGTH_LONG).show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(plausibilityCheck())
|
||||||
|
{
|
||||||
|
PointOfInterest.pointOfInterestCollection.add(this);
|
||||||
|
PointOfInterest.writePoisToFile();
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
public boolean change(Context context)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Check for change of rule name START
|
||||||
|
*/
|
||||||
|
if (this.oldName != null && !this.oldName.equals(this.name)) // catch oldName being null
|
||||||
|
{
|
||||||
|
//Name has changed. We need to look for rules that reference it by its name and update those references
|
||||||
|
|
||||||
|
// Check if the name is still available
|
||||||
|
int counter = 0; // this method should only be a temporary workaround, directly editing the referenced object may cause problems until reloading the config file
|
||||||
|
for (PointOfInterest poi : PointOfInterest.pointOfInterestCollection)
|
||||||
|
if (poi.getName().equals(this.getName()))
|
||||||
|
{
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
if (counter > 1)
|
||||||
|
{
|
||||||
|
Toast.makeText(context, context.getResources().getString(R.string.anotherPoiByThatName), Toast.LENGTH_LONG).show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if rules reference this poi
|
||||||
|
ArrayList<Rule> rulesThatReferenceMe = Rule.findRuleCandidatesByPoi(this);
|
||||||
|
if (rulesThatReferenceMe.size() > 0)
|
||||||
|
{
|
||||||
|
for (Rule oneRule : rulesThatReferenceMe)
|
||||||
|
{
|
||||||
|
for (Trigger oneTrigger : oneRule.getTriggerSet())
|
||||||
|
{
|
||||||
|
if (oneTrigger.getTriggerType() == Trigger_Enum.pointOfInterest)
|
||||||
|
{
|
||||||
|
oneTrigger.setPointOfInterest(this);
|
||||||
|
// We don't need to save the file. This will happen anyway in PointOfInterest.writePoisToFile() below.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
Check for change of rule name END
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (plausibilityCheck())
|
||||||
|
{
|
||||||
|
if(PointOfInterest.writePoisToFile())
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
Toast.makeText(context, context.getResources().getString(R.string.unknownError), Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
public boolean delete(Context context)
|
||||||
|
{
|
||||||
|
//Check if there's a rule that contains this poi
|
||||||
|
ArrayList<Rule> rulesThatReferenceMe = Rule.findRuleCandidatesByPoi(this);
|
||||||
|
if(rulesThatReferenceMe.size() > 0)
|
||||||
|
{
|
||||||
|
String rulesString = "";
|
||||||
|
for(Rule rule : rulesThatReferenceMe)
|
||||||
|
rulesString += rule.getName() + "; ";
|
||||||
|
|
||||||
|
rulesString = rulesString.substring(0, rulesString.length()-2);
|
||||||
|
|
||||||
|
Toast.makeText(context, String.format(context.getResources().getString(R.string.poiStillReferenced), rulesString), Toast.LENGTH_LONG).show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PointOfInterest.pointOfInterestCollection.remove(this);
|
||||||
|
PointOfInterest.writePoisToFile();
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PointOfInterest getByName(String searchName) throws Exception
|
||||||
|
{
|
||||||
|
for(PointOfInterest poi : pointOfInterestCollection)
|
||||||
|
{
|
||||||
|
if(poi.name.equals(searchName))
|
||||||
|
return poi;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception("PointOfInterest with name " + searchName + " not found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String[] getNamesInArray()
|
||||||
|
{
|
||||||
|
ArrayList<String> nameList = new ArrayList<String>();
|
||||||
|
for(PointOfInterest poi : pointOfInterestCollection)
|
||||||
|
{
|
||||||
|
nameList.add(poi.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (String[])nameList.toArray(new String[pointOfInterestCollection.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PointOfInterest getActivePoi()
|
||||||
|
{
|
||||||
|
for(PointOfInterest poi : PointOfInterest.pointOfInterestCollection)
|
||||||
|
{
|
||||||
|
if(poi.isActivated())
|
||||||
|
return poi;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(PointOfInterest another)
|
||||||
|
{
|
||||||
|
return this.getName().compareTo(another.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean addPositionToRingBuffer(Location newLocation)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* This method's purpose is to record the last n positions and check if they are different.
|
||||||
|
* In reality you will never get the exact same position twice. If you do the location engine
|
||||||
|
* seems to have hung up.
|
||||||
|
*/
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(++locationRingBufferLastPosition > locationRingBuffer.length-1)
|
||||||
|
locationRingBufferLastPosition = 0;
|
||||||
|
|
||||||
|
Miscellaneous.logEvent("i", "Ringbuffer.", "Adding location " + String.valueOf(newLocation.getLatitude()) + " / " + String.valueOf(newLocation.getLongitude()) + " to ringbuffer at index " + String.valueOf(locationRingBufferLastPosition), 5);
|
||||||
|
locationRingBuffer[locationRingBufferLastPosition] = newLocation;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return values:
|
||||||
|
* true if the new location is different to the last one
|
||||||
|
* false if we get repeated values, comparing all values
|
||||||
|
*
|
||||||
|
* false indicates problems with hangups in getting locations.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int counter = locationRingBufferLastPosition+1-1; // make a copy, not a reference
|
||||||
|
int previousIndex;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if(counter>0)
|
||||||
|
previousIndex = counter-1;
|
||||||
|
else
|
||||||
|
previousIndex = Settings.locationRingBufferSize-1;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(locationRingBuffer[counter].getLatitude() != locationRingBuffer[previousIndex].getLatitude() | locationRingBuffer[counter].getLongitude() != locationRingBuffer[previousIndex].getLongitude())
|
||||||
|
{
|
||||||
|
// If location different from last one we're fine.
|
||||||
|
Miscellaneous.logEvent("w", "Ringbuffer.", "Location has changed from the last one. We\'re fine.", 5);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(NullPointerException ne)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Just null pointer exception. Ringbuffer isn't filled to its maximum, yet.
|
||||||
|
*/
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(counter>0)
|
||||||
|
counter--;
|
||||||
|
else
|
||||||
|
counter = Settings.locationRingBufferSize-1;
|
||||||
|
} while(counter != locationRingBufferLastPosition);
|
||||||
|
|
||||||
|
Miscellaneous.logEvent("w", "Ringbuffer", "Location has not changed from the last one. Something\'s odd. Maybe the location engine kind of hung up.", 2);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch(ArrayIndexOutOfBoundsException e)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "Ringbuffer", "Probably not enough values, yet.", 5);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "Ringbuffer", "Error in ringbuffer: " + Log.getStackTraceString(e), 4);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class GpsComparisonLocationListener implements LocationListener
|
||||||
|
{
|
||||||
|
public AutomationService parent = null;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLocationChanged(Location up2DateLocation)
|
||||||
|
{
|
||||||
|
stopGpsMeasurement();
|
||||||
|
|
||||||
|
PointOfInterest.positionUpdate(up2DateLocation, parent, true, false);
|
||||||
|
|
||||||
|
Miscellaneous.logEvent("i", "LocationListener", "Disarmed location listener, accuracy reached", 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void startGpsMeasurement(AutomationService parentService)
|
||||||
|
{
|
||||||
|
// Arm location updates
|
||||||
|
if(!gpsLocationListenerArmed)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "PointOfInterest", "Unsatisfactory accuracy of network location. Performing comparison measurement via GPS.", 3);
|
||||||
|
|
||||||
|
String myGpsComparisonProviderName;
|
||||||
|
|
||||||
|
if(Settings.privacyLocationing)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "PointOfInterest", parentService.getResources().getString(R.string.enforcingGps), 4);
|
||||||
|
myGpsComparisonProviderName = LocationManager.GPS_PROVIDER;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Miscellaneous.logEvent("i", "PointOfInterest", parentService.getResources().getString(R.string.notEnforcingGps), 4);
|
||||||
|
Criteria crit = new Criteria();
|
||||||
|
// crit.setPowerRequirement(Criteria.POWER_LOW);
|
||||||
|
// crit.setAltitudeRequired(false);
|
||||||
|
// crit.setSpeedRequired(false);
|
||||||
|
// crit.setBearingRequired(false);
|
||||||
|
crit.setCostAllowed(true);
|
||||||
|
crit.setAccuracy(Criteria.ACCURACY_FINE);
|
||||||
|
gpsComparisonLocationManager = (LocationManager)parentService.getSystemService(parentService.LOCATION_SERVICE);
|
||||||
|
myGpsComparisonProviderName = gpsComparisonLocationManager.getBestProvider(crit, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Miscellaneous.logEvent("i", "LocationListener", "Arming location listener, Provider: " + myGpsComparisonProviderName, 4);
|
||||||
|
gpsComparisonLocationListener = new GpsComparisonLocationListener();
|
||||||
|
gpsComparisonLocationListener.parent = parentService;
|
||||||
|
gpsComparisonLocationManager.requestLocationUpdates(myGpsComparisonProviderName, Settings.minimumTimeBetweenUpdate, Settings.minimumDistanceChangeForNetworkUpdate, gpsComparisonLocationListener);
|
||||||
|
gpsLocationListenerArmed = true;
|
||||||
|
|
||||||
|
// set timeout
|
||||||
|
Message message = new Message();
|
||||||
|
message.what = 1;
|
||||||
|
Miscellaneous.logEvent("i", parentService.getResources().getString(R.string.gpsComparison), parentService.getResources().getString(R.string.startingGpsTimeout), 4);
|
||||||
|
if(timeoutHandler.parentService == null)
|
||||||
|
timeoutHandler.parentService = parentService;
|
||||||
|
timeoutHandler.sendMessageDelayed(message, Settings.gpsTimeout * 1000);
|
||||||
|
timeoutHandlerActive = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Miscellaneous.logEvent("i", "PointOfInterest", "Comparison measurement via GPS requested, but already active.", 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void stopGpsMeasurement()
|
||||||
|
{
|
||||||
|
if(gpsLocationListenerArmed)
|
||||||
|
{
|
||||||
|
gpsComparisonLocationManager.removeUpdates(gpsComparisonLocationListener);
|
||||||
|
gpsLocationListenerArmed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(timeoutHandlerActive)
|
||||||
|
{
|
||||||
|
timeoutHandler.removeMessages(1);
|
||||||
|
timeoutHandlerActive = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class TimeoutHandler extends Handler
|
||||||
|
{
|
||||||
|
public AutomationService parentService = null;
|
||||||
|
public Location locationToApplyIfGpsFails = null;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message msg)
|
||||||
|
{
|
||||||
|
super.handleMessage(msg);
|
||||||
|
|
||||||
|
if(msg.what == 1)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", parentService.getResources().getString(R.string.gpsComparison), parentService.getResources().getString(R.string.gpsComparisonTimeoutStop), 4);
|
||||||
|
stopGpsMeasurement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean plausibilityCheck()
|
||||||
|
{
|
||||||
|
double distance, minimumDistance, overlap;
|
||||||
|
|
||||||
|
if(this.getName().equals("null"))
|
||||||
|
{
|
||||||
|
// Invalid name
|
||||||
|
String text = Miscellaneous.getAnyContext().getResources().getString(R.string.invalidPoiName);
|
||||||
|
Miscellaneous.logEvent("w", "POI", text, 2);
|
||||||
|
Toast.makeText(Miscellaneous.getAnyContext(), text, Toast.LENGTH_LONG).show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(PointOfInterest otherPoi : this.getPointOfInterestCollection())
|
||||||
|
{
|
||||||
|
distance = otherPoi.getLocation().distanceTo(this.getLocation());
|
||||||
|
minimumDistance = otherPoi.getRadius()/2 + this.getRadius()/2;
|
||||||
|
overlap = Math.round(Math.abs(distance - minimumDistance));
|
||||||
|
|
||||||
|
if(distance <= minimumDistance && !otherPoi.getName().equals(this.getName()))
|
||||||
|
{
|
||||||
|
String text = String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.overlapBetweenPois), otherPoi.getName(), String.valueOf(overlap));
|
||||||
|
Miscellaneous.logEvent("w", "POI", text, 2);
|
||||||
|
Toast.makeText(Miscellaneous.getAnyContext(), text, Toast.LENGTH_LONG).show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Miscellaneous.logEvent("w", "POI", Miscellaneous.getAnyContext().getResources().getString(R.string.noOverLap), 2);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean reachedPoiWithActivateWifiRule()
|
||||||
|
{
|
||||||
|
PointOfInterest activePoi = PointOfInterest.getActivePoi();
|
||||||
|
if(activePoi != null)
|
||||||
|
{
|
||||||
|
for(Rule rule : Rule.findRuleCandidatesByPoi(activePoi, true))
|
||||||
|
{
|
||||||
|
for(Action action : rule.getActionSet())
|
||||||
|
{
|
||||||
|
if(action.getAction().equals(Action.Action_Enum.setWifi) && action.getParameter1())
|
||||||
|
{
|
||||||
|
// We are at a POI that specifies to enable wifi.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
543
app/src/main/java/com/jens/automation2/Profile.java
Normal file
@ -0,0 +1,543 @@
|
|||||||
|
package com.jens.automation2;
|
||||||
|
|
||||||
|
import android.content.ContentValues;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.media.AudioManager;
|
||||||
|
import android.media.RingtoneManager;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.provider.MediaStore;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.jens.automation2.Action.Action_Enum;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class Profile implements Comparable<Profile>
|
||||||
|
{
|
||||||
|
protected static ArrayList<Profile> profileCollection = new ArrayList<Profile>();
|
||||||
|
|
||||||
|
protected String name;
|
||||||
|
protected String oldName;
|
||||||
|
|
||||||
|
protected boolean changeSoundMode;
|
||||||
|
protected int soundMode;
|
||||||
|
|
||||||
|
boolean changeVolumeMusicVideoGameMedia;
|
||||||
|
protected int volumeMusic;
|
||||||
|
|
||||||
|
protected boolean changeVolumeNotifications;
|
||||||
|
protected int volumeNotifications;
|
||||||
|
|
||||||
|
protected boolean changeVolumeAlarms;
|
||||||
|
protected int volumeAlarms;
|
||||||
|
|
||||||
|
protected boolean changeIncomingCallsRingtone;
|
||||||
|
protected File incomingCallsRingtone;
|
||||||
|
|
||||||
|
protected boolean changeVibrateWhenRinging;
|
||||||
|
protected boolean vibrateWhenRinging;
|
||||||
|
|
||||||
|
protected boolean changeNotificationRingtone;
|
||||||
|
protected File notificationRingtone;
|
||||||
|
|
||||||
|
protected boolean changeAudibleSelection;
|
||||||
|
protected boolean audibleSelection;
|
||||||
|
|
||||||
|
protected boolean changeScreenLockUnlockSound;
|
||||||
|
boolean screenLockUnlockSound;
|
||||||
|
|
||||||
|
protected boolean changeHapticFeedback;
|
||||||
|
protected boolean hapticFeedback;
|
||||||
|
|
||||||
|
|
||||||
|
public void setName(String name)
|
||||||
|
{
|
||||||
|
this.oldName = this.name;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName()
|
||||||
|
{
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChangeSoundMode(boolean changeSoundMode)
|
||||||
|
{
|
||||||
|
this.changeSoundMode = changeSoundMode;
|
||||||
|
}
|
||||||
|
public boolean getChangeSoundMode()
|
||||||
|
{
|
||||||
|
return changeSoundMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSoundMode(int soundMode)
|
||||||
|
{
|
||||||
|
this.soundMode = soundMode;
|
||||||
|
}
|
||||||
|
public int getSoundMode()
|
||||||
|
{
|
||||||
|
return soundMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChangeVolumeMusicVideoGameMedia(boolean changeVolumeMusicVideoGameMedia)
|
||||||
|
{
|
||||||
|
this.changeVolumeMusicVideoGameMedia = changeVolumeMusicVideoGameMedia;
|
||||||
|
}
|
||||||
|
public boolean getChangeVolumeMusicVideoGameMedia()
|
||||||
|
{
|
||||||
|
return changeVolumeMusicVideoGameMedia;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVolumeMusic(int volumeMusic)
|
||||||
|
{
|
||||||
|
this.volumeMusic = volumeMusic;
|
||||||
|
}
|
||||||
|
public int getVolumeMusic()
|
||||||
|
{
|
||||||
|
return volumeMusic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChangeVolumeNotifications(boolean changeVolumeRingtoneNotifications)
|
||||||
|
{
|
||||||
|
this.changeVolumeNotifications = changeVolumeRingtoneNotifications;
|
||||||
|
}
|
||||||
|
public boolean getChangeVolumeNotifications()
|
||||||
|
{
|
||||||
|
return changeVolumeNotifications;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVolumeNotifications(int volumeNotifications)
|
||||||
|
{
|
||||||
|
this.volumeNotifications = volumeNotifications;
|
||||||
|
}
|
||||||
|
public int getVolumeNotifications()
|
||||||
|
{
|
||||||
|
return volumeNotifications;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChangeVolumeAlarms(boolean changeVolumeAlarms)
|
||||||
|
{
|
||||||
|
this.changeVolumeAlarms = changeVolumeAlarms;
|
||||||
|
}
|
||||||
|
public boolean getChangeVolumeAlarms()
|
||||||
|
{
|
||||||
|
return changeVolumeAlarms;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVolumeAlarms(int volumeAlarms)
|
||||||
|
{
|
||||||
|
this.volumeAlarms = volumeAlarms;
|
||||||
|
}
|
||||||
|
public int getVolumeAlarms()
|
||||||
|
{
|
||||||
|
return volumeAlarms;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChangeIncomingCallsRingtone(boolean changeIncomingCallsRingtone)
|
||||||
|
{
|
||||||
|
this.changeIncomingCallsRingtone = changeIncomingCallsRingtone;
|
||||||
|
}
|
||||||
|
public boolean getChangeIncomingCallsRingtone()
|
||||||
|
{
|
||||||
|
return changeIncomingCallsRingtone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIncomingCallsRingtone(File incomingCallsRingtone)
|
||||||
|
{
|
||||||
|
this.incomingCallsRingtone = incomingCallsRingtone;
|
||||||
|
}
|
||||||
|
public File getIncomingCallsRingtone()
|
||||||
|
{
|
||||||
|
return incomingCallsRingtone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChangeVibrateWhenRinging(boolean changeVibrateWhenRinging)
|
||||||
|
{
|
||||||
|
this.changeVibrateWhenRinging = changeVibrateWhenRinging;
|
||||||
|
}
|
||||||
|
public boolean getChangeVibrateWhenRinging()
|
||||||
|
{
|
||||||
|
return changeVibrateWhenRinging;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVibrateWhenRinging(boolean vibrateWhenRinging)
|
||||||
|
{
|
||||||
|
this.vibrateWhenRinging = vibrateWhenRinging;
|
||||||
|
}
|
||||||
|
public boolean getVibrateWhenRinging()
|
||||||
|
{
|
||||||
|
return vibrateWhenRinging;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChangeNotificationRingtone(boolean changeNotificationRingtone)
|
||||||
|
{
|
||||||
|
this.changeNotificationRingtone = changeNotificationRingtone;
|
||||||
|
}
|
||||||
|
public boolean getChangeNotificationRingtone()
|
||||||
|
{
|
||||||
|
return changeNotificationRingtone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNotificationRingtone(File notificationsRingtone)
|
||||||
|
{
|
||||||
|
this.notificationRingtone = notificationsRingtone;
|
||||||
|
}
|
||||||
|
public File getNotificationRingtone()
|
||||||
|
{
|
||||||
|
return notificationRingtone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChangeAudibleSelection(boolean changeAudibleSelection)
|
||||||
|
{
|
||||||
|
this.changeAudibleSelection = changeAudibleSelection;
|
||||||
|
}
|
||||||
|
public boolean getChangeAudibleSelection()
|
||||||
|
{
|
||||||
|
return changeAudibleSelection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAudibleSelection(boolean audibleSelection)
|
||||||
|
{
|
||||||
|
this.audibleSelection = audibleSelection;
|
||||||
|
}
|
||||||
|
public boolean getAudibleSelection()
|
||||||
|
{
|
||||||
|
return audibleSelection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChangeScreenLockUnlockSound(boolean changeScreenLockUnlockSound)
|
||||||
|
{
|
||||||
|
this.changeScreenLockUnlockSound = changeScreenLockUnlockSound;
|
||||||
|
}
|
||||||
|
public boolean getChangeScreenLockUnlockSound()
|
||||||
|
{
|
||||||
|
return changeScreenLockUnlockSound;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScreenLockUnlockSound(boolean screenLockUnlockSound)
|
||||||
|
{
|
||||||
|
this.screenLockUnlockSound = screenLockUnlockSound;
|
||||||
|
}
|
||||||
|
public boolean getScreenLockUnlockSound()
|
||||||
|
{
|
||||||
|
return screenLockUnlockSound;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChangeHapticFeedback(boolean changeHapticFeedback)
|
||||||
|
{
|
||||||
|
this.changeHapticFeedback = changeHapticFeedback;
|
||||||
|
}
|
||||||
|
public boolean getChangeHapticFeedback()
|
||||||
|
{
|
||||||
|
return changeHapticFeedback;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHapticFeedback(boolean hapticFeedback)
|
||||||
|
{
|
||||||
|
this.hapticFeedback = hapticFeedback;
|
||||||
|
}
|
||||||
|
public boolean getHapticFeedback()
|
||||||
|
{
|
||||||
|
return hapticFeedback;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ArrayList<Profile> getProfileCollection()
|
||||||
|
{
|
||||||
|
return profileCollection;
|
||||||
|
}
|
||||||
|
public static ArrayList<String> getProfileCollectionString()
|
||||||
|
{
|
||||||
|
ArrayList<String> returnList = new ArrayList<String>();
|
||||||
|
for(Profile p : profileCollection)
|
||||||
|
returnList.add(p.getName());
|
||||||
|
|
||||||
|
return returnList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Profile getByName(String name)
|
||||||
|
{
|
||||||
|
for(Profile p : Profile.getProfileCollection())
|
||||||
|
if(p.getName().equals(name))
|
||||||
|
return p;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean delete(AutomationService myAutomationService)
|
||||||
|
{
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean applyRingTone(File ringtoneFile, int ringtoneType, Context context)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "Profile", "Request to set ringtone to " + ringtoneFile.getAbsolutePath(), 3);
|
||||||
|
|
||||||
|
if(!ringtoneFile.exists() | !ringtoneFile.canRead())
|
||||||
|
{
|
||||||
|
String message = "Ringtone file does not exist or cannot read it: " + ringtoneFile.getAbsolutePath();
|
||||||
|
Miscellaneous.logEvent("i", "Profile", message, 3);
|
||||||
|
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put(MediaStore.MediaColumns.DATA, ringtoneFile.getAbsolutePath());
|
||||||
|
// values.put(MediaStore.MediaColumns.TITLE, context.getResources().getString(R.string.app_name) + " ringtone");
|
||||||
|
// values.put(MediaStore.MediaColumns.TITLE, ringtoneFile.getName().replace(".mp3", "").replace(".", ""));
|
||||||
|
values.put(MediaStore.MediaColumns.TITLE, ringtoneFile.getName());
|
||||||
|
// values.put(MediaStore.MediaColumns.MIME_TYPE, "audio/*");
|
||||||
|
values.put(MediaStore.MediaColumns.MIME_TYPE, "audio/mp3");
|
||||||
|
values.put(MediaStore.MediaColumns.SIZE, ringtoneFile.length());
|
||||||
|
// values.put(MediaStore.Audio.Media.ARTIST, R.string.app_name);
|
||||||
|
values.put(MediaStore.Audio.Media.IS_RINGTONE, ringtoneType == RingtoneManager.TYPE_RINGTONE);
|
||||||
|
values.put(MediaStore.Audio.Media.IS_NOTIFICATION, ringtoneType == RingtoneManager.TYPE_NOTIFICATION);
|
||||||
|
values.put(MediaStore.Audio.Media.IS_ALARM, false);
|
||||||
|
values.put(MediaStore.Audio.Media.IS_MUSIC, false);
|
||||||
|
|
||||||
|
Uri existingRingTone = MediaStore.Audio.Media.getContentUriForPath(ringtoneFile.getAbsolutePath());
|
||||||
|
if(existingRingTone != null)
|
||||||
|
context.getContentResolver().delete(existingRingTone, MediaStore.MediaColumns.DATA + "=\"" + ringtoneFile.getAbsolutePath() + "\"", null);
|
||||||
|
Uri newRingTone = context.getContentResolver().insert(existingRingTone, values);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
RingtoneManager.setActualDefaultRingtoneUri(context, ringtoneType, newRingTone);
|
||||||
|
Miscellaneous.logEvent("i", "Profile", "Ringtone set to: " + newRingTone.toString(), 1);
|
||||||
|
// Ringtone tone = RingtoneManager.getRingtone(context, RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE));
|
||||||
|
// tone.play();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Throwable t)
|
||||||
|
{
|
||||||
|
String message = "Error setting ringtone: " + Log.getStackTraceString(t);
|
||||||
|
Miscellaneous.logEvent("e", "Profile", message, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean create(Context context, boolean writeToFile)
|
||||||
|
{
|
||||||
|
for(Profile profile : Profile.profileCollection)
|
||||||
|
{
|
||||||
|
if (profile.getName().equals(this.getName()))
|
||||||
|
{
|
||||||
|
Toast.makeText(context, context.getResources().getString(R.string.anotherProfileByThatName), Toast.LENGTH_LONG).show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(plausibilityCheck())
|
||||||
|
{
|
||||||
|
// add to collection
|
||||||
|
Profile.getProfileCollection().add(this);
|
||||||
|
|
||||||
|
// write to file
|
||||||
|
if(writeToFile)
|
||||||
|
return XmlFileInterface.writeFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean change(Context context)
|
||||||
|
{
|
||||||
|
if(this.oldName != null && !this.oldName.equals(this.name))
|
||||||
|
{
|
||||||
|
//Name has changed. We need to look for rules that reference it by its name and update those references
|
||||||
|
|
||||||
|
// Check if the name is still available
|
||||||
|
int counter = 0; // this method should only be a temporary workaround, directly editing the referenced object may cause problems until reloading the config file
|
||||||
|
for(Profile profile : Profile.profileCollection)
|
||||||
|
{
|
||||||
|
if (profile.getName().equals(this.getName()))
|
||||||
|
{
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(counter > 1)
|
||||||
|
{
|
||||||
|
Toast.makeText(context, context.getResources().getString(R.string.anotherProfileByThatName), Toast.LENGTH_LONG).show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if rules reference this profile
|
||||||
|
ArrayList<Rule> rulesThatReferenceMe = Rule.findRuleCandidatesByProfile(this);
|
||||||
|
if(rulesThatReferenceMe.size() > 0)
|
||||||
|
{
|
||||||
|
for(Rule oneRule : rulesThatReferenceMe)
|
||||||
|
{
|
||||||
|
for(Action oneAction : oneRule.getActionSet())
|
||||||
|
{
|
||||||
|
if(oneAction.getAction() == Action_Enum.changeSoundProfile)
|
||||||
|
{
|
||||||
|
oneAction.setParameter2(this.name);
|
||||||
|
// We don't need to save the file. This will happen anyway in PointOfInterest.writePoisToFile() below.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(plausibilityCheck())
|
||||||
|
{
|
||||||
|
// write to file
|
||||||
|
if(XmlFileInterface.writeFile())
|
||||||
|
{
|
||||||
|
AutomationService service = AutomationService.getInstance();
|
||||||
|
if(service != null)
|
||||||
|
service.applySettingsAndRules();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean delete()
|
||||||
|
{
|
||||||
|
for(int i = 0; i< Profile.getProfileCollection().size(); i++)
|
||||||
|
{
|
||||||
|
if(Profile.getProfileCollection().get(i).getName().equals(this.getName()))
|
||||||
|
{
|
||||||
|
Profile.getProfileCollection().remove(0);
|
||||||
|
|
||||||
|
// write to file
|
||||||
|
return XmlFileInterface.writeFile();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean plausibilityCheck()
|
||||||
|
{
|
||||||
|
if(this.getName().equals("null"))
|
||||||
|
{
|
||||||
|
// Invalid name
|
||||||
|
String text = Miscellaneous.getAnyContext().getResources().getString(R.string.invalidProfileName);
|
||||||
|
Miscellaneous.logEvent("w", "Profile", text, 2);
|
||||||
|
Toast.makeText(Miscellaneous.getAnyContext(), text, Toast.LENGTH_LONG).show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(Profile another)
|
||||||
|
{
|
||||||
|
return this.getName().compareTo(another.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void activate(Context context)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "Profile " + this.getName(), String.format(context.getResources().getString(R.string.profileActivate), this.getName()), 3);
|
||||||
|
|
||||||
|
AutomationService.getInstance().checkLockSoundChangesTimeElapsed();
|
||||||
|
|
||||||
|
if(AutomationService.getInstance().getLockSoundChangesEnd() == null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
AudioManager am = (AudioManager) Miscellaneous.getAnyContext().getSystemService(Context.AUDIO_SERVICE);
|
||||||
|
|
||||||
|
if(changeSoundMode)
|
||||||
|
Actions.setSound(context, soundMode);
|
||||||
|
|
||||||
|
if(changeVolumeMusicVideoGameMedia)
|
||||||
|
am.setStreamVolume(AudioManager.STREAM_MUSIC, volumeMusic, AudioManager.FLAG_PLAY_SOUND);
|
||||||
|
|
||||||
|
if(changeVolumeNotifications)
|
||||||
|
am.setStreamVolume(AudioManager.STREAM_NOTIFICATION, volumeNotifications, AudioManager.FLAG_PLAY_SOUND);
|
||||||
|
|
||||||
|
if(changeVolumeAlarms)
|
||||||
|
am.setStreamVolume(AudioManager.STREAM_ALARM, volumeAlarms, AudioManager.FLAG_PLAY_SOUND);
|
||||||
|
|
||||||
|
if(changeIncomingCallsRingtone)
|
||||||
|
if(incomingCallsRingtone != null)
|
||||||
|
applyRingTone(incomingCallsRingtone, RingtoneManager.TYPE_RINGTONE, context);
|
||||||
|
|
||||||
|
if(changeVibrateWhenRinging)
|
||||||
|
if(vibrateWhenRinging)
|
||||||
|
am.setVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER, AudioManager.VIBRATE_SETTING_ON);
|
||||||
|
else
|
||||||
|
am.setVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER, AudioManager.VIBRATE_SETTING_OFF);
|
||||||
|
|
||||||
|
if(changeNotificationRingtone)
|
||||||
|
if(notificationRingtone != null)
|
||||||
|
applyRingTone(notificationRingtone, RingtoneManager.TYPE_NOTIFICATION, context);
|
||||||
|
|
||||||
|
if(changeScreenLockUnlockSound)
|
||||||
|
{
|
||||||
|
android.provider.Settings.System.putInt(context.getContentResolver(), "lockscreen_sounds_enabled" , screenLockUnlockSound ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(changeAudibleSelection)
|
||||||
|
{
|
||||||
|
if(audibleSelection)
|
||||||
|
android.provider.Settings.System.putInt(context.getContentResolver(), android.provider.Settings.System.SOUND_EFFECTS_ENABLED, 1); // enable
|
||||||
|
else
|
||||||
|
android.provider.Settings.System.putInt(context.getContentResolver(), android.provider.Settings.System.SOUND_EFFECTS_ENABLED, 0); // dissable
|
||||||
|
}
|
||||||
|
|
||||||
|
if(changeHapticFeedback)
|
||||||
|
{
|
||||||
|
if(hapticFeedback)
|
||||||
|
android.provider.Settings.System.putInt(context.getContentResolver(), android.provider.Settings.System.HAPTIC_FEEDBACK_ENABLED, 1); // enable
|
||||||
|
else
|
||||||
|
android.provider.Settings.System.putInt(context.getContentResolver(), android.provider.Settings.System.HAPTIC_FEEDBACK_ENABLED, 0); // disable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "Profile " + this.getName(), context.getResources().getString(R.string.errorActivatingProfile) + " " + Log.getStackTraceString(e), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "Profile " + this.getName(), context.getResources().getString(R.string.noProfileChangeSoundLocked), 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return this.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toStringLong()
|
||||||
|
{
|
||||||
|
return "no implemented, yet";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean createDummyProfile(Context context, String tagContent)
|
||||||
|
{
|
||||||
|
Profile newProfile = new Profile();
|
||||||
|
|
||||||
|
newProfile.setName(tagContent);
|
||||||
|
newProfile.setChangeSoundMode(true);
|
||||||
|
|
||||||
|
if(tagContent.equals("silent"))
|
||||||
|
newProfile.setSoundMode(AudioManager.RINGER_MODE_SILENT);
|
||||||
|
else if(tagContent.equals("vibrate"))
|
||||||
|
newProfile.setSoundMode(AudioManager.RINGER_MODE_VIBRATE);
|
||||||
|
else if(tagContent.equals("normal"))
|
||||||
|
newProfile.setSoundMode(AudioManager.RINGER_MODE_NORMAL);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return newProfile.create(context, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOldName()
|
||||||
|
{
|
||||||
|
return this.oldName;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
277
app/src/main/java/com/jens/automation2/ReceiverCoordinator.java
Normal file
@ -0,0 +1,277 @@
|
|||||||
|
package com.jens.automation2;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.jens.automation2.location.CellLocationChangedReceiver;
|
||||||
|
import com.jens.automation2.location.WifiBroadcastReceiver;
|
||||||
|
import com.jens.automation2.receivers.ActivityDetectionReceiver;
|
||||||
|
import com.jens.automation2.receivers.AlarmListener;
|
||||||
|
import com.jens.automation2.receivers.AutomationListenerInterface;
|
||||||
|
import com.jens.automation2.receivers.BatteryReceiver;
|
||||||
|
import com.jens.automation2.receivers.BluetoothReceiver;
|
||||||
|
import com.jens.automation2.receivers.ConnectivityReceiver;
|
||||||
|
import com.jens.automation2.receivers.HeadphoneJackListener;
|
||||||
|
import com.jens.automation2.receivers.NoiseListener;
|
||||||
|
import com.jens.automation2.receivers.PhoneStatusListener;
|
||||||
|
import com.jens.automation2.receivers.ProcessListener;
|
||||||
|
import com.jens.automation2.receivers.TimeZoneListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by jens on 08.03.2017.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class ReceiverCoordinator
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* This class will manage getting the device's location. It will utilize the following methods:
|
||||||
|
* - CellLocationListener
|
||||||
|
* - WifiListener
|
||||||
|
* - Accelerometer
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static final Class[] allImplementers = {
|
||||||
|
ActivityDetectionReceiver.class,
|
||||||
|
AlarmListener.class,
|
||||||
|
BatteryReceiver.class,
|
||||||
|
BluetoothReceiver.class,
|
||||||
|
ConnectivityReceiver.class,
|
||||||
|
HeadphoneJackListener.class,
|
||||||
|
//NfcReceiver.class,
|
||||||
|
NoiseListener.class,
|
||||||
|
PhoneStatusListener.class,
|
||||||
|
ProcessListener.class,
|
||||||
|
TimeZoneListener.class
|
||||||
|
};
|
||||||
|
|
||||||
|
private static AutomationListenerInterface[] listeners = null;
|
||||||
|
|
||||||
|
public static void startAllReceivers()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* New procedure:
|
||||||
|
* Save instances of Listeners in ArrayList and run them.
|
||||||
|
*/
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(listeners == null)
|
||||||
|
{
|
||||||
|
listeners = new AutomationListenerInterface[allImplementers.length];
|
||||||
|
int i = 0;
|
||||||
|
for(Class<AutomationListenerInterface> c : allImplementers)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
listeners[i] = (AutomationListenerInterface) c.newInstance();
|
||||||
|
|
||||||
|
// UNCOMMENT THE NEXT LINE WHEN THIS PART OF THE CODE GOES ONLINE
|
||||||
|
// listeners[i].startListener(AutomationService.getInstance());
|
||||||
|
}
|
||||||
|
catch (InstantiationException e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
catch (IllegalAccessException e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(AutomationListenerInterface listener : listeners)
|
||||||
|
{
|
||||||
|
if(listener != null && listener.getMonitoredTrigger() != null)
|
||||||
|
{
|
||||||
|
String jobDescription = "";
|
||||||
|
for (Trigger.Trigger_Enum name : listener.getMonitoredTrigger())
|
||||||
|
jobDescription += name + ", ";
|
||||||
|
jobDescription = jobDescription.substring(0, jobDescription.length() - 2);
|
||||||
|
Miscellaneous.logEvent("i", "Listener", "Listener instance: " + listener.getClass().getName() + ", monitoring: " + jobDescription, 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("w", "Error in new model", Log.getStackTraceString(e), 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if(Settings.useAccelerometerForPositioning && !Miscellaneous.isAndroidEmulator())
|
||||||
|
// {
|
||||||
|
// accelerometerHandler = new AccelerometerHandler();
|
||||||
|
// mySensorActivity = new SensorActivity(this);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// startPhoneStateListener
|
||||||
|
PhoneStatusListener.startPhoneStatusListener(AutomationService.getInstance()); // also used to mute anouncements during calls
|
||||||
|
|
||||||
|
// startConnectivityReceiver
|
||||||
|
ConnectivityReceiver.startConnectivityReceiver(AutomationService.getInstance());
|
||||||
|
|
||||||
|
// startCellLocationChangedReceiver
|
||||||
|
if(!ConnectivityReceiver.isAirplaneMode(AutomationService.getInstance()) && WifiBroadcastReceiver.mayCellLocationReceiverBeActivated() && (Rule.isAnyRuleUsing(Trigger.Trigger_Enum.pointOfInterest) | Rule.isAnyRuleUsing(Trigger.Trigger_Enum.speed)))
|
||||||
|
CellLocationChangedReceiver.startCellLocationChangedReceiver();
|
||||||
|
|
||||||
|
// startBatteryReceiver
|
||||||
|
if(Rule.isAnyRuleUsing(Trigger.Trigger_Enum.charging) | Rule.isAnyRuleUsing(Trigger.Trigger_Enum.usb_host_connection) | Rule.isAnyRuleUsing(Trigger.Trigger_Enum.batteryLevel))
|
||||||
|
BatteryReceiver.startBatteryReceiver(AutomationService.getInstance());
|
||||||
|
|
||||||
|
// startAlarmListener
|
||||||
|
AlarmListener.startAlarmListener(AutomationService.getInstance());
|
||||||
|
TimeZoneListener.startTimeZoneListener(AutomationService.getInstance());
|
||||||
|
|
||||||
|
// startNoiseListener
|
||||||
|
if(Rule.isAnyRuleUsing(Trigger.Trigger_Enum.noiseLevel))
|
||||||
|
NoiseListener.startNoiseListener(AutomationService.getInstance());
|
||||||
|
|
||||||
|
// startNoiseListener
|
||||||
|
if(Rule.isAnyRuleUsing(Trigger.Trigger_Enum.process_started_stopped))
|
||||||
|
ProcessListener.startProcessListener(AutomationService.getInstance());
|
||||||
|
|
||||||
|
//startActivityDetectionReceiver
|
||||||
|
if(Rule.isAnyRuleUsing(Trigger.Trigger_Enum.activityDetection))
|
||||||
|
ActivityDetectionReceiver.startActivityDetectionReceiver();
|
||||||
|
|
||||||
|
//startBluetoothReceiver
|
||||||
|
if(Rule.isAnyRuleUsing(Trigger.Trigger_Enum.bluetoothConnection))
|
||||||
|
BluetoothReceiver.startBluetoothReceiver();
|
||||||
|
|
||||||
|
//startHeadsetJackListener
|
||||||
|
if(Rule.isAnyRuleUsing(Trigger.Trigger_Enum.headsetPlugged))
|
||||||
|
HeadphoneJackListener.getInstance().startListener(AutomationService.getInstance());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void stopAllReceivers()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PhoneStatusListener.stopPhoneStatusListener(AutomationService.getInstance());
|
||||||
|
ConnectivityReceiver.stopConnectivityReceiver();
|
||||||
|
WifiBroadcastReceiver.stopWifiReceiver();
|
||||||
|
BatteryReceiver.stopBatteryReceiver();
|
||||||
|
TimeZoneListener.stopTimeZoneListener();
|
||||||
|
AlarmListener.stopAlarmListener(AutomationService.getInstance());
|
||||||
|
NoiseListener.stopNoiseListener();
|
||||||
|
ProcessListener.stopProcessListener(AutomationService.getInstance());
|
||||||
|
ActivityDetectionReceiver.stopActivityDetectionReceiver();
|
||||||
|
BluetoothReceiver.stopBluetoothReceiver();
|
||||||
|
HeadphoneJackListener.getInstance().stopListener(AutomationService.getInstance());
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "cellReceiver", "Error stopping LocationReceiver: " + Log.getStackTraceString(e), 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void applySettingsAndRules()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* This method's purpose is to check settings and rules and determine
|
||||||
|
* if changes in them require monitors to be started or stopped.
|
||||||
|
* It takes care only of those which are more expensive.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// TextToSpeech is handled in AutomationService class
|
||||||
|
|
||||||
|
Miscellaneous.logEvent("i", "LocationProvider", AutomationService.getInstance().getResources().getString(R.string.applyingSettingsAndRules), 3);
|
||||||
|
|
||||||
|
// *********** RULE CHANGES ***********
|
||||||
|
|
||||||
|
// timeFrame -> too inexpensive to shutdown
|
||||||
|
|
||||||
|
if(Rule.isAnyRuleUsing(Trigger.Trigger_Enum.charging) | Rule.isAnyRuleUsing(Trigger.Trigger_Enum.usb_host_connection) | Rule.isAnyRuleUsing(Trigger.Trigger_Enum.batteryLevel))
|
||||||
|
{
|
||||||
|
if(BatteryReceiver.haveAllPermission())
|
||||||
|
BatteryReceiver.startBatteryReceiver(AutomationService.getInstance());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
BatteryReceiver.stopBatteryReceiver();
|
||||||
|
|
||||||
|
if(Rule.isAnyRuleUsing(Trigger.Trigger_Enum.noiseLevel))
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "LocationProvider", "Starting NoiseListener because used in a new/changed rule.", 4);
|
||||||
|
if(NoiseListener.haveAllPermission())
|
||||||
|
NoiseListener.startNoiseListener(AutomationService.getInstance());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "LocationProvider", "Shutting down NoiseListener because not used in any rule.", 4);
|
||||||
|
NoiseListener.stopNoiseListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Rule.isAnyRuleUsing(Trigger.Trigger_Enum.process_started_stopped))
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "LocationProvider", "Starting ProcessListener because used in a new/changed rule.", 4);
|
||||||
|
if(ProcessListener.haveAllPermission())
|
||||||
|
ProcessListener.startProcessListener(AutomationService.getInstance());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "LocationProvider", "Shutting down ProcessListener because not used in any rule.", 4);
|
||||||
|
ProcessListener.stopProcessListener(AutomationService.getInstance());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Rule.isAnyRuleUsing(Trigger.Trigger_Enum.activityDetection))
|
||||||
|
{
|
||||||
|
if(ActivityDetectionReceiver.isActivityDetectionReceiverRunning())
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "LocationProvider", "Restarting ActivityDetectionReceiver because used in a new/changed rule.", 4);
|
||||||
|
if(ActivityDetectionReceiver.haveAllPermission())
|
||||||
|
ActivityDetectionReceiver.restartActivityDetectionReceiver();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "LocationProvider", "Starting ActivityDetectionReceiver because used in a new/changed rule.", 4);
|
||||||
|
if(ActivityDetectionReceiver.haveAllPermission())
|
||||||
|
ActivityDetectionReceiver.startActivityDetectionReceiver();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(ActivityDetectionReceiver.isActivityDetectionReceiverRunning())
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "LocationProvider", "Shutting down ActivityDetectionReceiver because not used in any rule.", 4);
|
||||||
|
ActivityDetectionReceiver.stopActivityDetectionReceiver();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Rule.isAnyRuleUsing(Trigger.Trigger_Enum.bluetoothConnection))
|
||||||
|
{
|
||||||
|
if(!BluetoothReceiver.isBluetoothReceiverActive())
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "LocationProvider", "Starting BluetoothReceiver because used in a new/changed rule.", 4);
|
||||||
|
if(BluetoothReceiver.haveAllPermission())
|
||||||
|
BluetoothReceiver.startBluetoothReceiver();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(BluetoothReceiver.isBluetoothReceiverActive())
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "LocationProvider", "Shutting down BluetoothReceiver because not used in any rule.", 4);
|
||||||
|
BluetoothReceiver.stopBluetoothReceiver();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Rule.isAnyRuleUsing(Trigger.Trigger_Enum.headsetPlugged))
|
||||||
|
{
|
||||||
|
if(!HeadphoneJackListener.isHeadphoneJackListenerActive())
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "LocationProvider", "Starting HeadphoneJackListener because used in a new/changed rule.", 4);
|
||||||
|
if(HeadphoneJackListener.getInstance().haveAllPermission())
|
||||||
|
HeadphoneJackListener.getInstance().startListener(AutomationService.getInstance());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(HeadphoneJackListener.isHeadphoneJackListenerActive())
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "LocationProvider", "Shutting down HeadphoneJackListener because not used in any rule.", 4);
|
||||||
|
HeadphoneJackListener.getInstance().stopListener(AutomationService.getInstance());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AutomationService.updateNotification();
|
||||||
|
}
|
||||||
|
}
|
1425
app/src/main/java/com/jens/automation2/Rule.java
Normal file
503
app/src/main/java/com/jens/automation2/Settings.java
Normal file
@ -0,0 +1,503 @@
|
|||||||
|
package com.jens.automation2;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class Settings implements SharedPreferences
|
||||||
|
{
|
||||||
|
public static final int rulesThatHaveBeenRanHistorySize = 10;
|
||||||
|
public static final String folderName = "Automation";
|
||||||
|
|
||||||
|
public static long minimumDistanceChangeForGpsUpdate;
|
||||||
|
public static long minimumDistanceChangeForNetworkUpdate;
|
||||||
|
public static long satisfactoryAccuracyGps;
|
||||||
|
public static long satisfactoryAccuracyNetwork;
|
||||||
|
public static int gpsTimeout;
|
||||||
|
public static long minimumTimeBetweenUpdate;
|
||||||
|
public static boolean startServiceAtSystemBoot;
|
||||||
|
public static boolean writeLogFile;
|
||||||
|
public static long logLevel;
|
||||||
|
public static int logFileMaxSize;
|
||||||
|
public static boolean useTextToSpeechOnNormal;
|
||||||
|
public static boolean useTextToSpeechOnVibrate;
|
||||||
|
public static boolean useTextToSpeechOnSilent;
|
||||||
|
public static boolean muteTextToSpeechDuringCalls;
|
||||||
|
public static int positioningEngine;
|
||||||
|
public static boolean useWifiForPositioning;
|
||||||
|
public static boolean useAccelerometerForPositioning;
|
||||||
|
public static long useAccelerometerAfterIdleTime;
|
||||||
|
public static long accelerometerMovementThreshold;
|
||||||
|
public static long speedMaximumTimeBetweenLocations;
|
||||||
|
public static long timeBetweenNoiseLevelMeasurements;
|
||||||
|
public static long lengthOfNoiseLevelMeasurements;
|
||||||
|
public static long referenceValueForNoiseLevelMeasurements;
|
||||||
|
public static boolean hasServiceBeenRunning;
|
||||||
|
public static boolean startServiceAfterAppUpdate;
|
||||||
|
public static boolean startNewThreadForRuleActivation;
|
||||||
|
public static boolean showIconWhenServiceIsRunning;
|
||||||
|
public static boolean httpAcceptAllCertificates;
|
||||||
|
public static int httpAttempts;
|
||||||
|
public static int httpAttemptsTimeout;
|
||||||
|
public static int httpAttemptGap;
|
||||||
|
public static PointOfInterest lastActivePoi;
|
||||||
|
public static boolean rememberLastActivePoi;
|
||||||
|
public static int locationRingBufferSize;
|
||||||
|
public static long timeBetweenProcessMonitorings;
|
||||||
|
public static int activityDetectionFrequency;
|
||||||
|
public static int activityDetectionRequiredProbability;
|
||||||
|
public static boolean privacyLocationing;
|
||||||
|
public static int startScreen;
|
||||||
|
public static boolean executeRulesAndProfilesWithSingleClick;
|
||||||
|
public static boolean lockSoundChanges;
|
||||||
|
public static boolean noticeAndroid9MicrophoneShown;
|
||||||
|
public static boolean noticeAndroid10WifiShown;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Generic settings valid for all installations and not changable
|
||||||
|
*/
|
||||||
|
public static final String dateFormat = "E dd.MM.yyyy HH:mm:ss:ssss";
|
||||||
|
|
||||||
|
protected static final int default_positioningEngine = 0;
|
||||||
|
protected static final long default_minimumDistanceChangeForGpsUpdate = 100;
|
||||||
|
protected static final long default_minimumDistanceChangeForNetworkUpdate = 500; // in Meters
|
||||||
|
protected static final long default_satisfactoryAccuracyGps = 50;
|
||||||
|
protected static final long default_satisfactoryAccuracyNetwork = 1000;
|
||||||
|
protected static final int default_gpsTimeout = 300; // seconds
|
||||||
|
protected static final long default_minimumTimeBetweenUpdate = 30000; // in Milliseconds
|
||||||
|
protected static final boolean default_startServiceAtSystemBoot = false;
|
||||||
|
protected static final boolean default_writeLogFile = false;
|
||||||
|
protected static final long default_logLevel = 2;
|
||||||
|
protected static final int default_logFileMaxSize = 10;
|
||||||
|
protected static final boolean default_useTextToSpeechOnNormal = false;
|
||||||
|
protected static final boolean default_useTextToSpeechOnVibrate = false;
|
||||||
|
protected static final boolean default_useTextToSpeechOnSilent = false;
|
||||||
|
protected static final boolean default_muteTextToSpeechDuringCalls = true;
|
||||||
|
protected static final boolean default_useWifiForPositioning = true;
|
||||||
|
protected static final boolean default_useAccelerometerForPositioning = true;
|
||||||
|
protected static final long default_useAccelerometerAfterIdleTime = 5;
|
||||||
|
protected static final long default_accelerometerMovementThreshold = 2;
|
||||||
|
protected static final long default_speedMaximumTimeBetweenLocations = 4;
|
||||||
|
protected static final long default_timeBetweenNoiseLevelMeasurements = 60;
|
||||||
|
protected static final long default_lengthOfNoiseLevelMeasurements = 5;
|
||||||
|
protected static final long default_referenceValueForNoiseLevelMeasurements = 20;
|
||||||
|
protected static final boolean default_hasServiceBeenRunning = false;
|
||||||
|
protected static final boolean default_startServiceAfterAppUpdate = true;
|
||||||
|
protected static final boolean default_startNewThreadForRuleActivation = true;
|
||||||
|
protected static final boolean default_showIconWhenServiceIsRunning = true;
|
||||||
|
protected static final boolean default_httpAcceptAllCertificates = false;
|
||||||
|
protected static final int default_httpAttempts = 3;
|
||||||
|
protected static final int default_httpAttemptsTimeout = 60;
|
||||||
|
protected static final int default_httpAttemptGap = 2;
|
||||||
|
protected static final PointOfInterest default_lastActivePoi = null;
|
||||||
|
protected static final boolean default_rememberLastActivePoi = true;
|
||||||
|
protected static final int default_locationRingBufferSize=3;
|
||||||
|
protected static final long default_timeBetweenProcessMonitorings = 60;
|
||||||
|
protected static final int default_activityDetectionFrequency = 60;
|
||||||
|
protected static final int default_activityDetectionRequiredProbability = 75;
|
||||||
|
protected static final boolean default_privacyLocationing = false;
|
||||||
|
protected static final int default_startScreen = 0;
|
||||||
|
protected static final boolean default_executeRulesAndProfilesWithSingleClick = false;
|
||||||
|
protected static final boolean default_lockSoundChanges = false;
|
||||||
|
public final static int lockSoundChangesInterval = 15;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean contains(String arg0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public Editor edit()
|
||||||
|
{
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public Map<String, ?> getAll()
|
||||||
|
{
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean getBoolean(String arg0, boolean arg1)
|
||||||
|
{
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public float getFloat(String arg0, float arg1)
|
||||||
|
{
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public int getInt(String arg0, int arg1)
|
||||||
|
{
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public long getLong(String arg0, long arg1)
|
||||||
|
{
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public String getString(String arg0, String arg1)
|
||||||
|
{
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener arg0)
|
||||||
|
{
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener arg0)
|
||||||
|
{
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void readFromPersistentStorage(Context context)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", context.getResources().getString(R.string.settings), context.getResources().getString(R.string.refreshingSettingsFromFileToMemory), 4);
|
||||||
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
|
||||||
|
startServiceAtSystemBoot = prefs.getBoolean("startServiceAtSystemBoot", default_startServiceAtSystemBoot);
|
||||||
|
writeLogFile = prefs.getBoolean("writeLogFile", default_writeLogFile);
|
||||||
|
|
||||||
|
boolean useTextToSpeech = false;
|
||||||
|
if(prefs.contains("useTextToSpeech"))
|
||||||
|
{
|
||||||
|
useTextToSpeech = prefs.getBoolean("useTextToSpeech", false);
|
||||||
|
}
|
||||||
|
if(prefs.contains("useTextToSpeech") && !useTextToSpeech) // until all old users have been upgraded
|
||||||
|
{
|
||||||
|
useTextToSpeechOnNormal = false;
|
||||||
|
useTextToSpeechOnVibrate = false;
|
||||||
|
useTextToSpeechOnSilent = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
useTextToSpeechOnNormal = prefs.getBoolean("useTextToSpeechOnNormal", default_useTextToSpeechOnNormal);
|
||||||
|
useTextToSpeechOnVibrate = prefs.getBoolean("useTextToSpeechOnVibrate", default_useTextToSpeechOnVibrate);
|
||||||
|
useTextToSpeechOnSilent = prefs.getBoolean("useTextToSpeechOnSilent", default_useTextToSpeechOnSilent);
|
||||||
|
}
|
||||||
|
|
||||||
|
muteTextToSpeechDuringCalls = prefs.getBoolean("muteTextToSpeechDuringCalls", default_muteTextToSpeechDuringCalls);
|
||||||
|
|
||||||
|
positioningEngine = Integer.parseInt(prefs.getString("positioningEngineOption", String.valueOf(default_positioningEngine)));
|
||||||
|
useWifiForPositioning = prefs.getBoolean("useWifiForPositioning", default_useWifiForPositioning);
|
||||||
|
useAccelerometerForPositioning = prefs.getBoolean("useAccelerometerForPositioning", default_useAccelerometerForPositioning);
|
||||||
|
useAccelerometerAfterIdleTime = Long.parseLong(prefs.getString("useAccelerometerAfterIdleTime", String.valueOf(default_useAccelerometerAfterIdleTime)));
|
||||||
|
accelerometerMovementThreshold = Long.parseLong(prefs.getString("accelerometerMovementThreshold", String.valueOf(default_accelerometerMovementThreshold)));
|
||||||
|
speedMaximumTimeBetweenLocations = Long.parseLong(prefs.getString("speedMaximumTimeBetweenLocations", String.valueOf(default_speedMaximumTimeBetweenLocations)));
|
||||||
|
hasServiceBeenRunning = prefs.getBoolean("hasServiceBeenRunning", default_hasServiceBeenRunning);
|
||||||
|
startServiceAfterAppUpdate = prefs.getBoolean("startServiceAfterAppUpdate", default_startServiceAfterAppUpdate);
|
||||||
|
startNewThreadForRuleActivation = prefs.getBoolean("startNewThreadForRuleActivation", default_startNewThreadForRuleActivation);
|
||||||
|
showIconWhenServiceIsRunning = prefs.getBoolean("showIconWhenServiceIsRunning", default_showIconWhenServiceIsRunning);
|
||||||
|
|
||||||
|
minimumDistanceChangeForGpsUpdate = Long.parseLong(prefs.getString("MINIMUM_DISTANCE_CHANGE_FOR_GPS_UPDATE", String.valueOf(default_minimumDistanceChangeForGpsUpdate)));
|
||||||
|
minimumDistanceChangeForNetworkUpdate = Long.parseLong(prefs.getString("MINIMUM_DISTANCE_CHANGE_FOR_NETWORK_UPDATE", String.valueOf(default_minimumDistanceChangeForNetworkUpdate)));
|
||||||
|
satisfactoryAccuracyGps = Long.parseLong(prefs.getString("SATISFACTORY_ACCURACY_GPS", String.valueOf(default_satisfactoryAccuracyGps)));
|
||||||
|
satisfactoryAccuracyNetwork = Long.parseLong(prefs.getString("SATISFACTORY_ACCURACY_NETWORK", String.valueOf(default_satisfactoryAccuracyNetwork)));
|
||||||
|
gpsTimeout = Integer.parseInt(prefs.getString("gpsTimeout", String.valueOf(default_gpsTimeout)));
|
||||||
|
minimumTimeBetweenUpdate = Long.parseLong(prefs.getString("MINIMUM_TIME_BETWEEN_UPDATE", String.valueOf(default_minimumTimeBetweenUpdate)));
|
||||||
|
timeBetweenNoiseLevelMeasurements = Long.parseLong(prefs.getString("timeBetweenNoiseLevelMeasurements", String.valueOf(default_timeBetweenNoiseLevelMeasurements)));
|
||||||
|
lengthOfNoiseLevelMeasurements = Long.parseLong(prefs.getString("lengthOfNoiseLevelMeasurements", String.valueOf(default_lengthOfNoiseLevelMeasurements)));
|
||||||
|
referenceValueForNoiseLevelMeasurements = Long.parseLong(prefs.getString("referenceValueForNoiseLevelMeasurements", String.valueOf(default_referenceValueForNoiseLevelMeasurements)));
|
||||||
|
timeBetweenProcessMonitorings = Long.parseLong(prefs.getString("timeBetweenProcessMonitorings", String.valueOf(default_timeBetweenProcessMonitorings)));
|
||||||
|
|
||||||
|
httpAcceptAllCertificates = prefs.getBoolean("httpAcceptAllCertificates", default_httpAcceptAllCertificates);
|
||||||
|
httpAttempts = Integer.parseInt(prefs.getString("httpAttempts", String.valueOf(default_httpAttempts)));
|
||||||
|
httpAttemptsTimeout = Integer.parseInt(prefs.getString("httpAttemptsTimeout", String.valueOf(default_httpAttemptsTimeout)));
|
||||||
|
httpAttemptGap = Integer.parseInt(prefs.getString("httpAttemptGap", String.valueOf(default_httpAttemptGap)));
|
||||||
|
|
||||||
|
logLevel = Long.parseLong(prefs.getString("logLevel", String.valueOf(default_logLevel)));
|
||||||
|
logFileMaxSize = Integer.parseInt(prefs.getString("logFileMaxSize", String.valueOf(default_logFileMaxSize)));
|
||||||
|
|
||||||
|
lastActivePoi = default_lastActivePoi;
|
||||||
|
rememberLastActivePoi = prefs.getBoolean("rememberLastActivePoi", default_rememberLastActivePoi);
|
||||||
|
|
||||||
|
locationRingBufferSize = Integer.parseInt(prefs.getString("locationRingBufferSize", String.valueOf(default_locationRingBufferSize)));
|
||||||
|
|
||||||
|
activityDetectionFrequency = Integer.parseInt(prefs.getString("activityDetectionFrequency", String.valueOf(default_activityDetectionFrequency)));
|
||||||
|
activityDetectionRequiredProbability = Integer.parseInt(prefs.getString("activityDetectionRequiredProbability", String.valueOf(default_activityDetectionRequiredProbability)));
|
||||||
|
|
||||||
|
privacyLocationing = prefs.getBoolean("privacyLocationing", default_privacyLocationing);
|
||||||
|
startScreen = Integer.parseInt(prefs.getString("startScreen", String.valueOf(default_startScreen)));
|
||||||
|
|
||||||
|
executeRulesAndProfilesWithSingleClick = prefs.getBoolean("executeRulesAndProfilesWithSingleClick", default_executeRulesAndProfilesWithSingleClick);
|
||||||
|
|
||||||
|
lockSoundChanges = prefs.getBoolean("lockSoundChanges", default_lockSoundChanges);
|
||||||
|
noticeAndroid9MicrophoneShown = prefs.getBoolean("noticeAndroid9MicrophoneShown", false);
|
||||||
|
noticeAndroid10WifiShown = prefs.getBoolean("noticeAndroid10WifiShown", false);
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", context.getResources().getString(R.string.settings), context.getResources().getString(R.string.errorReadingSettings) + " " + Log.getStackTraceString(e), 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
initializeSettings(context, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**Makes sure a settings has a valid setting. If not it will assign a reasonable default setting to it.
|
||||||
|
* If force settings will be initialized even if the user has set something.**/
|
||||||
|
public static boolean initializeSettings(Context context, boolean force)
|
||||||
|
{
|
||||||
|
if(force)
|
||||||
|
eraseSettings(context);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", context.getResources().getString(R.string.settings), context.getResources().getString(R.string.initializingSettingsToPersistentMemory), 5);
|
||||||
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
|
||||||
|
Editor editor = prefs.edit();
|
||||||
|
|
||||||
|
if(!prefs.contains("startServiceAtSystemBoot") | force)
|
||||||
|
editor.putBoolean("startServiceAtSystemBoot", default_startServiceAtSystemBoot);
|
||||||
|
|
||||||
|
if(!prefs.contains("writeLogFile") | force)
|
||||||
|
editor.putBoolean("writeLogFile", default_writeLogFile);
|
||||||
|
|
||||||
|
// if(!prefs.contains("useTextToSpeech") | force)
|
||||||
|
// editor.putBoolean("useTextToSpeech", default_useTextToSpeech);
|
||||||
|
|
||||||
|
if(!prefs.contains("useTextToSpeechOnNormal") | force)
|
||||||
|
editor.putBoolean("useTextToSpeechOnNormal", default_useTextToSpeechOnNormal);
|
||||||
|
|
||||||
|
if(!prefs.contains("useTextToSpeechOnVibrate") | force)
|
||||||
|
editor.putBoolean("useTextToSpeechOnVibrate", default_useTextToSpeechOnVibrate);
|
||||||
|
|
||||||
|
if(!prefs.contains("useTextToSpeechOnSilent") | force)
|
||||||
|
editor.putBoolean("useTextToSpeechOnSilent", default_useTextToSpeechOnSilent);
|
||||||
|
|
||||||
|
if(!prefs.contains("muteTextToSpeechDuringCalls") | force)
|
||||||
|
editor.putBoolean("muteTextToSpeechDuringCalls", default_muteTextToSpeechDuringCalls);
|
||||||
|
|
||||||
|
if(!prefs.contains("positioningEngine") | force)
|
||||||
|
editor.putString("positioningEngine", String.valueOf(default_positioningEngine));
|
||||||
|
|
||||||
|
if(!prefs.contains("useWifiForPositioning") | force)
|
||||||
|
editor.putBoolean("useWifiForPositioning", default_useWifiForPositioning);
|
||||||
|
|
||||||
|
if(!prefs.contains("hasServiceBeenRunning") | force)
|
||||||
|
editor.putBoolean("hasServiceBeenRunning", default_hasServiceBeenRunning);
|
||||||
|
|
||||||
|
if(!prefs.contains("startServiceAfterAppUpdate") | force)
|
||||||
|
editor.putBoolean("startServiceAfterAppUpdate", default_startServiceAfterAppUpdate);
|
||||||
|
|
||||||
|
if(!prefs.contains("startNewThreadForRuleActivation") | force)
|
||||||
|
editor.putBoolean("startNewThreadForRuleActivation", default_startNewThreadForRuleActivation);
|
||||||
|
|
||||||
|
if(!prefs.contains("showIconWhenServiceIsRunning") | force)
|
||||||
|
editor.putBoolean("showIconWhenServiceIsRunning", default_showIconWhenServiceIsRunning);
|
||||||
|
|
||||||
|
if(!prefs.contains("useAccelerometerForPositioning") | force)
|
||||||
|
editor.putBoolean("useAccelerometerForPositioning", default_useAccelerometerForPositioning);
|
||||||
|
|
||||||
|
if(!prefs.contains("useAccelerometerAfterIdleTime") | force)
|
||||||
|
editor.putString("useAccelerometerAfterIdleTime", String.valueOf(default_useAccelerometerAfterIdleTime));
|
||||||
|
|
||||||
|
if(!prefs.contains("accelerometerMovementThreshold") | force)
|
||||||
|
editor.putString("accelerometerMovementThreshold", String.valueOf(default_accelerometerMovementThreshold));
|
||||||
|
|
||||||
|
if(!prefs.contains("speedMaximumTimeBetweenLocations") | force)
|
||||||
|
editor.putString("speedMaximumTimeBetweenLocations", String.valueOf(default_speedMaximumTimeBetweenLocations));
|
||||||
|
|
||||||
|
if(!prefs.contains("MINIMUM_DISTANCE_CHANGE_FOR_GPS_UPDATE") | force)
|
||||||
|
editor.putString("MINIMUM_DISTANCE_CHANGE_FOR_GPS_UPDATE", String.valueOf(default_minimumDistanceChangeForGpsUpdate));
|
||||||
|
|
||||||
|
if(!prefs.contains("MINIMUM_DISTANCE_CHANGE_FOR_NETWORK_UPDATE") | force)
|
||||||
|
editor.putString("MINIMUM_DISTANCE_CHANGE_FOR_NETWORK_UPDATE", String.valueOf(default_minimumDistanceChangeForNetworkUpdate));
|
||||||
|
|
||||||
|
if(!prefs.contains("SATISFACTORY_ACCURACY_GPS") | force)
|
||||||
|
editor.putString("SATISFACTORY_ACCURACY_GPS", String.valueOf(default_satisfactoryAccuracyGps));
|
||||||
|
|
||||||
|
if(!prefs.contains("SATISFACTORY_ACCURACY_NETWORK") | force)
|
||||||
|
editor.putString("SATISFACTORY_ACCURACY_NETWORK", String.valueOf(default_satisfactoryAccuracyNetwork));
|
||||||
|
|
||||||
|
if(!prefs.contains("gpsTimeout") | force)
|
||||||
|
editor.putString("gpsTimeout", String.valueOf(default_gpsTimeout));
|
||||||
|
|
||||||
|
if(!prefs.contains("MINIMUM_TIME_BETWEEN_UPDATE") | force)
|
||||||
|
editor.putString("MINIMUM_TIME_BETWEEN_UPDATE", String.valueOf(default_minimumTimeBetweenUpdate));
|
||||||
|
|
||||||
|
if(!prefs.contains("timeBetweenNoiseLevelMeasurements") | force)
|
||||||
|
editor.putString("timeBetweenNoiseLevelMeasurements", String.valueOf(default_timeBetweenNoiseLevelMeasurements));
|
||||||
|
|
||||||
|
if(!prefs.contains("lengthOfNoiseLevelMeasurements") | force)
|
||||||
|
editor.putString("lengthOfNoiseLevelMeasurements", String.valueOf(default_lengthOfNoiseLevelMeasurements));
|
||||||
|
|
||||||
|
if(!prefs.contains("referenceValueForNoiseLevelMeasurements") | force)
|
||||||
|
editor.putString("referenceValueForNoiseLevelMeasurements", String.valueOf(default_referenceValueForNoiseLevelMeasurements));
|
||||||
|
|
||||||
|
if(!prefs.contains("logLevel") | force)
|
||||||
|
editor.putString("logLevel", String.valueOf(default_logLevel));
|
||||||
|
|
||||||
|
if(!prefs.contains("logFileMaxSize") | force)
|
||||||
|
editor.putString("logFileMaxSize", String.valueOf(default_logFileMaxSize));
|
||||||
|
|
||||||
|
if(!prefs.contains("httpAcceptAllCertificates") | force)
|
||||||
|
editor.putBoolean("httpAcceptAllCertificates", default_httpAcceptAllCertificates);
|
||||||
|
|
||||||
|
if(!prefs.contains("httpAttempts") | force)
|
||||||
|
editor.putString("httpAttempts", String.valueOf(default_httpAttempts));
|
||||||
|
|
||||||
|
if(!prefs.contains("httpAttemptsTimeout") | force)
|
||||||
|
editor.putString("httpAttemptsTimeout", String.valueOf(default_httpAttemptsTimeout));
|
||||||
|
|
||||||
|
if(!prefs.contains("httpAttemptGap") | force)
|
||||||
|
editor.putString("httpAttemptGap", String.valueOf(default_httpAttemptGap));
|
||||||
|
|
||||||
|
if(!prefs.contains("lastActivePoi") | force)
|
||||||
|
editor.putString("lastActivePoi", "null");
|
||||||
|
|
||||||
|
if(!prefs.contains("rememberLastActivePoi") | force)
|
||||||
|
editor.putBoolean("rememberLastActivePoi", default_rememberLastActivePoi);
|
||||||
|
|
||||||
|
if(!prefs.contains("locationRingBufferSize") | force)
|
||||||
|
editor.putString("locationRingBufferSize", String.valueOf(default_locationRingBufferSize));
|
||||||
|
|
||||||
|
if(!prefs.contains("timeBetweenProcessMonitorings") | force)
|
||||||
|
editor.putString("timeBetweenProcessMonitorings", String.valueOf(default_timeBetweenProcessMonitorings));
|
||||||
|
|
||||||
|
if(!prefs.contains("activityDetectionFrequency") | force)
|
||||||
|
editor.putString("activityDetectionFrequency", String.valueOf(default_activityDetectionFrequency));
|
||||||
|
|
||||||
|
if(!prefs.contains("activityDetectionRequiredProbability") | force)
|
||||||
|
editor.putString("activityDetectionRequiredProbability", String.valueOf(default_activityDetectionRequiredProbability));
|
||||||
|
|
||||||
|
if(!prefs.contains("privacyLocationing") | force)
|
||||||
|
editor.putBoolean("privacyLocationing", default_privacyLocationing);
|
||||||
|
|
||||||
|
if(!prefs.contains("startScreen") | force)
|
||||||
|
editor.putString("startScreen", String.valueOf(default_startScreen));
|
||||||
|
|
||||||
|
if(!prefs.contains("executeRulesAndProfilesWithSingleClick") | force)
|
||||||
|
editor.putBoolean("executeRulesAndProfilesWithSingleClick", default_executeRulesAndProfilesWithSingleClick);
|
||||||
|
|
||||||
|
if(!prefs.contains("lockSoundChanges") | force)
|
||||||
|
editor.putBoolean("lockSoundChanges", default_lockSoundChanges);
|
||||||
|
|
||||||
|
if(!prefs.contains("noticeAndroid9MicrophoneShown") | force)
|
||||||
|
editor.putBoolean("noticeAndroid9MicrophoneShown", false);
|
||||||
|
|
||||||
|
editor.commit();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", context.getResources().getString(R.string.settings), context.getResources().getString(R.string.errorInitializingSettingsToPersistentMemory), 1);
|
||||||
|
// eraseSettings(context);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void writeSettings(Context context)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", context.getResources().getString(R.string.settings), context.getResources().getString(R.string.writingSettingsToPersistentMemory), 5);
|
||||||
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
|
||||||
|
Editor editor = prefs.edit();
|
||||||
|
|
||||||
|
editor.putBoolean("startServiceAtSystemBoot", startServiceAtSystemBoot);
|
||||||
|
editor.putBoolean("writeLogFile", writeLogFile);
|
||||||
|
// editor.putBoolean("useTextToSpeech", useTextToSpeech);
|
||||||
|
editor.putBoolean("useTextToSpeechOnNormal", useTextToSpeechOnNormal);
|
||||||
|
editor.putBoolean("useTextToSpeechOnVibrate", useTextToSpeechOnVibrate);
|
||||||
|
editor.putBoolean("useTextToSpeechOnSilent", useTextToSpeechOnSilent);
|
||||||
|
editor.putBoolean("muteTextToSpeechDuringCalls", muteTextToSpeechDuringCalls);
|
||||||
|
|
||||||
|
editor.putString("positioningEngine", String.valueOf(positioningEngine));
|
||||||
|
editor.putBoolean("useWifiForPositioning", useWifiForPositioning);
|
||||||
|
editor.putBoolean("hasServiceBeenRunning", hasServiceBeenRunning);
|
||||||
|
editor.putBoolean("startServiceAfterAppUpdate", startServiceAfterAppUpdate);
|
||||||
|
editor.putBoolean("startNewThreadForRuleActivation", startNewThreadForRuleActivation);
|
||||||
|
editor.putBoolean("showIconWhenServiceIsRunning", showIconWhenServiceIsRunning);
|
||||||
|
editor.putBoolean("useAccelerometerForPositioning", useAccelerometerForPositioning);
|
||||||
|
editor.putString("useAccelerometerAfterIdleTime", String.valueOf(useAccelerometerAfterIdleTime));
|
||||||
|
editor.putString("accelerometerMovementThreshold", String.valueOf(accelerometerMovementThreshold));
|
||||||
|
editor.putString("speedMaximumTimeBetweenLocations", String.valueOf(speedMaximumTimeBetweenLocations));
|
||||||
|
editor.putString("MINIMUM_DISTANCE_CHANGE_FOR_GPS_UPDATE", String.valueOf(minimumDistanceChangeForGpsUpdate));
|
||||||
|
editor.putString("MINIMUM_DISTANCE_CHANGE_FOR_NETWORK_UPDATE", String.valueOf(minimumDistanceChangeForNetworkUpdate));
|
||||||
|
editor.putString("SATISFACTORY_ACCURACY_GPS", String.valueOf(satisfactoryAccuracyGps));
|
||||||
|
editor.putString("SATISFACTORY_ACCURACY_NETWORK", String.valueOf(satisfactoryAccuracyNetwork));
|
||||||
|
editor.putString("gpsTimeout", String.valueOf(gpsTimeout));
|
||||||
|
editor.putString("MINIMUM_TIME_BETWEEN_UPDATE", String.valueOf(minimumTimeBetweenUpdate));
|
||||||
|
editor.putString("timeBetweenNoiseLevelMeasurements", String.valueOf(timeBetweenNoiseLevelMeasurements));
|
||||||
|
editor.putString("lengthOfNoiseLevelMeasurements", String.valueOf(lengthOfNoiseLevelMeasurements));
|
||||||
|
editor.putString("referenceValueForNoiseLevelMeasurements", String.valueOf(referenceValueForNoiseLevelMeasurements));
|
||||||
|
editor.putString("logLevel", String.valueOf(logLevel));
|
||||||
|
editor.putString("logFileMaxSize", String.valueOf(logFileMaxSize));
|
||||||
|
editor.putBoolean("httpAcceptAllCertificates", httpAcceptAllCertificates);
|
||||||
|
editor.putString("httpAttempts", String.valueOf(httpAttempts));
|
||||||
|
editor.putString("httpAttemptsTimeout", String.valueOf(httpAttemptsTimeout));
|
||||||
|
editor.putString("httpAttemptGap", String.valueOf(httpAttemptGap));
|
||||||
|
editor.putString("locationRingBufferSize", String.valueOf(locationRingBufferSize));
|
||||||
|
editor.putString("timeBetweenProcessMonitorings", String.valueOf(timeBetweenProcessMonitorings));
|
||||||
|
editor.putString("activityDetectionFrequency", String.valueOf(activityDetectionFrequency));
|
||||||
|
editor.putString("activityDetectionRequiredProbability", String.valueOf(activityDetectionRequiredProbability));
|
||||||
|
editor.putBoolean("privacyLocationing", privacyLocationing);
|
||||||
|
editor.putString("startScreen", String.valueOf(startScreen));
|
||||||
|
editor.putBoolean("executeRulesAndProfilesWithSingleClick", executeRulesAndProfilesWithSingleClick);
|
||||||
|
|
||||||
|
editor.putBoolean("lockSoundChanges", lockSoundChanges);
|
||||||
|
editor.putBoolean("noticeAndroid9MicrophoneShown", noticeAndroid9MicrophoneShown);
|
||||||
|
editor.putBoolean("noticeAndroid10WifiShown", noticeAndroid10WifiShown);
|
||||||
|
|
||||||
|
if(lastActivePoi == null)
|
||||||
|
editor.putString("lastActivePoi", "null");
|
||||||
|
else
|
||||||
|
editor.putString("lastActivePoi", lastActivePoi.getName());
|
||||||
|
|
||||||
|
editor.putBoolean("rememberLastActivePoi", rememberLastActivePoi);
|
||||||
|
|
||||||
|
editor.commit();
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", context.getResources().getString(R.string.settings), context.getResources().getString(R.string.errorWritingSettingsToPersistentMemory), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean eraseSettings(Context context)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", context.getResources().getString(R.string.settings), context.getResources().getString(R.string.invalidStuffStoredInSettingsErasing), 1);
|
||||||
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
prefs.edit().clear().commit();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", context.getResources().getString(R.string.settings), context.getResources().getString(R.string.errorWritingSettingsToPersistentMemory), 1);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getStringSet(String arg0, Set<String> arg1)
|
||||||
|
{
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
75
app/src/main/java/com/jens/automation2/TimeFrame.java
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
package com.jens.automation2;
|
||||||
|
|
||||||
|
import java.sql.Time;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class TimeFrame
|
||||||
|
{
|
||||||
|
// Defines a timeframe
|
||||||
|
private Time triggerTimeStart;
|
||||||
|
private Time triggerTimeStop;
|
||||||
|
|
||||||
|
private ArrayList<Integer> dayList = new ArrayList<Integer>();
|
||||||
|
public ArrayList<Integer> getDayList()
|
||||||
|
{
|
||||||
|
return dayList;
|
||||||
|
}
|
||||||
|
public void setDayList(ArrayList<Integer> dayList)
|
||||||
|
{
|
||||||
|
this.dayList = dayList;
|
||||||
|
}
|
||||||
|
public void setDayListFromString(String dayListString)
|
||||||
|
{
|
||||||
|
// Log.i("Parsing", "Full string: " + dayListString);
|
||||||
|
char[] dayListCharArray = dayListString.toCharArray();
|
||||||
|
|
||||||
|
dayList = new ArrayList<Integer>();
|
||||||
|
for(char item : dayListCharArray)
|
||||||
|
{
|
||||||
|
// Log.i("Parsing", String.valueOf(item));
|
||||||
|
dayList.add(Integer.parseInt(String.valueOf(item)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Time getTriggerTimeStart()
|
||||||
|
{
|
||||||
|
return triggerTimeStart;
|
||||||
|
}
|
||||||
|
public void setTriggerTimeStart(Time triggerTimeStart)
|
||||||
|
{
|
||||||
|
this.triggerTimeStart = triggerTimeStart;
|
||||||
|
}
|
||||||
|
public Time getTriggerTimeStop()
|
||||||
|
{
|
||||||
|
return triggerTimeStop;
|
||||||
|
}
|
||||||
|
public void setTriggerTimeStop(Time triggerTimeStop)
|
||||||
|
{
|
||||||
|
this.triggerTimeStop = triggerTimeStop;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TimeFrame (Time timeStart, Time timeEnd, ArrayList<Integer> dayList2)
|
||||||
|
{
|
||||||
|
this.setTriggerTimeStart(timeStart);
|
||||||
|
this.setTriggerTimeStop(timeEnd);
|
||||||
|
this.setDayList(dayList2);
|
||||||
|
}
|
||||||
|
TimeFrame (String fileContent)
|
||||||
|
{
|
||||||
|
String[] dateArray = fileContent.split("/"); // example: timestart/timestop/days[int]
|
||||||
|
this.setTriggerTimeStart(Time.valueOf(dateArray[0]));
|
||||||
|
this.setTriggerTimeStop(Time.valueOf(dateArray[1]));
|
||||||
|
this.setDayListFromString(dateArray[2]);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
String returnString = this.getTriggerTimeStart().toString() + "/" + this.getTriggerTimeStop().toString() + "/";
|
||||||
|
|
||||||
|
for(Integer oneDay : this.getDayList())
|
||||||
|
returnString += String.valueOf(oneDay);
|
||||||
|
|
||||||
|
return returnString;
|
||||||
|
}
|
||||||
|
}
|
479
app/src/main/java/com/jens/automation2/Trigger.java
Normal file
@ -0,0 +1,479 @@
|
|||||||
|
package com.jens.automation2;
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothDevice;
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import com.jens.automation2.receivers.ActivityDetectionReceiver;
|
||||||
|
import com.jens.automation2.receivers.BluetoothReceiver;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
|
||||||
|
public class Trigger
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Can be several things:
|
||||||
|
* -PointOfInterest
|
||||||
|
* -TimeFrame
|
||||||
|
* -Event (like charging, cable plugged, etc.)
|
||||||
|
*/
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
public String getFullName(Context context)
|
||||||
|
{
|
||||||
|
switch(this)
|
||||||
|
{
|
||||||
|
case pointOfInterest:
|
||||||
|
return context.getResources().getString(R.string.triggerPointOfInterest);
|
||||||
|
case timeFrame:
|
||||||
|
return context.getResources().getString(R.string.triggerTimeFrame);
|
||||||
|
case charging:
|
||||||
|
return context.getResources().getString(R.string.triggerCharging);
|
||||||
|
case batteryLevel:
|
||||||
|
return context.getResources().getString(R.string.batteryLevel);
|
||||||
|
case usb_host_connection:
|
||||||
|
return context.getResources().getString(R.string.triggerUsb_host_connection);
|
||||||
|
case speed:
|
||||||
|
return context.getResources().getString(R.string.triggerSpeed);
|
||||||
|
case noiseLevel:
|
||||||
|
return context.getResources().getString(R.string.triggerNoiseLevel);
|
||||||
|
case wifiConnection:
|
||||||
|
return context.getResources().getString(R.string.wifiConnection);
|
||||||
|
case process_started_stopped:
|
||||||
|
return context.getResources().getString(R.string.anotherAppIsRunning);
|
||||||
|
case airplaneMode:
|
||||||
|
return context.getResources().getString(R.string.airplaneMode);
|
||||||
|
case roaming:
|
||||||
|
return context.getResources().getString(R.string.roaming);
|
||||||
|
case phoneCall:
|
||||||
|
return context.getResources().getString(R.string.phoneCall);
|
||||||
|
case nfcTag:
|
||||||
|
return context.getResources().getString(R.string.nfcTag);
|
||||||
|
case activityDetection:
|
||||||
|
return context.getResources().getString(R.string.activityDetection);
|
||||||
|
case bluetoothConnection:
|
||||||
|
return context.getResources().getString(R.string.bluetoothConnection);
|
||||||
|
case headsetPlugged:
|
||||||
|
return context.getResources().getString(R.string.triggerHeadsetPlugged);
|
||||||
|
default:
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
private boolean triggerParameter; //if true->started event, if false->stopped
|
||||||
|
|
||||||
|
private Trigger_Enum triggerType = null;
|
||||||
|
private PointOfInterest pointOfInterest = null;
|
||||||
|
private TimeFrame timeFrame;
|
||||||
|
|
||||||
|
private double speed; //km/h
|
||||||
|
private long noiseLevelDb;
|
||||||
|
private String wifiName = "";
|
||||||
|
private String processName = null;
|
||||||
|
private int batteryLevel;
|
||||||
|
private int phoneDirection = 0; // 0=any, 1=incoming, 2=outgoing
|
||||||
|
private String phoneNumber = null;
|
||||||
|
private String nfcTagId = null;
|
||||||
|
private String bluetoothEvent = null;
|
||||||
|
private String bluetoothDeviceAddress = null;
|
||||||
|
private int activityDetectionType = -1;
|
||||||
|
private int headphoneType = -1;
|
||||||
|
|
||||||
|
public int getHeadphoneType()
|
||||||
|
{
|
||||||
|
return headphoneType;
|
||||||
|
}
|
||||||
|
public void setHeadphoneType(int headphoneType)
|
||||||
|
{
|
||||||
|
this.headphoneType = headphoneType;
|
||||||
|
}
|
||||||
|
public String getNfcTagId()
|
||||||
|
{
|
||||||
|
return nfcTagId;
|
||||||
|
}
|
||||||
|
public void setNfcTagId(String nfcTagId)
|
||||||
|
{
|
||||||
|
this.nfcTagId = nfcTagId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getActivityDetectionType()
|
||||||
|
{
|
||||||
|
return activityDetectionType;
|
||||||
|
}
|
||||||
|
public void setActivityDetectionType(int activityDetectionType)
|
||||||
|
{
|
||||||
|
this.activityDetectionType = activityDetectionType;
|
||||||
|
}
|
||||||
|
public String getBluetoothDeviceAddress()
|
||||||
|
{
|
||||||
|
return bluetoothDeviceAddress;
|
||||||
|
}
|
||||||
|
public void setBluetoothDeviceAddress(String bluetoothDeviceAddress)
|
||||||
|
{
|
||||||
|
this.bluetoothDeviceAddress = bluetoothDeviceAddress;
|
||||||
|
}
|
||||||
|
public void setPhoneNumber(String phoneNumber)
|
||||||
|
{
|
||||||
|
this.phoneNumber = phoneNumber;
|
||||||
|
}
|
||||||
|
public String getPhoneNumber()
|
||||||
|
{
|
||||||
|
return phoneNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPhoneDirection(int phoneDirection)
|
||||||
|
{
|
||||||
|
this.phoneDirection = phoneDirection;
|
||||||
|
}
|
||||||
|
public int getPhoneDirection()
|
||||||
|
{
|
||||||
|
return phoneDirection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBatteryLevel()
|
||||||
|
{
|
||||||
|
return batteryLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBatteryLevel(int batteryLevel)
|
||||||
|
{
|
||||||
|
this.batteryLevel = batteryLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getProcessName()
|
||||||
|
{
|
||||||
|
return processName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProcessName(String processName)
|
||||||
|
{
|
||||||
|
this.processName = processName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PointOfInterest getPointOfInterest()
|
||||||
|
{
|
||||||
|
return pointOfInterest;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPointOfInterest(PointOfInterest setPointOfInterest)
|
||||||
|
{
|
||||||
|
this.pointOfInterest = setPointOfInterest;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getSpeed()
|
||||||
|
{
|
||||||
|
return speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSpeed(double speed)
|
||||||
|
{
|
||||||
|
this.speed = speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getNoiseLevelDb()
|
||||||
|
{
|
||||||
|
return noiseLevelDb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNoiseLevelDb(long noiseLevelDb)
|
||||||
|
{
|
||||||
|
this.noiseLevelDb = noiseLevelDb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Trigger_Enum getTriggerType()
|
||||||
|
{
|
||||||
|
return triggerType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTriggerType(Trigger_Enum settriggerType)
|
||||||
|
{
|
||||||
|
this.triggerType = settriggerType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getTriggerParameter()
|
||||||
|
{
|
||||||
|
return triggerParameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTriggerParameter(boolean triggerParameter)
|
||||||
|
{
|
||||||
|
this.triggerParameter = triggerParameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TimeFrame getTimeFrame()
|
||||||
|
{
|
||||||
|
return timeFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTimeFrame(TimeFrame timeFrame)
|
||||||
|
{
|
||||||
|
this.timeFrame = timeFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
StringBuilder returnString = new StringBuilder();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* public enum TriggerType_Enum { pointOfInterest, timeFrame, event };
|
||||||
|
public enum Event_Enum { charging_started, charging_stopped, usb_connected, usb_disconnected };
|
||||||
|
|
||||||
|
private TriggerType_Enum triggerType;
|
||||||
|
private PointOfInterest pointOfInterest;
|
||||||
|
private Event_Enum event;
|
||||||
|
private TimeFrame timeFrame;
|
||||||
|
*/
|
||||||
|
|
||||||
|
switch(this.getTriggerType())
|
||||||
|
{
|
||||||
|
case charging:
|
||||||
|
if(getTriggerParameter())
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.starting) + " ");
|
||||||
|
else
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.stopping) + " ");
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.triggerCharging));
|
||||||
|
break;
|
||||||
|
case batteryLevel:
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.batteryLevel));
|
||||||
|
if(getTriggerParameter())
|
||||||
|
returnString.append(" " + Miscellaneous.getAnyContext().getResources().getString(R.string.exceeds) + " ");
|
||||||
|
else
|
||||||
|
returnString.append(" " + Miscellaneous.getAnyContext().getResources().getString(R.string.dropsBelow) + " ");
|
||||||
|
returnString.append(String.valueOf(this.getBatteryLevel()) + " %");
|
||||||
|
break;
|
||||||
|
case usb_host_connection:
|
||||||
|
if(getTriggerParameter())
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.connecting) + " ");
|
||||||
|
else
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.disconnecting) + " ");
|
||||||
|
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.triggerUsb_host_connection));
|
||||||
|
break;
|
||||||
|
case pointOfInterest:
|
||||||
|
if(this.getPointOfInterest() != null)
|
||||||
|
{
|
||||||
|
if(getTriggerParameter())
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.entering) + " ");
|
||||||
|
else
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.leaving) + " ");
|
||||||
|
|
||||||
|
returnString.append(this.getPointOfInterest().getName().toString());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(getTriggerParameter())
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.leaving) + " " + Miscellaneous.getAnyContext().getResources().getString(R.string.anyLocation));
|
||||||
|
else
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.entering) + " " + Miscellaneous.getAnyContext().getResources().getString(R.string.anyLocation));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case timeFrame:
|
||||||
|
if(getTriggerParameter())
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.entering) + " ");
|
||||||
|
else
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.leaving) + " ");
|
||||||
|
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.triggerTimeFrame) + ": " + this.getTimeFrame().getTriggerTimeStart().toString() + " " + Miscellaneous.getAnyContext().getResources().getString(R.string.until) + " " + this.getTimeFrame().getTriggerTimeStop().toString() + " on days " + this.getTimeFrame().getDayList().toString());
|
||||||
|
break;
|
||||||
|
case speed:
|
||||||
|
if(getTriggerParameter())
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.exceeding) + " ");
|
||||||
|
else
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.droppingBelow) + " ");
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.triggerSpeed) + ": " + String.valueOf(this.getSpeed()) + " km/h");
|
||||||
|
break;
|
||||||
|
case noiseLevel:
|
||||||
|
if(getTriggerParameter())
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.exceeding) + " ");
|
||||||
|
else
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.droppingBelow) + " ");
|
||||||
|
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.triggerNoiseLevel) + ": " + String.valueOf(this.getNoiseLevelDb()) + " dB");
|
||||||
|
break;
|
||||||
|
case wifiConnection:
|
||||||
|
String wifiDisplayName = "";
|
||||||
|
if(this.getWifiName().length() == 0)
|
||||||
|
wifiDisplayName += Miscellaneous.getAnyContext().getResources().getString(R.string.anyWifi);
|
||||||
|
else
|
||||||
|
wifiDisplayName += this.getWifiName();
|
||||||
|
|
||||||
|
if(getTriggerParameter())
|
||||||
|
returnString.append(String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.connectedToWifi), wifiDisplayName));
|
||||||
|
else
|
||||||
|
returnString.append(String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.disconnectedFromWifi), wifiDisplayName));
|
||||||
|
|
||||||
|
break;
|
||||||
|
case process_started_stopped:
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.application) + " " + this.getProcessName() + " " + Miscellaneous.getAnyContext().getResources().getString(R.string.is) + " ");
|
||||||
|
if(this.triggerParameter)
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.started));
|
||||||
|
else
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.stopped));
|
||||||
|
break;
|
||||||
|
case airplaneMode:
|
||||||
|
if(getTriggerParameter())
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.activated) + " ");
|
||||||
|
else
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.deactivated) + " ");
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.airplaneMode));
|
||||||
|
break;
|
||||||
|
case roaming:
|
||||||
|
if(getTriggerParameter())
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.activated) + " ");
|
||||||
|
else
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.deactivated) + " ");
|
||||||
|
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) + " ");
|
||||||
|
|
||||||
|
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
|
||||||
|
// if(getTriggerParameter())
|
||||||
|
// returnString += Miscellaneous.getAnyContext().getResources().getString(R.string.activated) + " ";
|
||||||
|
// else
|
||||||
|
// returnString += Miscellaneous.getAnyContext().getResources().getString(R.string.deactivated) + " ";
|
||||||
|
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.closeTo) + " " + Miscellaneous.getAnyContext().getResources().getString(R.string.nfcTag) + " " + Miscellaneous.getAnyContext().getResources().getString(R.string.withLabel) + " " + this.getNfcTagId());
|
||||||
|
break;
|
||||||
|
case activityDetection:
|
||||||
|
// This type doesn't have an activate/deactivate equivalent, at least not yet.
|
||||||
|
returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.detectedActivity) + " " + ActivityDetectionReceiver.getDescription(getActivityDetectionType()));
|
||||||
|
break;
|
||||||
|
case bluetoothConnection:
|
||||||
|
String device = Miscellaneous.getAnyContext().getResources().getString(R.string.anyDevice);
|
||||||
|
// if(this.bluetoothDeviceAddress != null)
|
||||||
|
// {
|
||||||
|
if(bluetoothDeviceAddress.equals("<any>"))
|
||||||
|
{
|
||||||
|
device = Miscellaneous.getAnyContext().getResources().getString(R.string.any);
|
||||||
|
}
|
||||||
|
else if(bluetoothDeviceAddress.equals("<none>"))
|
||||||
|
{
|
||||||
|
device = Miscellaneous.getAnyContext().getResources().getString(R.string.noDevice);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
device = BluetoothReceiver.getDeviceByAddress(bluetoothDeviceAddress).getName() + " (" + this.bluetoothDeviceAddress + ")";
|
||||||
|
}
|
||||||
|
catch(NullPointerException e)
|
||||||
|
{
|
||||||
|
device = Miscellaneous.getAnyContext().getResources().getString(R.string.invalidDevice);
|
||||||
|
Miscellaneous.logEvent("w", "Trigger", Miscellaneous.getAnyContext().getResources().getString(R.string.invalidDevice), 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(bluetoothEvent.equals(BluetoothDevice.ACTION_ACL_CONNECTED) | bluetoothEvent.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED))
|
||||||
|
if(this.triggerParameter)
|
||||||
|
returnString.append(String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.bluetoothConnectionTo), device));
|
||||||
|
else
|
||||||
|
returnString.append(String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.bluetoothDisconnectFrom), device));
|
||||||
|
else if(bluetoothEvent.equals(BluetoothDevice.ACTION_FOUND))
|
||||||
|
if(this.triggerParameter)
|
||||||
|
returnString.append(String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.bluetoothDeviceInRange), device));
|
||||||
|
else
|
||||||
|
returnString.append(String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.bluetoothDeviceOutOfRange), device));
|
||||||
|
// }
|
||||||
|
break;
|
||||||
|
case headsetPlugged:
|
||||||
|
String type;
|
||||||
|
switch(headphoneType)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
type = Miscellaneous.getAnyContext().getResources().getString(R.string.headphoneSimple);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
type = Miscellaneous.getAnyContext().getResources().getString(R.string.headphoneMicrophone);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
type = Miscellaneous.getAnyContext().getResources().getString(R.string.headphoneAny);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
type = "not set";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(getTriggerParameter())
|
||||||
|
returnString.append(String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.headsetConnected), type));
|
||||||
|
else
|
||||||
|
returnString.append(String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.headsetDisconnected), type));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
returnString.append("error");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnString.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static String[] getTriggerTypesAsArray()
|
||||||
|
{
|
||||||
|
ArrayList<String> triggerTypesList = new ArrayList<String>();
|
||||||
|
|
||||||
|
/*for(int i=0; i<Trigger_Enum.values().length; i++)
|
||||||
|
{
|
||||||
|
triggerTypesList.add(Trigger_Enum.values()[i].toString());
|
||||||
|
}*/
|
||||||
|
for(Trigger_Enum triggerType : Trigger_Enum.values())
|
||||||
|
triggerTypesList.add(triggerType.name());
|
||||||
|
|
||||||
|
return (String[])triggerTypesList.toArray(new String[triggerTypesList.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static String[] getTriggerTypesStringAsArray(Context context)
|
||||||
|
{
|
||||||
|
ArrayList<String> triggerTypesList = new ArrayList<String>();
|
||||||
|
|
||||||
|
/*for(int i=0; i<Trigger_Enum.values().length; i++)
|
||||||
|
{
|
||||||
|
triggerTypesList.add(Trigger_Enum.values()[i].getFullName(context));
|
||||||
|
}*/
|
||||||
|
for(Trigger_Enum triggerType : Trigger_Enum.values())
|
||||||
|
triggerTypesList.add(triggerType.getFullName(context));
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
public Object getBluetoothEvent()
|
||||||
|
{
|
||||||
|
return this.bluetoothEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
1301
app/src/main/java/com/jens/automation2/XmlFileInterface.java
Normal file
@ -0,0 +1,407 @@
|
|||||||
|
package com.jens.automation2.location;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.location.Criteria;
|
||||||
|
import android.location.Location;
|
||||||
|
import android.location.LocationListener;
|
||||||
|
import android.location.LocationManager;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Message;
|
||||||
|
import android.telephony.CellLocation;
|
||||||
|
import android.telephony.PhoneStateListener;
|
||||||
|
import android.telephony.TelephonyManager;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.jens.automation2.Action;
|
||||||
|
import com.jens.automation2.ActivityPermissions;
|
||||||
|
import com.jens.automation2.AutomationService;
|
||||||
|
import com.jens.automation2.Miscellaneous;
|
||||||
|
import com.jens.automation2.PointOfInterest;
|
||||||
|
import com.jens.automation2.R;
|
||||||
|
import com.jens.automation2.Rule;
|
||||||
|
import com.jens.automation2.Settings;
|
||||||
|
import com.jens.automation2.receivers.ConnectivityReceiver;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public class CellLocationChangedReceiver extends PhoneStateListener
|
||||||
|
{
|
||||||
|
private LocationManager myLocationManager;
|
||||||
|
private Location currentLocation;
|
||||||
|
public MyLocationListener myLocationListener = new MyLocationListener();
|
||||||
|
public Boolean locationListenerArmed = false;
|
||||||
|
public Date lastCellLocationUpdate;
|
||||||
|
protected static boolean followUpdate = true;
|
||||||
|
protected static TimeoutHandler timeoutHandler = null;
|
||||||
|
protected static boolean timeoutHandlerActive = false;
|
||||||
|
protected static boolean cellLocationListenerActive = false;
|
||||||
|
protected static CellLocationChangedReceiver instance;
|
||||||
|
protected static TelephonyManager telephonyManager;
|
||||||
|
|
||||||
|
public static boolean isCellLocationListenerActive()
|
||||||
|
{
|
||||||
|
return cellLocationListenerActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static CellLocationChangedReceiver getInstance()
|
||||||
|
{
|
||||||
|
if(instance == null)
|
||||||
|
instance = new CellLocationChangedReceiver();
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCellLocationChanged(CellLocation location)
|
||||||
|
{
|
||||||
|
super.onCellLocationChanged(location);
|
||||||
|
|
||||||
|
if(Settings.useAccelerometerForPositioning)
|
||||||
|
SensorActivity.startAccelerometerTimer();
|
||||||
|
|
||||||
|
if(followUpdate)
|
||||||
|
{
|
||||||
|
Date currentDate = new Date();
|
||||||
|
|
||||||
|
Miscellaneous.logEvent("i", "CellLocation", String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.cellMastChanged), location.toString()), 3);
|
||||||
|
|
||||||
|
if(Settings.useAccelerometerForPositioning) //and last cell mast change longer than x minutes in the past
|
||||||
|
{
|
||||||
|
PointOfInterest possiblyActivePoi = PointOfInterest.getActivePoi();
|
||||||
|
if( possiblyActivePoi != null ) //if any poi is active
|
||||||
|
{
|
||||||
|
// Did the last activated rule activate wifi? Then we don't need accelerometer, we'll use wifiReceiver
|
||||||
|
try
|
||||||
|
{
|
||||||
|
for(Action action : Rule.getLastActivatedRule().getActionSet())
|
||||||
|
{
|
||||||
|
if(action.getAction() == Action.Action_Enum.turnWifiOn)
|
||||||
|
{
|
||||||
|
// we will be using wifiReceiver, deactivate AccelerometerTimer if applicable
|
||||||
|
SensorActivity.stopAccelerometerTimer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(NullPointerException ne)
|
||||||
|
{
|
||||||
|
// Nothing to do, there is no last activated rule. Wifi hasn't been activated so we don't
|
||||||
|
// deactive accelerometer receiver.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(lastCellLocationUpdate == null)
|
||||||
|
SensorActivity.startAccelerometerTimer();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
long timeSinceLastUpdate = currentDate.getTime() - lastCellLocationUpdate.getTime(); //in milliseconds
|
||||||
|
if(timeSinceLastUpdate > Settings.useAccelerometerAfterIdleTime*60*1000)
|
||||||
|
{
|
||||||
|
SensorActivity.startAccelerometerTimer();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//reset timer
|
||||||
|
SensorActivity.resetAccelerometerTimer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastCellLocationUpdate = currentDate;
|
||||||
|
|
||||||
|
myLocationManager = (LocationManager) AutomationService.getInstance().getSystemService(Context.LOCATION_SERVICE);
|
||||||
|
currentLocation = getLocation("coarse");
|
||||||
|
AutomationService.getInstance().getLocationProvider().setCurrentLocation(currentLocation, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "CellLocation", "Cell mast changed, but only initial update, ignoring this one.", 4);
|
||||||
|
followUpdate = true; //for next run
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Location getLocation(String accuracy)
|
||||||
|
{
|
||||||
|
Criteria crit = new Criteria();
|
||||||
|
|
||||||
|
String myProviderName;
|
||||||
|
|
||||||
|
// If privacy mode or no data connection available
|
||||||
|
if(Settings.privacyLocationing | !ConnectivityReceiver.isDataConnectionAvailable(AutomationService.getInstance()))
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "CellLocation", Miscellaneous.getAnyContext().getResources().getString(R.string.enforcingGps), 4);
|
||||||
|
myProviderName = LocationManager.GPS_PROVIDER;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "CellLocation", Miscellaneous.getAnyContext().getResources().getString(R.string.notEnforcingGps), 4);
|
||||||
|
|
||||||
|
if(accuracy.equals("coarse"))
|
||||||
|
{
|
||||||
|
crit.setPowerRequirement(Criteria.POWER_LOW);
|
||||||
|
crit.setAltitudeRequired(false);
|
||||||
|
crit.setSpeedRequired(false);
|
||||||
|
crit.setBearingRequired(false);
|
||||||
|
crit.setCostAllowed(false);
|
||||||
|
crit.setAccuracy(Criteria.ACCURACY_COARSE);
|
||||||
|
}
|
||||||
|
else //equals "fine"
|
||||||
|
{
|
||||||
|
crit.setPowerRequirement(Criteria.POWER_LOW);
|
||||||
|
crit.setAltitudeRequired(false);
|
||||||
|
crit.setSpeedRequired(false);
|
||||||
|
crit.setBearingRequired(false);
|
||||||
|
//crit.setCostAllowed(false);
|
||||||
|
crit.setAccuracy(Criteria.ACCURACY_FINE);
|
||||||
|
}
|
||||||
|
|
||||||
|
myProviderName = myLocationManager.getBestProvider(crit, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(myProviderName == null)
|
||||||
|
{
|
||||||
|
Toast.makeText(Miscellaneous.getAnyContext(), "No suitable location provider could be used.", Toast.LENGTH_LONG).show();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(!myLocationManager.isProviderEnabled(myProviderName))
|
||||||
|
{
|
||||||
|
if(myProviderName.equals(LocationManager.NETWORK_PROVIDER))
|
||||||
|
myProviderName = LocationManager.GPS_PROVIDER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
|
||||||
|
myProviderName = LocationManager.GPS_PROVIDER;
|
||||||
|
|
||||||
|
// Arm location updates
|
||||||
|
if(!locationListenerArmed)
|
||||||
|
startLocationListener(myProviderName);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return myLocationManager.getLastKnownLocation(myProviderName);
|
||||||
|
}
|
||||||
|
catch(NullPointerException e)
|
||||||
|
{
|
||||||
|
Toast.makeText(Miscellaneous.getAnyContext(), "No last known location. Aborting...", Toast.LENGTH_LONG).show();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startLocationListener(String providerToBeUsed)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "LocationListener", "Arming location listener, Provider " + providerToBeUsed, 4);
|
||||||
|
myLocationManager.requestLocationUpdates(providerToBeUsed, Settings.minimumTimeBetweenUpdate, Settings.minimumDistanceChangeForNetworkUpdate, myLocationListener);
|
||||||
|
locationListenerArmed = true;
|
||||||
|
|
||||||
|
// (re)set timeout
|
||||||
|
if(timeoutHandlerActive)
|
||||||
|
stopTimeOutHandler();
|
||||||
|
startTimeOutHandler();
|
||||||
|
}
|
||||||
|
private void stopLocationListener()
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "LocationListener", "Disarming location listener.", 4);
|
||||||
|
myLocationManager.removeUpdates(myLocationListener);
|
||||||
|
locationListenerArmed = false;
|
||||||
|
|
||||||
|
if(timeoutHandlerActive)
|
||||||
|
stopTimeOutHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Location getCurrentLocation()
|
||||||
|
{
|
||||||
|
return currentLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void setCurrentLocation(Location currentLocation)
|
||||||
|
{
|
||||||
|
this.currentLocation = currentLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class MyLocationListener implements LocationListener
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onLocationChanged(Location up2DateLocation)
|
||||||
|
{
|
||||||
|
if(timeoutHandlerActive)
|
||||||
|
{
|
||||||
|
stopTimeOutHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
setCurrentLocation(up2DateLocation);
|
||||||
|
AutomationService.getInstance().getLocationProvider().setCurrentLocation(up2DateLocation, false);
|
||||||
|
// This is relevant if the program just started, knows where it is, but hasn't reached any POI.
|
||||||
|
// The below PointOfInterest.positionUpdate() will not update the notification in that case.
|
||||||
|
// if(!currentLocation.equals(up2DateLocation))
|
||||||
|
// parentLocationProvider.parentService.updateNotification();
|
||||||
|
|
||||||
|
if(up2DateLocation.getAccuracy() < Settings.satisfactoryAccuracyNetwork)
|
||||||
|
{
|
||||||
|
myLocationManager.removeUpdates(this);
|
||||||
|
locationListenerArmed = false;
|
||||||
|
Miscellaneous.logEvent("i", "LocationListener", "Disarmed location listener, accuracy reached", 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Miscellaneous.logEvent("i", "LocationListener", "Giving update to POI class");
|
||||||
|
// PointOfInterest.positionUpdate(up2DateLocation, parentLocationProvider.parentService);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onProviderDisabled(String provider)
|
||||||
|
{
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onProviderEnabled(String provider)
|
||||||
|
{
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStatusChanged(String provider, int status, Bundle extras)
|
||||||
|
{
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TimeoutHandler extends Handler
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message msg)
|
||||||
|
{
|
||||||
|
super.handleMessage(msg);
|
||||||
|
|
||||||
|
if(msg.what == 1)
|
||||||
|
{
|
||||||
|
Context context = Miscellaneous.getAnyContext();
|
||||||
|
Miscellaneous.logEvent("i", context.getResources().getString(R.string.gpsMeasurement), context.getResources().getString(R.string.gpsMeasurementTimeout), 4);
|
||||||
|
stopLocationListener();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startTimeOutHandler()
|
||||||
|
{
|
||||||
|
if(timeoutHandler == null)
|
||||||
|
timeoutHandler = new TimeoutHandler();
|
||||||
|
|
||||||
|
Message message = new Message();
|
||||||
|
message.what = 1;
|
||||||
|
timeoutHandler.sendMessageDelayed(message, Settings.gpsTimeout * 1000);
|
||||||
|
timeoutHandlerActive = true;
|
||||||
|
}
|
||||||
|
private void stopTimeOutHandler()
|
||||||
|
{
|
||||||
|
if(timeoutHandler == null)
|
||||||
|
timeoutHandler = new TimeoutHandler();
|
||||||
|
|
||||||
|
timeoutHandler.removeMessages(1);
|
||||||
|
timeoutHandlerActive = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void startCellLocationChangedReceiver()
|
||||||
|
{
|
||||||
|
if(telephonyManager == null)
|
||||||
|
telephonyManager = (TelephonyManager) AutomationService.getInstance().getSystemService(Context.TELEPHONY_SERVICE);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(!cellLocationListenerActive)
|
||||||
|
{
|
||||||
|
if(!ConnectivityReceiver.isAirplaneMode(AutomationService.getInstance()))
|
||||||
|
{
|
||||||
|
if(WifiBroadcastReceiver.mayCellLocationReceiverBeActivated())
|
||||||
|
{
|
||||||
|
// if(!ConnectivityReceiver.isDataConnectionAvailable(parentService))
|
||||||
|
// {
|
||||||
|
telephonyManager.listen(getInstance(), PhoneStateListener.LISTEN_CELL_LOCATION);
|
||||||
|
cellLocationListenerActive = true;
|
||||||
|
Miscellaneous.logEvent("i", "cellReceiver", "Starting cellLocationListener", 4);
|
||||||
|
|
||||||
|
SensorActivity.stopAccelerometerTimer();
|
||||||
|
SensorActivity.stopAccelerometerReceiver();
|
||||||
|
// this.stopWifiReceiver();
|
||||||
|
|
||||||
|
/*
|
||||||
|
We could now set a timer when we could activate a location check.
|
||||||
|
If that fires we need to check if maybe another location check has been performed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if(!LocationProvider.speedTimerActive)
|
||||||
|
LocationProvider.startSpeedTimer(LocationProvider.getEtaAtNextPoi());
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// Miscellaneous.logEvent("i", "cellReceiver", "Not starting cellLocationListener because we have no data connection.", 4);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Miscellaneous.logEvent("w", "cellReceiver", "Wanted to activate CellLocationChangedReceiver, but Wifi-Receiver says not to.", 4);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Miscellaneous.logEvent("i", "cellReceiver", "Not starting cellLocationListener because Airplane mode is active.", 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "Wifi Listener", "Error starting cellLocationListener: " + Log.getStackTraceString(ex), 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void stopCellLocationChangedReceiver()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(cellLocationListenerActive)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "cellReceiver", "Stopping cellLocationListener", 4);
|
||||||
|
|
||||||
|
getInstance().stopTimeOutHandler();
|
||||||
|
getInstance().stopLocationListener();
|
||||||
|
|
||||||
|
if(LocationProvider.speedTimerActive)
|
||||||
|
LocationProvider.stopSpeedTimer();
|
||||||
|
|
||||||
|
telephonyManager.listen(instance, PhoneStateListener.LISTEN_NONE);
|
||||||
|
cellLocationListenerActive = false;
|
||||||
|
|
||||||
|
// May have comparison measurements active.
|
||||||
|
PointOfInterest.stopRoutine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "Wifi Listener", "Error stopping cellLocationListener: " + Log.getStackTraceString(ex), 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void resetFollowUpdate()
|
||||||
|
{
|
||||||
|
followUpdate = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean haveAllPermission()
|
||||||
|
{
|
||||||
|
return ActivityPermissions.havePermission("android.permission.ACCESS_FINE_LOCATION", Miscellaneous.getAnyContext())
|
||||||
|
&&
|
||||||
|
ActivityPermissions.havePermission("android.permission.ACCESS_COARSE_LOCATION", Miscellaneous.getAnyContext())
|
||||||
|
&&
|
||||||
|
ActivityPermissions.havePermission("android.permission.ACCESS_NETWORK_STATE", Miscellaneous.getAnyContext())
|
||||||
|
&&
|
||||||
|
ActivityPermissions.havePermission("android.permission.INTERNET", Miscellaneous.getAnyContext())
|
||||||
|
&&
|
||||||
|
ActivityPermissions.havePermission("android.permission.ACCESS_WIFI_STATE", Miscellaneous.getAnyContext());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,54 @@
|
|||||||
|
package com.jens.automation2.location;
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.google.android.gms.location.Geofence;
|
||||||
|
import com.google.android.gms.location.GeofencingEvent;
|
||||||
|
import com.jens.automation2.Miscellaneous;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static eu.chainfire.libsuperuser.Debug.TAG;
|
||||||
|
|
||||||
|
public class GeofenceBroadcastReceiver extends BroadcastReceiver
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent)
|
||||||
|
{
|
||||||
|
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
|
||||||
|
if (geofencingEvent.hasError())
|
||||||
|
{
|
||||||
|
// Miscellaneous.logEvent("i", "Geofence", geofenceTransitionDetails, 2);
|
||||||
|
// String errorMessage = GeofenceStatusCodes.getErrorString(geofencingEvent.getErrorCode());
|
||||||
|
Log.e(TAG, "Geofence error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the transition type.
|
||||||
|
int geofenceTransition = geofencingEvent.getGeofenceTransition();
|
||||||
|
|
||||||
|
// Test that the reported transition was of interest.
|
||||||
|
if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER || geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT)
|
||||||
|
{
|
||||||
|
// Get the geofences that were triggered. A single event can trigger
|
||||||
|
// multiple geofences.
|
||||||
|
List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences();
|
||||||
|
|
||||||
|
// Get the transition details as a String.
|
||||||
|
String geofenceTransitionDetails = "something happened";//getGeofenceTransitionDetails(this, geofenceTransition, triggeringGeofences);
|
||||||
|
|
||||||
|
// Send notification and log the transition details.
|
||||||
|
Miscellaneous.logEvent("i", "Geofence", geofenceTransitionDetails, 2);
|
||||||
|
Log.i(TAG, geofenceTransitionDetails);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Log the error.
|
||||||
|
// Log.e(TAG, getString(R.string.geofence_transition_invalid_type, geofenceTransition));
|
||||||
|
Log.e("Geofence", String.valueOf(geofenceTransition));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,109 @@
|
|||||||
|
package com.jens.automation2.location;
|
||||||
|
|
||||||
|
import android.app.IntentService;
|
||||||
|
import android.app.PendingIntent;
|
||||||
|
import android.content.Intent;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.google.android.gms.common.api.GoogleApiClient;
|
||||||
|
import com.google.android.gms.location.GeofencingClient;
|
||||||
|
import com.google.android.gms.location.GeofencingRequest;
|
||||||
|
import com.google.android.gms.location.LocationServices;
|
||||||
|
import com.jens.automation2.PointOfInterest;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class GeofenceIntentService extends IntentService
|
||||||
|
{
|
||||||
|
private GeofencingClient mGeofencingClient;
|
||||||
|
protected static GoogleApiClient googleApiClient = null;
|
||||||
|
PendingIntent geofencePendingIntent;
|
||||||
|
|
||||||
|
static GeofenceIntentService instance;
|
||||||
|
|
||||||
|
List<com.google.android.gms.location.Geofence> geoFenceList = new ArrayList<>();
|
||||||
|
|
||||||
|
public static GeofenceIntentService getInstance()
|
||||||
|
{
|
||||||
|
if (instance == null)
|
||||||
|
instance = new GeofenceIntentService("Automation");
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GeofenceIntentService(String name)
|
||||||
|
{
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onHandleIntent(@Nullable Intent intent)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate()
|
||||||
|
{
|
||||||
|
mGeofencingClient = LocationServices.getGeofencingClient(this);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addFence(PointOfInterest poi)
|
||||||
|
{
|
||||||
|
com.google.android.gms.location.Geofence geofence = new com.google.android.gms.location.Geofence.Builder()
|
||||||
|
.setRequestId(poi.getName()) // Geofence ID
|
||||||
|
.setCircularRegion(poi.getLocation().getLatitude(), poi.getLocation().getLongitude(), (float) poi.getRadius()) // defining fence region
|
||||||
|
.setExpirationDuration(com.google.android.gms.location.Geofence.NEVER_EXPIRE) // expiring date
|
||||||
|
// Transition types that it should look for
|
||||||
|
.setTransitionTypes(com.google.android.gms.location.Geofence.GEOFENCE_TRANSITION_ENTER | com.google.android.gms.location.Geofence.GEOFENCE_TRANSITION_EXIT)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
geoFenceList.add(geofence);
|
||||||
|
|
||||||
|
GeofencingRequest request = new GeofencingRequest.Builder()
|
||||||
|
// Notification to trigger when the Geofence is created
|
||||||
|
.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)
|
||||||
|
.addGeofence(geofence) // add a Geofence
|
||||||
|
.build();
|
||||||
|
|
||||||
|
mGeofencingClient.removeGeofences(getGeofencePendingIntent());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void startService()
|
||||||
|
{
|
||||||
|
for (PointOfInterest poi : PointOfInterest.getPointOfInterestCollection())
|
||||||
|
getInstance().addFence(poi);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void stopService()
|
||||||
|
{
|
||||||
|
for (PointOfInterest poi : PointOfInterest.getPointOfInterestCollection())
|
||||||
|
getInstance().addFence(poi);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a PendingIntent to send with the request to add or remove Geofences. Location Services
|
||||||
|
* issues the Intent inside this PendingIntent whenever a geofence transition occurs for the
|
||||||
|
* current list of geofences.
|
||||||
|
*
|
||||||
|
* @return A PendingIntent for the IntentService that handles geofence transitions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
private PendingIntent getGeofencePendingIntent()
|
||||||
|
{
|
||||||
|
// Reuse the PendingIntent if we already have it.
|
||||||
|
if (geofencePendingIntent != null)
|
||||||
|
{
|
||||||
|
return geofencePendingIntent;
|
||||||
|
}
|
||||||
|
Intent intent = new Intent(this, GeofenceBroadcastReceiver.class);
|
||||||
|
// We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when
|
||||||
|
// calling addGeofences() and removeGeofences().
|
||||||
|
geofencePendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||||
|
return geofencePendingIntent;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,506 @@
|
|||||||
|
package com.jens.automation2.location;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.location.Location;
|
||||||
|
import android.location.LocationListener;
|
||||||
|
import android.location.LocationManager;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Message;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.jens.automation2.ActivityMainScreen;
|
||||||
|
import com.jens.automation2.AutomationService;
|
||||||
|
import com.jens.automation2.Miscellaneous;
|
||||||
|
import com.jens.automation2.PointOfInterest;
|
||||||
|
import com.jens.automation2.R;
|
||||||
|
import com.jens.automation2.Rule;
|
||||||
|
import com.jens.automation2.Settings;
|
||||||
|
import com.jens.automation2.Trigger.Trigger_Enum;
|
||||||
|
import com.jens.automation2.receivers.ConnectivityReceiver;
|
||||||
|
import com.jens.automation2.receivers.PhoneStatusListener;
|
||||||
|
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Calendar;
|
||||||
|
|
||||||
|
public class LocationProvider
|
||||||
|
{
|
||||||
|
|
||||||
|
protected static boolean passiveLocationListenerActive = false;
|
||||||
|
|
||||||
|
protected static LocationListener passiveLocationListener;
|
||||||
|
|
||||||
|
protected static LocationProvider locationProviderInstance = null;
|
||||||
|
|
||||||
|
protected AutomationService parentService;
|
||||||
|
public AutomationService getParentService()
|
||||||
|
{
|
||||||
|
return parentService;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Location currentLocation;
|
||||||
|
protected static Location currentLocationStaticCopy;
|
||||||
|
protected static double speed;
|
||||||
|
protected ArrayList<Location> locationList = new ArrayList<Location>();
|
||||||
|
protected static Handler speedHandler = null;
|
||||||
|
protected static boolean speedTimerActive = false;
|
||||||
|
protected static Calendar etaAtNextPoi = null;
|
||||||
|
|
||||||
|
public static Calendar getEtaAtNextPoi()
|
||||||
|
{
|
||||||
|
return etaAtNextPoi;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocationProvider(AutomationService parent)
|
||||||
|
{
|
||||||
|
parentService = parent;
|
||||||
|
locationProviderInstance = this;
|
||||||
|
|
||||||
|
startLocationService();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LocationProvider getInstance()
|
||||||
|
{
|
||||||
|
return locationProviderInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Location getCurrentLocation()
|
||||||
|
{
|
||||||
|
return currentLocation;
|
||||||
|
}
|
||||||
|
public static Location getLastKnownLocation()
|
||||||
|
{
|
||||||
|
return currentLocationStaticCopy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double getSpeed()
|
||||||
|
{
|
||||||
|
return speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setSpeed(double speed)
|
||||||
|
{
|
||||||
|
LocationProvider.speed = speed;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Check if the last location update may be to old.
|
||||||
|
It could be that for whatever reason we didn't get a recent location, but the current speed
|
||||||
|
indicates we have moved quite a bit.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Calendar now = Calendar.getInstance();
|
||||||
|
|
||||||
|
float distanceToClosestPoi = PointOfInterest.getClosestPOI(getLastKnownLocation()).getLocation().distanceTo(getLastKnownLocation());
|
||||||
|
long timeInSecondsPassedSinceLastLocationUpdate = (now.getTimeInMillis() - getLastKnownLocation().getTime()) / 1000;
|
||||||
|
|
||||||
|
// Could be we were driving towards it instead of away, but we'll ignore that for the moment.
|
||||||
|
|
||||||
|
long secondsRequiredForArrival = now.getTimeInMillis()/1000 / (1000 / 60 * 60);
|
||||||
|
now.add(Calendar.SECOND, (int)secondsRequiredForArrival);
|
||||||
|
|
||||||
|
etaAtNextPoi = now;
|
||||||
|
|
||||||
|
if(speedTimerActive)
|
||||||
|
resetSpeedTimer(etaAtNextPoi);
|
||||||
|
else
|
||||||
|
startSpeedTimer(etaAtNextPoi);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrentLocation(Location newLocation, boolean skipVerification)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "Location", "Setting location.", 4);
|
||||||
|
|
||||||
|
currentLocation = newLocation;
|
||||||
|
currentLocationStaticCopy = newLocation;
|
||||||
|
|
||||||
|
Miscellaneous.logEvent("i", "LocationListener", "Giving update to POI class", 4);
|
||||||
|
PointOfInterest.positionUpdate(newLocation, parentService, false, skipVerification);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(
|
||||||
|
locationList.size() >= 1
|
||||||
|
&&
|
||||||
|
locationList.get(locationList.size()-1).getTime() == newLocation.getTime()
|
||||||
|
&&
|
||||||
|
locationList.get(locationList.size()-1).getProvider().equals(newLocation.getProvider())
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// This is a duplicate update, do not store it
|
||||||
|
Miscellaneous.logEvent("i", "LocationListener", "Duplicate location, ignoring.", 4);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "Speed", "Commencing speed calculation.", 4);
|
||||||
|
// This part keeps the last two location entries to determine the current speed.
|
||||||
|
|
||||||
|
locationList.add(newLocation);
|
||||||
|
|
||||||
|
if(newLocation.hasSpeed())
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "Speed", "Location has speed, taking that: " + String.valueOf(newLocation.getSpeed()) + " km/h", 4);
|
||||||
|
setSpeed(newLocation.getSpeed()); // Take the value that came with the location, that should be more precise
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (locationList.size() >= 2)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "Speed", "Trying to calculate speed based on the last locations.", 4);
|
||||||
|
|
||||||
|
double currentSpeed;
|
||||||
|
long timeDifferenceInSeconds = (Math.abs(locationList.get(locationList.size() - 2).getTime() - locationList.get(locationList.size() - 1).getTime())) / 1000; //milliseconds
|
||||||
|
if (timeDifferenceInSeconds <= Settings.speedMaximumTimeBetweenLocations * 60)
|
||||||
|
{
|
||||||
|
double distanceTraveled = locationList.get(locationList.size() - 2).distanceTo(locationList.get(locationList.size() - 1)); //results in meters
|
||||||
|
|
||||||
|
if (timeDifferenceInSeconds == 0)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("w", "Speed", "No time passed since last position. Can't calculate speed here.", 4);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentSpeed = distanceTraveled / timeDifferenceInSeconds * 3.6; // convert m/s --> km/h
|
||||||
|
|
||||||
|
/*
|
||||||
|
Due to strange factors the time difference might be 0 resulting in mathematical error.
|
||||||
|
*/
|
||||||
|
if (Double.isInfinite(currentSpeed) | Double.isNaN(currentSpeed))
|
||||||
|
Miscellaneous.logEvent("i", "Speed", "Error while calculating speed.", 4);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "Speed", "Current speed: " + String.valueOf(currentSpeed) + " km/h", 2);
|
||||||
|
|
||||||
|
setSpeed(currentSpeed);
|
||||||
|
|
||||||
|
// execute matching rules containing speed
|
||||||
|
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesBySpeed();
|
||||||
|
for (Rule oneRule : ruleCandidates)
|
||||||
|
{
|
||||||
|
if (oneRule.applies(this.getParentService()))
|
||||||
|
oneRule.activate(getParentService(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Miscellaneous.logEvent("i", "Speed", "Last two locations are too far apart in terms of time. Cannot use them for speed calculation.", 4);
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("w", "Speed", "Don't have enough values for speed calculation, yet.", 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "Speed", "Error during speed calculation: " + Log.getStackTraceString(e), 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
AutomationService.updateNotification();
|
||||||
|
|
||||||
|
if(AutomationService.isMainActivityRunning(parentService))
|
||||||
|
ActivityMainScreen.updateMainScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void startLocationService()
|
||||||
|
{
|
||||||
|
// if(Settings.useAccelerometerForPositioning && !Miscellaneous.isAndroidEmulator())
|
||||||
|
// {
|
||||||
|
// accelerometerHandler = new AccelerometerHandler();
|
||||||
|
// mySensorActivity = new SensorActivity(this);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// startPhoneStateListener
|
||||||
|
PhoneStatusListener.startPhoneStatusListener(parentService); // also used to mute anouncements during calls
|
||||||
|
|
||||||
|
// startConnectivityReceiver
|
||||||
|
ConnectivityReceiver.startConnectivityReceiver(parentService);
|
||||||
|
|
||||||
|
if(Settings.positioningEngine == 0)
|
||||||
|
{
|
||||||
|
// startCellLocationChangedReceiver
|
||||||
|
if (!ConnectivityReceiver.isAirplaneMode(this.parentService) && WifiBroadcastReceiver.mayCellLocationReceiverBeActivated() && (Rule.isAnyRuleUsing(Trigger_Enum.pointOfInterest) | Rule.isAnyRuleUsing(Trigger_Enum.speed)))
|
||||||
|
CellLocationChangedReceiver.startCellLocationChangedReceiver();
|
||||||
|
|
||||||
|
// startPassiveLocationListener
|
||||||
|
if(Rule.isAnyRuleUsing(Trigger_Enum.pointOfInterest) | Rule.isAnyRuleUsing(Trigger_Enum.speed))
|
||||||
|
startPassiveLocationListener();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(Rule.isAnyRuleUsing(Trigger_Enum.pointOfInterest))
|
||||||
|
GeofenceIntentService.startService();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopLocationService()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PhoneStatusListener.stopPhoneStatusListener(parentService);
|
||||||
|
CellLocationChangedReceiver.stopCellLocationChangedReceiver();
|
||||||
|
SensorActivity.stopAccelerometerReceiver();
|
||||||
|
WifiBroadcastReceiver.stopWifiReceiver();
|
||||||
|
SensorActivity.stopAccelerometerReceiver();
|
||||||
|
stopPassiveLocationListener();
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "cellReceiver", "Error stopping LocationReceiver: " + Log.getStackTraceString(e), 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void startPassiveLocationListener()
|
||||||
|
{
|
||||||
|
if(!passiveLocationListenerActive)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "LocationListener", "Arming passive location listener.", 4);
|
||||||
|
LocationManager myLocationManager = (LocationManager) parentService.getSystemService(Context.LOCATION_SERVICE);
|
||||||
|
passiveLocationListener = new MyPassiveLocationListener();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
myLocationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, Settings.minimumTimeBetweenUpdate, Settings.minimumDistanceChangeForNetworkUpdate, passiveLocationListener);
|
||||||
|
}
|
||||||
|
catch(SecurityException e)
|
||||||
|
{}
|
||||||
|
passiveLocationListenerActive = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void stopPassiveLocationListener()
|
||||||
|
{
|
||||||
|
if(passiveLocationListenerActive)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "LocationListener", "Disarming passive location listener.", 4);
|
||||||
|
LocationManager myLocationManager = (LocationManager) parentService.getSystemService(Context.LOCATION_SERVICE);
|
||||||
|
myLocationManager.removeUpdates(passiveLocationListener);
|
||||||
|
passiveLocationListenerActive = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MyPassiveLocationListener implements LocationListener
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onLocationChanged(Location up2DateLocation)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "Location", "Got passive location update, provider: " + up2DateLocation.getProvider(), 3);
|
||||||
|
setCurrentLocation(up2DateLocation, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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 void handleAirplaneMode(boolean state)
|
||||||
|
{
|
||||||
|
if(state)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "Airplane mode", "CellLocationChangedReceiver will be deactivated due to Airplane mode.", 2);
|
||||||
|
CellLocationChangedReceiver.stopCellLocationChangedReceiver();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "Airplane mode", "CellLocationChangedReceiver will be activated due to end of Airplane mode.", 2);
|
||||||
|
CellLocationChangedReceiver.startCellLocationChangedReceiver();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleRoaming(Boolean roaming)
|
||||||
|
{
|
||||||
|
if(roaming)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "Roaming", "We're on roaming.", 4);
|
||||||
|
if(CellLocationChangedReceiver.isCellLocationListenerActive())
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "Roaming", "Disabling CellLocationChangedReceiver because we're on roaming.", 3);
|
||||||
|
CellLocationChangedReceiver.stopCellLocationChangedReceiver();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "Roaming", "We're not on roaming.", 4);
|
||||||
|
if(!CellLocationChangedReceiver.isCellLocationListenerActive())
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "Roaming", "Enabling CellLocationChangedReceiver because we're not on roaming.", 3);
|
||||||
|
CellLocationChangedReceiver.startCellLocationChangedReceiver();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void applySettingsAndRules()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* This method's purpose is to check settings and rules and determine
|
||||||
|
* if changes in them require monitors to be started or stopped.
|
||||||
|
* It takes care only of those which are more expensive.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// TextToSpeech is handled in AutomationService class
|
||||||
|
|
||||||
|
Miscellaneous.logEvent("i", "LocationProvider", this.getParentService().getResources().getString(R.string.applyingSettingsAndRules), 3);
|
||||||
|
|
||||||
|
// *********** SETTING CHANGES ***********
|
||||||
|
if(Settings.useWifiForPositioning && !WifiBroadcastReceiver.isWifiListenerActive())
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "LocationProvider", "Starting WifiReceiver because settings now allow to.", 4);
|
||||||
|
WifiBroadcastReceiver.startWifiReceiver(this);
|
||||||
|
}
|
||||||
|
else if(!Settings.useWifiForPositioning && WifiBroadcastReceiver.isWifiListenerActive())
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "LocationProvider", "Shutting down WifiReceiver because settings forbid to.", 4);
|
||||||
|
WifiBroadcastReceiver.stopWifiReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Settings.useAccelerometerForPositioning && !SensorActivity.isAccelerometerReceiverActive())
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "LocationProvider", "Starting accelerometerReceiver because settings now allow to.", 4);
|
||||||
|
SensorActivity.startAccelerometerReceiver();
|
||||||
|
}
|
||||||
|
else if(!Settings.useAccelerometerForPositioning && SensorActivity.isAccelerometerReceiverActive())
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "LocationProvider", "Shutting down accelerometerReceiver because settings forbid to.", 4);
|
||||||
|
SensorActivity.stopAccelerometerReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
// *********** RULE CHANGES ***********
|
||||||
|
if(!CellLocationChangedReceiver.isCellLocationListenerActive() && (Rule.isAnyRuleUsing(Trigger_Enum.pointOfInterest) | Rule.isAnyRuleUsing(Trigger_Enum.speed)))
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "LocationProvider", "Starting NoiseListener CellLocationChangedReceiver because used in a new/changed rule.", 4);
|
||||||
|
if(CellLocationChangedReceiver.haveAllPermission())
|
||||||
|
CellLocationChangedReceiver.startCellLocationChangedReceiver();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "LocationProvider", "Shutting down CellLocationChangedReceiver because not used in any rule.", 4);
|
||||||
|
CellLocationChangedReceiver.stopCellLocationChangedReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
AutomationService.updateNotification();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void startSpeedTimer(Calendar timeOfForcedLocationCheck)
|
||||||
|
{
|
||||||
|
if(!speedTimerActive)
|
||||||
|
{
|
||||||
|
if(timeOfForcedLocationCheck == null)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "SpeedTimer", "Have no value for speed timer. Using 5 minutes in the future.", 4);
|
||||||
|
timeOfForcedLocationCheck = Calendar.getInstance();
|
||||||
|
timeOfForcedLocationCheck.add(Calendar.MINUTE, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
Calendar calendar = Calendar.getInstance();
|
||||||
|
SimpleDateFormat sdf = new SimpleDateFormat(Settings.dateFormat);
|
||||||
|
|
||||||
|
Miscellaneous.logEvent("i", "SpeedTimer", "Starting SpeedTimer. Next forced location check would be at " + sdf.format(calendar.getTime()), 4);
|
||||||
|
|
||||||
|
Message msg = new Message();
|
||||||
|
msg.what = 1;
|
||||||
|
|
||||||
|
if(speedHandler == null)
|
||||||
|
speedHandler = new SpeedHandler();
|
||||||
|
|
||||||
|
speedHandler.sendMessageAtTime(msg, timeOfForcedLocationCheck.getTimeInMillis());
|
||||||
|
// speedHandler.sendMessageDelayed(msg, delayTime);
|
||||||
|
speedTimerActive = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void stopSpeedTimer()
|
||||||
|
{
|
||||||
|
if(speedTimerActive)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "SpeedTimer", "Stopping SpeedTimer.", 4);
|
||||||
|
|
||||||
|
// Message msg = new Message();
|
||||||
|
// msg.what = 0;
|
||||||
|
|
||||||
|
if(speedHandler == null)
|
||||||
|
speedHandler = new SpeedHandler();
|
||||||
|
else
|
||||||
|
speedHandler.removeMessages(1);
|
||||||
|
|
||||||
|
speedTimerActive = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void resetSpeedTimer(Calendar timeOfForcedLocationCheck)
|
||||||
|
{
|
||||||
|
if(speedTimerActive)
|
||||||
|
{
|
||||||
|
if(timeOfForcedLocationCheck == null)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "SpeedTimer", "Have no value for speed timer. Using 5 minutes in the future.", 4);
|
||||||
|
timeOfForcedLocationCheck = Calendar.getInstance();
|
||||||
|
timeOfForcedLocationCheck.add(Calendar.MINUTE, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
Calendar calendar = Calendar.getInstance();
|
||||||
|
SimpleDateFormat sdf = new SimpleDateFormat(Settings.dateFormat);
|
||||||
|
|
||||||
|
Miscellaneous.logEvent("i", "SpeedTimer", "Resetting SpeedTimer. Next forced location check would be at " + sdf.format(calendar.getTime()), 5);
|
||||||
|
speedHandler.removeMessages(1);
|
||||||
|
|
||||||
|
Message msg = new Message();
|
||||||
|
msg.what = 1;
|
||||||
|
speedHandler.sendMessageAtTime(msg, timeOfForcedLocationCheck.getTimeInMillis());
|
||||||
|
// speedHandler.sendMessageDelayed(msg, delayTime);
|
||||||
|
speedTimerActive = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
startSpeedTimer(timeOfForcedLocationCheck);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class SpeedHandler extends Handler
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message msg)
|
||||||
|
{
|
||||||
|
super.handleMessage(msg);
|
||||||
|
|
||||||
|
if(msg.what == 1)
|
||||||
|
{
|
||||||
|
// 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();
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,220 @@
|
|||||||
|
package com.jens.automation2.location;
|
||||||
|
|
||||||
|
|
||||||
|
import android.hardware.Sensor;
|
||||||
|
import android.hardware.SensorEvent;
|
||||||
|
import android.hardware.SensorEventListener;
|
||||||
|
import android.hardware.SensorManager;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Message;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.jens.automation2.AutomationService;
|
||||||
|
import com.jens.automation2.Miscellaneous;
|
||||||
|
import com.jens.automation2.Settings;
|
||||||
|
|
||||||
|
public class SensorActivity implements SensorEventListener
|
||||||
|
{
|
||||||
|
protected static SensorActivity instance;
|
||||||
|
private final SensorManager mSensorManager;
|
||||||
|
private final Sensor mAccelerometer;
|
||||||
|
public LocationProvider parentLocationProvider;
|
||||||
|
public static boolean mInitialized = false;
|
||||||
|
public static float lastX, lastY, lastZ, deltaX, deltaY, deltaZ;
|
||||||
|
protected static Handler accelerometerHandler = null;
|
||||||
|
protected static boolean accelerometerReceiverActive = false;
|
||||||
|
protected static boolean accelerometerTimerActive = false;
|
||||||
|
|
||||||
|
public static boolean isAccelerometerReceiverActive()
|
||||||
|
{
|
||||||
|
return accelerometerReceiverActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isAccelerometerTimerActive()
|
||||||
|
{
|
||||||
|
return accelerometerTimerActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SensorActivity getInstance()
|
||||||
|
{
|
||||||
|
if(instance == null)
|
||||||
|
instance = new SensorActivity(AutomationService.getInstance().getLocationProvider());
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SensorActivity(LocationProvider parent)
|
||||||
|
{
|
||||||
|
this.parentLocationProvider = parent;
|
||||||
|
mSensorManager = (SensorManager)parentLocationProvider.parentService.getSystemService(parentLocationProvider.parentService.SENSOR_SERVICE);
|
||||||
|
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void start()
|
||||||
|
{
|
||||||
|
mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void stop()
|
||||||
|
{
|
||||||
|
mSensorManager.unregisterListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onAccuracyChanged(Sensor sensor, int accuracy)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onSensorChanged(SensorEvent event)
|
||||||
|
{
|
||||||
|
// Device has been moved
|
||||||
|
|
||||||
|
float x = event.values[0];
|
||||||
|
float y = event.values[1];
|
||||||
|
float z = event.values[2];
|
||||||
|
|
||||||
|
if(mInitialized)
|
||||||
|
{
|
||||||
|
deltaX = Math.abs(lastX-x);
|
||||||
|
deltaY = Math.abs(lastY-y);
|
||||||
|
deltaZ = Math.abs(lastZ-z);
|
||||||
|
//Wenn das jetzt einen gewissen Grenzwert übersteigt, müßten wir den CellListener wieder aktivieren
|
||||||
|
if(deltaX > Settings.accelerometerMovementThreshold | deltaY > Settings.accelerometerMovementThreshold | deltaZ > Settings.accelerometerMovementThreshold)
|
||||||
|
{
|
||||||
|
String text = "Device has been moved. " + String.valueOf(deltaX)+" / "+String.valueOf(deltaY)+" / "+String.valueOf(deltaZ);
|
||||||
|
Miscellaneous.logEvent("i", "Accelerometer", text, 5);
|
||||||
|
CellLocationChangedReceiver.resetFollowUpdate();
|
||||||
|
CellLocationChangedReceiver.startCellLocationChangedReceiver();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lastX = x;
|
||||||
|
lastY = y;
|
||||||
|
lastZ = z;
|
||||||
|
mInitialized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static void startAccelerometerReceiver()
|
||||||
|
{
|
||||||
|
if(Settings.useAccelerometerForPositioning && !Miscellaneous.isAndroidEmulator())
|
||||||
|
{
|
||||||
|
if(!accelerometerReceiverActive)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
getInstance().start();
|
||||||
|
accelerometerReceiverActive = true;
|
||||||
|
Miscellaneous.logEvent("i", "AccelerometerReceiver", "Starting AccelerometerReceiver", 4);
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "AccelerometerReceiver", "Error starting AccelerometerReceiver: " + Log.getStackTraceString(ex), 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected static void stopAccelerometerReceiver()
|
||||||
|
{
|
||||||
|
if(Settings.useAccelerometerForPositioning && !Miscellaneous.isAndroidEmulator() && accelerometerReceiverActive)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
getInstance().stop();
|
||||||
|
accelerometerReceiverActive = false;
|
||||||
|
Miscellaneous.logEvent("i", "AccelerometerReceiver", "Stopping AccelerometerReceiver", 4);
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "AccelerometerReceiver", "Error stopping AccelerometerReceiver: " + Log.getStackTraceString(ex), 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void startAccelerometerTimer()
|
||||||
|
{
|
||||||
|
if(Settings.useAccelerometerForPositioning && !Miscellaneous.isAndroidEmulator())
|
||||||
|
{
|
||||||
|
if(!accelerometerTimerActive)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "AccelerometerTimer", "Starting AccelerometerTimer", 4);
|
||||||
|
|
||||||
|
long delayTime = Settings.useAccelerometerAfterIdleTime * 60 * 1000;
|
||||||
|
|
||||||
|
Message msg = new Message();
|
||||||
|
msg.what = 1;
|
||||||
|
|
||||||
|
if(accelerometerHandler == null)
|
||||||
|
accelerometerHandler = new AccelerometerHandler();
|
||||||
|
|
||||||
|
accelerometerHandler.sendMessageDelayed(msg, delayTime);
|
||||||
|
accelerometerTimerActive = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* else
|
||||||
|
* reset timer
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
public static void stopAccelerometerTimer()
|
||||||
|
{
|
||||||
|
if(accelerometerTimerActive)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "AccelerometerTimer", "Stopping AccelerometerTimer", 4);
|
||||||
|
|
||||||
|
// Message msg = new Message();
|
||||||
|
// msg.what = 0;
|
||||||
|
|
||||||
|
if(accelerometerHandler == null)
|
||||||
|
accelerometerHandler = new AccelerometerHandler();
|
||||||
|
else
|
||||||
|
accelerometerHandler.removeMessages(1);
|
||||||
|
|
||||||
|
// accelerometerHandler.sendMessageDelayed(msg, 0);
|
||||||
|
accelerometerTimerActive = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void resetAccelerometerTimer()
|
||||||
|
{
|
||||||
|
if(accelerometerTimerActive)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "AccelerometerTimer", "Resetting AccelerometerTimer", 5);
|
||||||
|
accelerometerHandler.removeMessages(1);
|
||||||
|
|
||||||
|
long delayTime = Settings.useAccelerometerAfterIdleTime * 60 * 1000;
|
||||||
|
// Toast.makeText(parentService, "Sending message, delayed for " + String.valueOf(delayTime), Toast.LENGTH_LONG).show();
|
||||||
|
|
||||||
|
Message msg = new Message();
|
||||||
|
msg.what = 1;
|
||||||
|
accelerometerHandler.sendMessageDelayed(msg, delayTime);
|
||||||
|
accelerometerTimerActive = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class AccelerometerHandler extends Handler
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message msg)
|
||||||
|
{
|
||||||
|
super.handleMessage(msg);
|
||||||
|
|
||||||
|
if(msg.what == 1)
|
||||||
|
{
|
||||||
|
// time is up, no cell location updates since x minutes, start accelerometer
|
||||||
|
String text = String.valueOf(Settings.useAccelerometerAfterIdleTime) + " minutes passed";
|
||||||
|
Miscellaneous.logEvent("i", "AccelerometerHandler", text, 5);
|
||||||
|
CellLocationChangedReceiver.stopCellLocationChangedReceiver();
|
||||||
|
startAccelerometerReceiver();
|
||||||
|
}
|
||||||
|
else if(msg.what == 0)
|
||||||
|
{
|
||||||
|
String text = "Abort command received, deactivating accelerometerReceiver";
|
||||||
|
Miscellaneous.logEvent("i", "AccelerometerHandler", text, 4);
|
||||||
|
stopAccelerometerReceiver();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,229 @@
|
|||||||
|
package com.jens.automation2.location;
|
||||||
|
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
import android.net.ConnectivityManager;
|
||||||
|
import android.net.NetworkInfo;
|
||||||
|
import android.net.wifi.WifiManager;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.jens.automation2.Miscellaneous;
|
||||||
|
import com.jens.automation2.PointOfInterest;
|
||||||
|
import com.jens.automation2.R;
|
||||||
|
import com.jens.automation2.Rule;
|
||||||
|
import com.jens.automation2.Settings;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class WifiBroadcastReceiver extends BroadcastReceiver
|
||||||
|
{
|
||||||
|
public static LocationProvider parentLocationProvider;
|
||||||
|
public static Boolean wasConnected = false;
|
||||||
|
protected static String lastWifiSsid = "";
|
||||||
|
public static boolean lastConnectedState = false;
|
||||||
|
protected static boolean mayCellLocationChangedReceiverBeActivatedFromWifiPointOfWifi = true;
|
||||||
|
protected static WifiBroadcastReceiver wifiBrInstance;
|
||||||
|
protected static IntentFilter wifiListenerIntentFilter;
|
||||||
|
protected static boolean wifiListenerActive=false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static String getLastWifiSsid()
|
||||||
|
{
|
||||||
|
return lastWifiSsid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setLastWifiSsid(String newWifiSsid)
|
||||||
|
{
|
||||||
|
if(newWifiSsid.startsWith("\"") && newWifiSsid.endsWith("\""))
|
||||||
|
newWifiSsid = newWifiSsid.substring(1, newWifiSsid.length()-1);
|
||||||
|
|
||||||
|
WifiBroadcastReceiver.lastWifiSsid = newWifiSsid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isWifiListenerActive()
|
||||||
|
{
|
||||||
|
return wifiListenerActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean mayCellLocationReceiverBeActivated()
|
||||||
|
{
|
||||||
|
return mayCellLocationChangedReceiverBeActivatedFromWifiPointOfWifi;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// int state = -1;
|
||||||
|
NetworkInfo myWifi = null;
|
||||||
|
|
||||||
|
// if(intent.getAction().equals(WifiManager.RSSI_CHANGED_ACTION)) //gefeuert bei Verbindung
|
||||||
|
// {
|
||||||
|
// Miscellaneous.logEvent("i", "WifiReceiver", "RSSI_CHANGED_ACTION: " + String.valueOf(intent.getIntExtra(WifiManager.RSSI_CHANGED_ACTION, -1)));
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
if(intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) //gefeuert bei Trennung
|
||||||
|
{
|
||||||
|
// state = intent.getIntExtra(WifiManager.NETWORK_STATE_CHANGED_ACTION, -1);
|
||||||
|
// Miscellaneous.logEvent("i", "WifiReceiver", "NETWORK_STATE_CHANGED_ACTION: " + String.valueOf(state));
|
||||||
|
myWifi = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
WifiManager myWifiManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
|
||||||
|
// ConnectivityManager connManager = (ConnectivityManager)context.getSystemService(context.CONNECTIVITY_SERVICE);
|
||||||
|
// myWifi = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
|
||||||
|
// myWifi = state
|
||||||
|
// WifiInfo wifiInfo = myWifiManager.getConnectionInfo();
|
||||||
|
|
||||||
|
// SupplicantState supState = wifiInfo.getSupplicantState();
|
||||||
|
|
||||||
|
if(intent.getAction().equals(WifiManager.RSSI_CHANGED_ACTION)) // fired upon connection
|
||||||
|
{
|
||||||
|
String ssid = myWifiManager.getConnectionInfo().getSSID();
|
||||||
|
setLastWifiSsid(ssid);
|
||||||
|
Miscellaneous.logEvent("i", "WifiReceiver", String.format(context.getResources().getString(R.string.connectedToWifi), getLastWifiSsid()), 2);
|
||||||
|
wasConnected = true;
|
||||||
|
lastConnectedState = true;
|
||||||
|
|
||||||
|
if(Settings.useWifiForPositioning && PointOfInterest.reachedPoiWithActivateWifiRule()) // Poi has wifi
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "WifiReceiver", context.getResources().getString(R.string.poiHasWifiStoppingCellLocationListener), 2);
|
||||||
|
mayCellLocationChangedReceiverBeActivatedFromWifiPointOfWifi = false;
|
||||||
|
CellLocationChangedReceiver.stopCellLocationChangedReceiver();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(!PointOfInterest.reachedPoiWithActivateWifiRule()) // Poi has no wifi
|
||||||
|
Miscellaneous.logEvent("i", "WifiReceiver", context.getResources().getString(R.string.poiHasNoWifiNotStoppingCellLocationListener), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
findRules(parentLocationProvider);
|
||||||
|
}
|
||||||
|
else if(myWifi.isConnectedOrConnecting()) // first time connect from wifi-listener-perspective
|
||||||
|
{
|
||||||
|
wasConnected = true;
|
||||||
|
Miscellaneous.logEvent("i", "WifiReceiver", "WifiReceiver just activated. Wifi already connected. Stopping CellLocationReceiver", 3);
|
||||||
|
mayCellLocationChangedReceiverBeActivatedFromWifiPointOfWifi = false;
|
||||||
|
CellLocationChangedReceiver.stopCellLocationChangedReceiver();
|
||||||
|
SensorActivity.stopAccelerometerTimer();
|
||||||
|
String ssid = myWifiManager.getConnectionInfo().getSSID();
|
||||||
|
setLastWifiSsid(ssid);
|
||||||
|
lastConnectedState = true;
|
||||||
|
findRules(parentLocationProvider);
|
||||||
|
}
|
||||||
|
else if(!myWifi.isConnectedOrConnecting()) // really disconnected? because sometimes also fires on connect
|
||||||
|
{
|
||||||
|
if(wasConnected) // wir könnten einfach noch nicht daheim sein
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
wasConnected = false;
|
||||||
|
Miscellaneous.logEvent("i", "WifiReceiver", String.format(context.getResources().getString(R.string.disconnectedFromWifi), getLastWifiSsid()) + " Switching to CellLocationChangedReceiver.", 3);
|
||||||
|
mayCellLocationChangedReceiverBeActivatedFromWifiPointOfWifi = true;
|
||||||
|
CellLocationChangedReceiver.startCellLocationChangedReceiver();
|
||||||
|
lastConnectedState = false;
|
||||||
|
findRules(parentLocationProvider);
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "WifiReceiver", "Error starting CellLocationChangedReceiver", 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "WifiReceiver", "Error in WifiReceiver->onReceive(): " + e.getMessage(), 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void findRules(LocationProvider parentLocationProvider)
|
||||||
|
{
|
||||||
|
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByWifiConnection();
|
||||||
|
for(Rule oneRule : ruleCandidates)
|
||||||
|
{
|
||||||
|
if(oneRule.applies(parentLocationProvider.parentService))
|
||||||
|
oneRule.activate(parentLocationProvider.parentService, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isWifiEnabled(Context context)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
WifiManager myWifiManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
|
||||||
|
return myWifiManager.isWifiEnabled();
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "WifiReceiver->isWifiEnabled()", Log.getStackTraceString(e), 3);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isWifiConnected(Context context)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ConnectivityManager connManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||||
|
NetworkInfo myWifi = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
|
||||||
|
return myWifi.isConnected();
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "WifiReceiver->isWifiConnected()", Log.getStackTraceString(e), 3);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void startWifiReceiver(LocationProvider loc)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(!wifiListenerActive)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "Wifi Listener", "Starting wifiListener", 4);
|
||||||
|
if(wifiListenerIntentFilter == null)
|
||||||
|
{
|
||||||
|
wifiListenerIntentFilter = new IntentFilter();
|
||||||
|
wifiListenerIntentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION);
|
||||||
|
wifiListenerIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
|
||||||
|
}
|
||||||
|
if(wifiBrInstance == null)
|
||||||
|
{
|
||||||
|
wifiBrInstance = new WifiBroadcastReceiver();
|
||||||
|
WifiBroadcastReceiver.parentLocationProvider = loc;
|
||||||
|
}
|
||||||
|
loc.getParentService().registerReceiver(wifiBrInstance, wifiListenerIntentFilter);
|
||||||
|
wifiListenerActive = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "Wifi Listener", "Error starting wifiListener: " + Log.getStackTraceString(ex), 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static void stopWifiReceiver()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(wifiListenerActive)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "Wifi Listener", "Stopping wifiListener", 4);
|
||||||
|
wifiListenerActive = false;
|
||||||
|
parentLocationProvider.getParentService().unregisterReceiver(wifiBrInstance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "Wifi Listener", "Error stopping wifiListener: " + Log.getStackTraceString(ex), 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,400 @@
|
|||||||
|
package com.jens.automation2.receivers;
|
||||||
|
|
||||||
|
import android.app.IntentService;
|
||||||
|
import android.app.PendingIntent;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.google.android.gms.common.ConnectionResult;
|
||||||
|
import com.google.android.gms.common.GooglePlayServicesUtil;
|
||||||
|
import com.google.android.gms.common.api.GoogleApiClient;
|
||||||
|
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
|
||||||
|
import com.google.android.gms.location.ActivityRecognition;
|
||||||
|
import com.google.android.gms.location.ActivityRecognitionApi;
|
||||||
|
import com.google.android.gms.location.ActivityRecognitionResult;
|
||||||
|
import com.google.android.gms.location.DetectedActivity;
|
||||||
|
import com.jens.automation2.ActivityPermissions;
|
||||||
|
import com.jens.automation2.AutomationService;
|
||||||
|
import com.jens.automation2.Miscellaneous;
|
||||||
|
import com.jens.automation2.R;
|
||||||
|
import com.jens.automation2.Rule;
|
||||||
|
import com.jens.automation2.Settings;
|
||||||
|
import com.jens.automation2.Trigger.Trigger_Enum;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
// See also: http://developer.android.com/reference/com/google/android/gms/location/ActivityRecognitionClient.html
|
||||||
|
// https://www.sitepoint.com/google-play-services-location-activity-recognition/
|
||||||
|
|
||||||
|
public class ActivityDetectionReceiver extends IntentService implements AutomationListenerInterface, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener
|
||||||
|
{
|
||||||
|
protected static ActivityRecognitionApi activityRecognitionClient = null;
|
||||||
|
protected static boolean connected = false;
|
||||||
|
protected static enum LastRequestEnum { start, stop, restart };
|
||||||
|
protected static LastRequestEnum lastRequest = null;
|
||||||
|
protected static GoogleApiClient googleApiClient = null;
|
||||||
|
protected static ActivityRecognitionResult activityDetectionLastResult = null;
|
||||||
|
protected static long lastUpdate = 0;
|
||||||
|
protected static Date currentTime;
|
||||||
|
protected static ActivityDetectionReceiver instance = null;
|
||||||
|
|
||||||
|
protected static ActivityDetectionReceiver getInstance()
|
||||||
|
{
|
||||||
|
if(instance == null)
|
||||||
|
instance = new ActivityDetectionReceiver();
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static boolean activityDetectionReceiverRunning = false;
|
||||||
|
protected static ActivityDetectionReceiver activityDetectionReceiverInstance = null;
|
||||||
|
|
||||||
|
public static boolean isActivityDetectionReceiverRunning()
|
||||||
|
{
|
||||||
|
return activityDetectionReceiverRunning;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ActivityRecognitionResult getActivityDetectionLastResult()
|
||||||
|
{
|
||||||
|
return activityDetectionLastResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GoogleApiClient getApiClient()
|
||||||
|
{
|
||||||
|
if(googleApiClient == null)
|
||||||
|
{
|
||||||
|
googleApiClient = new GoogleApiClient.Builder(AutomationService.getInstance())
|
||||||
|
.addConnectionCallbacks(getInstance())
|
||||||
|
.addOnConnectionFailedListener(getInstance())
|
||||||
|
.addApi(ActivityRecognition.API)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
return googleApiClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void requestUpdates()
|
||||||
|
{
|
||||||
|
long frequency = Settings.activityDetectionFrequency * 1000;
|
||||||
|
Miscellaneous.logEvent("i", "ActivityDetectionReceiver", "Requesting ActivityDetection updates with frequency " + String.valueOf(frequency) + " milliseconds.", 4);
|
||||||
|
|
||||||
|
|
||||||
|
ActivityRecognition.ActivityRecognitionApi.requestActivityUpdates(getApiClient(), 1000, getInstance().getActivityDetectionPendingIntent());
|
||||||
|
}
|
||||||
|
private void reloadUpdates()
|
||||||
|
{
|
||||||
|
long frequency = Settings.activityDetectionFrequency * 1000;
|
||||||
|
Miscellaneous.logEvent("i", "ActivityDetectionReceiver", "Re-requesting ActivityDetection updates with frequency " + String.valueOf(frequency) + " milliseconds.", 4);
|
||||||
|
|
||||||
|
activityRecognitionClient.removeActivityUpdates(getApiClient(), getInstance().getActivityDetectionPendingIntent());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(1000);
|
||||||
|
}
|
||||||
|
catch (InterruptedException e)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "ActivityDetectionReceiver", "Error reloading updates for ActivityDetectionReceiver: " + Log.getStackTraceString(e), 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActivityRecognition.ActivityRecognitionApi.requestActivityUpdates(getApiClient(), frequency, getInstance().getActivityDetectionPendingIntent());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void stopUpdates()
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "ActivityDetectionReceiver", "Unsubscribing from ActivityDetection-updates.", 4);
|
||||||
|
|
||||||
|
ActivityRecognition.ActivityRecognitionApi.removeActivityUpdates(getApiClient(), getInstance().getActivityDetectionPendingIntent());
|
||||||
|
// activityRecognitionClient.removeActivityUpdates(getApiClient(), getInstance().getActivityDetectionPendingIntent());
|
||||||
|
// activityRecognitionClient.disconnect();
|
||||||
|
}
|
||||||
|
public static void startActivityDetectionReceiver()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "ActivityDetectionReceiver", "Starting ActivityDetectionReceiver", 3);
|
||||||
|
|
||||||
|
if(activityDetectionReceiverInstance == null)
|
||||||
|
activityDetectionReceiverInstance = new ActivityDetectionReceiver();
|
||||||
|
|
||||||
|
if(!activityDetectionReceiverRunning && Rule.isAnyRuleUsing(Trigger_Enum.activityDetection))
|
||||||
|
{
|
||||||
|
if(isPlayServiceAvailable())
|
||||||
|
{
|
||||||
|
/*if(activityRecognitionClient == null)
|
||||||
|
activityRecognitionClient = new ActivityRecognitionClient(Miscellaneous.getAnyContext(), activityDetectionReceiverInstance, activityDetectionReceiverInstance);*/
|
||||||
|
|
||||||
|
lastRequest = LastRequestEnum.start;
|
||||||
|
|
||||||
|
if(!connected)
|
||||||
|
getApiClient().connect();
|
||||||
|
else
|
||||||
|
requestUpdates();
|
||||||
|
|
||||||
|
activityDetectionReceiverRunning = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "ActivityDetectionReceiver", "Error starting ActivityDetectionReceiver: " + Log.getStackTraceString(ex), 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void restartActivityDetectionReceiver()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(!activityDetectionReceiverRunning && Rule.isAnyRuleUsing(Trigger_Enum.activityDetection))
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "ActivityDetectionReceiver", "Restarting ActivityDetectionReceiver", 3);
|
||||||
|
|
||||||
|
if(activityDetectionReceiverInstance == null)
|
||||||
|
activityDetectionReceiverInstance = new ActivityDetectionReceiver();
|
||||||
|
|
||||||
|
if(isPlayServiceAvailable())
|
||||||
|
{
|
||||||
|
// if(activityRecognitionClient == null)
|
||||||
|
// activityRecognitionClient = new ActivityRecognitionClient(Miscellaneous.getAnyContext(), activityDetectionReceiverInstance, activityDetectionReceiverInstance);
|
||||||
|
|
||||||
|
lastRequest = LastRequestEnum.restart;
|
||||||
|
|
||||||
|
if(!connected)
|
||||||
|
getApiClient().connect();
|
||||||
|
else
|
||||||
|
requestUpdates();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "ActivityDetectionReceiver", "Error starting ActivityDetectionReceiver: " + Log.getStackTraceString(ex), 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void stopActivityDetectionReceiver()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(activityDetectionReceiverRunning)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "ActivityDetectionReceiver", "Stopping ActivityDetectionReceiver", 3);
|
||||||
|
|
||||||
|
if(isPlayServiceAvailable())
|
||||||
|
{
|
||||||
|
lastRequest = LastRequestEnum.stop;
|
||||||
|
|
||||||
|
if(!connected)
|
||||||
|
getApiClient().connect();
|
||||||
|
else
|
||||||
|
stopUpdates();
|
||||||
|
|
||||||
|
activityDetectionReceiverRunning = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "ActivityDetectionReceiver", "Error stopping ActivityDetectionReceiver: " + Log.getStackTraceString(ex), 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isPlayServiceAvailable()
|
||||||
|
{
|
||||||
|
if(GooglePlayServicesUtil.isGooglePlayServicesAvailable(Miscellaneous.getAnyContext()) == ConnectionResult.SUCCESS)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onConnectionFailed(ConnectionResult arg0)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "ActivityDetectionReceiver", "Connection to Play Services failed.", 4);
|
||||||
|
if(connected && getApiClient().isConnected())
|
||||||
|
{
|
||||||
|
connected = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onConnected(Bundle arg0)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "ActivityDetectionReceiver", "Connected to Play Services.", 4);
|
||||||
|
|
||||||
|
connected = true;
|
||||||
|
|
||||||
|
if(lastRequest == null)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("w", "ActivityDetectionReceiver", "Request type not specified. Start or stop listening to activity detection updates?", 4);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(lastRequest.equals(LastRequestEnum.start))
|
||||||
|
requestUpdates();
|
||||||
|
else if(lastRequest.equals(LastRequestEnum.stop))
|
||||||
|
stopUpdates();
|
||||||
|
else //reload, e.g. to set a new update time
|
||||||
|
reloadUpdates();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onConnectionSuspended(int arg0)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "ActivityDetectionReceiver", "Connection to Play Services suspended.", 4);
|
||||||
|
// activityRecognitionClient.disconnect();
|
||||||
|
connected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ActivityDetectionReceiver()
|
||||||
|
{
|
||||||
|
super("ActivityDetectionIntentService");
|
||||||
|
if(instance == null)
|
||||||
|
instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onHandleIntent(Intent intent)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "ActivityDetectionReceiver", "onHandleIntent(): Received some status.", 5);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(isActivityDetectionReceiverRunning())
|
||||||
|
{
|
||||||
|
currentTime = new Date();
|
||||||
|
|
||||||
|
if(lastUpdate == 0 | currentTime.getTime() >= lastUpdate + Settings.activityDetectionFrequency * 1000 - 1000) // -1000 to include updates only marginaly below the threshold
|
||||||
|
{
|
||||||
|
lastUpdate = currentTime.getTime();
|
||||||
|
|
||||||
|
if(ActivityRecognitionResult.hasResult(intent))
|
||||||
|
{
|
||||||
|
activityDetectionLastResult = ActivityRecognitionResult.extractResult(intent);
|
||||||
|
|
||||||
|
for(DetectedActivity activity : activityDetectionLastResult.getProbableActivities())
|
||||||
|
{
|
||||||
|
int loglevel = 3;
|
||||||
|
if(activity.getConfidence() < Settings.activityDetectionRequiredProbability)
|
||||||
|
loglevel = 4;
|
||||||
|
|
||||||
|
Miscellaneous.logEvent("i", "ActivityDetectionReceiver", "Detected activity (probability " + String.valueOf(activity.getConfidence()) + "%): " + getDescription(activity.getType()), loglevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the list of activities that where detected with the confidence value associated with each activity.
|
||||||
|
* The activities are sorted by most probable activity first.
|
||||||
|
* The sum of the confidences of all detected activities this method returns does not have to be <= 100
|
||||||
|
* since some activities are not mutually exclusive (for example, you can be walking while in a bus)
|
||||||
|
* and some activities are hierarchical (ON_FOOT is a generalization of WALKING and RUNNING).
|
||||||
|
*/
|
||||||
|
|
||||||
|
ArrayList<Rule> allRulesWithActivityDetection = Rule.findRuleCandidatesByActivityDetection();
|
||||||
|
for(int i=0; i<allRulesWithActivityDetection.size(); i++)
|
||||||
|
{
|
||||||
|
if(allRulesWithActivityDetection.get(i).applies(Miscellaneous.getAnyContext()))
|
||||||
|
allRulesWithActivityDetection.get(i).activate(AutomationService.getInstance(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Miscellaneous.logEvent("w", "ActivityDetectionReceiver", String.format(getResources().getString(R.string.ignoringActivityDetectionUpdateTooSoon), String.valueOf(Settings.activityDetectionFrequency)), 5);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Miscellaneous.logEvent("w", "ActivityDetectionReceiver", "I am not running. I shouldn't be getting updates. Ignoring it.", 5);
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
// some error, don't care.
|
||||||
|
Miscellaneous.logEvent("e", "ActivityDetectionReceiver", "onHandleIntent(): Error while receiving status: " + Log.getStackTraceString(e), 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int[] getAllTypes()
|
||||||
|
{
|
||||||
|
return new int[] {
|
||||||
|
DetectedActivity.IN_VEHICLE,
|
||||||
|
DetectedActivity.ON_BICYCLE,
|
||||||
|
DetectedActivity.ON_FOOT,
|
||||||
|
DetectedActivity.STILL,
|
||||||
|
DetectedActivity.TILTING,
|
||||||
|
DetectedActivity.WALKING,
|
||||||
|
DetectedActivity.RUNNING,
|
||||||
|
DetectedActivity.UNKNOWN
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getDescription(int type)
|
||||||
|
{
|
||||||
|
switch(type)
|
||||||
|
{
|
||||||
|
case(DetectedActivity.IN_VEHICLE):
|
||||||
|
return Miscellaneous.getAnyContext().getResources().getString(R.string.detectedActivityInVehicle);
|
||||||
|
case(DetectedActivity.ON_BICYCLE):
|
||||||
|
return Miscellaneous.getAnyContext().getResources().getString(R.string.detectedActivityOnBicycle);
|
||||||
|
case(DetectedActivity.ON_FOOT):
|
||||||
|
return Miscellaneous.getAnyContext().getResources().getString(R.string.detectedActivityOnFoot);
|
||||||
|
case(DetectedActivity.STILL):
|
||||||
|
return Miscellaneous.getAnyContext().getResources().getString(R.string.detectedActivityStill);
|
||||||
|
case(DetectedActivity.TILTING):
|
||||||
|
return Miscellaneous.getAnyContext().getResources().getString(R.string.detectedActivityTilting);
|
||||||
|
case(DetectedActivity.WALKING):
|
||||||
|
return Miscellaneous.getAnyContext().getResources().getString(R.string.detectedActivityWalking);
|
||||||
|
case(DetectedActivity.RUNNING):
|
||||||
|
return Miscellaneous.getAnyContext().getResources().getString(R.string.detectedActivityRunning);
|
||||||
|
case(DetectedActivity.UNKNOWN):
|
||||||
|
return Miscellaneous.getAnyContext().getResources().getString(R.string.detectedActivityUnknown);
|
||||||
|
default:
|
||||||
|
return Miscellaneous.getAnyContext().getResources().getString(R.string.detectedActivityInvalidStatus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String[] getAllDescriptions()
|
||||||
|
{
|
||||||
|
ArrayList<String> types = new ArrayList<String>();
|
||||||
|
|
||||||
|
for(int type : getAllTypes())
|
||||||
|
types.add(getDescription(type));
|
||||||
|
|
||||||
|
return types.toArray(new String[types.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startListener(AutomationService automationService)
|
||||||
|
{
|
||||||
|
ActivityDetectionReceiver.startActivityDetectionReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stopListener(AutomationService automationService)
|
||||||
|
{
|
||||||
|
ActivityDetectionReceiver.stopActivityDetectionReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean haveAllPermission()
|
||||||
|
{
|
||||||
|
return ActivityPermissions.havePermission("com.google.android.gms.permission.ACTIVITY_RECOGNITION", Miscellaneous.getAnyContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isListenerRunning()
|
||||||
|
{
|
||||||
|
return ActivityDetectionReceiver.isActivityDetectionReceiverRunning();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Trigger_Enum[] getMonitoredTrigger()
|
||||||
|
{
|
||||||
|
return new Trigger_Enum[] { Trigger_Enum.activityDetection };
|
||||||
|
}
|
||||||
|
|
||||||
|
private PendingIntent getActivityDetectionPendingIntent()
|
||||||
|
{
|
||||||
|
Intent intent = new Intent(AutomationService.getInstance(), ActivityDetectionReceiver.class);
|
||||||
|
PendingIntent returnValue = PendingIntent.getService(AutomationService.getInstance(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,301 @@
|
|||||||
|
package com.jens.automation2.receivers;
|
||||||
|
|
||||||
|
import android.app.AlarmManager;
|
||||||
|
import android.app.PendingIntent;
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
|
||||||
|
import com.jens.automation2.AutomationService;
|
||||||
|
import com.jens.automation2.Miscellaneous;
|
||||||
|
import com.jens.automation2.Rule;
|
||||||
|
import com.jens.automation2.Trigger;
|
||||||
|
import com.jens.automation2.Trigger.Trigger_Enum;
|
||||||
|
|
||||||
|
import java.sql.Time;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public class AlarmListener extends BroadcastReceiver implements AutomationListenerInterface
|
||||||
|
{
|
||||||
|
private static AutomationService automationServiceRef;
|
||||||
|
private static AlarmManager centralAlarmManagerInstance;
|
||||||
|
// private static Intent alarmIntent;
|
||||||
|
// private static PendingIntent alarmPendingIntent;
|
||||||
|
private static boolean alarmListenerActive=false;
|
||||||
|
private static ArrayList<Long> alarmCandidates = new ArrayList<Long>();
|
||||||
|
|
||||||
|
private static ArrayList<Integer> requestCodeList = new ArrayList<Integer>();
|
||||||
|
|
||||||
|
public static void startAlarmListener(final AutomationService automationServiceRef)
|
||||||
|
{
|
||||||
|
AlarmListener.startAlarmListenerInternal(automationServiceRef);
|
||||||
|
}
|
||||||
|
public static void stopAlarmListener(Context context)
|
||||||
|
{
|
||||||
|
AlarmListener.stopAlarmListenerInternal();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isAlarmListenerActive()
|
||||||
|
{
|
||||||
|
return alarmListenerActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "AlarmListener", "Alarm received", 2);
|
||||||
|
Date now = new Date();
|
||||||
|
String timeString = String.valueOf(now.getHours()) + ":" + String.valueOf(now.getMinutes()) + ":" + String.valueOf(now.getSeconds());
|
||||||
|
Time passTime = Time.valueOf(timeString);
|
||||||
|
|
||||||
|
ArrayList<Rule> allRulesWithNowInTimeFrame = Rule.findRuleCandidatesByTime(passTime);
|
||||||
|
for(int i=0; i<allRulesWithNowInTimeFrame.size(); i++)
|
||||||
|
{
|
||||||
|
if(allRulesWithNowInTimeFrame.get(i).applies(context))
|
||||||
|
allRulesWithNowInTimeFrame.get(i).activate(automationServiceRef, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
setAlarms();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setAlarms()
|
||||||
|
{
|
||||||
|
alarmCandidates.clear();
|
||||||
|
|
||||||
|
SimpleDateFormat sdf = new SimpleDateFormat("E dd.MM.yyyy HH:mm");
|
||||||
|
|
||||||
|
clearAlarms();
|
||||||
|
|
||||||
|
int i=0;
|
||||||
|
|
||||||
|
// // get a Calendar object with current time
|
||||||
|
// Calendar cal = Calendar.getInstance();
|
||||||
|
// // add 5 minutes to the calendar object
|
||||||
|
// cal.add(Calendar.SECOND, 10);
|
||||||
|
// String calSetWorkingCopyString2 = null;
|
||||||
|
// SimpleDateFormat sdf2 = new SimpleDateFormat("E dd.MM.yyyy HH:mm");
|
||||||
|
// if (cal != null)
|
||||||
|
// {
|
||||||
|
// calSetWorkingCopyString2 = sdf2.format(cal.getTime());
|
||||||
|
// }
|
||||||
|
// Miscellaneous.logEvent("i", "AlarmManager", "Setting repeating alarm because of hardcoded test: beginning at " + calSetWorkingCopyString2);
|
||||||
|
// Intent alarmIntent2 = new Intent(automationServiceRef, AlarmListener.class);
|
||||||
|
// PendingIntent alarmPendingIntent2 = PendingIntent.getBroadcast(automationServiceRef, 0, alarmIntent2, 0);
|
||||||
|
// centralAlarmManagerInstance.setInexactRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 5000, alarmPendingIntent2);
|
||||||
|
// requestCodeList.add(0);
|
||||||
|
|
||||||
|
ArrayList<Rule> allRulesWithTimeFrames = new ArrayList<Rule>();
|
||||||
|
allRulesWithTimeFrames = Rule.findRuleCandidatesByTimeFrame();
|
||||||
|
for(Rule oneRule : allRulesWithTimeFrames)
|
||||||
|
{
|
||||||
|
for(Trigger oneTrigger : oneRule.getTriggerSet())
|
||||||
|
{
|
||||||
|
if(oneTrigger.getTriggerType() == Trigger_Enum.timeFrame)
|
||||||
|
{
|
||||||
|
Calendar calNow, calSet;
|
||||||
|
Time setTime;
|
||||||
|
|
||||||
|
if(oneTrigger.getTriggerParameter())
|
||||||
|
setTime = oneTrigger.getTimeFrame().getTriggerTimeStart();
|
||||||
|
else
|
||||||
|
setTime = oneTrigger.getTimeFrame().getTriggerTimeStop();
|
||||||
|
|
||||||
|
calNow = Calendar.getInstance();
|
||||||
|
calSet = (Calendar) calNow.clone();
|
||||||
|
calSet.set(Calendar.HOUR_OF_DAY, setTime.getHours());
|
||||||
|
calSet.set(Calendar.MINUTE, setTime.getMinutes());
|
||||||
|
calSet.set(Calendar.SECOND, 0);
|
||||||
|
calSet.set(Calendar.MILLISECOND, 0);
|
||||||
|
// At this point calSet would be a scheduling candidate. It's just the day the might not be right, yet.
|
||||||
|
|
||||||
|
long milliSecondsInAWeek = 1000 * 60 * 60 * 24 * 7;
|
||||||
|
|
||||||
|
for(int dayOfWeek : oneTrigger.getTimeFrame().getDayList())
|
||||||
|
{
|
||||||
|
Calendar calSetWorkingCopy = (Calendar) calSet.clone();
|
||||||
|
|
||||||
|
// calSetWorkingCopy.set(Calendar.HOUR_OF_DAY, setTime.getHours());
|
||||||
|
// calSetWorkingCopy.set(Calendar.MINUTE, setTime.getMinutes());
|
||||||
|
// calSetWorkingCopy.set(Calendar.SECOND, 0);
|
||||||
|
// calSetWorkingCopy.set(Calendar.MILLISECOND, 0);
|
||||||
|
|
||||||
|
int diff = dayOfWeek - calNow.get(Calendar.DAY_OF_WEEK);
|
||||||
|
// Log.i("AlarmManager", "Today: " + String.valueOf(calNow.get(Calendar.DAY_OF_WEEK)) + " / Sched.Day: " + String.valueOf(dayOfWeek) + " Difference to target day is: " + String.valueOf(diff));
|
||||||
|
if(diff == 0) //if we're talking about the current day, is the time still in the future?
|
||||||
|
{
|
||||||
|
if(calSetWorkingCopy.getTime().getHours() < calNow.getTime().getHours())
|
||||||
|
{
|
||||||
|
// Log.i("AlarmManager", "calSetWorkingCopy.getTime().getHours(" + String.valueOf(calSetWorkingCopy.getTime().getHours()) + ") < calNow.getTime().getHours(" + String.valueOf(calNow.getTime().getHours()) + ")");
|
||||||
|
calSetWorkingCopy.add(Calendar.DAY_OF_MONTH, 7); //add a week
|
||||||
|
}
|
||||||
|
else if(calSetWorkingCopy.getTime().getHours() == calNow.getTime().getHours())
|
||||||
|
{
|
||||||
|
// Log.i("AlarmManager", "calSetWorkingCopy.getTime().getHours() == calNow.getTime().getHours()");
|
||||||
|
if(calSetWorkingCopy.getTime().getMinutes() <= calNow.getTime().getMinutes())
|
||||||
|
{
|
||||||
|
// Log.i("AlarmManager", "calSetWorkingCopy.getTime().getMinutes() < calNow.getTime().getMinutes()");
|
||||||
|
calSetWorkingCopy.add(Calendar.DAY_OF_MONTH, 7); //add a week
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(diff < 0)
|
||||||
|
{
|
||||||
|
// Miscellaneous.logEvent("i", "AlarmManager", "Adding " + String.valueOf(diff+7) + " on top of " + String.valueOf(calSetWorkingCopy.get(Calendar.DAY_OF_WEEK)));
|
||||||
|
calSetWorkingCopy.add(Calendar.DAY_OF_WEEK, diff+7); // it's a past weekday, schedule for next week
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Miscellaneous.logEvent("i", "AlarmManager", "Adding " + String.valueOf(diff) + " on top of " + String.valueOf(calSetWorkingCopy.get(Calendar.DAY_OF_WEEK)));
|
||||||
|
calSetWorkingCopy.add(Calendar.DAY_OF_WEEK, diff); // it's a future weekday, schedule for that day
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
i=(int)System.currentTimeMillis();
|
||||||
|
String calSetWorkingCopyString = sdf.format(calSetWorkingCopy.getTime()) + " RequestCode: " + String.valueOf(i);
|
||||||
|
// Miscellaneous.logEvent("i", "AlarmManager", "Setting repeating alarm because of rule: " + oneRule.getName() + " beginning at " + calSetWorkingCopyString);
|
||||||
|
|
||||||
|
alarmCandidates.add(calSetWorkingCopy.getTimeInMillis());
|
||||||
|
// Intent alarmIntent = new Intent(automationServiceRef, AlarmListener.class);
|
||||||
|
// alarmIntent.setData(Uri.parse("myalarms://" + i));
|
||||||
|
// PendingIntent alarmPendingIntent = PendingIntent.getBroadcast(automationServiceRef, i, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||||
|
// centralAlarmManagerInstance.setInexactRepeating(AlarmManager.RTC_WAKEUP, calSetWorkingCopy.getTimeInMillis(), milliSecondsInAWeek, alarmPendingIntent);
|
||||||
|
// requestCodeList.add(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// // get a Calendar object with current time
|
||||||
|
// Calendar cal = Calendar.getInstance();
|
||||||
|
// cal.add(Calendar.SECOND, 10);
|
||||||
|
// String calSetWorkingCopyString2 = sdf.format(cal.getTime());
|
||||||
|
// Miscellaneous.logEvent("i", "AlarmManager", "Setting repeating alarm because of hardcoded test: beginning at " + calSetWorkingCopyString2);
|
||||||
|
// Intent alarmIntent2 = new Intent(automationServiceRef, AlarmListener.class);
|
||||||
|
// PendingIntent alarmPendingIntent2 = PendingIntent.getBroadcast(automationServiceRef, 0, alarmIntent2, 0);
|
||||||
|
// centralAlarmManagerInstance.setInexactRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 5000, alarmPendingIntent2);
|
||||||
|
// requestCodeList.add(0);
|
||||||
|
|
||||||
|
scheduleNextAlarm();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void scheduleNextAlarm()
|
||||||
|
{
|
||||||
|
Long currentTime = System.currentTimeMillis();
|
||||||
|
Long scheduleCandidate = null;
|
||||||
|
|
||||||
|
if(alarmCandidates.size() == 0)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "AlarmManager", "No alarms to be scheduled.", 3);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if(alarmCandidates.size() == 1)
|
||||||
|
{
|
||||||
|
// only one alarm, schedule that
|
||||||
|
scheduleCandidate = alarmCandidates.get(0);
|
||||||
|
}
|
||||||
|
else if(alarmCandidates.size() > 1)
|
||||||
|
{
|
||||||
|
scheduleCandidate = alarmCandidates.get(0);
|
||||||
|
|
||||||
|
for(long alarmCandidate : alarmCandidates)
|
||||||
|
{
|
||||||
|
if(Math.abs(currentTime - alarmCandidate) < Math.abs(currentTime - scheduleCandidate))
|
||||||
|
scheduleCandidate = alarmCandidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Intent alarmIntent = new Intent(automationServiceRef, AlarmListener.class);
|
||||||
|
PendingIntent alarmPendingIntent = PendingIntent.getBroadcast(automationServiceRef, 0, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||||
|
centralAlarmManagerInstance.set(AlarmManager.RTC_WAKEUP, scheduleCandidate, alarmPendingIntent);
|
||||||
|
|
||||||
|
|
||||||
|
SimpleDateFormat sdf = new SimpleDateFormat("E dd.MM.yyyy HH:mm");
|
||||||
|
Calendar calendar = Calendar.getInstance();
|
||||||
|
calendar.setTimeInMillis(scheduleCandidate);
|
||||||
|
Miscellaneous.logEvent("i", "AlarmManager", "Chose " + sdf.format(calendar.getTime()) + " as next scheduled alarm.", 4);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void clearAlarms()
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "AlarmManager", "Clearing possibly standing alarms.", 4);
|
||||||
|
for(int requestCode : requestCodeList)
|
||||||
|
{
|
||||||
|
Intent alarmIntent = new Intent(automationServiceRef, AlarmListener.class);
|
||||||
|
PendingIntent alarmPendingIntent = PendingIntent.getBroadcast(automationServiceRef, requestCode, alarmIntent, 0);
|
||||||
|
// Miscellaneous.logEvent("i", "AlarmManager", "Clearing alarm with request code: " + String.valueOf(requestCode));
|
||||||
|
centralAlarmManagerInstance.cancel(alarmPendingIntent);
|
||||||
|
}
|
||||||
|
requestCodeList.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void startAlarmListenerInternal(AutomationService givenAutomationServiceRef)
|
||||||
|
{
|
||||||
|
if(!alarmListenerActive)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "AlarmListener", "Starting alarm listener.", 4);
|
||||||
|
AlarmListener.automationServiceRef = givenAutomationServiceRef;
|
||||||
|
centralAlarmManagerInstance = (AlarmManager)automationServiceRef.getSystemService(automationServiceRef.ALARM_SERVICE);
|
||||||
|
// alarmIntent = new Intent(automationServiceRef, AlarmListener.class);
|
||||||
|
// alarmPendingIntent = PendingIntent.getBroadcast(automationServiceRef, 0, alarmIntent, 0);
|
||||||
|
alarmListenerActive = true;
|
||||||
|
Miscellaneous.logEvent("i", "AlarmListener", "Alarm listener started.", 4);
|
||||||
|
AlarmListener.setAlarms();
|
||||||
|
|
||||||
|
// // get a Calendar object with current time
|
||||||
|
// Calendar cal = Calendar.getInstance();
|
||||||
|
// // add 5 minutes to the calendar object
|
||||||
|
// cal.add(Calendar.SECOND, 10);
|
||||||
|
// centralAlarmManagerInstance.setInexactRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 5000, alarmPendingIntent);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Miscellaneous.logEvent("i", "AlarmListener", "Request to start AlarmListener. But it's already active.", 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void stopAlarmListenerInternal()
|
||||||
|
{
|
||||||
|
if(alarmListenerActive)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "AlarmListener", "Stopping alarm listener.", 4);
|
||||||
|
clearAlarms();
|
||||||
|
// centralAlarmManagerInstance.cancel(alarmPendingIntent);
|
||||||
|
alarmListenerActive = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Miscellaneous.logEvent("i", "AlarmListener", "Request to stop AlarmListener. But it's not running.", 5);
|
||||||
|
}
|
||||||
|
public static void reloadAlarms()
|
||||||
|
{
|
||||||
|
AlarmListener.setAlarms();
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void startListener(AutomationService automationService)
|
||||||
|
{
|
||||||
|
AlarmListener.startAlarmListener(automationService);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void stopListener(AutomationService automationService)
|
||||||
|
{
|
||||||
|
AlarmListener.stopAlarmListener(automationService);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean haveAllPermission()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isListenerRunning()
|
||||||
|
{
|
||||||
|
return isAlarmListenerActive();
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public Trigger_Enum[] getMonitoredTrigger()
|
||||||
|
{
|
||||||
|
return new Trigger_Enum[] { Trigger_Enum.timeFrame };
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package com.jens.automation2.receivers;
|
||||||
|
|
||||||
|
import com.jens.automation2.AutomationService;
|
||||||
|
import com.jens.automation2.Trigger.Trigger_Enum;
|
||||||
|
|
||||||
|
public interface AutomationListenerInterface
|
||||||
|
{
|
||||||
|
public void startListener(AutomationService automationService);
|
||||||
|
public void stopListener(AutomationService automationService);
|
||||||
|
public boolean isListenerRunning();
|
||||||
|
public Trigger_Enum[] getMonitoredTrigger();
|
||||||
|
}
|
@ -0,0 +1,314 @@
|
|||||||
|
package com.jens.automation2.receivers;
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
import android.os.BatteryManager;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.jens.automation2.ActivityPermissions;
|
||||||
|
import com.jens.automation2.AutomationService;
|
||||||
|
import com.jens.automation2.Miscellaneous;
|
||||||
|
import com.jens.automation2.Rule;
|
||||||
|
import com.jens.automation2.Trigger.Trigger_Enum;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class BatteryReceiver extends BroadcastReceiver implements AutomationListenerInterface
|
||||||
|
{
|
||||||
|
private static int batteryLevel=-1; // initialize with a better value than this
|
||||||
|
public static AutomationService automationServiceRef = null;
|
||||||
|
private static boolean usbHostConnected = false;
|
||||||
|
|
||||||
|
private static boolean batteryReceiverActive = false;
|
||||||
|
private static IntentFilter batteryIntentFilter = null;
|
||||||
|
private static Intent batteryStatus = null;
|
||||||
|
private static BroadcastReceiver batteryInfoReceiverInstance = null;
|
||||||
|
public static void startBatteryReceiver(final AutomationService automationServiceRef)
|
||||||
|
{
|
||||||
|
if(!batteryReceiverActive)
|
||||||
|
{
|
||||||
|
BatteryReceiver.automationServiceRef = automationServiceRef;
|
||||||
|
|
||||||
|
if(batteryInfoReceiverInstance == null)
|
||||||
|
batteryInfoReceiverInstance = new BatteryReceiver();
|
||||||
|
|
||||||
|
if(batteryIntentFilter == null)
|
||||||
|
{
|
||||||
|
batteryIntentFilter = new IntentFilter();
|
||||||
|
batteryIntentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
|
||||||
|
batteryIntentFilter.addAction(Intent.ACTION_BATTERY_LOW);
|
||||||
|
// batteryIntentFilter.addAction(Intent.ACTION_POWER_CONNECTED);
|
||||||
|
// batteryIntentFilter.addAction(Intent.ACTION_POWER_DISCONNECTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
batteryStatus = automationServiceRef.registerReceiver(batteryInfoReceiverInstance, batteryIntentFilter);
|
||||||
|
|
||||||
|
batteryReceiverActive = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static void stopBatteryReceiver()
|
||||||
|
{
|
||||||
|
if(batteryReceiverActive)
|
||||||
|
{
|
||||||
|
if(batteryInfoReceiverInstance != null)
|
||||||
|
{
|
||||||
|
automationServiceRef.unregisterReceiver(batteryInfoReceiverInstance);
|
||||||
|
batteryInfoReceiverInstance = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
batteryReceiverActive = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isBatteryReceiverActive()
|
||||||
|
{
|
||||||
|
return batteryReceiverActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isUsbHostConnected()
|
||||||
|
{
|
||||||
|
return usbHostConnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getBatteryLevel()
|
||||||
|
{
|
||||||
|
return batteryLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int deviceIsCharging = 0; //0=unknown, 1=no, 2=yes
|
||||||
|
|
||||||
|
public static int getDeviceIsCharging()
|
||||||
|
{
|
||||||
|
return deviceIsCharging;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent)
|
||||||
|
{
|
||||||
|
// Log.i("Battery", "Some battery event");
|
||||||
|
|
||||||
|
if (intent == null)
|
||||||
|
return;
|
||||||
|
if (context == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(intent.getAction().equals(Intent.ACTION_BATTERY_LOW))
|
||||||
|
{
|
||||||
|
Log.i("Battery", "Low battery event");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Miscellaneous.logEvent("i", "BatteryReceiver", "Received battery event.");
|
||||||
|
// if(intent.getAction().equals(Intent.ACTION_BATTERY_CHANGED))
|
||||||
|
// {
|
||||||
|
batteryLevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
|
||||||
|
// int scale = -1;
|
||||||
|
// int voltage = -1;
|
||||||
|
// int temp = -1;
|
||||||
|
// scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
|
||||||
|
// temp = intent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, -1);
|
||||||
|
// voltage = intent.getIntExtra(BatteryManager.EXTRA_VOLTAGE, -1);
|
||||||
|
Log.i("Battery", "Level: " + String.valueOf(batteryLevel));
|
||||||
|
this.actionBatteryLevel(context);
|
||||||
|
|
||||||
|
int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
|
||||||
|
int statusPlugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
|
||||||
|
// Miscellaneous.logEvent("i", "BatteryReceiver", "Status: " + String.valueOf(statusPlugged));
|
||||||
|
|
||||||
|
switch(statusPlugged)
|
||||||
|
{
|
||||||
|
case BatteryManager.BATTERY_PLUGGED_AC:
|
||||||
|
// Toast.makeText(context, "Regular charging", Toast.LENGTH_LONG).show();
|
||||||
|
// Miscellaneous.logEvent("i", "BatteryReceiver", "Regular charging.");
|
||||||
|
this.actionCharging(context);
|
||||||
|
break;
|
||||||
|
case BatteryManager.BATTERY_PLUGGED_USB:
|
||||||
|
this.actionUsbConnected(context);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(status)
|
||||||
|
{
|
||||||
|
// case BatteryManager.BATTERY_STATUS_CHARGING:
|
||||||
|
// break;
|
||||||
|
case BatteryManager.BATTERY_STATUS_FULL:
|
||||||
|
// Toast.makeText(context, "Regular charging full", Toast.LENGTH_LONG).show();
|
||||||
|
// Miscellaneous.logEvent("i", "BatteryReceiver", "Device has been fully charged.");
|
||||||
|
this.actionCharging(context);
|
||||||
|
break;
|
||||||
|
case BatteryManager.BATTERY_STATUS_DISCHARGING:
|
||||||
|
this.actionDischarging(context);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// }
|
||||||
|
// else if(intent.getAction().equals(Intent.ACTION_POWER_CONNECTED))
|
||||||
|
// {
|
||||||
|
//// Miscellaneous.logEvent("i", "BatteryReceiver", "Battery is charging or full.");
|
||||||
|
// deviceIsCharging = 2;
|
||||||
|
// //activate rule(s)
|
||||||
|
// ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByCharging(true);
|
||||||
|
// for(int i=0; i<ruleCandidates.size(); i++)
|
||||||
|
// {
|
||||||
|
// if(ruleCandidates.get(i).applies(context))
|
||||||
|
// ruleCandidates.get(i).activate(locationProviderRef.getParentService());
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// else if(intent.getAction().equals(Intent.ACTION_POWER_DISCONNECTED))
|
||||||
|
// {
|
||||||
|
//// Miscellaneous.logEvent("i", "BatteryReceiver", "Battery is discharging.");
|
||||||
|
// deviceIsCharging = 1;
|
||||||
|
// //activate rule(s)
|
||||||
|
// ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByCharging(false);
|
||||||
|
// for(int i=0; i<ruleCandidates.size(); i++)
|
||||||
|
// {
|
||||||
|
// if(ruleCandidates.get(i).applies(context))
|
||||||
|
// ruleCandidates.get(i).activate(locationProviderRef.getParentService());
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "BatteryReceiver", "Error receiving battery status: " + e.getMessage(), 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int isDeviceCharging(Context context)
|
||||||
|
{
|
||||||
|
switch(deviceIsCharging)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
Miscellaneous.logEvent("w", "ChargingInfo", "Status of device charging was requested. Information isn't available, yet.", 4);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
Miscellaneous.logEvent("i", "ChargingInfo", "Status of device charging was requested. Device is discharging.", 3);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
Miscellaneous.logEvent("i", "ChargingInfo", "Status of device charging was requested. Device is charging.", 3);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return deviceIsCharging;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void actionCharging(Context context)
|
||||||
|
{
|
||||||
|
if(deviceIsCharging != 2) // Avoid flooding the log. This event will occur on a regular basis even though charging state wasn't changed.
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "BatteryReceiver", "Battery is charging or full.", 3);
|
||||||
|
deviceIsCharging = 2;
|
||||||
|
//activate rule(s)
|
||||||
|
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByCharging(true);
|
||||||
|
for(int i=0; i<ruleCandidates.size(); i++)
|
||||||
|
{
|
||||||
|
if(ruleCandidates.get(i).applies(context))
|
||||||
|
ruleCandidates.get(i).activate(automationServiceRef, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void actionBatteryLevel(Context context)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "BatteryReceiver", "Battery level has changed.", 3);
|
||||||
|
//activate rule(s)
|
||||||
|
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByBatteryLevel();
|
||||||
|
for(int i=0; i<ruleCandidates.size(); i++)
|
||||||
|
{
|
||||||
|
if(ruleCandidates.get(i).applies(context))
|
||||||
|
ruleCandidates.get(i).activate(automationServiceRef, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void actionDischarging(Context context)
|
||||||
|
{
|
||||||
|
if(deviceIsCharging != 1) // Avoid flooding the log. This event will occur on a regular basis even though charging state wasn't changed.
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "BatteryReceiver", "Battery is discharging.", 3);
|
||||||
|
deviceIsCharging = 1;
|
||||||
|
//activate rule(s)
|
||||||
|
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByCharging(false);
|
||||||
|
for(int i=0; i<ruleCandidates.size(); i++)
|
||||||
|
{
|
||||||
|
if(ruleCandidates.get(i).applies(context))
|
||||||
|
ruleCandidates.get(i).activate(automationServiceRef, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.actionUsbDisconnected(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void actionUsbConnected(Context context)
|
||||||
|
{
|
||||||
|
// Event usbConnected
|
||||||
|
|
||||||
|
// Miscellaneous.logEvent("i", "BatteryReceiver", "BATTERY_PLUGGED_USB");
|
||||||
|
|
||||||
|
if(!usbHostConnected)
|
||||||
|
{
|
||||||
|
usbHostConnected = true;
|
||||||
|
Miscellaneous.logEvent("i", "BatteryReceiver", "Connected to computer.", 3);
|
||||||
|
Toast.makeText(context, "Connected to computer.", Toast.LENGTH_LONG).show();
|
||||||
|
|
||||||
|
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByUsbHost(true);
|
||||||
|
for(Rule oneRule : ruleCandidates)
|
||||||
|
{
|
||||||
|
if(oneRule.applies(context))
|
||||||
|
oneRule.activate(automationServiceRef, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.actionCharging(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void actionUsbDisconnected(Context context)
|
||||||
|
{
|
||||||
|
// Event usbDisConnected
|
||||||
|
|
||||||
|
if(usbHostConnected)
|
||||||
|
{
|
||||||
|
usbHostConnected = false;
|
||||||
|
Miscellaneous.logEvent("i", "BatteryReceiver", "Disconnected from computer.", 3);
|
||||||
|
Toast.makeText(context, "Disconnected from computer.", Toast.LENGTH_LONG).show();
|
||||||
|
|
||||||
|
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByUsbHost(false);
|
||||||
|
for(Rule oneRule : ruleCandidates)
|
||||||
|
{
|
||||||
|
if(oneRule.applies(context))
|
||||||
|
oneRule.activate(automationServiceRef, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void startListener(AutomationService automationService)
|
||||||
|
{
|
||||||
|
BatteryReceiver.startBatteryReceiver(automationService);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void stopListener(AutomationService automationService)
|
||||||
|
{
|
||||||
|
BatteryReceiver.stopBatteryReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean haveAllPermission()
|
||||||
|
{
|
||||||
|
return ActivityPermissions.havePermission("android.permission.READ_PHONE_STATE", Miscellaneous.getAnyContext()) &&
|
||||||
|
ActivityPermissions.havePermission("android.permission.BATTERY_STATS", Miscellaneous.getAnyContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isListenerRunning()
|
||||||
|
{
|
||||||
|
return BatteryReceiver.isBatteryReceiverActive();
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public Trigger_Enum[] getMonitoredTrigger()
|
||||||
|
{
|
||||||
|
// actually monitores several
|
||||||
|
return new Trigger_Enum[] { Trigger_Enum.batteryLevel, Trigger_Enum.charging, Trigger_Enum.usb_host_connection };
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,303 @@
|
|||||||
|
package com.jens.automation2.receivers;
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothAdapter;
|
||||||
|
import android.bluetooth.BluetoothDevice;
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.jens.automation2.ActivityPermissions;
|
||||||
|
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.Trigger_Enum;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class BluetoothReceiver extends BroadcastReceiver implements AutomationListenerInterface
|
||||||
|
{
|
||||||
|
protected static ArrayList<BluetoothDevice> connectedDevices = new ArrayList<BluetoothDevice>();
|
||||||
|
protected static ArrayList<BluetoothDevice> devicesInRange = new ArrayList<BluetoothDevice>();
|
||||||
|
|
||||||
|
protected static BluetoothDevice lastAffectedDevice = null;
|
||||||
|
protected static String lastAction = null;
|
||||||
|
|
||||||
|
protected static IntentFilter bluetoothReceiverIntentFilter = null;
|
||||||
|
protected static boolean bluetoothReceiverActive = false;
|
||||||
|
protected static BluetoothReceiver bluetoothReceiverInstance = null;
|
||||||
|
|
||||||
|
public static boolean isBluetoothReceiverActive()
|
||||||
|
{
|
||||||
|
return bluetoothReceiverActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void startBluetoothReceiver()
|
||||||
|
{
|
||||||
|
if(bluetoothReceiverInstance == null)
|
||||||
|
bluetoothReceiverInstance = new BluetoothReceiver();
|
||||||
|
|
||||||
|
if(bluetoothReceiverIntentFilter == null)
|
||||||
|
{
|
||||||
|
bluetoothReceiverIntentFilter = new IntentFilter();
|
||||||
|
bluetoothReceiverIntentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
|
||||||
|
bluetoothReceiverIntentFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED);
|
||||||
|
bluetoothReceiverIntentFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(!bluetoothReceiverActive)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "BluetoothReceiver", "Starting BluetoothReceiver", 4);
|
||||||
|
bluetoothReceiverActive = true;
|
||||||
|
AutomationService.getInstance().registerReceiver(bluetoothReceiverInstance, bluetoothReceiverIntentFilter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "BluetoothReceiver", "Error starting BluetoothReceiver: " + Log.getStackTraceString(ex), 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static void stopBluetoothReceiver()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(bluetoothReceiverActive)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "BluetoothReceiver", "Stopping BluetoothReceiver", 4);
|
||||||
|
bluetoothReceiverActive = false;
|
||||||
|
AutomationService.getInstance().unregisterReceiver(bluetoothReceiverInstance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "BluetoothReceiver", "Error stopping BluetoothReceiver: " + Log.getStackTraceString(ex), 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BluetoothDevice getLastAffectedDevice()
|
||||||
|
{
|
||||||
|
return lastAffectedDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getLastAction()
|
||||||
|
{
|
||||||
|
return lastAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent)
|
||||||
|
{
|
||||||
|
// Miscellaneous.logEvent("i", "BluetoothReceiver", "Bluetooth event.", 4);
|
||||||
|
|
||||||
|
String action = intent.getAction();
|
||||||
|
BluetoothDevice bluetoothDevice = null;
|
||||||
|
|
||||||
|
if(action.equals(BluetoothDevice.ACTION_ACL_CONNECTED) | action.equals("android.bluetooth.device.action.ACL_CONNECTED"))
|
||||||
|
{
|
||||||
|
bluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
|
||||||
|
lastAffectedDevice = bluetoothDevice;
|
||||||
|
lastAction = action;
|
||||||
|
connectedDevices.add(bluetoothDevice);
|
||||||
|
Miscellaneous.logEvent("i", "BluetoothReceiver", String.format(context.getResources().getString(R.string.bluetoothConnectionTo), bluetoothDevice.getName()), 3);
|
||||||
|
}
|
||||||
|
else if(action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED) | action.equals(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED) | action.equals("android.bluetooth.device.ACTION_ACL_DISCONNECTED") | action.equals("android.bluetooth.device.ACTION_ACL_DISCONNECT_REQUESTED"))
|
||||||
|
{
|
||||||
|
bluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
|
||||||
|
lastAffectedDevice = bluetoothDevice;
|
||||||
|
lastAction = action;
|
||||||
|
connectedDevices.remove(bluetoothDevice);
|
||||||
|
Miscellaneous.logEvent("i", "BluetoothReceiver", String.format(context.getResources().getString(R.string.bluetoothDisconnectFrom), bluetoothDevice.getName()), 3);
|
||||||
|
}
|
||||||
|
else if(action.equals(BluetoothDevice.ACTION_FOUND) | action.equals("android.bluetooth.device.ACTION_FOUND"))
|
||||||
|
{
|
||||||
|
bluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
|
||||||
|
lastAffectedDevice = bluetoothDevice;
|
||||||
|
lastAction = action;
|
||||||
|
devicesInRange.add(bluetoothDevice);
|
||||||
|
Miscellaneous.logEvent("i", "BluetoothReceiver", String.format(context.getResources().getString(R.string.bluetoothDeviceInRange), bluetoothDevice.getName()), 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByBluetoothConnection();
|
||||||
|
for(int i=0; i<ruleCandidates.size(); i++)
|
||||||
|
{
|
||||||
|
if(ruleCandidates.get(i).applies(AutomationService.getInstance()))
|
||||||
|
ruleCandidates.get(i).activate(AutomationService.getInstance(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BluetoothDevice[] getAllPairedBluetoothDevices()
|
||||||
|
{
|
||||||
|
BluetoothDevice[] returnArray;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Set<BluetoothDevice> deviceList = BluetoothAdapter.getDefaultAdapter().getBondedDevices();
|
||||||
|
returnArray = deviceList.toArray(new BluetoothDevice[deviceList.size()]);
|
||||||
|
|
||||||
|
Arrays.sort(returnArray, new Comparator<BluetoothDevice>()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public int compare(BluetoothDevice lhs, BluetoothDevice rhs)
|
||||||
|
{
|
||||||
|
return lhs.getName().compareTo(rhs.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch(NullPointerException e)
|
||||||
|
{
|
||||||
|
// There are no paired bluetooth devices.
|
||||||
|
|
||||||
|
returnArray = new BluetoothDevice[] {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String[] getAllPairedBluetoothDevicesStrings()
|
||||||
|
{
|
||||||
|
ArrayList<String> names = new ArrayList<String>();
|
||||||
|
for(BluetoothDevice device : getAllPairedBluetoothDevices())
|
||||||
|
names.add(device.getName() + " (" + device.getAddress() + ")");
|
||||||
|
|
||||||
|
return names.toArray(new String[names.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BluetoothDevice getDeviceByName(String name)
|
||||||
|
{
|
||||||
|
for(BluetoothDevice device : getAllPairedBluetoothDevices())
|
||||||
|
{
|
||||||
|
if(device.getName().equals(name))
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BluetoothDevice getDeviceByAddress(String address)
|
||||||
|
{
|
||||||
|
for(BluetoothDevice device : getAllPairedBluetoothDevices())
|
||||||
|
{
|
||||||
|
if(device.getAddress().equals(address))
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getDevicePositionByAddress(String address)
|
||||||
|
{
|
||||||
|
BluetoothDevice[] allDevices = getAllPairedBluetoothDevices();
|
||||||
|
for(int i=0; i<allDevices.length; i++)
|
||||||
|
{
|
||||||
|
if(allDevices[i].getAddress().equals(address))
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isDeviceCurrentlyConnected(BluetoothDevice searchDevice)
|
||||||
|
{
|
||||||
|
for(BluetoothDevice device : connectedDevices)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (device.getAddress().equals(searchDevice.getAddress()))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch(NullPointerException e)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Just proceed with the next loop.
|
||||||
|
|
||||||
|
This may happen if devices have been unpaired since
|
||||||
|
they have been added for usage in a rule.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isAnyDeviceConnected()
|
||||||
|
{
|
||||||
|
if(connectedDevices.size() > 0)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isAnyDeviceInRange()
|
||||||
|
{
|
||||||
|
if(devicesInRange.size() > 0)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isDeviceInRange(BluetoothDevice searchDevice)
|
||||||
|
{
|
||||||
|
for(BluetoothDevice device : devicesInRange)
|
||||||
|
if(device.getAddress().equals(searchDevice.getAddress()))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void discovery()
|
||||||
|
{
|
||||||
|
BluetoothAdapter.getDefaultAdapter().startDiscovery();
|
||||||
|
BroadcastReceiver discoveryReceiver = new BroadcastReceiver()
|
||||||
|
{
|
||||||
|
public void onReceive(Context context, Intent intent)
|
||||||
|
{
|
||||||
|
String action = intent.getAction();
|
||||||
|
//ACTION_DISCOVERY_STARTED and ACTION_DISCOVERY_FINISHED
|
||||||
|
if(action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED))
|
||||||
|
{
|
||||||
|
// This would be a good point to look for devices that are not in range anymore.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startListener(AutomationService automationService)
|
||||||
|
{
|
||||||
|
BluetoothReceiver.startBluetoothReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stopListener(AutomationService automationService)
|
||||||
|
{
|
||||||
|
BluetoothReceiver.stopBluetoothReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean haveAllPermission()
|
||||||
|
{
|
||||||
|
return ActivityPermissions.havePermission("android.permission.BLUETOOTH_ADMIN", Miscellaneous.getAnyContext()) &&
|
||||||
|
ActivityPermissions.havePermission("android.permission.BLUETOOTH", Miscellaneous.getAnyContext()) &&
|
||||||
|
ActivityPermissions.havePermission("android.permission.ACCESS_NETWORK_STATE", Miscellaneous.getAnyContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isListenerRunning()
|
||||||
|
{
|
||||||
|
return BluetoothReceiver.isBluetoothReceiverActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Trigger_Enum[] getMonitoredTrigger()
|
||||||
|
{
|
||||||
|
return new Trigger_Enum[] { Trigger_Enum.bluetoothConnection };
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,263 @@
|
|||||||
|
package com.jens.automation2.receivers;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
import android.net.ConnectivityManager;
|
||||||
|
import android.net.NetworkInfo;
|
||||||
|
import android.net.wifi.WifiInfo;
|
||||||
|
import android.net.wifi.WifiManager;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.telephony.TelephonyManager;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.jens.automation2.ActivityPermissions;
|
||||||
|
import com.jens.automation2.AutomationService;
|
||||||
|
import com.jens.automation2.Miscellaneous;
|
||||||
|
import com.jens.automation2.Rule;
|
||||||
|
import com.jens.automation2.Trigger.Trigger_Enum;
|
||||||
|
import com.jens.automation2.location.WifiBroadcastReceiver;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class ConnectivityReceiver extends BroadcastReceiver implements AutomationListenerInterface
|
||||||
|
{
|
||||||
|
protected static boolean connectivityReceiverActive = false;
|
||||||
|
private static ConnectivityReceiver connectivityReceiverInstance = null;
|
||||||
|
private static IntentFilter connectivityIntentFilter = null;
|
||||||
|
private static AutomationService automationServiceRef = null;
|
||||||
|
protected static boolean dataConnectionLastState = false;
|
||||||
|
protected static boolean roamingLastState = false;
|
||||||
|
|
||||||
|
public static boolean isConnectivityReceiverActive()
|
||||||
|
{
|
||||||
|
return connectivityReceiverActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void startConnectivityReceiver(AutomationService ref)
|
||||||
|
{
|
||||||
|
automationServiceRef = ref;
|
||||||
|
|
||||||
|
if(connectivityReceiverInstance == null)
|
||||||
|
connectivityReceiverInstance = new ConnectivityReceiver();
|
||||||
|
|
||||||
|
|
||||||
|
if(connectivityIntentFilter == null)
|
||||||
|
{
|
||||||
|
connectivityIntentFilter = new IntentFilter();
|
||||||
|
connectivityIntentFilter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
|
||||||
|
connectivityIntentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(!connectivityReceiverActive)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "Wifi Listener", "Starting connectivityReceiver", 4);
|
||||||
|
connectivityReceiverActive = true;
|
||||||
|
automationServiceRef.registerReceiver(connectivityReceiverInstance, connectivityIntentFilter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "Wifi Listener", "Error starting connectivityReceiver: " + Log.getStackTraceString(ex), 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void stopConnectivityReceiver()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(connectivityReceiverActive)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "Wifi Listener", "Stopping connectivityReceiver", 4);
|
||||||
|
connectivityReceiverActive = false;
|
||||||
|
automationServiceRef.unregisterReceiver(connectivityReceiverInstance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "Wifi Listener", "Error stopping connectivityReceiver: " + Log.getStackTraceString(ex), 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get roaming state from telephony manager
|
||||||
|
public static Boolean isRoaming(Context context)
|
||||||
|
{
|
||||||
|
TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
|
||||||
|
return telephonyManager.isNetworkRoaming();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setDataConnectionLastState(boolean newState)
|
||||||
|
{
|
||||||
|
if(dataConnectionLastState != newState)
|
||||||
|
{
|
||||||
|
dataConnectionLastState = newState;
|
||||||
|
|
||||||
|
// Run rules if I decide to create such a trigger
|
||||||
|
// automationServiceRef.getLocationProvider().handleDataConnectionChange(newState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static Boolean isDataConnectionAvailable(Context context)
|
||||||
|
{
|
||||||
|
ConnectivityManager connManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||||
|
NetworkInfo ni = connManager.getActiveNetworkInfo();
|
||||||
|
return ni != null && ni.isConnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get airplane mode state from system settings
|
||||||
|
@SuppressLint("NewApi")
|
||||||
|
public static boolean isAirplaneMode(Context context)
|
||||||
|
{
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1)
|
||||||
|
{
|
||||||
|
int value = android.provider.Settings.System.getInt(context.getContentResolver(), android.provider.Settings.System.AIRPLANE_MODE_ON, 0);
|
||||||
|
return value != 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return android.provider.Settings.Global.getInt(context.getContentResolver(), android.provider.Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (context == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(intent.getAction().equals(Intent.ACTION_AIRPLANE_MODE_CHANGED))
|
||||||
|
{
|
||||||
|
// Airplane mode status has changed.
|
||||||
|
Miscellaneous.logEvent("i", "Connectivity", "Airplane mode changed.", 2);
|
||||||
|
boolean isAirplaneMode = isAirplaneMode(context);
|
||||||
|
automationServiceRef.getLocationProvider().handleAirplaneMode(isAirplaneMode);
|
||||||
|
|
||||||
|
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByAirplaneMode(isAirplaneMode);
|
||||||
|
for(int i=0; i<ruleCandidates.size(); i++)
|
||||||
|
{
|
||||||
|
if(ruleCandidates.get(i).applies(automationServiceRef))
|
||||||
|
ruleCandidates.get(i).activate(automationServiceRef, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION))
|
||||||
|
{
|
||||||
|
ConnectivityManager connManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||||
|
// NetworkInfo ni = connManager.getActiveNetworkInfo();
|
||||||
|
NetworkInfo ni = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
|
||||||
|
if(ni != null)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "Connectivity", "Change of network with type " + ni.getType() + " noticed.", 4);
|
||||||
|
|
||||||
|
switch(ni.getType())
|
||||||
|
{
|
||||||
|
case ConnectivityManager.TYPE_WIFI:
|
||||||
|
WifiBroadcastReceiver.lastConnectedState = ni.isConnected();
|
||||||
|
WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
|
||||||
|
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
|
||||||
|
WifiBroadcastReceiver.setLastWifiSsid(wifiInfo.getSSID());
|
||||||
|
WifiBroadcastReceiver.findRules(automationServiceRef.getLocationProvider());
|
||||||
|
break;
|
||||||
|
case ConnectivityManager.TYPE_MOBILE:
|
||||||
|
boolean isRoaming = isRoaming(context);
|
||||||
|
if(isRoaming != roamingLastState)
|
||||||
|
{
|
||||||
|
roamingLastState = isRoaming;
|
||||||
|
|
||||||
|
automationServiceRef.getLocationProvider().handleRoaming(isRoaming);
|
||||||
|
|
||||||
|
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByRoaming(isRoaming);
|
||||||
|
for(int i=0; i<ruleCandidates.size(); i++)
|
||||||
|
{
|
||||||
|
if(ruleCandidates.get(i).applies(automationServiceRef))
|
||||||
|
ruleCandidates.get(i).activate(automationServiceRef, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
// case ConnectivityManager.TYPE_BLUETOOTH:
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* BluetoothAdapter.ACTION_STATE_CHANGED ("android.bluetooth.adapter.action.STATE_CHANGED")
|
||||||
|
|
||||||
|
Broadcast Action: The state of the local Bluetooth adapter has been changed. For example, Bluetooth has been turned on or off.
|
||||||
|
|
||||||
|
and for Ringer mode changes:
|
||||||
|
|
||||||
|
AudioManager.RINGER_MODE_CHANGED_ACTION ("android.media.RINGER_MODE_CHANGED")
|
||||||
|
|
||||||
|
Sticky broadcast intent action indicating that the ringer mode has changed. Includes the new ringer mode.
|
||||||
|
|
||||||
|
Not a ringer mode change, but this can be good to have also AudioManager.VIBRATE_SETTING_CHANGED_ACTION ("android.media.VIBRATE_SETTING_CHANGED")
|
||||||
|
|
||||||
|
Broadcast intent action indicating that the vibrate setting has changed. Includes the vibrate type and its new setting.
|
||||||
|
*/
|
||||||
|
// BluetoothDevice bluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
|
||||||
|
// if(bluetoothDevice.getBondState()
|
||||||
|
// if(BluetoothDevice.)
|
||||||
|
// ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByRoaming(isRoaming);
|
||||||
|
// for(int i=0; i<ruleCandidates.size(); i++)
|
||||||
|
// {
|
||||||
|
// if(ruleCandidates.get(i).applies(parentLocationProvider.getParentService()))
|
||||||
|
// ruleCandidates.get(i).activate(parentLocationProvider.getParentService());
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
default:
|
||||||
|
Miscellaneous.logEvent("i", "Connectivity", "Type of changed network not specified. Doing nothing.", 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NetworkInfo wifiInfo = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
|
||||||
|
if(!wifiInfo.isAvailable() && WifiBroadcastReceiver.lastConnectedState)
|
||||||
|
{
|
||||||
|
// 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "Connectivity", "Error in ConnectivityReceiver->onReceive(): " + Log.getStackTraceString(e), 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startListener(AutomationService automationService)
|
||||||
|
{
|
||||||
|
ConnectivityReceiver.startConnectivityReceiver(automationService);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stopListener(AutomationService automationService)
|
||||||
|
{
|
||||||
|
ConnectivityReceiver.stopConnectivityReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean haveAllPermission()
|
||||||
|
{
|
||||||
|
return ActivityPermissions.havePermission("android.permission.ACCESS_NETWORK_STATE", Miscellaneous.getAnyContext()) &&
|
||||||
|
ActivityPermissions.havePermission("android.permission.ACCESS_WIFI_STATE", Miscellaneous.getAnyContext()) &&
|
||||||
|
ActivityPermissions.havePermission("android.permission.ACCESS_NETWORK_STATE", Miscellaneous.getAnyContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isListenerRunning()
|
||||||
|
{
|
||||||
|
return ConnectivityReceiver.isConnectivityReceiverActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Trigger_Enum[] getMonitoredTrigger()
|
||||||
|
{
|
||||||
|
return new Trigger_Enum[] { Trigger_Enum.airplaneMode, Trigger_Enum.roaming, Trigger_Enum.wifiConnection };
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,152 @@
|
|||||||
|
package com.jens.automation2.receivers;
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.jens.automation2.ActivityPermissions;
|
||||||
|
import com.jens.automation2.AutomationService;
|
||||||
|
import com.jens.automation2.Miscellaneous;
|
||||||
|
import com.jens.automation2.Rule;
|
||||||
|
import com.jens.automation2.Trigger.Trigger_Enum;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class HeadphoneJackListener extends BroadcastReceiver implements AutomationListenerInterface
|
||||||
|
{
|
||||||
|
private static boolean headsetConnected = false;
|
||||||
|
private static int headphoneType = -1;
|
||||||
|
|
||||||
|
protected static boolean headphoneJackListenerActive=false;
|
||||||
|
protected static IntentFilter headphoneJackListenerIntentFilter = null;
|
||||||
|
protected static HeadphoneJackListener instance;
|
||||||
|
|
||||||
|
public static HeadphoneJackListener getInstance()
|
||||||
|
{
|
||||||
|
if(instance == null)
|
||||||
|
instance = new HeadphoneJackListener();
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isHeadphoneJackListenerActive()
|
||||||
|
{
|
||||||
|
return headphoneJackListenerActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static boolean isHeadsetConnected()
|
||||||
|
{
|
||||||
|
return headsetConnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getHeadphoneType()
|
||||||
|
{
|
||||||
|
return headphoneType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
/*Broadcast Action: Wired Headset plugged in or unplugged.
|
||||||
|
The intent will have the following extra values:
|
||||||
|
|
||||||
|
state - 0 for unplugged, 1 for plugged.
|
||||||
|
name - Headset type, human readable string
|
||||||
|
microphone - 1 if headset has a microphone, 0 otherwise*/
|
||||||
|
|
||||||
|
int state = intent.getExtras().getInt("state");
|
||||||
|
String name = intent.getExtras().getString("name");
|
||||||
|
headphoneType = intent.getExtras().getInt("microphone");
|
||||||
|
|
||||||
|
if(state == 0)
|
||||||
|
{
|
||||||
|
headsetConnected = false;
|
||||||
|
Miscellaneous.logEvent("i", "HeadphoneJackListener", "Headset " + name + " unplugged.", 4);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
headsetConnected = true;
|
||||||
|
Miscellaneous.logEvent("i", "HeadphoneJackListener", "Headset " + name + " plugged in.", 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByHeadphoneJack(isHeadsetConnected());
|
||||||
|
for(int i=0; i<ruleCandidates.size(); i++)
|
||||||
|
{
|
||||||
|
if(ruleCandidates.get(i).applies(context))
|
||||||
|
ruleCandidates.get(i).activate(AutomationService.getInstance(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startListener(AutomationService automationService)
|
||||||
|
{
|
||||||
|
if(headphoneJackListenerIntentFilter == null)
|
||||||
|
{
|
||||||
|
headphoneJackListenerIntentFilter = new IntentFilter();
|
||||||
|
headphoneJackListenerIntentFilter.addAction(Intent.ACTION_HEADSET_PLUG);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(!headphoneJackListenerActive && Rule.isAnyRuleUsing(Trigger_Enum.headsetPlugged))
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "HeadsetJackListener", "Starting HeadsetJackListener", 4);
|
||||||
|
headphoneJackListenerActive = true;
|
||||||
|
// getInstance().startHeadphoneJackListener(AutomationService.getInstance(), headphoneJackListenerIntentFilter);
|
||||||
|
automationService.registerReceiver(this, headphoneJackListenerIntentFilter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "ActivityDetectionReceiver", "Error starting HeadsetJackListener: " + Log.getStackTraceString(ex), 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stopListener(AutomationService automationService)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(headphoneJackListenerActive)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "HeadsetJackListener", "Stopping HeadsetJackListener", 4);
|
||||||
|
// getInstance().stopHeadphoneJackListener(AutomationService.getInstance());
|
||||||
|
automationService.unregisterReceiver(this);
|
||||||
|
headphoneJackListenerActive = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "ActivityDetectionReceiver", "Error stopping HeadsetJackListener: " + Log.getStackTraceString(ex), 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean haveAllPermission()
|
||||||
|
{
|
||||||
|
return ActivityPermissions.havePermission("android.permission.READ_PHONE_STATE", Miscellaneous.getAnyContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isListenerRunning()
|
||||||
|
{
|
||||||
|
return HeadphoneJackListener.isHeadphoneJackListenerActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Trigger_Enum[] getMonitoredTrigger()
|
||||||
|
{
|
||||||
|
return new Trigger_Enum[] { Trigger_Enum.headsetPlugged };
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,344 @@
|
|||||||
|
package com.jens.automation2.receivers;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.nfc.NdefMessage;
|
||||||
|
import android.nfc.NdefRecord;
|
||||||
|
import android.nfc.NfcAdapter;
|
||||||
|
import android.nfc.Tag;
|
||||||
|
import android.nfc.tech.Ndef;
|
||||||
|
import android.nfc.tech.NdefFormatable;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.jens.automation2.AutomationService;
|
||||||
|
import com.jens.automation2.Miscellaneous;
|
||||||
|
import com.jens.automation2.R;
|
||||||
|
import com.jens.automation2.Rule;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
@SuppressLint("NewApi")
|
||||||
|
public class NfcReceiver
|
||||||
|
{
|
||||||
|
public static final String MIME_TEXT_PLAIN = "text/plain";
|
||||||
|
public static String lastReadLabel = null;
|
||||||
|
|
||||||
|
private static NfcAdapter nfcAdapter = null;
|
||||||
|
public static NfcAdapter getNfcAdapter(Context context)
|
||||||
|
{
|
||||||
|
if(nfcAdapter == null)
|
||||||
|
{
|
||||||
|
if(Build.VERSION.SDK_INT <= 10)
|
||||||
|
{
|
||||||
|
// NFC not supported until after Gingerbread.
|
||||||
|
Miscellaneous.logEvent("w", "NFC", context.getResources().getString(R.string.nfcNotSupportedInThisAndroidVersionYet), 3);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nfcAdapter = NfcAdapter.getDefaultAdapter(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nfcAdapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setNfcAdapter(NfcAdapter nfcAdapter)
|
||||||
|
{
|
||||||
|
NfcReceiver.nfcAdapter = nfcAdapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("NewApi")
|
||||||
|
public static void checkIntentForNFC(Context context, Intent intent)
|
||||||
|
{
|
||||||
|
if(!NfcReceiver.checkNfcRequirements(context, false))
|
||||||
|
return;
|
||||||
|
|
||||||
|
String action = intent.getAction();
|
||||||
|
if(action == null)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "NFC", "action=null", 5);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(action.equals(NfcAdapter.ACTION_NDEF_DISCOVERED))
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "NFC", "ACTION_NDEF_DISCOVERED", 4);
|
||||||
|
|
||||||
|
getNfcAdapter(context);
|
||||||
|
|
||||||
|
if(nfcAdapter == null) // if it's still null the device doesn't support NFC
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String mimeType = intent.getType();
|
||||||
|
if(mimeType.equals(MIME_TEXT_PLAIN))
|
||||||
|
{
|
||||||
|
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
|
||||||
|
|
||||||
|
// if(NfcReceiver.discoveredTag == null)
|
||||||
|
// NfcReceiver.discoveredTag = tag;
|
||||||
|
|
||||||
|
new NdefReaderTask().execute(tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// else if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(action))
|
||||||
|
// {
|
||||||
|
//
|
||||||
|
// // In case we would still use the Tech Discovered Intent
|
||||||
|
// Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
|
||||||
|
// String[] techList = tag.getTechList();
|
||||||
|
// String searchedTech = Ndef.class.getName();
|
||||||
|
//
|
||||||
|
// for (String tech : techList)
|
||||||
|
// {
|
||||||
|
// if (searchedTech.equals(tech))
|
||||||
|
// {
|
||||||
|
// new NdefReaderTask().execute(tag);
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// // No NFC NDEF intent
|
||||||
|
// Miscellaneous.logEvent("w", "NFC", context.getResources().getString(R.string.nfcNoNdefIntentBut) + " " + action + ".", 5);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("NewApi")
|
||||||
|
public static class NdefReaderTask extends AsyncTask<Tag, Void, String>
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
protected String doInBackground(Tag... params)
|
||||||
|
{
|
||||||
|
Tag tag = params[0];
|
||||||
|
|
||||||
|
Ndef ndef = Ndef.get(tag);
|
||||||
|
if (ndef == null)
|
||||||
|
{
|
||||||
|
// NDEF is not supported by this Tag.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
NdefMessage ndefMessage = ndef.getCachedNdefMessage();
|
||||||
|
NdefRecord[] records = ndefMessage.getRecords();
|
||||||
|
for (NdefRecord ndefRecord : records)
|
||||||
|
{
|
||||||
|
if (ndefRecord.getTnf() == NdefRecord.TNF_WELL_KNOWN && Arrays.equals(ndefRecord.getType(), NdefRecord.RTD_TEXT))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return readText(ndefRecord);
|
||||||
|
}
|
||||||
|
catch (UnsupportedEncodingException e)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "NFC", Miscellaneous.getAnyContext().getString(R.string.nfcUnsupportedEncoding) + " " + Log.getStackTraceString(e), 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// return readTag(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(String result)
|
||||||
|
{
|
||||||
|
if (result != null && result.length() > 0)
|
||||||
|
{
|
||||||
|
// Text of tag is now stored in variable "result"
|
||||||
|
lastReadLabel = result;
|
||||||
|
Miscellaneous.logEvent("i", "NFC", Miscellaneous.getAnyContext().getResources().getString(R.string.nfcTagFoundWithText) + " " + result, 3);
|
||||||
|
Toast.makeText(Miscellaneous.getAnyContext(), Miscellaneous.getAnyContext().getResources().getString(R.string.nfcTagFoundWithText) + " " + result, Toast.LENGTH_LONG).show();
|
||||||
|
|
||||||
|
AutomationService asInstance = AutomationService.getInstance();
|
||||||
|
if(asInstance == null)
|
||||||
|
{
|
||||||
|
Context context = Miscellaneous.getAnyContext();
|
||||||
|
if(context != null)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("w", "NFC", context.getResources().getString(R.string.serviceNotRunning) + " " + context.getResources().getString(R.string.cantRunRule), 4);
|
||||||
|
Toast.makeText(context, context.getResources().getString(R.string.serviceNotRunning) + " " + context.getResources().getString(R.string.cantRunRule), Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ArrayList<Rule> allRulesWithNfcTags = Rule.findRuleCandidatesByNfc();
|
||||||
|
for(int i=0; i<allRulesWithNfcTags.size(); i++)
|
||||||
|
{
|
||||||
|
if(allRulesWithNfcTags.get(i).applies(asInstance))
|
||||||
|
allRulesWithNfcTags.get(i).activate(asInstance, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class NdefWriterTask extends AsyncTask<Object, Void, Boolean>
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
protected Boolean doInBackground(Object... params)
|
||||||
|
{
|
||||||
|
String textToWrite = (String)params[0];
|
||||||
|
Tag tagToWrite = (Tag)params[1];
|
||||||
|
return writeTag(textToWrite, tagToWrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Override
|
||||||
|
// protected void onPostExecute(Boolean result)
|
||||||
|
// {
|
||||||
|
// return result;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String readTag(Tag tag)
|
||||||
|
{
|
||||||
|
// if(tag == null)
|
||||||
|
// {
|
||||||
|
// Toast.makeText(Miscellaneous.getAnyContext(), Miscellaneous.getAnyContext().getResources().getString(R.string.nfcNoTag), Toast.LENGTH_LONG).show();
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
|
||||||
|
Ndef ndef = Ndef.get(tag);
|
||||||
|
if (ndef == null)
|
||||||
|
{
|
||||||
|
// NDEF is not supported by this Tag.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
NdefMessage ndefMessage = ndef.getCachedNdefMessage();
|
||||||
|
|
||||||
|
NdefRecord[] records = ndefMessage.getRecords();
|
||||||
|
for (NdefRecord ndefRecord : records)
|
||||||
|
{
|
||||||
|
if (ndefRecord.getTnf() == NdefRecord.TNF_WELL_KNOWN && Arrays.equals(ndefRecord.getType(), NdefRecord.RTD_TEXT))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return readText(ndefRecord);
|
||||||
|
}
|
||||||
|
catch (UnsupportedEncodingException e)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("w", "NFC", "Unsupported Encoding: " + Log.getStackTraceString(e), 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String readText(NdefRecord record) throws UnsupportedEncodingException
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* See NFC forum specification for "Text Record Type Definition" at 3.2.1
|
||||||
|
*
|
||||||
|
* http://www.nfc-forum.org/specs/
|
||||||
|
*
|
||||||
|
* bit_7 defines encoding
|
||||||
|
* bit_6 reserved for future use, must be 0
|
||||||
|
* bit_5..0 length of IANA language code
|
||||||
|
*/
|
||||||
|
|
||||||
|
byte[] payload = record.getPayload();
|
||||||
|
|
||||||
|
// Get the Text Encoding
|
||||||
|
String textEncoding = ((payload[0] & 128) == 0) ? "UTF-8" : "UTF-16";
|
||||||
|
|
||||||
|
// Get the Language Code
|
||||||
|
int languageCodeLength = payload[0] & 0063;
|
||||||
|
|
||||||
|
// String languageCode = new String(payload, 1, languageCodeLength, "US-ASCII");
|
||||||
|
// e.g. "en"
|
||||||
|
|
||||||
|
// Get the Text
|
||||||
|
return new String(payload, languageCodeLength + 1, payload.length - languageCodeLength - 1, textEncoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean writeTag(String textToWrite, Tag tag)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "NFC", "Attempting to write tag...", 2);
|
||||||
|
|
||||||
|
String packageName = Miscellaneous.getAnyContext().getPackageName();
|
||||||
|
NdefRecord appRecord = NdefRecord.createApplicationRecord(packageName);
|
||||||
|
// Record with actual data we care about
|
||||||
|
byte[] textBytes = textToWrite.getBytes();
|
||||||
|
byte[] textPayload = new byte[textBytes.length + 3];
|
||||||
|
textPayload[0] = 0x02; // 0x02 = UTF8
|
||||||
|
textPayload[1] = 'e'; // Language = en
|
||||||
|
textPayload[2] = 'n';
|
||||||
|
System.arraycopy(textBytes, 0, textPayload, 3, textBytes.length);
|
||||||
|
NdefRecord textRecord = new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], textPayload);
|
||||||
|
|
||||||
|
// Complete NDEF message with both records
|
||||||
|
NdefMessage completeMessageToWrite = new NdefMessage(new NdefRecord[] {textRecord, appRecord});
|
||||||
|
|
||||||
|
int size = completeMessageToWrite.toByteArray().length;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Ndef ndef = Ndef.get(tag);
|
||||||
|
if (ndef != null)
|
||||||
|
{
|
||||||
|
ndef.connect();
|
||||||
|
if (ndef.isWritable() && ndef.getMaxSize() > size)
|
||||||
|
{
|
||||||
|
ndef.writeNdefMessage(completeMessageToWrite);
|
||||||
|
Miscellaneous.logEvent("i", "NFC", "Done writing tag.", 2);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NdefFormatable format = NdefFormatable.get(tag);
|
||||||
|
if (format != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
format.connect();
|
||||||
|
format.format(completeMessageToWrite);
|
||||||
|
Miscellaneous.logEvent("i", "NFC", "Done writing tag.", 2);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch(IOException e)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "NFC", "Error writing tag: " + Log.getStackTraceString(e), 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "NFC", "Error writing tag: " + Log.getStackTraceString(e), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean checkNfcRequirements(Context context, boolean showErrorMessage)
|
||||||
|
{
|
||||||
|
if(!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC))
|
||||||
|
{
|
||||||
|
if(showErrorMessage)
|
||||||
|
Toast.makeText(context, context.getResources().getString(R.string.deviceDoesNotHaveNfc), Toast.LENGTH_LONG).show();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if(Build.VERSION.SDK_INT <= 10)
|
||||||
|
{
|
||||||
|
// NFC not supported until after Gingerbread.
|
||||||
|
if(showErrorMessage)
|
||||||
|
Toast.makeText(context, context.getResources().getString(R.string.nfcNotSupportedInThisAndroidVersionYet), Toast.LENGTH_LONG).show();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,215 @@
|
|||||||
|
package com.jens.automation2.receivers;
|
||||||
|
|
||||||
|
import android.media.MediaRecorder;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Message;
|
||||||
|
|
||||||
|
import com.jens.automation2.ActivityPermissions;
|
||||||
|
import com.jens.automation2.AutomationService;
|
||||||
|
import com.jens.automation2.Miscellaneous;
|
||||||
|
import com.jens.automation2.Rule;
|
||||||
|
import com.jens.automation2.Settings;
|
||||||
|
import com.jens.automation2.Trigger.Trigger_Enum;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class NoiseListener implements AutomationListenerInterface
|
||||||
|
{
|
||||||
|
private static AutomationService automationService;
|
||||||
|
private static boolean isMeasuringActive = false;
|
||||||
|
private static boolean isTimerActive = false;
|
||||||
|
private static long noiseLevelDb;
|
||||||
|
private static Handler workHandler = new Handler()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message msg)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "Noise level", "Message received stating measurement is complete.", 5);
|
||||||
|
// This will take care of results delivered by the actual measuring instance
|
||||||
|
noiseLevelDb = msg.getData().getLong("noiseLevelDb");
|
||||||
|
|
||||||
|
// execute matching rules containing noise
|
||||||
|
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByNoiseLevel();
|
||||||
|
for(Rule oneRule : ruleCandidates)
|
||||||
|
{
|
||||||
|
if(oneRule.applies(automationService))
|
||||||
|
oneRule.activate(automationService, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
private static NoiseListenerMeasuring listener;
|
||||||
|
|
||||||
|
private static boolean stopRequested = false;
|
||||||
|
private static Handler schedulingHandler = new Handler()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message msg)
|
||||||
|
{
|
||||||
|
if(msg.arg1 == 1)
|
||||||
|
{
|
||||||
|
if(!stopRequested)
|
||||||
|
{
|
||||||
|
if(listener == null)
|
||||||
|
listener = new NoiseListenerMeasuring();
|
||||||
|
listener.doMeasuring();
|
||||||
|
Miscellaneous.logEvent("i", "Noise level", "Rearming noise level message.", 5);
|
||||||
|
Message message = new Message();
|
||||||
|
message.arg1 = 1;
|
||||||
|
schedulingHandler.sendMessageDelayed(message, Settings.timeBetweenNoiseLevelMeasurements * 1000);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Miscellaneous.logEvent("i", "Noise level", "Not rearming noise level message, stop requested.", 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
private static class NoiseListenerMeasuring
|
||||||
|
{
|
||||||
|
Thread measuringThread;
|
||||||
|
|
||||||
|
public void doMeasuring()
|
||||||
|
{
|
||||||
|
measuringThread = new Thread()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
if(!isMeasuringActive)
|
||||||
|
{
|
||||||
|
isMeasuringActive = true;
|
||||||
|
|
||||||
|
Miscellaneous.logEvent("i", "Noise level", "Periodic noise level measurement started.", 5);
|
||||||
|
|
||||||
|
// Start recording but don't store data
|
||||||
|
MediaRecorder mediaRecorder = new MediaRecorder();
|
||||||
|
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
|
||||||
|
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
|
||||||
|
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
|
||||||
|
mediaRecorder.setOutputFile("/dev/null");
|
||||||
|
// Date myDate = new Date();
|
||||||
|
// mediaRecorder.setOutputFile("/sdcard/temp/" + String.valueOf(myDate.getTime()) + ".3gpp");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
mediaRecorder.prepare();
|
||||||
|
mediaRecorder.getMaxAmplitude();
|
||||||
|
mediaRecorder.start();
|
||||||
|
mediaRecorder.getMaxAmplitude();
|
||||||
|
|
||||||
|
long noiseLevel;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
sleep(Settings.lengthOfNoiseLevelMeasurements * 1000);
|
||||||
|
// Obtain maximum amplitude since last call of getMaxAmplitude()
|
||||||
|
noiseLevel = mediaRecorder.getMaxAmplitude();
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
noiseLevel = -1;
|
||||||
|
Miscellaneous.logEvent("e", "Noise level", "Error getting sound level: " + e.getMessage(), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
double db = 20 * Math.log(noiseLevel / Settings.referenceValueForNoiseLevelMeasurements);
|
||||||
|
noiseLevelDb = Math.round(db);
|
||||||
|
|
||||||
|
Message answer = new Message();
|
||||||
|
Bundle answerBundle = new Bundle();
|
||||||
|
answerBundle.putLong("noiseLevelDb", noiseLevelDb);
|
||||||
|
answer.setData(answerBundle);
|
||||||
|
workHandler.sendMessage(answer);
|
||||||
|
|
||||||
|
Miscellaneous.logEvent("i", "Noise level", "Measured noise level: " + String.valueOf(noiseLevel) + " / converted to db: " + String.valueOf(db), 3);
|
||||||
|
|
||||||
|
// Don't forget to release
|
||||||
|
mediaRecorder.reset();
|
||||||
|
mediaRecorder.release();
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{}
|
||||||
|
|
||||||
|
isMeasuringActive = false;
|
||||||
|
|
||||||
|
Miscellaneous.logEvent("i", "Noise level", "Periodic noise level measurement stopped.", 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
measuringThread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void interrupt()
|
||||||
|
{
|
||||||
|
measuringThread.interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void startNoiseListener(AutomationService newAutomationService)
|
||||||
|
{
|
||||||
|
automationService = newAutomationService;
|
||||||
|
|
||||||
|
if(!isTimerActive)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "Noise level", "Starting periodic noise level measurement engine.", 2);
|
||||||
|
isTimerActive = true;
|
||||||
|
|
||||||
|
Message message = new Message();
|
||||||
|
message.arg1 = 1;
|
||||||
|
schedulingHandler.sendMessageDelayed(message, Settings.timeBetweenNoiseLevelMeasurements * 1000);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Miscellaneous.logEvent("i", "Noise level", "Periodic noise level measurement is already running. Won't start it again.", 2);
|
||||||
|
}
|
||||||
|
public static void stopNoiseListener()
|
||||||
|
{
|
||||||
|
if(isTimerActive)
|
||||||
|
{
|
||||||
|
stopRequested = true;
|
||||||
|
Miscellaneous.logEvent("i", "Noise level", "Stopping periodic noise level measurement engine.", 2);
|
||||||
|
|
||||||
|
if(schedulingHandler.hasMessages(1))
|
||||||
|
schedulingHandler.removeMessages(1);
|
||||||
|
|
||||||
|
if(listener != null)
|
||||||
|
listener.interrupt();
|
||||||
|
|
||||||
|
isTimerActive = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Miscellaneous.logEvent("i", "Noise level", "Periodic noise level measurement is not active. Can't stop it.", 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long getNoiseLevelDb()
|
||||||
|
{
|
||||||
|
return noiseLevelDb;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startListener(AutomationService automationService)
|
||||||
|
{
|
||||||
|
NoiseListener.startNoiseListener(automationService);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void stopListener(AutomationService automationService)
|
||||||
|
{
|
||||||
|
NoiseListener.stopNoiseListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean haveAllPermission()
|
||||||
|
{
|
||||||
|
return ActivityPermissions.havePermission("android.permission.RECORD_AUDIO", Miscellaneous.getAnyContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isListenerRunning()
|
||||||
|
{
|
||||||
|
return NoiseListener.isMeasuringActive | NoiseListener.isTimerActive;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public Trigger_Enum[] getMonitoredTrigger()
|
||||||
|
{
|
||||||
|
return new Trigger_Enum[] { Trigger_Enum.noiseLevel };
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
package com.jens.automation2.receivers;
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
|
||||||
|
import com.jens.automation2.AutomationService;
|
||||||
|
import com.jens.automation2.Miscellaneous;
|
||||||
|
import com.jens.automation2.R;
|
||||||
|
import com.jens.automation2.Settings;
|
||||||
|
|
||||||
|
public class PackageReplacedReceiver extends BroadcastReceiver
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent)
|
||||||
|
{
|
||||||
|
// Toast.makeText(context, "package replaced", Toast.LENGTH_LONG).show();
|
||||||
|
// int intentUid = intent.getExtras().getInt("android.intent.extra.UID"); // userid of the application that has just been updated
|
||||||
|
// int myUid = android.os.Process.myUid(); // userid of this application
|
||||||
|
//
|
||||||
|
// boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
|
||||||
|
|
||||||
|
// if(intentUid == myUid)
|
||||||
|
// {
|
||||||
|
Settings.readFromPersistentStorage(context);
|
||||||
|
|
||||||
|
Miscellaneous.logEvent("i", context.getResources().getString(R.string.applicationHasBeenUpdated), context.getResources().getString(R.string.applicationHasBeenUpdated), 2);
|
||||||
|
if(hasServiceBeenRunning() && Settings.startServiceAfterAppUpdate)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "Service", context.getResources().getString(R.string.logStartingServiceAfterAppUpdate), 1);
|
||||||
|
AutomationService.startAutomationService(context, true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "Service", context.getResources().getString(R.string.logNotStartingServiceAfterAppUpdate), 2);
|
||||||
|
}
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// Miscellaneous.logEvent("i", "Service", "Some other app has been updated.", 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean hasServiceBeenRunning()
|
||||||
|
{
|
||||||
|
return Settings.hasServiceBeenRunning;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setHasServiceBeenRunning(boolean state, Context context)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "State", "Writing stateFile to " + String.valueOf(state), 4);
|
||||||
|
Settings.readFromPersistentStorage(context);
|
||||||
|
// Settings.initializeSettings(context, false);
|
||||||
|
Settings.hasServiceBeenRunning = state;
|
||||||
|
Settings.writeSettings(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,331 @@
|
|||||||
|
package com.jens.automation2.receivers;
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
import android.telephony.PhoneStateListener;
|
||||||
|
import android.telephony.TelephonyManager;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.jens.automation2.ActivityPermissions;
|
||||||
|
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.Trigger_Enum;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class PhoneStatusListener implements AutomationListenerInterface
|
||||||
|
{
|
||||||
|
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 boolean incomingCallsReceiverActive = false;
|
||||||
|
protected static boolean outgoingCallsReceiverActive = false;
|
||||||
|
|
||||||
|
protected static IntentFilter outgoingCallsIntentFilter;
|
||||||
|
protected static IncomingCallsReceiver incomingCallsReceiverInstance;
|
||||||
|
protected static BroadcastReceiver outgoingCallsReceiverInstance;
|
||||||
|
|
||||||
|
|
||||||
|
public static boolean isIncomingCallsReceiverActive()
|
||||||
|
{
|
||||||
|
return incomingCallsReceiverActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isOutgoingCallsReceiverActive()
|
||||||
|
{
|
||||||
|
return outgoingCallsReceiverActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static boolean receivedInitialIncomingSignal = false;
|
||||||
|
|
||||||
|
public static int getLastPhoneDirection()
|
||||||
|
{
|
||||||
|
return lastPhoneDirection;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static void setLastPhoneNumber(String lastPhoneNumber)
|
||||||
|
{
|
||||||
|
PhoneStatusListener.lastPhoneNumber = lastPhoneNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getLastPhoneNumber()
|
||||||
|
{
|
||||||
|
return lastPhoneNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class IncomingCallsReceiver extends PhoneStateListener
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onCallStateChanged(int state, String incomingNumber)
|
||||||
|
{
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static void startPhoneStatusListener(AutomationService automationService)
|
||||||
|
{
|
||||||
|
if(outgoingCallsIntentFilter == null)
|
||||||
|
{
|
||||||
|
outgoingCallsIntentFilter = new IntentFilter();
|
||||||
|
outgoingCallsIntentFilter.addAction(Intent.ACTION_NEW_OUTGOING_CALL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(incomingCallsReceiverInstance == null)
|
||||||
|
incomingCallsReceiverInstance = new IncomingCallsReceiver();
|
||||||
|
|
||||||
|
if(outgoingCallsReceiverInstance == null)
|
||||||
|
outgoingCallsReceiverInstance = new OutgoingCallsReceiver();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(!incomingCallsReceiverActive)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "PhoneStatusListener", "Starting PhoneStatusListener->incomingCallsReceiver", 4);
|
||||||
|
TelephonyManager tm = (TelephonyManager)automationService.getSystemService(Context.TELEPHONY_SERVICE);
|
||||||
|
tm.listen(incomingCallsReceiverInstance, PhoneStateListener.LISTEN_CALL_STATE);
|
||||||
|
incomingCallsReceiverActive = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!outgoingCallsReceiverActive)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "PhoneStatusListener", "Starting PhoneStatusListener->outgoingCallsReceiver", 4);
|
||||||
|
automationService.registerReceiver(outgoingCallsReceiverInstance, outgoingCallsIntentFilter);
|
||||||
|
outgoingCallsReceiverActive = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "PhoneStatusListener", "Error starting PhoneStatusListener: " + Log.getStackTraceString(ex), 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void stopPhoneStatusListener(AutomationService automationService)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(incomingCallsReceiverActive)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "PhoneStatusListener", "Stopping phoneStatusListener", 4);
|
||||||
|
TelephonyManager tm = (TelephonyManager)automationService.getSystemService(Context.TELEPHONY_SERVICE);
|
||||||
|
tm.listen(incomingCallsReceiverInstance, PhoneStateListener.LISTEN_NONE);
|
||||||
|
incomingCallsReceiverActive = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(outgoingCallsReceiverActive)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "PhoneStatusListener", "Stopping phoneStatusListener", 4);
|
||||||
|
automationService.unregisterReceiver(outgoingCallsReceiverInstance);
|
||||||
|
outgoingCallsReceiverActive = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "PhoneStatusListener", "Error stopping phoneStatusListener: " + Log.getStackTraceString(ex), 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startListener(AutomationService automationService)
|
||||||
|
{
|
||||||
|
PhoneStatusListener.startPhoneStatusListener(automationService);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stopListener(AutomationService automationService)
|
||||||
|
{
|
||||||
|
PhoneStatusListener.stopPhoneStatusListener(automationService);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean haveAllPermission()
|
||||||
|
{
|
||||||
|
return
|
||||||
|
ActivityPermissions.havePermission("android.permission.READ_PHONE_STATE", Miscellaneous.getAnyContext())
|
||||||
|
&&
|
||||||
|
ActivityPermissions.havePermission(ActivityPermissions.permissionNameCall, Miscellaneous.getAnyContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isListenerRunning()
|
||||||
|
{
|
||||||
|
return PhoneStatusListener.incomingCallsReceiverActive | PhoneStatusListener.isOutgoingCallsReceiverActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Trigger_Enum[] getMonitoredTrigger()
|
||||||
|
{
|
||||||
|
return new Trigger_Enum[] { Trigger_Enum.phoneCall };
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,470 @@
|
|||||||
|
package com.jens.automation2.receivers;
|
||||||
|
|
||||||
|
import android.app.ActivityManager;
|
||||||
|
import android.app.ActivityManager.RunningAppProcessInfo;
|
||||||
|
import android.app.ActivityManager.RunningServiceInfo;
|
||||||
|
import android.app.ActivityManager.RunningTaskInfo;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Message;
|
||||||
|
|
||||||
|
import com.jens.automation2.ActivityPermissions;
|
||||||
|
import com.jens.automation2.AutomationService;
|
||||||
|
import com.jens.automation2.Miscellaneous;
|
||||||
|
import com.jens.automation2.R;
|
||||||
|
import com.jens.automation2.Rule;
|
||||||
|
import com.jens.automation2.Settings;
|
||||||
|
import com.jens.automation2.Trigger.Trigger_Enum;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ProcessListener implements AutomationListenerInterface
|
||||||
|
{
|
||||||
|
private static ArrayList<String> runningAppsList1 = new ArrayList<String>();
|
||||||
|
private static ArrayList<String> runningAppsList2 = new ArrayList<String>();
|
||||||
|
private static int lastWritten = 2;
|
||||||
|
private static int runCounter = 0;
|
||||||
|
private static AutomationService automationService;
|
||||||
|
private static boolean isMonitoringActive = false;
|
||||||
|
private static boolean isTimerActive = false;
|
||||||
|
private static ArrayList<RunningAppProcessInfo> runningAppProcessInfoList;
|
||||||
|
private static ProcessListenerMonitoring listener = null;
|
||||||
|
|
||||||
|
public static boolean isProcessListenerActive()
|
||||||
|
{
|
||||||
|
return isMonitoringActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Handler workHandler = new Handler()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message msg)
|
||||||
|
{
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
Miscellaneous.logEvent("i", automationService.getResources().getString(R.string.processMonitoring), automationService.getResources().getString(R.string.messageReceivedStatingProcessMonitoringIsComplete), 5);
|
||||||
|
// This will take care of results delivered by the actual monitoring instance
|
||||||
|
|
||||||
|
for(String entry : getRunningApps())
|
||||||
|
Miscellaneous.logEvent("i", automationService.getResources().getString(R.string.runningApp), entry, 5);
|
||||||
|
|
||||||
|
// execute matching rules containing processes
|
||||||
|
if(getRecentlyStartedApps().size()>0 | getRecentlyStoppedApps().size()>0)
|
||||||
|
{
|
||||||
|
for(String entry : getRecentlyStartedApps())
|
||||||
|
Miscellaneous.logEvent("i", automationService.getResources().getString(R.string.appStarted), entry, 3);
|
||||||
|
for(String entry : getRecentlyStoppedApps())
|
||||||
|
Miscellaneous.logEvent("i", automationService.getResources().getString(R.string.appStopped), entry, 3);
|
||||||
|
|
||||||
|
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByProcess();
|
||||||
|
for(int i=0; i<ruleCandidates.size(); i++)
|
||||||
|
{
|
||||||
|
if(ruleCandidates.get(i).applies(automationService))
|
||||||
|
ruleCandidates.get(i).activate(automationService, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// }
|
||||||
|
// catch(Exception e)
|
||||||
|
// {
|
||||||
|
// Miscellaneous.logEvent("e", "Noise level", "Error in workHandler->handleMessage(): " + e.getMessage());
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static ArrayList<String> getRunningApps()
|
||||||
|
{
|
||||||
|
if(runningAppsList1.size() == 0 && runningAppsList2.size() == 0)
|
||||||
|
ProcessListenerMonitoring.refreshRunningAppsList();
|
||||||
|
|
||||||
|
ArrayList<String> runningAppsListReference;
|
||||||
|
|
||||||
|
if(lastWritten == 1)
|
||||||
|
{
|
||||||
|
runningAppsListReference = runningAppsList1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
runningAppsListReference = runningAppsList2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return runningAppsListReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ArrayList<String> getRecentlyStartedApps()
|
||||||
|
{
|
||||||
|
ArrayList<String> returnList = new ArrayList<String>();
|
||||||
|
|
||||||
|
if(runCounter == 0) // Nothing ever happened.
|
||||||
|
return returnList;
|
||||||
|
|
||||||
|
if(runCounter == 1)
|
||||||
|
// Only one run so far, all running apps are considered to have just started.
|
||||||
|
return runningAppsList1;
|
||||||
|
|
||||||
|
ArrayList<String> oldOne = null, newOne = null;
|
||||||
|
if(lastWritten == 1)
|
||||||
|
{
|
||||||
|
oldOne = runningAppsList2;
|
||||||
|
newOne = runningAppsList1;
|
||||||
|
}
|
||||||
|
else if(lastWritten == 2)
|
||||||
|
{
|
||||||
|
oldOne = runningAppsList1;
|
||||||
|
newOne = runningAppsList2;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(String runningApp : newOne)
|
||||||
|
{
|
||||||
|
if(!oldOne.contains(runningApp))
|
||||||
|
//Started
|
||||||
|
returnList.add(runningApp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ArrayList<String> getRecentlyStoppedApps()
|
||||||
|
{
|
||||||
|
ArrayList<String> returnList = new ArrayList<String>();
|
||||||
|
|
||||||
|
if(runCounter == 1) // Nothing ever happened.
|
||||||
|
return returnList;
|
||||||
|
|
||||||
|
if(runCounter == 1)
|
||||||
|
// Only one run so far, all running apps are considered to have just started, so return empty list.
|
||||||
|
return returnList;
|
||||||
|
|
||||||
|
ArrayList<String> oldOne = null, newOne = null;
|
||||||
|
if(lastWritten == 1)
|
||||||
|
{
|
||||||
|
oldOne = runningAppsList2;
|
||||||
|
newOne = runningAppsList1;
|
||||||
|
}
|
||||||
|
else if(lastWritten == 2)
|
||||||
|
{
|
||||||
|
oldOne = runningAppsList1;
|
||||||
|
newOne = runningAppsList2;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(String runningApp : oldOne)
|
||||||
|
{
|
||||||
|
if(!newOne.contains(runningApp))
|
||||||
|
//Stopped
|
||||||
|
returnList.add(runningApp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean stopRequested = false;
|
||||||
|
private static Handler schedulingHandler = new Handler()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message msg)
|
||||||
|
{
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
if(msg.arg1 == 1)
|
||||||
|
{
|
||||||
|
if(!stopRequested)
|
||||||
|
{
|
||||||
|
listener = new ProcessListenerMonitoring();
|
||||||
|
listener.doMonitoring();
|
||||||
|
Miscellaneous.logEvent("i", automationService.getResources().getString(R.string.processMonitoring), automationService.getResources().getString(R.string.rearmingProcessMonitoringMessage), 5);
|
||||||
|
Message message = new Message();
|
||||||
|
message.arg1 = 1;
|
||||||
|
schedulingHandler.sendMessageDelayed(message, Settings.timeBetweenProcessMonitorings * 1000);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Miscellaneous.logEvent("i", automationService.getResources().getString(R.string.processMonitoring), automationService.getResources().getString(R.string.notRearmingProcessMonitoringMessageStopRequested), 5);
|
||||||
|
}
|
||||||
|
// }
|
||||||
|
// catch(Exception e)
|
||||||
|
// {
|
||||||
|
// Miscellaneous.logEvent("e", "Noise level", "Error in schedulingHandler->handleMessage(): " + e.getMessage());
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
private static class ProcessListenerMonitoring
|
||||||
|
{
|
||||||
|
Thread monitoringThread;
|
||||||
|
|
||||||
|
public void doMonitoring()
|
||||||
|
{
|
||||||
|
monitoringThread = new Thread()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
if(!isMonitoringActive)
|
||||||
|
{
|
||||||
|
isMonitoringActive = true;
|
||||||
|
|
||||||
|
Miscellaneous.logEvent("i", automationService.getResources().getString(R.string.processMonitoring), automationService.getResources().getString(R.string.periodicProcessMonitoringStarted), 5);
|
||||||
|
|
||||||
|
refreshRunningAppsList();
|
||||||
|
|
||||||
|
Message answer = new Message();
|
||||||
|
// Bundle answerBundle = new Bundle();
|
||||||
|
// answer.setData(answerBundle);
|
||||||
|
workHandler.sendMessage(answer);
|
||||||
|
|
||||||
|
//activate rule(s)
|
||||||
|
/*ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByProcess();
|
||||||
|
for(int i=0; i<ruleCandidates.size(); i++)
|
||||||
|
{
|
||||||
|
if(ruleCandidates.get(i).applies(automationService))
|
||||||
|
ruleCandidates.get(i).activate(automationService);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
isMonitoringActive = false;
|
||||||
|
|
||||||
|
Miscellaneous.logEvent("i", automationService.getResources().getString(R.string.processMonitoring), automationService.getResources().getString(R.string.periodicProcessMonitoringStopped), 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
monitoringThread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void refreshRunningAppsList()
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", automationService.getResources().getString(R.string.processes), automationService.getResources().getString(R.string.refreshingProcessList), 5);
|
||||||
|
|
||||||
|
final ActivityManager activityManager = (ActivityManager)automationService.getSystemService(Context.ACTIVITY_SERVICE);
|
||||||
|
final List<RunningTaskInfo> services = activityManager.getRunningTasks(Integer.MAX_VALUE);
|
||||||
|
|
||||||
|
ArrayList<String> runningAppsListReference;
|
||||||
|
if(lastWritten == 1)
|
||||||
|
{
|
||||||
|
// Log.i("Processes", "Writing var 2");
|
||||||
|
runningAppsListReference = runningAppsList2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Log.i("Processes", "Writing var 1");
|
||||||
|
runningAppsListReference = runningAppsList1;
|
||||||
|
}
|
||||||
|
|
||||||
|
runningAppsListReference.clear();
|
||||||
|
|
||||||
|
for (int i = 0; i < services.size(); i++)
|
||||||
|
{
|
||||||
|
if(!runningAppsListReference.contains(services.get(i).baseActivity.getClassName()))
|
||||||
|
{
|
||||||
|
// you may broadcast a new application launch here.
|
||||||
|
runningAppsListReference.add(services.get(i).baseActivity.getClassName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// for(String runningApp : runningAppsListReference)
|
||||||
|
// {
|
||||||
|
// Miscellaneous.logEvent("i", "Running app", runningApp, 5);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// List<RunningAppProcessInfo> procInfos = activityManager.getRunningAppProcesses();
|
||||||
|
// for(int i = 0; i < procInfos.size(); i++)
|
||||||
|
// {
|
||||||
|
// ArrayList<String> runningPkgs = new ArrayList<String>(Arrays.asList(procInfos.get(i).pkgList));
|
||||||
|
//
|
||||||
|
// Collection diff = subtractSets(runningPkgs, stalkList);
|
||||||
|
//
|
||||||
|
// if(diff != null)
|
||||||
|
// {
|
||||||
|
// stalkList.removeAll(diff);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Set marker to the one to be written next.
|
||||||
|
if(lastWritten == 1)
|
||||||
|
lastWritten = 2;
|
||||||
|
else if(lastWritten == 2)
|
||||||
|
lastWritten = 1;
|
||||||
|
else
|
||||||
|
lastWritten = -1;
|
||||||
|
|
||||||
|
if(runCounter == 0 | runCounter == 1)
|
||||||
|
runCounter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void interrupt()
|
||||||
|
{
|
||||||
|
monitoringThread.interrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
private RunningAppProcessInfo getForegroundApp()
|
||||||
|
{
|
||||||
|
RunningAppProcessInfo result = null, info = null;
|
||||||
|
|
||||||
|
final ActivityManager activityManager = (ActivityManager)automationService.getSystemService(Context.ACTIVITY_SERVICE);
|
||||||
|
|
||||||
|
List <RunningAppProcessInfo> l = activityManager.getRunningAppProcesses();
|
||||||
|
Iterator <RunningAppProcessInfo> i = l.iterator();
|
||||||
|
while(i.hasNext())
|
||||||
|
{
|
||||||
|
info = i.next();
|
||||||
|
if(info.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND
|
||||||
|
&& !isRunningService(info.processName))
|
||||||
|
{
|
||||||
|
result = info;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isRunningService(String processName)
|
||||||
|
{
|
||||||
|
if(processName == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
RunningServiceInfo service;
|
||||||
|
|
||||||
|
final ActivityManager activityManager = (ActivityManager)automationService.getSystemService(Context.ACTIVITY_SERVICE);
|
||||||
|
|
||||||
|
List <RunningServiceInfo> l = activityManager.getRunningServices(9999);
|
||||||
|
Iterator <RunningServiceInfo> i = l.iterator();
|
||||||
|
while(i.hasNext())
|
||||||
|
{
|
||||||
|
service = i.next();
|
||||||
|
if(service.process.equals(processName))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isRunningApp(String processName)
|
||||||
|
{
|
||||||
|
if(processName == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
RunningAppProcessInfo app;
|
||||||
|
|
||||||
|
final ActivityManager activityManager = (ActivityManager)automationService.getSystemService(Context.ACTIVITY_SERVICE);
|
||||||
|
|
||||||
|
List <RunningAppProcessInfo> l = activityManager.getRunningAppProcesses();
|
||||||
|
Iterator <RunningAppProcessInfo> i = l.iterator();
|
||||||
|
while(i.hasNext())
|
||||||
|
{
|
||||||
|
app = i.next();
|
||||||
|
if(app.processName.equals(processName) && app.importance != RunningAppProcessInfo.IMPORTANCE_SERVICE)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkifThisIsActive(RunningAppProcessInfo target)
|
||||||
|
{
|
||||||
|
boolean result = false;
|
||||||
|
RunningTaskInfo info;
|
||||||
|
|
||||||
|
if(target == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
final ActivityManager activityManager = (ActivityManager)automationService.getSystemService(Context.ACTIVITY_SERVICE);
|
||||||
|
|
||||||
|
List <RunningTaskInfo> l = activityManager.getRunningTasks(9999);
|
||||||
|
Iterator <RunningTaskInfo> i = l.iterator();
|
||||||
|
|
||||||
|
while(i.hasNext())
|
||||||
|
{
|
||||||
|
info=i.next();
|
||||||
|
if(info.baseActivity.getPackageName().equals(target.processName))
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// what is in b that is not in a ?
|
||||||
|
public static Collection subtractSets(Collection a, Collection b)
|
||||||
|
{
|
||||||
|
Collection result = new ArrayList(b);
|
||||||
|
result.removeAll(a);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void startProcessListener(AutomationService newAutomationService)
|
||||||
|
{
|
||||||
|
automationService = newAutomationService;
|
||||||
|
|
||||||
|
if(!isTimerActive)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", automationService.getResources().getString(R.string.processMonitoring), automationService.getResources().getString(R.string.startingPeriodicProcessMonitoringEngine), 2);
|
||||||
|
isTimerActive = true;
|
||||||
|
|
||||||
|
Message message = new Message();
|
||||||
|
message.arg1 = 1;
|
||||||
|
// schedulingHandler.sendMessageDelayed(message, Settings.timeBetweenNoiseLevelMeasurements * 1000);
|
||||||
|
schedulingHandler.sendMessageDelayed(message, 10000);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Miscellaneous.logEvent("i", automationService.getResources().getString(R.string.processMonitoring), automationService.getResources().getString(R.string.periodicProcessMonitoringIsAlreadyRunning), 2);
|
||||||
|
}
|
||||||
|
public static void stopProcessListener(AutomationService newAutomationService)
|
||||||
|
{
|
||||||
|
if(isTimerActive)
|
||||||
|
{
|
||||||
|
stopRequested = true;
|
||||||
|
Miscellaneous.logEvent("i", automationService.getResources().getString(R.string.processMonitoring), automationService.getResources().getString(R.string.stoppingPeriodicProcessMonitoringEngine), 2);
|
||||||
|
|
||||||
|
if(schedulingHandler.hasMessages(1))
|
||||||
|
schedulingHandler.removeMessages(1);
|
||||||
|
|
||||||
|
if(listener != null)
|
||||||
|
listener.interrupt();
|
||||||
|
|
||||||
|
isTimerActive = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
automationService = newAutomationService;
|
||||||
|
Miscellaneous.logEvent("i", automationService.getResources().getString(R.string.processMonitoring), automationService.getResources().getString(R.string.periodicProcessMonitoringIsNotActive), 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ArrayList<RunningAppProcessInfo> getRunningAppProcessInfo()
|
||||||
|
{
|
||||||
|
return runningAppProcessInfoList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startListener(AutomationService automationService)
|
||||||
|
{
|
||||||
|
ProcessListener.startProcessListener(automationService);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stopListener(AutomationService automationService)
|
||||||
|
{
|
||||||
|
ProcessListener.stopProcessListener(automationService);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean haveAllPermission()
|
||||||
|
{
|
||||||
|
return ActivityPermissions.havePermission("android.permission.GET_TASKS", Miscellaneous.getAnyContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isListenerRunning()
|
||||||
|
{
|
||||||
|
return ProcessListener.isProcessListenerActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Trigger_Enum[] getMonitoredTrigger()
|
||||||
|
{
|
||||||
|
return new Trigger_Enum[] { Trigger_Enum.process_started_stopped };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package com.jens.automation2.receivers;
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
|
||||||
|
import com.jens.automation2.AutomationService;
|
||||||
|
import com.jens.automation2.Miscellaneous;
|
||||||
|
import com.jens.automation2.R;
|
||||||
|
import com.jens.automation2.Settings;
|
||||||
|
|
||||||
|
public class StartupIntentReceiver extends BroadcastReceiver
|
||||||
|
{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent)
|
||||||
|
{
|
||||||
|
Settings.readFromPersistentStorage(context);
|
||||||
|
|
||||||
|
Miscellaneous.logEvent("i", "Boot event", "Received event: " + intent.getAction(), 5);
|
||||||
|
|
||||||
|
if(Settings.startServiceAtSystemBoot)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "Service", context.getResources().getString(R.string.logStartingServiceAtPhoneBoot), 1);
|
||||||
|
// Settings.readFromPersistentStorage(context);
|
||||||
|
AutomationService.startAutomationService(context, true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "Service", context.getResources().getString(R.string.logNotStartingServiceAtPhoneBoot), 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,114 @@
|
|||||||
|
package com.jens.automation2.receivers;
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.jens.automation2.AutomationService;
|
||||||
|
import com.jens.automation2.Miscellaneous;
|
||||||
|
import com.jens.automation2.Rule;
|
||||||
|
import com.jens.automation2.Trigger.Trigger_Enum;
|
||||||
|
|
||||||
|
public class TimeZoneListener extends BroadcastReceiver implements AutomationListenerInterface
|
||||||
|
{
|
||||||
|
private static TimeZoneListener timeZoneListenerInstance = null;
|
||||||
|
protected static boolean timeZoneListenerActive = false;
|
||||||
|
protected static AutomationService automationServiceRef = null;
|
||||||
|
protected static IntentFilter timeZoneListenerIntentFilter = null;
|
||||||
|
|
||||||
|
|
||||||
|
public static boolean isTimeZoneListenerActive()
|
||||||
|
{
|
||||||
|
return timeZoneListenerActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void startTimeZoneListener(AutomationService automationService)
|
||||||
|
{
|
||||||
|
if(timeZoneListenerInstance == null)
|
||||||
|
timeZoneListenerInstance = new TimeZoneListener();
|
||||||
|
|
||||||
|
automationServiceRef = automationService;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(!timeZoneListenerActive && Rule.isAnyRuleUsing(Trigger_Enum.timeFrame))
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "TimeZoneListener", "Starting TimeZoneListener", 4);
|
||||||
|
timeZoneListenerActive = true;
|
||||||
|
|
||||||
|
if(timeZoneListenerIntentFilter == null)
|
||||||
|
{
|
||||||
|
timeZoneListenerIntentFilter = new IntentFilter();
|
||||||
|
timeZoneListenerIntentFilter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
|
||||||
|
timeZoneListenerIntentFilter.addAction(Intent.ACTION_TIME_CHANGED);
|
||||||
|
}
|
||||||
|
|
||||||
|
automationService.registerReceiver(timeZoneListenerInstance, timeZoneListenerIntentFilter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "TimeZoneListener", "Error starting TimeZoneListener: " + Log.getStackTraceString(ex), 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static void stopTimeZoneListener()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(timeZoneListenerActive)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "TimeZoneListener", "Stopping TimeZoneListener", 4);
|
||||||
|
automationServiceRef.unregisterReceiver(timeZoneListenerInstance);
|
||||||
|
timeZoneListenerActive = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "TimeZoneListener", "Error stopping TimeZoneListener: " + Log.getStackTraceString(ex), 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent)
|
||||||
|
{
|
||||||
|
String action = intent.getAction();
|
||||||
|
if(action.equals(Intent.ACTION_TIMEZONE_CHANGED))
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "TimeZoneListener", "Device timezone changed. Reloading alarms.", 3);
|
||||||
|
AlarmListener.reloadAlarms();
|
||||||
|
}
|
||||||
|
else if(action.equals(Intent.ACTION_TIME_CHANGED))
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("i", "TimeZoneListener", "Device time changed. Reloading alarms.", 4);
|
||||||
|
AlarmListener.reloadAlarms();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void startListener(AutomationService automationService)
|
||||||
|
{
|
||||||
|
TimeZoneListener.startTimeZoneListener(automationService);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void stopListener(AutomationService automationService)
|
||||||
|
{
|
||||||
|
TimeZoneListener.stopTimeZoneListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean haveAllPermission()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isListenerRunning()
|
||||||
|
{
|
||||||
|
return TimeZoneListener.isTimeZoneListenerActive();
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public Trigger_Enum[] getMonitoredTrigger()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
80
app/src/main/java/eu/chainfire/libsuperuser/Application.java
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2012-2014 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.content.Context;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base application class to extend from, solving some issues with
|
||||||
|
* toasts and AsyncTasks you are likely to run into
|
||||||
|
*/
|
||||||
|
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) {
|
||||||
|
// this is a static method so it is easier to call,
|
||||||
|
// as the context checking and casting is done for you
|
||||||
|
|
||||||
|
if (context == null) return;
|
||||||
|
|
||||||
|
if (!(context instanceof Application)) {
|
||||||
|
context = context.getApplicationContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context instanceof Application) {
|
||||||
|
final Context c = context;
|
||||||
|
final String m = message;
|
||||||
|
|
||||||
|
((Application)context).runInApplicationThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Toast.makeText(c, m, Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Handler mApplicationHandler = new Handler();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run a runnable in the main application thread
|
||||||
|
*
|
||||||
|
* @param r Runnable to run
|
||||||
|
*/
|
||||||
|
public void runInApplicationThread(Runnable r) {
|
||||||
|
mApplicationHandler.post(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate() {
|
||||||
|
super.onCreate();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// workaround bug in AsyncTask, can show up (for example) when you toast from a service
|
||||||
|
// this makes sure AsyncTask's internal handler is created from the right (main) thread
|
||||||
|
Class.forName("android.os.AsyncTask");
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
// will never happen
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
242
app/src/main/java/eu/chainfire/libsuperuser/Debug.java
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2012-2014 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.Looper;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.jens.automation2.BuildConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility class for logging and debug features that (by default) does nothing when not in debug mode
|
||||||
|
*/
|
||||||
|
public class Debug {
|
||||||
|
|
||||||
|
// ----- DEBUGGING -----
|
||||||
|
|
||||||
|
private static boolean debug = BuildConfig.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Is debug mode enabled ?</p>
|
||||||
|
*
|
||||||
|
* @return Debug mode enabled
|
||||||
|
*/
|
||||||
|
public static boolean getDebug() {
|
||||||
|
return debug;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- LOGGING -----
|
||||||
|
|
||||||
|
public interface OnLogListener {
|
||||||
|
void onLog(int type, String typeIndicator, String message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final String TAG = "libsuperuser";
|
||||||
|
|
||||||
|
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_NONE = 0x0000;
|
||||||
|
public static final int LOG_ALL = 0xFFFF;
|
||||||
|
|
||||||
|
private static int logTypes = LOG_ALL;
|
||||||
|
|
||||||
|
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
|
||||||
|
* @param typeIndicator String indicator for message type
|
||||||
|
* @param message The message to log
|
||||||
|
*/
|
||||||
|
private static void logCommon(int type, String typeIndicator, String message) {
|
||||||
|
if (debug && ((logTypes & type) == type)) {
|
||||||
|
if (logListener != null) {
|
||||||
|
logListener.onLog(type, typeIndicator, message);
|
||||||
|
} else {
|
||||||
|
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) {
|
||||||
|
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) {
|
||||||
|
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) {
|
||||||
|
logCommon(LOG_OUTPUT, "O", 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 enable Enable or disable
|
||||||
|
*/
|
||||||
|
public static void setLogTypeEnabled(int type, boolean enable) {
|
||||||
|
if (enable) {
|
||||||
|
logTypes |= type;
|
||||||
|
} else {
|
||||||
|
logTypes &= ~type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <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
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
public static boolean getLogTypeEnabledEffective(int type) {
|
||||||
|
return getDebug() && getLogTypeEnabled(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <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) {
|
||||||
|
logListener = onLogListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Get the currently registered custom log handler</p>
|
||||||
|
*
|
||||||
|
* @return Current custom log handler or NULL if none is present
|
||||||
|
*/
|
||||||
|
public static OnLogListener getOnLogListener() {
|
||||||
|
return logListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- SANITY CHECKS -----
|
||||||
|
|
||||||
|
private static boolean sanityChecks = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Enable or disable sanity checks</p>
|
||||||
|
*
|
||||||
|
* <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) {
|
||||||
|
sanityChecks = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Are sanity checks enabled ?</p>
|
||||||
|
*
|
||||||
|
* <p>Note that debug mode must also be enabled for actual
|
||||||
|
* sanity checks to occur.</p>
|
||||||
|
*
|
||||||
|
* @return True if enabled
|
||||||
|
*/
|
||||||
|
public static boolean getSanityChecksEnabled() {
|
||||||
|
return sanityChecks;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Are sanity checks enabled ?</p>
|
||||||
|
*
|
||||||
|
* <p>Takes debug mode into account for the result.</p>
|
||||||
|
*
|
||||||
|
* @return True if enabled
|
||||||
|
*/
|
||||||
|
public static boolean getSanityChecksEnabledEffective() {
|
||||||
|
return getDebug() && getSanityChecksEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <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()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2012-2014 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.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Base receiver to extend to catch notifications when overlays should be
|
||||||
|
* hidden.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* Tapjacking protection in SuperSU prevents some dialogs from receiving user
|
||||||
|
* input when overlays are present. For security reasons this notification is
|
||||||
|
* only sent to apps that have previously been granted root access, so even if
|
||||||
|
* your app does not <em>require</em> root, you still need to <em>request</em>
|
||||||
|
* it, and the user must grant it.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* Note that the word overlay as used here should be interpreted as "any view or
|
||||||
|
* window possibly obscuring SuperSU dialogs".
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
public static final String EXTRA_HIDE_OVERLAYS = "eu.chainfire.supersu.extra.HIDE";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void onReceive(Context context, Intent intent) {
|
||||||
|
if (intent.hasExtra(EXTRA_HIDE_OVERLAYS)) {
|
||||||
|
onHideOverlays(intent.getBooleanExtra(EXTRA_HIDE_OVERLAYS, false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when overlays <em>should</em> be hidden or <em>may</em> be shown
|
||||||
|
* again.
|
||||||
|
*
|
||||||
|
* @param hide Should overlays be hidden?
|
||||||
|
*/
|
||||||
|
public abstract void onHideOverlays(boolean hide);
|
||||||
|
}
|
1757
app/src/main/java/eu/chainfire/libsuperuser/Shell.java
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2012-2014 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception class used to notify developer that a shell was not close()d
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("serial")
|
||||||
|
public class ShellNotClosedException extends RuntimeException {
|
||||||
|
public static final String EXCEPTION_NOT_CLOSED = "Application did not close() interactive shell";
|
||||||
|
|
||||||
|
public ShellNotClosedException() {
|
||||||
|
super(EXCEPTION_NOT_CLOSED);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2012-2014 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception class used to crash application when shell commands are executed
|
||||||
|
* from the main thread, and we are in debug mode.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("serial")
|
||||||
|
public class ShellOnMainThreadException extends RuntimeException {
|
||||||
|
public static final String EXCEPTION_COMMAND = "Application attempted to run a shell command from the main thread";
|
||||||
|
public static final String EXCEPTION_NOT_IDLE = "Application attempted to wait for a non-idle shell to close on the main thread";
|
||||||
|
public static final String EXCEPTION_WAIT_IDLE = "Application attempted to wait for a shell to become idle on the main thread";
|
||||||
|
|
||||||
|
public ShellOnMainThreadException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
105
app/src/main/java/eu/chainfire/libsuperuser/StreamGobbler.java
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2012-2014 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.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thread utility class continuously reading from an InputStream
|
||||||
|
*/
|
||||||
|
public class StreamGobbler extends Thread {
|
||||||
|
/**
|
||||||
|
* Line callback interface
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>StreamGobbler constructor</p>
|
||||||
|
*
|
||||||
|
* <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
|
||||||
|
*/
|
||||||
|
public StreamGobbler(String shell, InputStream inputStream, List<String> outputList) {
|
||||||
|
this.shell = shell;
|
||||||
|
reader = new BufferedReader(new InputStreamReader(inputStream));
|
||||||
|
writer = outputList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>StreamGobbler constructor</p>
|
||||||
|
*
|
||||||
|
* <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
|
||||||
|
*/
|
||||||
|
public StreamGobbler(String shell, InputStream inputStream, OnLineListener onLineListener) {
|
||||||
|
this.shell = shell;
|
||||||
|
reader = new BufferedReader(new InputStreamReader(inputStream));
|
||||||
|
listener = onLineListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
// keep reading the InputStream until it ends (or an error occurs)
|
||||||
|
try {
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
Debug.logOutput(String.format("[%s] %s", shell, line));
|
||||||
|
if (writer != null) writer.add(line);
|
||||||
|
if (listener != null) listener.onLine(line);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
// reader probably closed, expected exit condition
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure our stream is closed and resources will be freed
|
||||||
|
try {
|
||||||
|
reader.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// read already closed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
app/src/main/res/drawable-hdpi/activitydetection.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
app/src/main/res/drawable-hdpi/alarm.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
app/src/main/res/drawable-hdpi/battery.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
app/src/main/res/drawable-hdpi/bluetooth.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
app/src/main/res/drawable-hdpi/brightness.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
app/src/main/res/drawable-hdpi/compass.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
app/src/main/res/drawable-hdpi/compass_small.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
app/src/main/res/drawable-hdpi/contacts.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
app/src/main/res/drawable-hdpi/dataconnection.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
app/src/main/res/drawable-hdpi/displayrotation.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
app/src/main/res/drawable-hdpi/ear.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
app/src/main/res/drawable-hdpi/gear.png
Normal file
After Width: | Height: | Size: 60 KiB |
BIN
app/src/main/res/drawable-hdpi/gears.png
Normal file
After Width: | Height: | Size: 847 KiB |
BIN
app/src/main/res/drawable-hdpi/headphone.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
app/src/main/res/drawable-hdpi/help.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
app/src/main/res/drawable-hdpi/home.png
Normal file
After Width: | Height: | Size: 7.6 KiB |
BIN
app/src/main/res/drawable-hdpi/ic_action_search.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
app/src/main/res/drawable-hdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
8
app/src/main/res/drawable-hdpi/icon_overview_tab.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<!-- When selected, use grey -->
|
||||||
|
<item android:drawable="@drawable/home"
|
||||||
|
android:state_selected="true" />
|
||||||
|
<!-- When not selected, use white-->
|
||||||
|
<item android:drawable="@drawable/home" />
|
||||||
|
</selector>
|
8
app/src/main/res/drawable-hdpi/icon_poi_tab.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<!-- When selected, use grey -->
|
||||||
|
<item android:drawable="@drawable/map"
|
||||||
|
android:state_selected="true" />
|
||||||
|
<!-- When not selected, use white-->
|
||||||
|
<item android:drawable="@drawable/map" />
|
||||||
|
</selector>
|
8
app/src/main/res/drawable-hdpi/icon_rules_tab.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<!-- When selected, use grey -->
|
||||||
|
<item android:drawable="@drawable/rule"
|
||||||
|
android:state_selected="true" />
|
||||||
|
<!-- When not selected, use white-->
|
||||||
|
<item android:drawable="@drawable/rule" />
|
||||||
|
</selector>
|
BIN
app/src/main/res/drawable-hdpi/map.png
Normal file
After Width: | Height: | Size: 6.2 KiB |
BIN
app/src/main/res/drawable-hdpi/message.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
app/src/main/res/drawable-hdpi/nfc.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
app/src/main/res/drawable-hdpi/phone.png
Normal file
After Width: | Height: | Size: 1.4 KiB |