Compare commits
33 Commits
Author | SHA1 | Date | |
---|---|---|---|
a1ed6eb45b | |||
517ae884b4 | |||
45e324fe8c | |||
c4c612c0ce | |||
118e6cf34a | |||
093de96c68 | |||
7810231e19 | |||
2bb2bdc3bc | |||
6c386d5baf | |||
55e8777d42 | |||
048d56c84d | |||
615b81e295 | |||
20f99f2b5f | |||
571df2f2c2 | |||
54bd082e89 | |||
6eb1ebe188 | |||
db6c41fe72 | |||
74994b99ee | |||
b98934c15d | |||
66e615bb20 | |||
e6266d4ed6 | |||
6532182fb8 | |||
f9204e52f3 | |||
fb886aabe9 | |||
36b796fd13 | |||
4c1e6a5a1a | |||
c36a1ab907 | |||
a0c2f37b07 | |||
ad051bc1c2 | |||
249a185649 | |||
d7bf2832ea | |||
1813f3faa6 | |||
c2806f2231 |
3
.idea/dictionaries/tim.xml
generated
Normal file
@ -0,0 +1,3 @@
|
||||
<component name="ProjectDictionaryState">
|
||||
<dictionary name="tim" />
|
||||
</component>
|
10
.idea/libraries/appcompat_v7_19_0_1.xml
generated
@ -1,10 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="appcompat-v7-19.0.1">
|
||||
<CLASSES>
|
||||
<root url="file://$PROJECT_DIR$/HypoAlarm/build/exploded-aar/com.android.support/appcompat-v7/19.0.1/res" />
|
||||
<root url="jar://$PROJECT_DIR$/HypoAlarm/build/exploded-aar/com.android.support/appcompat-v7/19.0.1/classes.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
13
.idea/libraries/appcompat_v7_20_0_0.xml
generated
Normal file
@ -0,0 +1,13 @@
|
||||
<component name="libraryTable">
|
||||
<library name="appcompat-v7-20.0.0">
|
||||
<ANNOTATIONS>
|
||||
<root url="jar://$PROJECT_DIR$/HypoAlarm/build/intermediates/exploded-aar/com.android.support/appcompat-v7/20.0.0/annotations.zip!/" />
|
||||
</ANNOTATIONS>
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/HypoAlarm/build/intermediates/exploded-aar/com.android.support/appcompat-v7/20.0.0/classes.jar!/" />
|
||||
<root url="file://$PROJECT_DIR$/HypoAlarm/build/intermediates/exploded-aar/com.android.support/appcompat-v7/20.0.0/res" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
10
.idea/libraries/glowpadbackport_2_1_0.xml
generated
Normal file
@ -0,0 +1,10 @@
|
||||
<component name="libraryTable">
|
||||
<library name="glowpadbackport-2.1.0">
|
||||
<CLASSES>
|
||||
<root url="file://$PROJECT_DIR$/HypoAlarm/build/intermediates/exploded-aar/net.frakbot.glowpadbackport/glowpadbackport/2.1.0/res" />
|
||||
<root url="jar://$PROJECT_DIR$/HypoAlarm/build/intermediates/exploded-aar/net.frakbot.glowpadbackport/glowpadbackport/2.1.0/classes.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
10
.idea/libraries/play_services_5_0_77.xml
generated
Normal file
@ -0,0 +1,10 @@
|
||||
<component name="libraryTable">
|
||||
<library name="play-services-5.0.77">
|
||||
<CLASSES>
|
||||
<root url="file://$PROJECT_DIR$/HypoAlarm/build/intermediates/exploded-aar/com.google.android.gms/play-services/5.0.77/res" />
|
||||
<root url="jar://$PROJECT_DIR$/HypoAlarm/build/intermediates/exploded-aar/com.google.android.gms/play-services/5.0.77/classes.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
@ -1,11 +1,11 @@
|
||||
<component name="libraryTable">
|
||||
<library name="support-v4-19.0.1">
|
||||
<library name="support-annotations-20.0.0">
|
||||
<CLASSES>
|
||||
<root url="jar://$APPLICATION_HOME_DIR$/sdk/extras/android/m2repository/com/android/support/support-v4/19.0.1/support-v4-19.0.1.jar!/" />
|
||||
<root url="jar://$APPLICATION_HOME_DIR$/sdk/extras/android/m2repository/com/android/support/support-annotations/20.0.0/support-annotations-20.0.0.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="jar://$APPLICATION_HOME_DIR$/sdk/extras/android/m2repository/com/android/support/support-v4/19.0.1/support-v4-19.0.1-sources.jar!/" />
|
||||
<root url="jar://$APPLICATION_HOME_DIR$/sdk/extras/android/m2repository/com/android/support/support-annotations/20.0.0/support-annotations-20.0.0-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
11
.idea/libraries/support_v4_20_0_0.xml
generated
Normal file
@ -0,0 +1,11 @@
|
||||
<component name="libraryTable">
|
||||
<library name="support-v4-20.0.0">
|
||||
<CLASSES>
|
||||
<root url="file://$PROJECT_DIR$/HypoAlarm/build/intermediates/exploded-aar/com.android.support/support-v4/20.0.0/res" />
|
||||
<root url="jar://$PROJECT_DIR$/HypoAlarm/build/intermediates/exploded-aar/com.android.support/support-v4/20.0.0/libs/internal_impl-20.0.0.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/HypoAlarm/build/intermediates/exploded-aar/com.android.support/support-v4/20.0.0/classes.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
@ -1,76 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="HypoAlarm" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="android-gradle" name="Android-Gradle">
|
||||
<configuration>
|
||||
<option name="GRADLE_PROJECT_PATH" value=":GlowPadBackport" />
|
||||
</configuration>
|
||||
</facet>
|
||||
<facet type="android" name="Android">
|
||||
<configuration>
|
||||
<option name="SELECTED_BUILD_VARIANT" value="debug" />
|
||||
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
|
||||
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugJava" />
|
||||
<option name="ASSEMBLE_TEST_TASK_NAME" value="assembleDebugTest" />
|
||||
<option name="SOURCE_GEN_TASK_NAME" value="generateDebugSources" />
|
||||
<option name="ALLOW_USER_CONFIGURATION" value="false" />
|
||||
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
|
||||
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
|
||||
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
|
||||
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
|
||||
<option name="LIBRARY_PROJECT" value="true" />
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="false">
|
||||
<output url="file://$MODULE_DIR$/build/classes/debug" />
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/source/r/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/source/aidl/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/source/buildConfig/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/source/rs/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/res/rs/debug" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/source/r/test/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/source/aidl/test/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/source/buildConfig/test/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/source/rs/test/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/res/rs/test/debug" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/apk" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/assets" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/bundles" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/classes" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/dependency-cache" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/incremental" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/libs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/manifests" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/res" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/symbols" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Android API 19 Platform" jdkType="Android SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
|
@ -1,19 +0,0 @@
|
||||
apply plugin: 'android-library'
|
||||
|
||||
android {
|
||||
compileSdkVersion 19
|
||||
buildToolsVersion "19.0.1"
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 10
|
||||
targetSdkVersion 19
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
runProguard false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
|
||||
}
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in /home/tim/sources/android-studio/sdk/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the ProGuard
|
||||
# include property in project.properties.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# 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 *;
|
||||
#}
|
@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="net.sebastianopoggi.ui.GlowPadBackport">
|
||||
</manifest>
|
Before Width: | Height: | Size: 9.2 KiB |
Before Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 19 KiB |
@ -1,3 +0,0 @@
|
||||
<resources>
|
||||
<string name="app_name">GlowPadBackport</string>
|
||||
</resources>
|
@ -8,11 +8,10 @@
|
||||
</facet>
|
||||
<facet type="android" name="Android">
|
||||
<configuration>
|
||||
<option name="SELECTED_BUILD_VARIANT" value="debug" />
|
||||
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
|
||||
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugJava" />
|
||||
<option name="ASSEMBLE_TEST_TASK_NAME" value="assembleDebugTest" />
|
||||
<option name="SOURCE_GEN_TASK_NAME" value="generateDebugSources" />
|
||||
<option name="SELECTED_BUILD_VARIANT" value="release" />
|
||||
<option name="ASSEMBLE_TASK_NAME" value="assembleRelease" />
|
||||
<option name="COMPILE_JAVA_TASK_NAME" value="compileReleaseJava" />
|
||||
<option name="SOURCE_GEN_TASK_NAME" value="generateReleaseSources" />
|
||||
<option name="ALLOW_USER_CONFIGURATION" value="false" />
|
||||
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
|
||||
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
|
||||
@ -22,56 +21,63 @@
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="false">
|
||||
<output url="file://$MODULE_DIR$/build/classes/debug" />
|
||||
<output url="file://$MODULE_DIR$/build/intermediates/classes/release" />
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/source/r/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/source/aidl/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/source/buildConfig/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/source/rs/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/res/rs/debug" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/source/r/test/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/source/aidl/test/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/source/buildConfig/test/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/source/rs/test/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/res/rs/test/debug" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/release" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/release" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/release" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/release" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/release" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/release/res" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/release/resources" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/release/assets" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/release/aidl" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/release/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/release/jni" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/release/rs" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/apk" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/assets" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/bundles" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/classes" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/dependency-cache" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/incremental" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/libs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/manifests" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/res" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/symbols" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundles" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/coverage-instrumented-classes" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dependency-cache" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex-cache" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jacoco" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/javaResources" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/libs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/ndk" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/proguard" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Android API 19 Platform" jdkType="Android SDK" />
|
||||
<orderEntry type="jdk" jdkName="Android API 20 Platform" jdkType="Android SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" exported="" name="appcompat-v7-19.0.1" level="project" />
|
||||
<orderEntry type="library" exported="" name="support-v4-19.0.1" level="project" />
|
||||
<orderEntry type="library" exported="" name="appcompat-v7-20.0.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="play-services-5.0.77" level="project" />
|
||||
<orderEntry type="library" exported="" name="glowpadbackport-2.1.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="support-annotations-20.0.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="support-v4-20.0.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="library-2.4.0" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
|
@ -1,27 +1,41 @@
|
||||
apply plugin: 'android'
|
||||
|
||||
android {
|
||||
compileSdkVersion 19
|
||||
buildToolsVersion '19.0.1'
|
||||
|
||||
signingConfigs {
|
||||
config {
|
||||
keyAlias 'druid-android-keystore'
|
||||
keyPassword 'android56Loops'
|
||||
storeFile file('/home/tim/.android-apk-keystore.jks')
|
||||
storePassword 'PurpleApes&20Flowers'
|
||||
}
|
||||
}
|
||||
compileSdkVersion 20
|
||||
buildToolsVersion '20.0.0'
|
||||
defaultConfig {
|
||||
minSdkVersion 10
|
||||
targetSdkVersion 19
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
targetSdkVersion 20
|
||||
versionCode 2
|
||||
versionName '1.0'
|
||||
signingConfig signingConfigs.config
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
runProguard false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
|
||||
signingConfig signingConfigs.config
|
||||
}
|
||||
}
|
||||
productFlavors {
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile 'com.android.support:support-v4:19.0.1'
|
||||
compile 'com.android.support:appcompat-v7:19.0.1'
|
||||
compile 'com.nineoldandroids:library:2.4.0'
|
||||
compile fileTree(dir: 'libs', include: ['*.aar'])
|
||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||
compile 'com.android.support:appcompat-v7:20.+'
|
||||
compile 'com.android.support:support-v4:20.+'
|
||||
compile 'com.google.android.gms:play-services:+'
|
||||
//compile 'com.google.android.gms:play-services:4.2.42'
|
||||
compile 'net.frakbot.glowpadbackport:glowpadbackport:2.1.0'
|
||||
//compile 'com.doomonafireball.betterpickers:library:+'
|
||||
//compile 'com.doomonafireball.betterpickers:library:1.5.2'
|
||||
//compile 'com.doomonafireball.betterpickers:library:1.5.3-SNAPSHOT'
|
||||
//compile 'com.github.flavienlaurent.datetimepicker:library:+'
|
||||
//compile 'com.github.flavienlaurent.datetimepicker:library:0.0.1'
|
||||
}
|
||||
|
@ -1,6 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="za.org.treehouse.hypoalarm" >
|
||||
package="za.org.treehouse.HypoAlarm" >
|
||||
|
||||
<!-- permission required to read contacts -->
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
||||
<!-- permission required to tell if a phone call is active -->
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||
<!-- permission required to set an alarm -->
|
||||
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
|
||||
<!-- permission required to send an SMS -->
|
||||
<uses-permission android:name="android.permission.SEND_SMS" />
|
||||
<!-- permission required to message the user's location -->
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<!-- permission to restart the alarm on device boot -->
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<!-- permission required to vibrate -->
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<!-- permission required for AlarmService to keep the CPU awake -->
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
@ -8,45 +25,48 @@
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme" >
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:name="za.org.treehouse.HypoAlarm.MainActivity"
|
||||
android:label="@string/app_name" >
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".AlarmAlertActivity"
|
||||
android:name="za.org.treehouse.HypoAlarm.AlarmAlertActivity"
|
||||
android:label="@string/alarm_alert"
|
||||
android:launchMode="singleInstance"
|
||||
android:noHistory="true" >
|
||||
</activity>
|
||||
<receiver android:name=".AlarmReceiver"/>
|
||||
<receiver android:name=".GraceReceiver"/>
|
||||
<receiver android:name=".CancelGraceReceiver"/>
|
||||
<receiver android:name=".BootReceiver"
|
||||
|
||||
<receiver android:name="za.org.treehouse.HypoAlarm.PreAlarmReceiver" />
|
||||
<receiver android:name="za.org.treehouse.HypoAlarm.CancelAlarmReceiver" />
|
||||
<receiver android:name="za.org.treehouse.HypoAlarm.AlarmReceiver" />
|
||||
<receiver android:name="za.org.treehouse.HypoAlarm.GraceReceiver" />
|
||||
<receiver android:name="za.org.treehouse.HypoAlarm.CancelGraceReceiver" />
|
||||
<receiver
|
||||
android:name="za.org.treehouse.HypoAlarm.AlarmChangeReceiver"
|
||||
android:enabled="false" >
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
<action android:name="android.intent.action.TIMEZONE_CHANGED" />
|
||||
<!--action android:name="android.intent.action.TIME_SET" /-->
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<service
|
||||
android:name=".AlarmNotify"
|
||||
android:label="@string/alarm_notification" >
|
||||
</service>
|
||||
android:name="za.org.treehouse.HypoAlarm.AlarmService" />
|
||||
<service
|
||||
android:name="za.org.treehouse.HypoAlarm.AlarmNotify"
|
||||
android:label="@string/alarm_notification" />
|
||||
<service
|
||||
android:name="za.org.treehouse.HypoAlarm.PreAlarmNotify"
|
||||
android:label="@string/pre_alarm_notification" />
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.android.gms.version"
|
||||
android:value="@integer/google_play_services_version" />
|
||||
|
||||
</application>
|
||||
|
||||
<!-- permission required to read contacts -->
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS"/>
|
||||
<!-- permission required to set an alarm -->
|
||||
<uses-permission android:name="com.android.alarm.permission.SET_ALARM"/>
|
||||
<!-- permission required to Send SMS -->
|
||||
<uses-permission android:name="android.permission.SEND_SMS"/>
|
||||
<!-- permission to restart the alarm on device boot -->
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||
<!-- permission required to vibrate -->
|
||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||
<!-- permission required to wake the device -->
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||
|
||||
</manifest>
|
||||
|
@ -0,0 +1,103 @@
|
||||
package za.org.treehouse.HypoAlarm;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import net.frakbot.glowpadbackport.GlowPadView;
|
||||
|
||||
public class AlarmAlertActivity extends Activity {
|
||||
public static Activity alertActivity;
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
alertActivity = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// Self-reference so we can run finish() from other classes
|
||||
alertActivity = this;
|
||||
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
final Window window = getWindow();
|
||||
// Set to use the full screen
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
|
||||
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
|
||||
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
|
||||
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
|
||||
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
|
||||
| WindowManager.LayoutParams.FLAG_FULLSCREEN
|
||||
);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 11) {
|
||||
window.getDecorView().
|
||||
setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
|
||||
}
|
||||
|
||||
setContentView(R.layout.alarm_alert);
|
||||
|
||||
Intent notifyIntent = new Intent(getApplicationContext(), AlarmNotify.class);
|
||||
// Disable any current notifications (if we're snoozing)
|
||||
stopService(notifyIntent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
|
||||
final GlowPadView cancelGlowPad = (GlowPadView) findViewById(R.id.cancel_glowpad);
|
||||
cancelGlowPad.setOnTriggerListener(new GlowPadView.OnTriggerListener() {
|
||||
@Override
|
||||
public void onGrabbed(View v, int handle) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReleased(View v, int handle) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrigger(View v, int target) {
|
||||
// if (target == "")
|
||||
AlarmService.dismissAlarm(alertActivity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGrabbedStateChange(View v, int handle) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinishFinalAnimation() {
|
||||
// Do nothing
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the user pressing the back/return and home buttons
|
||||
*/
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (!AlarmService.alarmStatus.contentEquals(AlarmService.ALARM_SNOOZE_RUNNING)) {
|
||||
AlarmService.setAlarmStatus(AlarmService.ALARM_IGNORED);
|
||||
}
|
||||
AlarmService.snoozeAlarm(this);
|
||||
}
|
||||
|
||||
public void onUserLeaveHint() {
|
||||
if (!AlarmService.alarmStatus.contentEquals(AlarmService.ALARM_SNOOZE_RUNNING)) {
|
||||
AlarmService.setAlarmStatus(AlarmService.ALARM_IGNORED);
|
||||
}
|
||||
AlarmService.snoozeAlarm(this);
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package za.org.treehouse.HypoAlarm;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
public class AlarmChangeReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
// Don't set this to happen on TIME_SET, or it'll restart the alarm every time the network (or NTP) sets the time.
|
||||
// intent.getAction().equals("android.intent.action.TIME_SET")
|
||||
if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED") ||
|
||||
intent.getAction().equals("android.intent.action.TIMEZONE_CHANGED")) {
|
||||
String alarmTimeStr = sharedPref.getString(context.getString(R.string.AlarmTimePref), MainActivity.defaultTimeStr);
|
||||
Calendar cal = MainActivity.TimeStringToCalendar(alarmTimeStr);
|
||||
Log.d("AlarmChangeReceiver", intent.getAction() + ": resetting alarm for " + MainActivity.debugDate(cal));
|
||||
MainActivity.setAlarm(context, cal);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,139 @@
|
||||
package za.org.treehouse.HypoAlarm;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.AssetFileDescriptor;
|
||||
import android.media.AudioManager;
|
||||
import android.media.MediaPlayer;
|
||||
import android.media.RingtoneManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Vibrator;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.telephony.PhoneStateListener;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class AlarmKlaxon {
|
||||
private static Boolean klaxonActive = false;
|
||||
private static final long[] vPattern = {500, 500};
|
||||
// Volume modification for alarms while a phone call is active, from com.android.deskclock.alarms
|
||||
private static final float IN_CALL_VOLUME = 0.125f;
|
||||
private static MediaPlayer mediaPlayer = null;
|
||||
private static TelephonyManager telephonyManager;
|
||||
private static PhoneStateListener phoneStateListener;
|
||||
private static int initialCallState;
|
||||
private static Vibrator vibrator;
|
||||
|
||||
public static void start(final Context context) {
|
||||
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
|
||||
if (klaxonActive) {
|
||||
stop(context);
|
||||
}
|
||||
klaxonActive = true;
|
||||
|
||||
vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
|
||||
vibrator.cancel();
|
||||
vibrator.vibrate(vPattern, 0);
|
||||
|
||||
telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
|
||||
initialCallState = telephonyManager.getCallState();
|
||||
phoneStateListener = new PhoneStateListener() {
|
||||
@Override
|
||||
public void onCallStateChanged(int state, String ignored) {
|
||||
// The user might already be in a call when the alarm fires. When
|
||||
// we register onCallStateChanged, we get the initial in-call state
|
||||
// which kills the alarm. Check against the initial call state so
|
||||
// we don't kill the alarm during a call.
|
||||
if (state != TelephonyManager.CALL_STATE_IDLE && state != initialCallState) {
|
||||
if (mediaPlayer != null) {
|
||||
mediaPlayer.setVolume(IN_CALL_VOLUME, IN_CALL_VOLUME);
|
||||
}
|
||||
// or just stop the audio entirely...
|
||||
//stopAudio(context);
|
||||
}
|
||||
}
|
||||
};
|
||||
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
|
||||
|
||||
stopAudio(context);
|
||||
mediaPlayer = new MediaPlayer();
|
||||
mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
|
||||
@Override
|
||||
public boolean onError(MediaPlayer mp, int what, int extra) {
|
||||
Log.e("AlarmKlaxon", "Error occurred while playing audio. Stopping alarm.");
|
||||
stopAudio(context);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
// Get preferred ringtone, or fall back to the default alarm tone
|
||||
String ringtoneStr = sharedPref.getString(context.getString(R.string.RingtonePref), RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM).toString());
|
||||
Uri ringtoneUri = Uri.parse(ringtoneStr);
|
||||
|
||||
try {
|
||||
mediaPlayer.setDataSource(context, ringtoneUri);
|
||||
startAudio(context);
|
||||
} catch (Exception ex) {
|
||||
// The ringtoneUri may be on the sd card which could be busy right
|
||||
// now. Use the fallback ringtone.
|
||||
try {
|
||||
// Reset the media player to clear the error state.
|
||||
mediaPlayer.reset();
|
||||
setDataSourceFromResource(context, mediaPlayer, R.raw.fallbackring);
|
||||
startAudio(context);
|
||||
} catch (Exception ex2) {
|
||||
// At this point we just don't play anything.
|
||||
Log.e("AlarmKlaxon", "Failed to play fallback ringtone", ex2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void stop(final Context context) {
|
||||
if (klaxonActive) {
|
||||
vibrator.cancel();
|
||||
stopAudio(context);
|
||||
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);
|
||||
klaxonActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void startAudio(final Context context) throws IOException {
|
||||
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
|
||||
// do not play alarms if stream volume is 0 (typically because ringer mode is silent).
|
||||
if (audioManager.getStreamVolume(AudioManager.STREAM_ALARM) != 0) {
|
||||
mediaPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
|
||||
mediaPlayer.setLooping(true);
|
||||
try {
|
||||
mediaPlayer.prepare();
|
||||
} catch (Exception e) {
|
||||
Log.e("AlarmAlertActivity", "Prepare failed. Exiting", e);
|
||||
return;
|
||||
}
|
||||
audioManager.requestAudioFocus(null,
|
||||
AudioManager.STREAM_ALARM, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
|
||||
mediaPlayer.start();
|
||||
}
|
||||
}
|
||||
|
||||
private static void stopAudio(final Context context) {
|
||||
if (mediaPlayer != null) {
|
||||
mediaPlayer.stop();
|
||||
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
|
||||
audioManager.abandonAudioFocus(null);
|
||||
mediaPlayer.release();
|
||||
mediaPlayer = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Load ringtone from a resource
|
||||
private static void setDataSourceFromResource(Context context, MediaPlayer player, int res) throws IOException {
|
||||
AssetFileDescriptor afd = context.getResources().openRawResourceFd(res);
|
||||
if (afd != null) {
|
||||
player.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
|
||||
afd.close();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package za.org.treehouse.hypoalarm;
|
||||
package za.org.treehouse.HypoAlarm;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
@ -9,13 +9,15 @@ import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.util.Log;
|
||||
|
||||
public class AlarmNotify extends Service {
|
||||
public static final int notifyID = 1;
|
||||
public volatile boolean notificationRunning = false;
|
||||
private static final int notifyID = 1;
|
||||
private volatile boolean notificationRunning = false;
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
@ -26,10 +28,10 @@ public class AlarmNotify extends Service {
|
||||
public void onDestroy() {
|
||||
// If the notification is cancelled, stop updating.
|
||||
notificationRunning = false;
|
||||
Log.d("AlarmNotify", "1: Setting notificationRunning to false");
|
||||
// Remove the notification in the notification bar
|
||||
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
||||
nm.cancel(notifyID);
|
||||
Log.d("AlarmNotify", "Notification stopped.");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -37,21 +39,23 @@ public class AlarmNotify extends Service {
|
||||
final int UPDATE_INTERVAL = 10*1000; // Timer is updated six times a minute
|
||||
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
|
||||
Log.d("AlarmNotify", "Notification started.");
|
||||
|
||||
//final String phoneNumber = sharedPref.getString(getString(R.string.PhoneNumberPref), null);
|
||||
final int gracePeriod = sharedPref.getInt(getString(R.string.GracePeriodPref), 60);
|
||||
// convert gracePeriod to milliseconds and calculate when it'll fire
|
||||
final long endTime = System.currentTimeMillis() + (gracePeriod * 60 * 1000);
|
||||
final int gracePeriod = sharedPref.getInt(getString(R.string.GracePeriodPref), MainActivity.defaultGracePeriod);
|
||||
|
||||
Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_grey);
|
||||
final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
final Notification.Builder notification = new Notification.Builder(this)
|
||||
final NotificationCompat.Builder notification = new NotificationCompat.Builder(this)
|
||||
.setContentTitle(getString(R.string.app_name))
|
||||
.setContentText(String.format(getString(R.string.notificationText), MainActivity.MinutesToGracePeriodStr(gracePeriod)))
|
||||
.setSmallIcon(R.drawable.alarm_notification)
|
||||
.setLargeIcon(bm)
|
||||
.setOnlyAlertOnce(true)
|
||||
.setAutoCancel(false)
|
||||
.setPriority(Notification.PRIORITY_HIGH);
|
||||
.setAutoCancel(false);
|
||||
if (Build.VERSION.SDK_INT >= 16) {
|
||||
notification.setPriority(Notification.PRIORITY_HIGH);
|
||||
}
|
||||
|
||||
// Set up dismiss action
|
||||
Intent cancellerIntent = new Intent(getBaseContext(), CancelGraceReceiver.class);
|
||||
@ -64,15 +68,6 @@ public class AlarmNotify extends Service {
|
||||
// Allow the user to cancel by selecting the ContentText or ContentTitle
|
||||
notification.setContentIntent(cancellerPendingIntent);
|
||||
|
||||
/**
|
||||
* TODO load alert activity (without sound or vibration) on select?
|
||||
* TODO This would allow the user to test competence
|
||||
Intent alertActivityIntent = new Intent(this, AlarmAlertActivity.class);
|
||||
alertActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
|
||||
Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
|
||||
notification.setContentIntent(alertActivityIntent);
|
||||
*/
|
||||
|
||||
nm.cancel(notifyID);
|
||||
nm.notify(notifyID, notification.build());
|
||||
|
||||
@ -80,36 +75,39 @@ public class AlarmNotify extends Service {
|
||||
@Override
|
||||
public void run() {
|
||||
notificationRunning = true;
|
||||
Log.d("AlarmNotify", "2: Setting notificationRunning to true");
|
||||
// Make progress out of 1000 and not just 100, for greater resolution
|
||||
int max = 1000;
|
||||
// Convert endTime from milliseconds to seconds, and translate to time remaining
|
||||
int secondsLeft = (int) ((endTime - System.currentTimeMillis())) / (1000);
|
||||
int gracePeriodSeconds = gracePeriod * 60;
|
||||
// Multiply each int by 1000 for greater progress resolution
|
||||
int progress = (((gracePeriodSeconds * 1000) - (secondsLeft * 1000)) * max) / (gracePeriodSeconds * 1000);
|
||||
// Count in milliseconds for greater progress resolution
|
||||
long graceEndTime = AlarmService.graceEndTime;
|
||||
long milliSecondsLeft = ((graceEndTime - System.currentTimeMillis()));
|
||||
long gracePeriodMilliSeconds = gracePeriod * 60 * 1000;
|
||||
int progress = (int) (((gracePeriodMilliSeconds - milliSecondsLeft) * max) / gracePeriodMilliSeconds);
|
||||
|
||||
while (progress < max) {
|
||||
// Stop the thread if cancelled elsewhere
|
||||
Log.d("AlarmNotify", "notificationRunning is "+notificationRunning);
|
||||
// Stop the thread if the notification is cancelled elsewhere
|
||||
if (!notificationRunning) {
|
||||
return;
|
||||
}
|
||||
int minutesLeft = secondsLeft / 60;
|
||||
// Recalculate milliSecondsLeft so that progress gets updated correctly.
|
||||
milliSecondsLeft = ((graceEndTime - System.currentTimeMillis()));
|
||||
// Recalculate the progress
|
||||
progress = (int) (((gracePeriodMilliSeconds - milliSecondsLeft) * max) / gracePeriodMilliSeconds);
|
||||
int minutesLeft = (int) ((milliSecondsLeft / 1000) / 60);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 11) {
|
||||
notification.setContentText(String.format(getString(R.string.notificationText), MainActivity.MinutesToGracePeriodStr(minutesLeft)));
|
||||
notification.setProgress(max, progress, false);
|
||||
// Update the notification
|
||||
nm.notify(notifyID, notification.build());
|
||||
// Prepare secondsLeft and progress for the next loop
|
||||
secondsLeft = secondsLeft - (UPDATE_INTERVAL / 1000);
|
||||
// Multiply each int by 1000 for greater progress resolution
|
||||
progress = (((gracePeriodSeconds * 1000) - (secondsLeft * 1000)) * max) / (gracePeriodSeconds * 1000);
|
||||
Log.d("AlarmNotify", "secondsLeft is "+secondsLeft+" and progress is "+progress+" (gracePeriodSeconds is "+gracePeriodSeconds+")");
|
||||
// Sleeps the thread, simulating an operation
|
||||
// that takes time
|
||||
}
|
||||
//Log.d("AlarmNotify", "milliSecondsLeft is " + milliSecondsLeft + " and gracePeriodMilliSeconds is " + gracePeriodMilliSeconds);
|
||||
//Log.d("AlarmNotify", "progress is " + progress + "; max is " + max);
|
||||
|
||||
// Sleep until we need to update again
|
||||
try {
|
||||
Thread.sleep(UPDATE_INTERVAL);
|
||||
} catch (InterruptedException e) {
|
||||
Log.d("AlarmNotify", "sleep failure");
|
||||
Log.d("AlarmNotify", "sleep failure: " + e.toString());
|
||||
}
|
||||
}
|
||||
stopSelf(); // stop notification service
|
@ -0,0 +1,15 @@
|
||||
package za.org.treehouse.HypoAlarm;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
public class AlarmReceiver extends BroadcastReceiver {
|
||||
|
||||
@Override
|
||||
public void onReceive(final Context context, final Intent intent) {
|
||||
Intent alarmIntent = new Intent(context, AlarmService.class);
|
||||
context.startService(alarmIntent);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,194 @@
|
||||
package za.org.treehouse.HypoAlarm;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.PowerManager;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
public class AlarmService extends Service {
|
||||
private static final int SNOOZE_TIME = 1000*60*5; // Snooze for 5 minutes if need be
|
||||
private static final int ALERT_LIFE = 1000*60*2; // 2 minutes
|
||||
private static PowerManager.WakeLock wl;
|
||||
private static Intent alarmServiceIntent, alertActivityIntent, notifyIntent;
|
||||
private static Boolean alarmStarted = false;
|
||||
public static final String ALARM_RUNNING = "ALARM_RUNNING";
|
||||
public static final String ALARM_DISMISSED = "ALARM_DISMISSED";
|
||||
public static final String ALARM_IGNORED = "ALARM_IGNORED";
|
||||
public static final String ALARM_SNOOZED = "ALARM_SNOOZED";
|
||||
public static final String ALARM_SNOOZE_RUNNING = "ALARM_SNOOZE_RUNNING";
|
||||
public static volatile String alarmStatus = ALARM_DISMISSED; // Register ALARM_DISMISSED and its brethren here
|
||||
public static long graceEndTime;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
// Ensure that CPU runs while the service is running, so we don't miss an alert after snoozing
|
||||
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
|
||||
wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "AlarmService");
|
||||
wl.acquire();
|
||||
}
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
Log.d("AlarmService", "Destroying alarm (alarmStarted: " + alarmStarted + ")");
|
||||
if (alarmStarted) {
|
||||
stopAlert(getApplicationContext());
|
||||
alarmStarted = false;
|
||||
}
|
||||
if (wl.isHeld()) {
|
||||
wl.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
alarmServiceIntent = intent;
|
||||
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
final Boolean alarmActive = sharedPref.getBoolean(getString(R.string.AlarmActivePref), MainActivity.defaultActive);
|
||||
final String alarmTimeStr = sharedPref.getString(getString(R.string.AlarmTimePref), MainActivity.defaultTimeStr);
|
||||
final int gracePeriod = sharedPref.getInt(getString(R.string.GracePeriodPref), MainActivity.defaultGracePeriod);
|
||||
|
||||
if (alarmActive) {
|
||||
// Cancel the pre-alarm notification, if it exists
|
||||
stopService(new Intent(this, PreAlarmNotify.class));
|
||||
|
||||
// Set up intents for later use
|
||||
notifyIntent = new Intent(this, AlarmNotify.class);
|
||||
alertActivityIntent = new Intent(this, AlarmAlertActivity.class);
|
||||
alertActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
|
||||
Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
|
||||
|
||||
if (alarmStarted) {
|
||||
stopService(notifyIntent);
|
||||
}
|
||||
alarmStarted = true;
|
||||
|
||||
// if nothing else happens, assume the alert was ignored.
|
||||
alarmStatus = ALARM_RUNNING;
|
||||
|
||||
// Reset for tomorrow; as of API 19, setRepeating() is inexact, so we use setExact()
|
||||
Calendar cal = MainActivity.TimeStringToCalendar(alarmTimeStr);
|
||||
// Advance the calendar to tomorrow (and make sure the calendar hasn't already been advanced)
|
||||
if (cal.before(Calendar.getInstance())) {
|
||||
cal.add(Calendar.DAY_OF_MONTH, 1);
|
||||
}
|
||||
|
||||
MainActivity.setAlarm(getApplicationContext(), cal);
|
||||
Log.d("AlarmService", "Alarm reset for next period");
|
||||
|
||||
// If dialing, active in a phone call, or on hold, don't bother with today's alarm, just reset it for tomorrow
|
||||
TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
|
||||
if (telephonyManager.getCallState() != TelephonyManager.CALL_STATE_OFFHOOK) {
|
||||
|
||||
// set grace period, which sends the text message upon firing
|
||||
MainActivity.setGraceAlarm(getApplicationContext());
|
||||
|
||||
// Calculate when the grace period (converted from minutes to milliseconds) ends
|
||||
graceEndTime = System.currentTimeMillis() + (gracePeriod * 60 * 1000);
|
||||
|
||||
// Allow user to acknowledge alarm and cancel grace alarm
|
||||
startAlert(this);
|
||||
}
|
||||
}
|
||||
return super.onStartCommand(intent, flags, startId);
|
||||
}
|
||||
|
||||
private static void startAlert(final Context context) {
|
||||
Log.d("AlarmService", "Starting alert; status is " + alarmStatus);
|
||||
// Turn off any notifications first
|
||||
context.stopService(notifyIntent);
|
||||
|
||||
context.startActivity(alertActivityIntent);
|
||||
AlarmKlaxon.start(context);
|
||||
|
||||
// Turn off the alert activity after a period, and switch to a notification
|
||||
new Handler().postDelayed(new Runnable() {
|
||||
public void run() {
|
||||
Log.d("AlarmService", "Closing alert activity, status is " + alarmStatus);
|
||||
// Close the dialogue and switch to notification
|
||||
// if the Activity has not been closed by the user
|
||||
// (that is, snoozeAlert and dismissAlert have not been called)
|
||||
if (alarmStatus.contentEquals(ALARM_DISMISSED) ||
|
||||
alarmStatus.contentEquals(ALARM_SNOOZED)) {
|
||||
// Do nothing
|
||||
// Stop if we've already run the snooze alert
|
||||
} else if (alarmStatus.contentEquals(ALARM_SNOOZE_RUNNING)) {
|
||||
alarmStatus = ALARM_IGNORED;
|
||||
context.stopService(alarmServiceIntent);
|
||||
} else {
|
||||
alarmStatus = ALARM_IGNORED; // This is true, although we are about to switch to ALARM_SNOOZED
|
||||
snoozeAlarm(context);
|
||||
}
|
||||
}
|
||||
}, ALERT_LIFE);
|
||||
}
|
||||
|
||||
private static void stopAlert(final Context context) {
|
||||
Log.d("AlarmService", "Stopping alert; status is " + alarmStatus);
|
||||
if (alarmStarted) {
|
||||
AlarmKlaxon.stop(context);
|
||||
if (AlarmAlertActivity.alertActivity != null) {
|
||||
AlarmAlertActivity.alertActivity.finish();
|
||||
}
|
||||
if (!alarmStatus.contentEquals(ALARM_DISMISSED)) {
|
||||
context.startService(notifyIntent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void dismissAlarm(final Context context) {
|
||||
Log.d("AlarmService", "Dismissing alarm");
|
||||
alarmStatus = ALARM_DISMISSED;
|
||||
|
||||
// Cancel the graceAlarm
|
||||
MainActivity.cancelGraceAlarm(context);
|
||||
|
||||
// Stop this service, along with the alert and all notifications
|
||||
context.stopService(alarmServiceIntent);
|
||||
}
|
||||
|
||||
public static void snoozeAlarm(final Context context) {
|
||||
Log.d("AlarmService", "Snoozing alarm");
|
||||
// Close the alert, stop the klaxon, and start the notification,
|
||||
// but only if there's time left before the gracePeriod triggers,
|
||||
// and we haven't snoozed before
|
||||
if (((System.currentTimeMillis() + SNOOZE_TIME) < graceEndTime) &&
|
||||
(!alarmStatus.contentEquals(ALARM_SNOOZE_RUNNING)) &&
|
||||
(!alarmStatus.contentEquals(ALARM_SNOOZED)) &&
|
||||
(!alarmStatus.contentEquals(ALARM_DISMISSED))) {
|
||||
stopAlert(context);
|
||||
new Handler().postDelayed(new Runnable() {
|
||||
public void run() {
|
||||
Log.d("AlarmService", "Resuming after snooze; status is " + alarmStatus);
|
||||
// Don't run if the alarm was dismissed before the timer ran out
|
||||
// (because a notification was acknowledged)
|
||||
if (!alarmStatus.contentEquals(ALARM_DISMISSED)) {
|
||||
alarmStatus = ALARM_SNOOZE_RUNNING;
|
||||
startAlert(context);
|
||||
}
|
||||
}
|
||||
}, SNOOZE_TIME);
|
||||
// Change alarm status from ignored to snoozed
|
||||
alarmStatus = ALARM_SNOOZED;
|
||||
} else {
|
||||
Log.d("AlarmService", "Actually, not snoozing!");
|
||||
context.stopService(alarmServiceIntent);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setAlarmStatus (String status) {
|
||||
Log.d("AlarmService", "Setting alarm status to " + status);
|
||||
alarmStatus = status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package za.org.treehouse.HypoAlarm;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
public class CancelAlarmReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
String alarmTimeStr = sharedPref.getString(context.getString(R.string.AlarmTimePref), MainActivity.defaultTimeStr);
|
||||
|
||||
// Cancel alarm. This isn't technically necessary, as it'll happen in setAlarm
|
||||
MainActivity.cancelAlarm(context);
|
||||
|
||||
// Reset for tomorrow. setAlarm will also advance the day, but
|
||||
// make it explicit here.
|
||||
Calendar cal = MainActivity.TimeStringToCalendar(alarmTimeStr);
|
||||
cal.add(Calendar.DAY_OF_MONTH, 1);
|
||||
|
||||
// Reset alarm for tomorrow
|
||||
MainActivity.setAlarm(context, cal);
|
||||
|
||||
// Display toast
|
||||
Toast.makeText(context, context.getString(R.string.alarmCancelToast), Toast.LENGTH_LONG).show();
|
||||
|
||||
// Stop any snoozed/existing alarms that may have started
|
||||
AlarmService.setAlarmStatus(AlarmService.ALARM_DISMISSED);
|
||||
context.stopService(new Intent(context, AlarmService.class));
|
||||
|
||||
// Remove notification
|
||||
context.stopService(new Intent(context, PreAlarmNotify.class));
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package za.org.treehouse.HypoAlarm;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class CancelGraceReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
// Ensure that any snoozes that are pending never happen.
|
||||
AlarmService.setAlarmStatus(AlarmService.ALARM_DISMISSED);
|
||||
context.stopService(new Intent(context, AlarmService.class));
|
||||
|
||||
MainActivity.cancelGraceAlarm(context);
|
||||
|
||||
// Display toast
|
||||
Toast.makeText(context, context.getString(R.string.graceCancelToast), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
package za.org.treehouse.HypoAlarm;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.location.Location;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.telephony.SmsManager;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.google.android.gms.common.ConnectionResult;
|
||||
import com.google.android.gms.common.GooglePlayServicesClient;
|
||||
import com.google.android.gms.common.GooglePlayServicesUtil;
|
||||
import com.google.android.gms.location.LocationClient;
|
||||
|
||||
/*
|
||||
* TODO: translate geographic coordinates into an address?
|
||||
* import android.location.Address;
|
||||
* import android.location.Geocoder;
|
||||
*/
|
||||
|
||||
public class GraceReceiver extends BroadcastReceiver {
|
||||
private static LocationClient locationClient = null;
|
||||
private static String phoneNumber;
|
||||
private static String message;
|
||||
|
||||
@Override
|
||||
public void onReceive(final Context context, Intent intent) {
|
||||
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
Boolean alarmActive = sharedPref.getBoolean(context.getString(R.string.AlarmActivePref), MainActivity.defaultActive);
|
||||
phoneNumber = sharedPref.getString(context.getString(R.string.PhoneNumberPref), null);
|
||||
message = sharedPref.getString(context.getString(R.string.MessagePref), context.getString(R.string.defaultMessage));
|
||||
|
||||
// Stop any lingering alarm service
|
||||
context.stopService(new Intent(context, AlarmService.class));
|
||||
|
||||
if (alarmActive) {
|
||||
if (GooglePlayServicesUtil.isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS) {
|
||||
locationClient = new LocationClient(context,
|
||||
new GooglePlayServicesClient.ConnectionCallbacks() {
|
||||
@Override
|
||||
public void onConnected(Bundle bundle) {
|
||||
Location location = locationClient.getLastLocation();
|
||||
if (location != null) {
|
||||
// uri must begin with a space
|
||||
String uri = " http://maps.google.com/maps/?q=loc:" + location.getLatitude() + "," + location.getLongitude();
|
||||
message += uri;
|
||||
sendText(context);
|
||||
} else {
|
||||
Log.e("GraceReceiver", "No location data available. Sending text message anyway.");
|
||||
sendText(context);
|
||||
}
|
||||
locationClient.disconnect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisconnected() {
|
||||
}
|
||||
},
|
||||
new GooglePlayServicesClient.OnConnectionFailedListener() {
|
||||
@Override
|
||||
public void onConnectionFailed(ConnectionResult connectionResult) {
|
||||
Log.e("GraceReceiver", "Failed connection to location manager " + connectionResult.toString() + ". Sending text message anyway.");
|
||||
sendText(context);
|
||||
}
|
||||
}
|
||||
);
|
||||
locationClient.connect();
|
||||
} else {
|
||||
Log.e("GraceReceiver", "Google Play Services is not available. Sending text message anyway.");
|
||||
sendText(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
private void sendText(Context context) {
|
||||
SmsManager sms = SmsManager.getDefault();
|
||||
if (phoneNumber == null || phoneNumber.isEmpty()) {
|
||||
message = "You have not specified a phone number. No text message will be sent.";
|
||||
Toast.makeText(context, message, Toast.LENGTH_LONG).show();
|
||||
Log.e("GraceReceiver", "ERROR: " + message);
|
||||
} else {
|
||||
if (!MainActivity.HYPOALARM_DEBUG) {
|
||||
sms.sendTextMessage(phoneNumber, null, message, null, null);
|
||||
} else {
|
||||
Toast.makeText(context, message, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
Log.d("GraceReceiver", "Sending sms to " + phoneNumber + " with message: " + message);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,719 @@
|
||||
package za.org.treehouse.HypoAlarm;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.TimePickerDialog;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.database.Cursor;
|
||||
import android.location.Location;
|
||||
import android.media.Ringtone;
|
||||
import android.media.RingtoneManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.provider.ContactsContract;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
import android.text.InputType;
|
||||
import android.text.format.DateFormat;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TimePicker;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.google.android.gms.common.ConnectionResult;
|
||||
import com.google.android.gms.common.GooglePlayServicesClient;
|
||||
import com.google.android.gms.common.GooglePlayServicesUtil;
|
||||
import com.google.android.gms.location.LocationClient;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
// Settings: alarm time, phone number, custom message, grace period length
|
||||
// Set alarm
|
||||
// Display alarm notification
|
||||
// Display countdown (in seconds) or time till alarm fires (in minutes)
|
||||
// Reset alarm
|
||||
// Send SMS
|
||||
|
||||
// Possible settings:
|
||||
// More than one phone number?
|
||||
// Alerts via Whatsapp and other protocols?
|
||||
|
||||
public class MainActivity extends ActionBarActivity {
|
||||
private static LocationClient locationClient = null;
|
||||
public static final int ALARM_REQUEST = 1;
|
||||
public static final int GRACE_REQUEST = 2;
|
||||
public static final int PRE_NOTIFY_REQUEST = 3;
|
||||
public static final int CANCEL_GRACE_REQUEST = 4;
|
||||
public static final int CANCEL_ALARM_REQUEST = 5;
|
||||
public static final int PHONE_NUMBER_REQUEST = 6;
|
||||
public static final int RINGTONE_REQUEST = 7;
|
||||
public static final String TIMEPICKER_TAG = "alarmTimePicker";
|
||||
public static final String defaultTimeStr = "09:00";
|
||||
public static final int defaultGracePeriod = 60;
|
||||
public static final Boolean defaultActive = true;
|
||||
|
||||
// Write a message to the screen instead of sending a text as normal
|
||||
public static final Boolean HYPOALARM_DEBUG = false;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.add(R.id.container, new MainFragment())
|
||||
.commit();
|
||||
}
|
||||
}
|
||||
|
||||
// Main screen
|
||||
|
||||
/**
|
||||
* To use a radial timepicker, uncomment this line instead
|
||||
public static class MainFragment extends Fragment implements RadialTimePickerDialog.OnTimeSetListener {
|
||||
*/
|
||||
public static class MainFragment extends Fragment {
|
||||
|
||||
public MainFragment() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.fragment_main, container, false);
|
||||
}
|
||||
|
||||
public void onStart() {
|
||||
final SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
||||
|
||||
super.onStart();
|
||||
|
||||
/**
|
||||
* To use a radial timepicker, uncomment here:
|
||||
final RadialTimePickerDialog timePickerDialog = RadialTimePickerDialog.newInstance(this, 0, 0, DateFormat.is24HourFormat(getActivity()));
|
||||
*/
|
||||
// Set alarm time
|
||||
String alarmTimeStr = verifyTimeString(sharedPref.getString(getString(R.string.AlarmTimePref), defaultTimeStr));
|
||||
final Button alarmTimeButton = (Button) getActivity().findViewById(R.id.alarm_time);
|
||||
alarmTimeButton.setText(alarmTimeStr);
|
||||
alarmTimeButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
DialogFragment alarmFragment = new TimePickerFragment();
|
||||
alarmFragment.show(getActivity().getSupportFragmentManager(), TIMEPICKER_TAG);
|
||||
|
||||
/**
|
||||
* To use a radial time picker, uncomment here:
|
||||
// Use the current set time as the default value for the picker
|
||||
String alarmTimeStr = verifyTimeString(sharedPref.getString(getString(R.string.AlarmTimePref), defaultTimeStr));
|
||||
timePickerDialog.setStartTime(hour, minute);
|
||||
timePickerDialog.setThemeDark(true); // available from version 1.5.3...
|
||||
timePickerDialog.show(getActivity().getSupportFragmentManager(), TIMEPICKER_TAG);
|
||||
*/
|
||||
}
|
||||
});
|
||||
|
||||
// Allow alarm to activate
|
||||
Boolean alarmActive = sharedPref.getBoolean(getString(R.string.AlarmActivePref), defaultActive);
|
||||
final CompoundButton alarmActiveSwitch = (CompoundButton) getActivity().findViewById(R.id.alarm_active_switch);
|
||||
alarmActiveSwitch.setChecked(alarmActive);
|
||||
alarmActiveSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton compoundButton, boolean active) {
|
||||
SharedPreferences.Editor editor = sharedPref.edit();
|
||||
editor.putBoolean(getString(R.string.AlarmActivePref), active);
|
||||
editor.commit();
|
||||
|
||||
if (!active) {
|
||||
// Prevent any snoozed alarm from returning
|
||||
if (AlarmService.alarmStatus.contentEquals(AlarmService.ALARM_SNOOZE_RUNNING) ||
|
||||
AlarmService.alarmStatus.contentEquals(AlarmService.ALARM_SNOOZED) ||
|
||||
AlarmService.alarmStatus.contentEquals(AlarmService.ALARM_RUNNING)) {
|
||||
AlarmService.setAlarmStatus(AlarmService.ALARM_DISMISSED);
|
||||
}
|
||||
// Cancel any alarms
|
||||
cancelAllAlarms(getActivity());
|
||||
Toast.makeText(getActivity(), getString(R.string.alarmCancelled), Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
String alarmTimeStr = verifyTimeString(sharedPref.getString(getString(R.string.AlarmTimePref), defaultTimeStr));
|
||||
Calendar cal = TimeStringToCalendar(alarmTimeStr);
|
||||
setAlarm(getActivity(), cal);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Activate the time (after setting alarmActive) when starting the app (but don't cancel any existing grace period alarms)
|
||||
Calendar cal = TimeStringToCalendar(alarmTimeStr);
|
||||
setAlarm(getActivity(), cal);
|
||||
|
||||
// Set grace period
|
||||
int gracePeriod = sharedPref.getInt(getString(R.string.GracePeriodPref), defaultGracePeriod);
|
||||
final Spinner gracePeriodSpinner = (Spinner) getActivity().findViewById(R.id.grace_period);
|
||||
|
||||
gracePeriodSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
final SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
||||
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
|
||||
Object value = parent.getItemAtPosition(pos);
|
||||
if (value != null) {
|
||||
SharedPreferences.Editor editor = sharedPref.edit();
|
||||
int minutes = GracePeriodToMinutes(value.toString());
|
||||
editor.putInt(getString(R.string.GracePeriodPref), minutes);
|
||||
editor.commit();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
}
|
||||
});
|
||||
// Set value of drop-down list to value of gracePeriodStr
|
||||
ArrayAdapter<String> gracePeriodSpinnerAdapter = (ArrayAdapter<String>) gracePeriodSpinner.getAdapter();
|
||||
int spinnerPosition = gracePeriodSpinnerAdapter.getPosition(MinutesToGracePeriodStr(gracePeriod));
|
||||
gracePeriodSpinner.setSelection(spinnerPosition);
|
||||
|
||||
|
||||
// Allow user to select ringtone
|
||||
final Button ringtoneButton = (Button) getActivity().findViewById(R.id.ringtone);
|
||||
String ringtoneStr = sharedPref.getString(getString(R.string.RingtonePref), RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM).toString());
|
||||
final Uri ringtoneUri = Uri.parse(ringtoneStr);
|
||||
Ringtone currentRingtone = RingtoneManager.getRingtone(getActivity().getApplicationContext(), ringtoneUri);
|
||||
ringtoneButton.setText(currentRingtone.getTitle(getActivity().getApplicationContext()));
|
||||
ringtoneButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
Intent ringtoneIntent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
|
||||
ringtoneIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_TITLE, "Select ringtone:");
|
||||
ringtoneIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, false);
|
||||
ringtoneIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_ALARM);
|
||||
ringtoneIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, ringtoneUri);
|
||||
|
||||
startActivityForResult(ringtoneIntent, RINGTONE_REQUEST);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Set phone number
|
||||
String phoneNumberStr = sharedPref.getString(getString(R.string.PhoneNumberPref), null);
|
||||
final EditText phoneNumberButton = (EditText) getActivity().findViewById(R.id.phone_number);
|
||||
phoneNumberButton.setText(phoneNumberStr);
|
||||
phoneNumberButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
DialogFragment phoneFragment = new PhonePickerFragment();
|
||||
phoneFragment.show(getActivity().getSupportFragmentManager(), "phoneNumberPicker");
|
||||
}
|
||||
});
|
||||
|
||||
// Set message
|
||||
String messageStr = sharedPref.getString(getString(R.string.MessagePref), getString(R.string.defaultMessage));
|
||||
final EditText messageButton = (EditText) getActivity().findViewById(R.id.message);
|
||||
messageButton.setText(messageStr);
|
||||
messageButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
final SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
||||
final InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());
|
||||
|
||||
final EditText messageInput = new EditText(getActivity());
|
||||
messageInput.setInputType(InputType.TYPE_CLASS_TEXT |
|
||||
InputType.TYPE_TEXT_FLAG_MULTI_LINE |
|
||||
InputType.TYPE_TEXT_FLAG_CAP_SENTENCES |
|
||||
InputType.TYPE_TEXT_FLAG_AUTO_CORRECT);
|
||||
if (messageButton.getText() != null) {
|
||||
messageInput.setText(messageButton.getText().toString());
|
||||
}
|
||||
if (messageInput.getText() != null) {
|
||||
messageInput.setSelection(messageInput.getText().length());
|
||||
}
|
||||
alert.setView(messageInput);
|
||||
alert.setMessage(getString(R.string.setMessage));
|
||||
|
||||
alert.setPositiveButton("OK", new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
String value = messageInput.getText().toString();
|
||||
if (value.compareTo("") == 0) {
|
||||
value = getString(R.string.defaultMessage);
|
||||
}
|
||||
SharedPreferences.Editor editor = sharedPref.edit();
|
||||
editor.putString(getString(R.string.MessagePref), value);
|
||||
editor.commit();
|
||||
messageButton.setText(value);
|
||||
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
|
||||
}
|
||||
});
|
||||
alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
|
||||
// Canceled.
|
||||
}
|
||||
});
|
||||
alert.show();
|
||||
messageInput.requestFocus();
|
||||
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
|
||||
}
|
||||
});
|
||||
|
||||
// Set time change and boot receiver, so alarm restarts on boot
|
||||
ComponentName bootReceiver = new ComponentName(getActivity(), AlarmChangeReceiver.class);
|
||||
PackageManager pm = getActivity().getPackageManager();
|
||||
if (pm != null) {
|
||||
pm.setComponentEnabledSetting(bootReceiver,
|
||||
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
|
||||
PackageManager.DONT_KILL_APP);
|
||||
Log.d("MainActivity", "Setting boot receiver");
|
||||
}
|
||||
|
||||
// Get the location now, so that user has to grant permission for location now, not when
|
||||
// the text message is sent.
|
||||
if (GooglePlayServicesUtil.isGooglePlayServicesAvailable(getActivity()) == ConnectionResult.SUCCESS) {
|
||||
locationClient = new LocationClient(getActivity(),
|
||||
new GooglePlayServicesClient.ConnectionCallbacks() {
|
||||
@Override
|
||||
public void onConnected(Bundle bundle) {
|
||||
Location location = locationClient.getLastLocation();
|
||||
if (location == null) {
|
||||
Log.e("MainActivity", "No location data available.");
|
||||
}
|
||||
locationClient.disconnect();
|
||||
}
|
||||
@Override
|
||||
public void onDisconnected() {
|
||||
}
|
||||
},
|
||||
new GooglePlayServicesClient.OnConnectionFailedListener() {
|
||||
@Override
|
||||
public void onConnectionFailed(ConnectionResult connectionResult) {
|
||||
Log.e("MainActivity", "Failed connection to location manager " + connectionResult.toString());
|
||||
}
|
||||
}
|
||||
);
|
||||
locationClient.connect();
|
||||
} else {
|
||||
Log.e("GraceReceiver", "Google Play Services is not available.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
|
||||
// If we're answering a ringtone dialogue, update the correct button
|
||||
if (requestCode == RINGTONE_REQUEST && resultCode == RESULT_OK) {
|
||||
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
||||
SharedPreferences.Editor editor = sharedPref.edit();
|
||||
Button ringtoneButton = (Button) getActivity().findViewById(R.id.ringtone);
|
||||
|
||||
Uri uri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
|
||||
if (uri == null) {
|
||||
editor.putString(getString(R.string.RingtonePref), null);
|
||||
} else {
|
||||
editor.putString(getString(R.string.RingtonePref), uri.toString());
|
||||
}
|
||||
editor.commit();
|
||||
Ringtone currentRingtone = RingtoneManager.getRingtone(getActivity().getApplicationContext(), uri);
|
||||
ringtoneButton.setText(currentRingtone.getTitle(getActivity().getApplicationContext()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* To use a radial timepicker, uncomment this function
|
||||
*
|
||||
@Override
|
||||
public void onTimeSet(RadialPickerLayout view, int hourOfDay, int minute) {
|
||||
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
||||
|
||||
// Set time preference
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.set(Calendar.HOUR_OF_DAY, hourOfDay);
|
||||
cal.set(Calendar.MINUTE, minute);
|
||||
cal.set(Calendar.SECOND, 0);
|
||||
String alarmStr = CalendarToTimeString(cal);
|
||||
|
||||
SharedPreferences.Editor editor = sharedPref.edit();
|
||||
editor.putString(getString(R.string.AlarmTimePref), alarmStr);
|
||||
editor.commit();
|
||||
|
||||
Button alarm_time = (Button) getActivity().findViewById(R.id.alarm_time);
|
||||
alarm_time.setText(alarmStr);
|
||||
|
||||
// Set actual alarm
|
||||
setAlarm(getActivity(), cal);
|
||||
|
||||
// Display toast
|
||||
CharSequence text = getString(R.string.alarmSetToast) + " " + CalendarToTimeString(cal);
|
||||
Toast.makeText(getActivity(), text, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel main alarm, but not grace alarm.
|
||||
* This should be run whenever the alarm is set.
|
||||
*/
|
||||
public static void cancelAlarm(Context context) {
|
||||
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
|
||||
// Cancel any current alarm
|
||||
Intent alarmIntent = new Intent(context, AlarmReceiver.class);
|
||||
PendingIntent alarmPendingIntent = PendingIntent.getBroadcast(context, ALARM_REQUEST, alarmIntent, 0);
|
||||
alarmManager.cancel(alarmPendingIntent);
|
||||
|
||||
// Cancel any pre-alarm notification that may fire
|
||||
Intent preNotifyIntent = new Intent(context, PreAlarmReceiver.class);
|
||||
PendingIntent preNotifyPendingIntent = PendingIntent.getBroadcast(context, PRE_NOTIFY_REQUEST, preNotifyIntent, 0);
|
||||
alarmManager.cancel(preNotifyPendingIntent);
|
||||
|
||||
// Stop any existing pre-alarm notification that has already fired
|
||||
context.stopService(new Intent(context, PreAlarmNotify.class));
|
||||
|
||||
Log.d("MainActivity", "Alarm cancelled");
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel grace alarm and notifications
|
||||
*/
|
||||
public static void cancelGraceAlarm(Context context) {
|
||||
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
|
||||
// Cancel any grace period
|
||||
Intent graceIntent = new Intent(context, GraceReceiver.class);
|
||||
PendingIntent gracePendingIntent = PendingIntent.getBroadcast(context, GRACE_REQUEST, graceIntent, 0);
|
||||
alarmManager.cancel(gracePendingIntent);
|
||||
|
||||
// Stop any notification of grace period expiry
|
||||
context.stopService(new Intent(context, AlarmNotify.class));
|
||||
|
||||
Log.d("MainActivity", "Grace alarm cancelled");
|
||||
}
|
||||
/**
|
||||
* Cancels main alarm and grace alarm
|
||||
* This should only be run when we're disabling the alarm entirely.
|
||||
*/
|
||||
public static void cancelAllAlarms(Context context) {
|
||||
cancelAlarm(context);
|
||||
cancelGraceAlarm(context);
|
||||
Log.d("MainActivity", "All alarms cancelled");
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the alarm.
|
||||
*
|
||||
* @param context Context
|
||||
* @param cal Time at which to fire alarm
|
||||
*/
|
||||
public static void setAlarm(Context context, Calendar cal) {
|
||||
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
PendingIntent alarmPendingIntent, preNotifyPendingIntent;
|
||||
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
Boolean alarmActive = sharedPref.getBoolean(context.getString(R.string.AlarmActivePref), defaultActive);
|
||||
|
||||
cancelAlarm(context);
|
||||
|
||||
// Advance cal to tomorrow if setting a time earlier than now
|
||||
if (cal.before(Calendar.getInstance())) {
|
||||
cal.add(Calendar.DAY_OF_MONTH, 1);
|
||||
}
|
||||
|
||||
if (alarmActive) {
|
||||
// Initialise alarm, which displays a dialog and system alert, and
|
||||
// calls AlarmManager with grace_period as the delay
|
||||
// which in turn, sends SMS if dialog is not exited.
|
||||
Intent alarmIntent = new Intent(context, AlarmReceiver.class);
|
||||
alarmPendingIntent = PendingIntent.getBroadcast(context, ALARM_REQUEST, alarmIntent, 0);
|
||||
// Set or reset alarm
|
||||
if (Build.VERSION.SDK_INT >= 19) {
|
||||
alarmManager.setExact(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), alarmPendingIntent);
|
||||
} else {
|
||||
alarmManager.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), alarmPendingIntent);
|
||||
}
|
||||
Log.d("MainActivity", "Setting alarm for " + debugDate(cal));
|
||||
|
||||
// Set an alarm for the pre-alarm notification, an hour before the alarm
|
||||
Calendar preNotifyCal = (Calendar) cal.clone();
|
||||
preNotifyCal.add(Calendar.MINUTE, -60);
|
||||
Intent preNotifyIntent = new Intent(context, PreAlarmReceiver.class);
|
||||
preNotifyPendingIntent = PendingIntent.getBroadcast(context, PRE_NOTIFY_REQUEST, preNotifyIntent, 0);
|
||||
// Set or reset alarm
|
||||
if (Build.VERSION.SDK_INT >= 19) {
|
||||
alarmManager.setExact(AlarmManager.RTC_WAKEUP, preNotifyCal.getTimeInMillis(), preNotifyPendingIntent);
|
||||
} else {
|
||||
alarmManager.set(AlarmManager.RTC_WAKEUP, preNotifyCal.getTimeInMillis(), preNotifyPendingIntent);
|
||||
}
|
||||
Log.d("MainActivity", "Setting pre-alarm for " + debugDate(preNotifyCal));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the grace alarm, to fire at the end of the grace period and send a text message.
|
||||
*/
|
||||
public static void setGraceAlarm(Context context) {
|
||||
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
Boolean alarmActive = sharedPref.getBoolean(context.getString(R.string.AlarmActivePref), defaultActive);
|
||||
int gracePeriod = sharedPref.getInt(context.getString(R.string.GracePeriodPref), defaultGracePeriod);
|
||||
|
||||
cancelGraceAlarm(context);
|
||||
|
||||
if (alarmActive) {
|
||||
// Set a grace period alarm to send SMS
|
||||
Calendar graceCal = Calendar.getInstance();
|
||||
graceCal.set(Calendar.SECOND, 0);
|
||||
graceCal.add(Calendar.MINUTE, gracePeriod);
|
||||
Intent graceIntent = new Intent(context, GraceReceiver.class);
|
||||
PendingIntent gracePendingIntent = PendingIntent.getBroadcast(context, GRACE_REQUEST, graceIntent, 0);
|
||||
if (Build.VERSION.SDK_INT >= 19) {
|
||||
alarmManager.setExact(AlarmManager.RTC_WAKEUP, graceCal.getTimeInMillis(), gracePendingIntent);
|
||||
} else {
|
||||
alarmManager.set(AlarmManager.RTC_WAKEUP, graceCal.getTimeInMillis(), gracePendingIntent);
|
||||
}
|
||||
Log.d("MainActivity", "Setting grace alarm for " + debugDate(graceCal));
|
||||
}
|
||||
}
|
||||
|
||||
public static class TimePickerFragment extends DialogFragment implements TimePickerDialog.OnTimeSetListener {
|
||||
SharedPreferences sharedPref;
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
sharedPref = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
||||
// Use the current set time as the default value for the picker
|
||||
String alarmTimeStr = verifyTimeString(sharedPref.getString(getString(R.string.AlarmTimePref), defaultTimeStr));
|
||||
// For selecting a time, the date doesn't matter, just the hour and minute
|
||||
Calendar cal = TimeStringToCalendar(alarmTimeStr);
|
||||
int hour = cal.get(Calendar.HOUR_OF_DAY);
|
||||
int minute = cal.get(Calendar.MINUTE);
|
||||
|
||||
// Create a new instance of TimePickerDialog and return it
|
||||
return new TimePickerDialog(getActivity(), this, hour, minute, DateFormat.is24HourFormat(getActivity()));
|
||||
}
|
||||
|
||||
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
|
||||
// Set time preference
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.set(Calendar.HOUR_OF_DAY, hourOfDay);
|
||||
cal.set(Calendar.MINUTE, minute);
|
||||
cal.set(Calendar.SECOND, 0);
|
||||
String alarmStr = CalendarToTimeString(cal);
|
||||
|
||||
SharedPreferences.Editor editor = sharedPref.edit();
|
||||
editor.putString(getString(R.string.AlarmTimePref), alarmStr);
|
||||
editor.commit();
|
||||
|
||||
Button alarm_time = (Button) getActivity().findViewById(R.id.alarm_time);
|
||||
alarm_time.setText(alarmStr);
|
||||
|
||||
// Set actual alarm
|
||||
setAlarm(getActivity(), cal);
|
||||
|
||||
// Display toast
|
||||
CharSequence text = getString(R.string.alarmSetToast) + " " + CalendarToTimeString(cal);
|
||||
Toast.makeText(getActivity(), text, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
public static class PhonePickerFragment extends DialogFragment {
|
||||
SharedPreferences sharedPref;
|
||||
EditText phoneInput;
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
sharedPref = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
||||
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());
|
||||
alert.setMessage(R.string.setPhoneNumber);
|
||||
|
||||
LayoutInflater inflater = getActivity().getLayoutInflater();
|
||||
// Pass null instead of the parent ViewGroup, as the parent View is a
|
||||
// ScrollView, which can only have one direct child
|
||||
View dialogView = inflater.inflate(R.layout.phone_dialog, null);
|
||||
alert.setView(dialogView);
|
||||
|
||||
final EditText phoneButton = (EditText) getActivity().findViewById(R.id.phone_number);
|
||||
phoneInput = (EditText) dialogView.findViewById(R.id.dialog_phone_number);
|
||||
phoneInput.setText(phoneButton.getText().toString());
|
||||
phoneInput.setSelection(phoneInput.getText().length());
|
||||
final Button contactsButton = (Button) dialogView.findViewById(R.id.dialog_contacts_button);
|
||||
|
||||
alert.setPositiveButton("OK", new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
String value = phoneInput.getText().toString();
|
||||
SharedPreferences.Editor editor = sharedPref.edit();
|
||||
editor.putString(getString(R.string.PhoneNumberPref), value);
|
||||
editor.commit();
|
||||
phoneButton.setText(value);
|
||||
}
|
||||
});
|
||||
alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
// Cancelled
|
||||
}
|
||||
});
|
||||
contactsButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
|
||||
intent.setType(ContactsContract.CommonDataKinds.Phone.CONTENT_TYPE);
|
||||
startActivityForResult(intent, PHONE_NUMBER_REQUEST);
|
||||
}
|
||||
});
|
||||
return alert.create();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (requestCode == PHONE_NUMBER_REQUEST && resultCode == RESULT_OK && data != null) {
|
||||
Uri uri = data.getData();
|
||||
if (uri != null) {
|
||||
Cursor c = null;
|
||||
try {
|
||||
c = getActivity().getContentResolver().query(uri, new String[]{
|
||||
ContactsContract.CommonDataKinds.Phone.NUMBER,
|
||||
ContactsContract.CommonDataKinds.Phone.TYPE},
|
||||
null, null, null
|
||||
);
|
||||
|
||||
if (c != null && c.moveToFirst()) {
|
||||
String number = c.getString(0);
|
||||
phoneInput.setText(number);
|
||||
}
|
||||
} finally {
|
||||
if (c != null) {
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String verifyTimeString(String timeStr) {
|
||||
return CalendarToTimeString(TimeStringToCalendar(timeStr));
|
||||
}
|
||||
|
||||
public static Calendar TimeStringToCalendar(String dateString) {
|
||||
Date date;
|
||||
Calendar cal;
|
||||
final String FORMAT = "HH:mm";
|
||||
SimpleDateFormat sdf = new SimpleDateFormat(FORMAT, Locale.getDefault());
|
||||
sdf.format(new Date());
|
||||
try {
|
||||
date = sdf.parse(dateString);
|
||||
// date has the correct hour and minute, but the incorrect day,
|
||||
// month and year information. To get information out of it, we need to
|
||||
// convert it to a Calendar.
|
||||
Calendar dateCal = Calendar.getInstance();
|
||||
dateCal.setTime(date);
|
||||
|
||||
// Create a new calendar with the correct day, month and year,
|
||||
// and set the hour and minute by hand.
|
||||
cal = Calendar.getInstance();
|
||||
cal.set(Calendar.HOUR_OF_DAY, dateCal.get(Calendar.HOUR_OF_DAY));
|
||||
cal.set(Calendar.MINUTE, dateCal.get(Calendar.MINUTE));
|
||||
cal.set(Calendar.SECOND, 0);
|
||||
return cal;
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String CalendarToTimeString(Calendar cal) {
|
||||
final String FORMAT = "HH:mm";
|
||||
SimpleDateFormat sdf = new SimpleDateFormat(FORMAT, Locale.getDefault());
|
||||
return sdf.format(cal.getTime());
|
||||
}
|
||||
|
||||
public static String formattedTime(Context context, Calendar cal) {
|
||||
SimpleDateFormat print;
|
||||
if (DateFormat.is24HourFormat(context)) {
|
||||
print = new SimpleDateFormat("E HH:mm");
|
||||
} else {
|
||||
print = new SimpleDateFormat("E hh:mm a");
|
||||
}
|
||||
return print.format(cal.getTime());
|
||||
}
|
||||
|
||||
public static int GracePeriodToMinutes(String gracePeriod) {
|
||||
Pattern p = Pattern.compile("(?:(\\d+)\\s+hours?)?\\s*(?:(\\d+)\\s+minutes?)?");
|
||||
|
||||
Matcher m = p.matcher(gracePeriod);
|
||||
if (m.find()) {
|
||||
int hours = 0;
|
||||
int minutes = 0;
|
||||
if (m.group(1) != null) {
|
||||
hours = Integer.parseInt(m.group(1));
|
||||
}
|
||||
if (m.group(2) != null) {
|
||||
minutes = Integer.parseInt(m.group(2));
|
||||
}
|
||||
minutes = minutes + (hours * 60);
|
||||
return minutes;
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
public static String MinutesToGracePeriodStr(int minutes) {
|
||||
int hours = minutes / 60;
|
||||
int remMinutes = minutes % 60;
|
||||
|
||||
String hourStr = " hours";
|
||||
if (hours == 1) {
|
||||
hourStr = " hour";
|
||||
}
|
||||
|
||||
String minStr = " minutes";
|
||||
if (remMinutes == 1) {
|
||||
minStr = " minute";
|
||||
}
|
||||
|
||||
if (hours > 0) {
|
||||
if (remMinutes == 0) {
|
||||
return hours + hourStr;
|
||||
}
|
||||
return hours + hourStr + " " + remMinutes + minStr;
|
||||
}
|
||||
return remMinutes + minStr;
|
||||
}
|
||||
|
||||
public static String debugDate(Calendar cal) {
|
||||
SimpleDateFormat print = new SimpleDateFormat("dd-MM-yyyy HH:mm:ssZ");
|
||||
return print.format(cal.getTime());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
package za.org.treehouse.HypoAlarm;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
public class PreAlarmNotify extends Service {
|
||||
private static final int preNotifyID = 2;
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
// Remove the notification in the notification bar
|
||||
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
||||
nm.cancel(preNotifyID);
|
||||
Log.d("AlarmNotify", "Pre-notification stopped.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
|
||||
Log.d("PreAlarmNotify", "Pre-notification started.");
|
||||
|
||||
// Get alarm time, and convert it into something readable.
|
||||
String alarmTimeStr = sharedPref.getString(getString(R.string.AlarmTimePref), MainActivity.defaultTimeStr);
|
||||
Calendar alarmCal = MainActivity.TimeStringToCalendar(alarmTimeStr);
|
||||
alarmTimeStr = MainActivity.formattedTime(getApplicationContext(), alarmCal);
|
||||
|
||||
Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_grey);
|
||||
final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
final NotificationCompat.Builder notification = new NotificationCompat.Builder(this)
|
||||
.setContentTitle(getString(R.string.preNotificationTitle))
|
||||
.setContentText(alarmTimeStr)
|
||||
.setSmallIcon(R.drawable.alarm_notification)
|
||||
.setLargeIcon(bm)
|
||||
.setOnlyAlertOnce(true)
|
||||
.setAutoCancel(false);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 16) {
|
||||
notification.setPriority(Notification.PRIORITY_DEFAULT);
|
||||
}
|
||||
|
||||
// Set up dismiss action
|
||||
Intent cancelAlarmIntent = new Intent(getBaseContext(), CancelAlarmReceiver.class);
|
||||
PendingIntent cancelAlarmPendingIntent = PendingIntent.getBroadcast(getBaseContext(), MainActivity.CANCEL_ALARM_REQUEST, cancelAlarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
|
||||
// Cancel the grace period if the user clears the notification
|
||||
notification.setDeleteIntent(cancelAlarmPendingIntent);
|
||||
// Allow the user to cancel by clicking a "Cancel" button
|
||||
notification.addAction(android.R.drawable.ic_menu_close_clear_cancel, getString(R.string.preNotificationCancellation), cancelAlarmPendingIntent);
|
||||
// Allow the user to cancel by selecting the ContentText or ContentTitle
|
||||
notification.setContentIntent(cancelAlarmPendingIntent);
|
||||
|
||||
nm.cancel(preNotifyID);
|
||||
nm.notify(preNotifyID, notification.build());
|
||||
|
||||
return super.onStartCommand(intent, flags, startId);
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package za.org.treehouse.HypoAlarm;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.preference.PreferenceManager;
|
||||
|
||||
public class PreAlarmReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(final Context context, Intent intent) {
|
||||
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
Boolean alarmActive = sharedPref.getBoolean(context.getString(R.string.AlarmActivePref), MainActivity.defaultActive);
|
||||
|
||||
if (alarmActive) {
|
||||
// Create notification
|
||||
Intent preNotifyIntent = new Intent(context, PreAlarmNotify.class);
|
||||
// The PreAlarmNotify service can either be stopped by calling CancelAlarmReceiver, or by waiting for AlarmReceiver to run
|
||||
context.startService(preNotifyIntent);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,116 +0,0 @@
|
||||
package za.org.treehouse.hypoalarm;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlarmManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Vibrator;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.Button;
|
||||
|
||||
// TODO See GlowPad.
|
||||
|
||||
// TODO sound audible alarm -- see AlarmKlaxon.java
|
||||
// TODO Lower alarm volume if in phone call (and detect phone call!)
|
||||
// TODO Snooze? set another alarm for the next half-hour (or grace_period / 2)?
|
||||
|
||||
public class AlarmAlertActivity extends Activity {
|
||||
// TODO correct alert lifetime
|
||||
private static final int ALERT_LIFE = 1000*10; //1000*60*2; // 2 minutes
|
||||
private static final long[] vPattern = {500, 500};
|
||||
private static Boolean userCancelled;
|
||||
private static Vibrator vibrator;
|
||||
private static Intent notifyIntent;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
Window window = getWindow();
|
||||
// Set to use the full screen
|
||||
int fullScreen = WindowManager.LayoutParams.FLAG_FULLSCREEN;
|
||||
// TODO if KitKat, mimic the main alarm
|
||||
fullScreen = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
|
||||
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
|
||||
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
|
||||
| fullScreen
|
||||
);
|
||||
setContentView(R.layout.alarm_alert);
|
||||
|
||||
notifyIntent = new Intent(getApplicationContext(), AlarmNotify.class);
|
||||
// Disable any current notifications
|
||||
stopService(notifyIntent);
|
||||
|
||||
// Turn off the alert activity, and switch to a notification
|
||||
new Handler().postDelayed(new Runnable() {
|
||||
public void run() {
|
||||
// Close the dialogue and switch to notification
|
||||
// if the Activity has not been closed by the user
|
||||
if (!userCancelled) {
|
||||
startService(notifyIntent);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
}, ALERT_LIFE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
userCancelled = false;
|
||||
|
||||
vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
|
||||
vibrator.vibrate(vPattern, 0);
|
||||
|
||||
// TODO change button to slide...
|
||||
// TODO change slide to circle slide? https://github.com/JesusM/HoloCircleSeekBar
|
||||
Button cancelButton = (Button) findViewById(R.id.cancel_dialog_button);
|
||||
cancelButton.setOnClickListener (new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
cancelGraceAlarm();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the user pressing the back/return button
|
||||
* TODO Do we want this to cancel the alarm and grace period?
|
||||
* TODO Or do we trigger the notification and finish() right away?
|
||||
* TODO probably most intuitive to cancel the alarms...
|
||||
*/
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
cancelGraceAlarm();
|
||||
/* OR:
|
||||
// Ensure that the we don't trigger the notification a second time
|
||||
userCancelled = true;
|
||||
startService(notifyIntent);
|
||||
finish();
|
||||
*/
|
||||
}
|
||||
|
||||
public void onStop() {
|
||||
vibrator.cancel();
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
private void cancelGraceAlarm() {
|
||||
AlarmManager graceManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
|
||||
Intent graceIntent = new Intent(getApplicationContext(), GraceReceiver.class);
|
||||
PendingIntent gracePendingIntent = PendingIntent.getBroadcast(getApplicationContext(), MainActivity.GRACE_REQUEST, graceIntent, 0);
|
||||
graceManager.cancel(gracePendingIntent);
|
||||
Log.d("AlarmAlertActivity", "Cancelled grace alarm.");
|
||||
// Ensure we don't load a notification now
|
||||
userCancelled = true;
|
||||
// Close the dialogue (stop vibration &c)
|
||||
finish();
|
||||
}
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
package za.org.treehouse.hypoalarm;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
|
||||
public class AlarmReceiver extends BroadcastReceiver {
|
||||
private static SharedPreferences sharedPref;
|
||||
private static AlarmManager alarmManager, graceManager;
|
||||
private static PendingIntent alarmPendingIntent, gracePendingIntent;
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
Boolean alarmActive = sharedPref.getBoolean(context.getString(R.string.AlarmActivePref), true);
|
||||
|
||||
if (alarmActive) {
|
||||
// Set a grace period alarm to send SMS
|
||||
int gracePeriod = sharedPref.getInt(context.getString(R.string.GracePeriodPref), 60);
|
||||
|
||||
Calendar graceCal = Calendar.getInstance();
|
||||
graceCal.set(Calendar.SECOND, 0);
|
||||
graceCal.add(Calendar.MINUTE, gracePeriod);
|
||||
graceManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
Intent graceIntent = new Intent(context, GraceReceiver.class);
|
||||
gracePendingIntent = PendingIntent.getBroadcast(context, MainActivity.GRACE_REQUEST, graceIntent, 0);
|
||||
graceManager.cancel(gracePendingIntent);
|
||||
graceManager.setExact(AlarmManager.RTC_WAKEUP, graceCal.getTimeInMillis(), gracePendingIntent);
|
||||
Log.d("AlarmReceiver", "Setting grace alarm for " + MainActivity.debugDate(graceCal));
|
||||
|
||||
// Allow user to acknowledge alarm and cancel grace alarm
|
||||
Intent alertActivityIntent = new Intent(context, AlarmAlertActivity.class);
|
||||
alertActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
|
||||
Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
|
||||
context.startActivity(alertActivityIntent);
|
||||
|
||||
|
||||
// Reset for tomorrow; as of API 19, setRepeating() is inexact, so we use setExact()
|
||||
String alarmTimeStr = sharedPref.getString(context.getString(R.string.AlarmTimePref), null);
|
||||
// Calendar automatically advances the day since alarmTimeStr is now in the past.
|
||||
Calendar cal = MainActivity.TimeStringToCalendar(alarmTimeStr);
|
||||
alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
alarmPendingIntent = PendingIntent.getBroadcast(context, MainActivity.ALARM_REQUEST, intent, 0);
|
||||
alarmManager.cancel(alarmPendingIntent);
|
||||
// TODO use set() for older APIs
|
||||
alarmManager.setExact(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), alarmPendingIntent);
|
||||
Log.d("AlarmReceiver", "Resetting alarm for " + MainActivity.debugDate(cal));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
package za.org.treehouse.hypoalarm;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
public class BootReceiver extends BroadcastReceiver {
|
||||
private static SharedPreferences sharedPref;
|
||||
private static AlarmManager alarmManager;
|
||||
private static PendingIntent alarmIntent;
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
|
||||
// Reset for tomorrow; as of API 19, setRepeating() is inexact, so we use setExact()
|
||||
String alarmTimeStr = sharedPref.getString(context.getString(R.string.AlarmTimePref), null);
|
||||
if (alarmTimeStr != null) {
|
||||
// If it's later than alarmTimeStr, Calendar automatically advances the day.
|
||||
Calendar cal = MainActivity.TimeStringToCalendar(alarmTimeStr);
|
||||
alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
|
||||
// TODO use set() for older APIs
|
||||
alarmManager.setExact(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), alarmIntent);
|
||||
Log.d("BootReceiver", "Setting alarm for "+MainActivity.debugDate(cal));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
package za.org.treehouse.hypoalarm;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class CancelGraceReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
AlarmManager graceManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
Intent graceIntent = new Intent(context, GraceReceiver.class);
|
||||
PendingIntent gracePendingIntent = PendingIntent.getBroadcast(context, MainActivity.GRACE_REQUEST, graceIntent, 0);
|
||||
graceManager.cancel(gracePendingIntent);
|
||||
Log.d("CancelGraceReceiver", "Cancelled grace alarm");
|
||||
|
||||
// Display toast
|
||||
Toast.makeText(context, context.getString(R.string.alarmCancelToast), Toast.LENGTH_LONG).show();
|
||||
|
||||
// Remove notification
|
||||
context.stopService(new Intent(context, AlarmNotify.class));
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
package za.org.treehouse.hypoalarm;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.PowerManager;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.telephony.SmsManager;
|
||||
import android.util.Log;
|
||||
|
||||
public class GraceReceiver extends BroadcastReceiver {
|
||||
private static SharedPreferences sharedPref;
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
Boolean alarmActive = sharedPref.getBoolean(context.getString(R.string.AlarmActivePref), true);
|
||||
|
||||
if (alarmActive) {
|
||||
String phoneNumber = sharedPref.getString(context.getString(R.string.PhoneNumberPref), null);
|
||||
String message = sharedPref.getString(context.getString(R.string.MessagePref), null);
|
||||
|
||||
SmsManager sms = SmsManager.getDefault();
|
||||
// TODO uncomment this:
|
||||
//sms.sendTextMessage(phoneNumber, null, message, null, null);
|
||||
Log.d("GraceReceiver", "Sending sms to " + phoneNumber);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,493 +0,0 @@
|
||||
package za.org.treehouse.hypoalarm;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.TimePickerDialog;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.provider.ContactsContract;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
import android.text.InputType;
|
||||
import android.text.format.DateFormat;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.Switch;
|
||||
import android.widget.TimePicker;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
// Settings: alarm time, phone number, custom message, grace period length
|
||||
// Set alarm
|
||||
// Display alarm notification
|
||||
// Display countdown (in seconds) or time till alarm fires (in minutes)
|
||||
// Reset alarm
|
||||
// Send SMS
|
||||
|
||||
// Possible settings:
|
||||
// More than one phone number?
|
||||
// Alerts via Whatsapp and other protocols?
|
||||
|
||||
// TODO: klaxon
|
||||
// TODO: glowpad dismissal (or circular seekbar)
|
||||
|
||||
public class MainActivity extends ActionBarActivity {
|
||||
public static int ALARM_REQUEST = 1;
|
||||
public static int GRACE_REQUEST = 2;
|
||||
public static int CANCEL_GRACE_REQUEST = 3;
|
||||
private static Switch alarmActiveSwitch;
|
||||
private static Button alarmTimeButton;
|
||||
private static Spinner gracePeriodSpinner;
|
||||
private static EditText phoneNumberButton;
|
||||
private static EditText messageButton;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.add(R.id.container, new MainFragment())
|
||||
.commit();
|
||||
}
|
||||
}
|
||||
|
||||
// Main screen
|
||||
public static class MainFragment extends Fragment {
|
||||
|
||||
public MainFragment() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
|
||||
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
|
||||
return rootView;
|
||||
}
|
||||
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
|
||||
final SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
||||
|
||||
// Allow alarm to activate
|
||||
Boolean alarmActive = sharedPref.getBoolean(getString(R.string.AlarmActivePref), true);
|
||||
alarmActiveSwitch = (Switch) getActivity().findViewById(R.id.alarm_active_switch);
|
||||
alarmActiveSwitch.setChecked(alarmActive);
|
||||
alarmActiveSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
|
||||
AlarmManager alarmManager, graceManager;
|
||||
PendingIntent alarmPendingIntent, gracePendingIntent;
|
||||
SharedPreferences.Editor editor = sharedPref.edit();
|
||||
|
||||
editor.putBoolean(getString(R.string.AlarmActivePref), b);
|
||||
editor.commit();
|
||||
|
||||
if (!b) {
|
||||
// Cancel any current alarm
|
||||
alarmManager = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE);
|
||||
Intent alarmIntent = new Intent(getActivity(), AlarmReceiver.class);
|
||||
alarmPendingIntent = PendingIntent.getBroadcast(getActivity(), ALARM_REQUEST, alarmIntent, 0);
|
||||
alarmManager.cancel(alarmPendingIntent);
|
||||
// Cancel any grace period
|
||||
graceManager = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE);
|
||||
Intent graceIntent = new Intent(getActivity(), GraceReceiver.class);
|
||||
gracePendingIntent = PendingIntent.getBroadcast(getActivity(), GRACE_REQUEST, graceIntent, 0);
|
||||
graceManager.cancel(gracePendingIntent);
|
||||
// Stop any notifications
|
||||
getActivity().stopService(new Intent(getActivity(), AlarmNotify.class));
|
||||
Log.d("MainActivity", "Alarms cancelled");
|
||||
Toast.makeText(getActivity().getApplicationContext(), getString(R.string.alarmCancelled), Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
// Activate the alarm
|
||||
DialogFragment alarmFragment = new TimePickerFragment();
|
||||
alarmFragment.show(getActivity().getSupportFragmentManager(), "alarmTimePicker");
|
||||
alarmFragment.dismiss();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Set alarm time
|
||||
String defaultTimeStr = "09:00";
|
||||
String alarmTimeStr = verifyTimeString(sharedPref.getString(getString(R.string.AlarmTimePref), defaultTimeStr));
|
||||
alarmTimeButton = (Button) getActivity().findViewById(R.id.alarm_time);
|
||||
|
||||
// TODO remove this testing stuff
|
||||
Calendar c = Calendar.getInstance();
|
||||
c.add(Calendar.MINUTE, 1);
|
||||
alarmTimeStr = CalendarToTimeString(c);
|
||||
|
||||
alarmTimeButton.setText(alarmTimeStr);
|
||||
alarmTimeButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
DialogFragment alarmFragment = new TimePickerFragment();
|
||||
alarmFragment.show(getActivity().getSupportFragmentManager(), "alarmTimePicker");
|
||||
}
|
||||
});
|
||||
|
||||
// TODO remove these simulated clicks
|
||||
DialogFragment alarmFragment = new TimePickerFragment();
|
||||
alarmFragment.show(getActivity().getSupportFragmentManager(), "alarmTimePicker");
|
||||
alarmFragment.dismiss();
|
||||
|
||||
|
||||
// Set grace period
|
||||
int defaultGrace = 60;
|
||||
int gracePeriod = sharedPref.getInt(getString(R.string.GracePeriodPref), defaultGrace);
|
||||
gracePeriodSpinner = (Spinner) getActivity().findViewById(R.id.grace_period);
|
||||
gracePeriodSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
final SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
||||
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
|
||||
Object value = parent.getItemAtPosition(pos);
|
||||
SharedPreferences.Editor editor = sharedPref.edit();
|
||||
int minutes = GracePeriodToMinutes(value.toString());
|
||||
editor.putInt(getString(R.string.GracePeriodPref), minutes);
|
||||
editor.commit();
|
||||
/*
|
||||
CharSequence text = "Grace period is " + GracePeriodToMinutes(value.toString()) + " or " + MinutesToGracePeriodStr(GracePeriodToMinutes(value.toString()))+ ".";
|
||||
Toast.makeText(getActivity().getApplicationContext(), text, Toast.LENGTH_SHORT).show();
|
||||
*/
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
}
|
||||
});
|
||||
// Set value of drop-down list to value of gracePeriodStr
|
||||
ArrayAdapter gracePeriodSpinnerAdapter = (ArrayAdapter) gracePeriodSpinner.getAdapter();
|
||||
int spinnerPosition = gracePeriodSpinnerAdapter.getPosition(MinutesToGracePeriodStr(gracePeriod));
|
||||
gracePeriodSpinner.setSelection(spinnerPosition);
|
||||
|
||||
// Set phone number
|
||||
String phoneNumberStr = sharedPref.getString(getString(R.string.PhoneNumberPref), null);
|
||||
phoneNumberButton = (EditText) getActivity().findViewById(R.id.phone_number);
|
||||
phoneNumberButton.setText(phoneNumberStr);
|
||||
phoneNumberButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
DialogFragment phoneFragment = new PhonePickerFragment();
|
||||
phoneFragment.show(getActivity().getSupportFragmentManager(), "phoneNumberPicker");
|
||||
}
|
||||
});
|
||||
|
||||
// Set message
|
||||
String messageStr = sharedPref.getString(getString(R.string.MessagePref), getString(R.string.defaultMessage));
|
||||
messageButton = (EditText) getActivity().findViewById(R.id.message);
|
||||
messageButton.setText(messageStr);
|
||||
messageButton.setOnClickListener(new View.OnClickListener() {
|
||||
SharedPreferences sharedPref;
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
final SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
||||
|
||||
String messageStr = sharedPref.getString(getString(R.string.MessagePref), getString(R.string.defaultMessage));
|
||||
|
||||
final InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());
|
||||
|
||||
final EditText messageInput = new EditText(getActivity());
|
||||
messageInput.setInputType(InputType.TYPE_CLASS_TEXT |
|
||||
InputType.TYPE_TEXT_FLAG_MULTI_LINE |
|
||||
InputType.TYPE_TEXT_FLAG_CAP_SENTENCES |
|
||||
InputType.TYPE_TEXT_FLAG_AUTO_CORRECT);
|
||||
if (messageButton != null) {
|
||||
messageInput.setText(messageButton.getText().toString());
|
||||
}
|
||||
messageInput.setSelection(messageInput.getText().length());
|
||||
alert.setView(messageInput);
|
||||
alert.setMessage(getString(R.string.setMessage));
|
||||
|
||||
|
||||
alert.setPositiveButton("OK", new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
String value = messageInput.getText().toString();
|
||||
if (value.compareTo("") == 0) {
|
||||
value = getString(R.string.defaultMessage);
|
||||
}
|
||||
SharedPreferences.Editor editor = sharedPref.edit();
|
||||
editor.putString(getString(R.string.MessagePref), value);
|
||||
editor.commit();
|
||||
messageButton.setText(value);
|
||||
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
|
||||
}
|
||||
});
|
||||
alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
|
||||
// Canceled.
|
||||
}
|
||||
});
|
||||
alert.show();
|
||||
messageInput.requestFocus();
|
||||
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Alarm time picker
|
||||
public static class TimePickerFragment extends DialogFragment implements TimePickerDialog.OnTimeSetListener {
|
||||
SharedPreferences sharedPref;
|
||||
private AlarmManager alarmManager;
|
||||
private PendingIntent alarmPendingIntent;
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
sharedPref = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
||||
// Use the current set time as the default value for the picker
|
||||
String alarmTimeStr = alarmTimeButton.getText().toString();
|
||||
Calendar cal = TimeStringToCalendar(alarmTimeStr);
|
||||
int hour = cal.get(Calendar.HOUR_OF_DAY);
|
||||
int minute = cal.get(Calendar.MINUTE);
|
||||
|
||||
// Create a new instance of TimePickerDialog and return it
|
||||
return new TimePickerDialog(getActivity(), this, hour, minute,
|
||||
DateFormat.is24HourFormat(getActivity()));
|
||||
}
|
||||
|
||||
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
|
||||
String alarmStr = HourMinuteToTimeString(hourOfDay, minute);
|
||||
Boolean alarmActive = sharedPref.getBoolean(getString(R.string.AlarmActivePref), true);
|
||||
|
||||
// Set time preference
|
||||
SharedPreferences.Editor editor = sharedPref.edit();
|
||||
editor.putString(getString(R.string.AlarmTimePref), alarmStr);
|
||||
editor.commit();
|
||||
|
||||
Button alarm_time = (Button) getActivity().findViewById(R.id.alarm_time);
|
||||
alarm_time.setText(alarmStr);
|
||||
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTimeInMillis(System.currentTimeMillis());
|
||||
cal.set(Calendar.HOUR_OF_DAY, hourOfDay);
|
||||
cal.set(Calendar.MINUTE, minute);
|
||||
cal.set(Calendar.SECOND, 0);
|
||||
|
||||
if (alarmActive) {
|
||||
// Initialise alarm, which displays a dialog and system alert, and
|
||||
// calls AlarmManager with grace_period as the delay
|
||||
// which in turn, sends SMS if dialog is not exited.
|
||||
alarmManager = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE);
|
||||
Intent alarmIntent = new Intent(getActivity(), AlarmReceiver.class);
|
||||
alarmPendingIntent = PendingIntent.getBroadcast(getActivity(), ALARM_REQUEST, alarmIntent, 0);
|
||||
// Cancel any existing alarms
|
||||
alarmManager.cancel(alarmPendingIntent);
|
||||
// Set or reset alarm
|
||||
// TODO use set() for older APIs
|
||||
alarmManager.setExact(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), alarmPendingIntent);
|
||||
Log.d("MainActivity", "Setting alarm for " + MainActivity.debugDate(cal));
|
||||
|
||||
// Set boot receiver, so alarm restarts on boot
|
||||
ComponentName receiver = new ComponentName(getActivity(), BootReceiver.class);
|
||||
PackageManager pm = getActivity().getPackageManager();
|
||||
pm.setComponentEnabledSetting(receiver,
|
||||
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
|
||||
PackageManager.DONT_KILL_APP);
|
||||
|
||||
// Display toast
|
||||
CharSequence text = getString(R.string.alarmSetToast) + " " + alarmStr;
|
||||
Toast.makeText(getActivity().getApplicationContext(), text, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class PhonePickerFragment extends DialogFragment {
|
||||
SharedPreferences sharedPref;
|
||||
EditText phoneButton;
|
||||
EditText phoneInput;
|
||||
Button contactsButton;
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
final SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
||||
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());
|
||||
alert.setMessage(R.string.setPhoneNumber);
|
||||
|
||||
LayoutInflater inflater = getActivity().getLayoutInflater();
|
||||
View dialogView = inflater.inflate(R.layout.phone_dialog, null);
|
||||
alert.setView(dialogView);
|
||||
|
||||
phoneButton = (EditText) getActivity().findViewById(R.id.phone_number);
|
||||
phoneInput = (EditText) dialogView.findViewById(R.id.dialog_phone_number);
|
||||
phoneInput.setText(phoneButton.getText().toString());
|
||||
phoneInput.setSelection(phoneInput.getText().length());
|
||||
contactsButton = (Button) dialogView.findViewById(R.id.dialog_contacts_button);
|
||||
|
||||
alert.setPositiveButton("OK", new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
String value = phoneInput.getText().toString();
|
||||
SharedPreferences.Editor editor = sharedPref.edit();
|
||||
editor.putString(getString(R.string.PhoneNumberPref), value);
|
||||
editor.commit();
|
||||
phoneButton.setText(value);
|
||||
}
|
||||
});
|
||||
alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
// Cancelled
|
||||
}
|
||||
});
|
||||
contactsButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
|
||||
intent.setType(ContactsContract.CommonDataKinds.Phone.CONTENT_TYPE);
|
||||
startActivityForResult(intent, 1);
|
||||
}
|
||||
});
|
||||
return alert.create();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (data != null) {
|
||||
Uri uri = data.getData();
|
||||
if (uri != null) {
|
||||
Cursor c = null;
|
||||
try {
|
||||
c = getActivity().getContentResolver().query(uri, new String[]{
|
||||
ContactsContract.CommonDataKinds.Phone.NUMBER,
|
||||
ContactsContract.CommonDataKinds.Phone.TYPE },
|
||||
null, null, null);
|
||||
|
||||
if (c != null && c.moveToFirst()) {
|
||||
String number = c.getString(0);
|
||||
phoneInput.setText(number);
|
||||
}
|
||||
} finally {
|
||||
if (c != null) {
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static String verifyTimeString(String timeStr) {
|
||||
return CalendarToTimeString(TimeStringToCalendar(timeStr));
|
||||
}
|
||||
public static String HourMinuteToTimeString(int hour, int minute) {
|
||||
return CalendarToTimeString(TimeStringToCalendar(hour + ":" + minute));
|
||||
}
|
||||
|
||||
public static Calendar TimeStringToCalendar(String dateString) {
|
||||
Date date;
|
||||
Calendar cal;
|
||||
final String FORMAT="HH:mm"; // z = time zone
|
||||
SimpleDateFormat sdf = new SimpleDateFormat(FORMAT, Locale.getDefault());
|
||||
sdf.format(new Date());
|
||||
try {
|
||||
date = sdf.parse(dateString);
|
||||
// date has the correct hour and minute, but the incorrect day,
|
||||
// month and year information. To get information out of it, we need to
|
||||
// convert it to a Calendar.
|
||||
Calendar dateCal = Calendar.getInstance();
|
||||
dateCal.setTime(date);
|
||||
|
||||
// Create a new calendar with the correct day, month and year,
|
||||
// and set the hour and minute by hand.
|
||||
cal = Calendar.getInstance();
|
||||
cal.set(Calendar.HOUR, dateCal.get(Calendar.HOUR));
|
||||
cal.set(Calendar.MINUTE, dateCal.get(Calendar.MINUTE));
|
||||
cal.set(Calendar.SECOND, 0);
|
||||
// Ensure that this date is in the future
|
||||
if (date.before(new Date())) {
|
||||
cal.add(Calendar.DAY_OF_MONTH, 1);
|
||||
}
|
||||
return cal;
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public static String CalendarToTimeString(Calendar cal) {
|
||||
final String FORMAT="HH:mm";
|
||||
SimpleDateFormat sdf = new SimpleDateFormat(FORMAT, Locale.getDefault());
|
||||
return sdf.format(cal.getTime());
|
||||
}
|
||||
public static String debugDate(Calendar cal) {
|
||||
SimpleDateFormat print = new SimpleDateFormat("dd-MM-yyyy HH:mm:ssZ");
|
||||
return print.format(cal.getTime());
|
||||
}
|
||||
public static int GracePeriodToMinutes(String gracePeriod) {
|
||||
Pattern p = Pattern.compile("(?:(\\d+)\\s+hours?)?\\s*(?:(\\d+)\\s+minutes?)?");
|
||||
|
||||
Matcher m = p.matcher(gracePeriod);
|
||||
if (m.find()) {
|
||||
int hours = 0;
|
||||
int minutes = 0;
|
||||
if (m.group(1) != null) {
|
||||
hours = Integer.parseInt(m.group(1));
|
||||
}
|
||||
if (m.group(2) != null) {
|
||||
minutes = Integer.parseInt(m.group(2));
|
||||
}
|
||||
minutes = minutes + (hours * 60);
|
||||
return minutes;
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
public static String MinutesToGracePeriodStr(int minutes) {
|
||||
int hours = minutes / 60;
|
||||
int remMinutes = minutes % 60;
|
||||
|
||||
String hourStr = " hours";
|
||||
if (hours == 1) {
|
||||
hourStr = " hour";
|
||||
}
|
||||
|
||||
String minStr = " minutes";
|
||||
if (remMinutes == 1) {
|
||||
minStr = " minute";
|
||||
}
|
||||
|
||||
if (hours > 0) {
|
||||
if (remMinutes == 0) {
|
||||
return hours + hourStr;
|
||||
}
|
||||
return hours + hourStr + " " + remMinutes + minStr;
|
||||
}
|
||||
return remMinutes + minStr;
|
||||
}
|
||||
|
||||
|
||||
}
|
BIN
HypoAlarm/src/main/res/drawable-hdpi/ic_alarm_activated.png
Normal file
After Width: | Height: | Size: 5.9 KiB |
BIN
HypoAlarm/src/main/res/drawable-hdpi/ic_alarm_normal.png
Normal file
After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 738 B After Width: | Height: | Size: 738 B |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 6.4 KiB |
Before Width: | Height: | Size: 8.2 KiB |
BIN
HypoAlarm/src/main/res/drawable-mdpi/ic_alarm_activated.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
HypoAlarm/src/main/res/drawable-mdpi/ic_alarm_normal.png
Normal file
After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 538 B After Width: | Height: | Size: 538 B |
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 6.0 KiB |
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 4.2 KiB |
BIN
HypoAlarm/src/main/res/drawable-xhdpi/ic_alarm_activated.png
Normal file
After Width: | Height: | Size: 9.3 KiB |
BIN
HypoAlarm/src/main/res/drawable-xhdpi/ic_alarm_normal.png
Normal file
After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 964 B After Width: | Height: | Size: 964 B |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 9.8 KiB |
Before Width: | Height: | Size: 12 KiB |
BIN
HypoAlarm/src/main/res/drawable-xxhdpi/ic_alarm_activated.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
HypoAlarm/src/main/res/drawable-xxhdpi/ic_alarm_normal.png
Normal file
After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
BIN
HypoAlarm/src/main/res/drawable-xxhdpi/ic_launcher_grey.png
Normal file
After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 66 KiB |
27
HypoAlarm/src/main/res/drawable/ic_alarm.xml
Normal file
@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2012 The Android Open Source Project
|
||||
|
||||
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.
|
||||
-->
|
||||
<!-- Used with alarm widget. -->
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:state_enabled="true" android:state_active="false" android:state_focused="false"
|
||||
android:drawable="@drawable/ic_alarm_normal_layer"/>
|
||||
<item
|
||||
android:state_enabled="true" android:state_active="true" android:state_focused="false"
|
||||
android:drawable="@drawable/ic_alarm_activated_layer" />
|
||||
<item
|
||||
android:state_enabled="true" android:state_active="false" android:state_focused="true"
|
||||
android:drawable="@drawable/ic_alarm_activated_layer" />
|
||||
</selector>
|
31
HypoAlarm/src/main/res/drawable/ic_alarm_activated_layer.xml
Normal file
@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2012 The Android Open Source Project
|
||||
|
||||
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.
|
||||
-->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
|
||||
<solid android:color="#58c233"/>
|
||||
<size
|
||||
android:width="@dimen/alarm_widget_circle_size"
|
||||
android:height="@dimen/alarm_widget_circle_size" />
|
||||
</shape>
|
||||
</item>
|
||||
<item
|
||||
android:top="@dimen/alarm_widget_asset_margin"
|
||||
android:right="@dimen/alarm_widget_asset_margin"
|
||||
android:bottom="@dimen/alarm_widget_asset_margin"
|
||||
android:left="@dimen/alarm_widget_asset_margin"
|
||||
android:drawable="@drawable/ic_alarm_activated" />
|
||||
</layer-list>
|
32
HypoAlarm/src/main/res/drawable/ic_alarm_normal_layer.xml
Normal file
@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2012 The Android Open Source Project
|
||||
|
||||
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.
|
||||
-->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- A fake circle to fix the size of this layer asset. -->
|
||||
<item>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
|
||||
<solid android:color="#00000000"/>
|
||||
<size
|
||||
android:width="@dimen/alarm_widget_circle_size"
|
||||
android:height="@dimen/alarm_widget_circle_size" />
|
||||
</shape>
|
||||
</item>
|
||||
<item
|
||||
android:top="@dimen/alarm_widget_asset_margin"
|
||||
android:right="@dimen/alarm_widget_asset_margin"
|
||||
android:bottom="@dimen/alarm_widget_asset_margin"
|
||||
android:left="@dimen/alarm_widget_asset_margin"
|
||||
android:drawable="@drawable/ic_alarm_normal" />
|
||||
</layer-list>
|
24
HypoAlarm/src/main/res/drawable/ic_outerring.xml
Normal file
@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2011 The Android Open Source Project
|
||||
|
||||
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.
|
||||
-->
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval"
|
||||
>
|
||||
<size android:height="@dimen/alarm_outerring_diameter"
|
||||
android:width="@dimen/alarm_outerring_diameter" />
|
||||
<solid android:color="#00000000" />
|
||||
<stroke android:color="#1affffff" android:width="2dp" />
|
||||
</shape>
|
9
HypoAlarm/src/main/res/layout-v14/activeswitch.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<Switch
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/alarm_active_switch"
|
||||
android:layout_gravity="left" />
|
||||
</merge>
|
9
HypoAlarm/src/main/res/layout/activeswitch.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<ToggleButton
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/alarm_active_switch"
|
||||
android:layout_gravity="left" />
|
||||
</merge>
|
@ -1,40 +1,39 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:context=".AlarmNotificationActivity"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".AlarmNotificationActivity">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/cancel_dialog_imageView"
|
||||
android:src="@drawable/hypoalarm"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="60dp"/>
|
||||
android:background="@android:color/black">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:text="HypoAlarm!"
|
||||
android:text="@string/app_name"
|
||||
android:id="@+id/cancel_dialog_title"
|
||||
android:layout_below="@+id/cancel_dialog_imageView"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="25dp" />
|
||||
android:layout_marginTop="@dimen/alarm_widget_vertical_margin" />
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="I'm awake"
|
||||
android:id="@+id/cancel_dialog_button"
|
||||
android:layout_marginTop="25dp"
|
||||
<net.frakbot.glowpadbackport.GlowPadView
|
||||
android:id="@+id/cancel_glowpad"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_below="@+id/cancel_dialog_title"
|
||||
android:layout_centerHorizontal="true" />
|
||||
android:background="@android:color/black"
|
||||
android:visibility="visible"
|
||||
android:gravity="center"
|
||||
|
||||
app:targetDrawables="@array/glowpad_target"
|
||||
app:handleDrawable="@drawable/ic_alarm_activated"
|
||||
app:innerRadius="@dimen/glowpadview_inner_radius"
|
||||
app:outerRadius="@dimen/glowpadview_target_placement_radius"
|
||||
app:outerRingDrawable="@drawable/ic_outerring"
|
||||
app:snapMargin="@dimen/glowpadview_snap_margin"
|
||||
app:glowRadius="@dimen/glowpadview_glow_radius"
|
||||
app:pointDrawable="@drawable/ic_glowdot" />
|
||||
|
||||
</RelativeLayout>
|
||||
</FrameLayout>
|
@ -1,8 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:fillViewport="true" >
|
||||
|
||||
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:stretchColumns="0"
|
||||
android:shrinkColumns="1"
|
||||
android:dividerPadding="10dp"
|
||||
@ -36,12 +41,9 @@
|
||||
android:id="@+id/alarm_active_text"
|
||||
android:layout_column="0" />
|
||||
|
||||
<Switch
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/alarm_active_switch"
|
||||
android:layout_column="1"
|
||||
android:layout_gravity="left" />
|
||||
<include
|
||||
layout="@layout/activeswitch"
|
||||
android:layout_column="1" />
|
||||
</TableRow>
|
||||
|
||||
<TableRow
|
||||
@ -55,13 +57,12 @@
|
||||
android:id="@+id/alarm_time_text"
|
||||
android:layout_column="0" />
|
||||
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/alarm_time"
|
||||
android:gravity="center_vertical"
|
||||
style="?android:attr/borderlessButtonStyle"
|
||||
style="@style/borderless_button"
|
||||
android:layout_column="1" />
|
||||
</TableRow>
|
||||
|
||||
@ -108,6 +109,28 @@
|
||||
android:layout_column="1" />
|
||||
</TableRow>
|
||||
|
||||
<TableRow
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/ringtone_text"
|
||||
android:id="@+id/ringtone_text"
|
||||
android:layout_column="0" />
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/ringtone"
|
||||
android:focusable="false"
|
||||
android:focusableInTouchMode="false"
|
||||
android:clickable="true"
|
||||
android:gravity="left"
|
||||
android:layout_column="1" />
|
||||
</TableRow>
|
||||
|
||||
<TableRow
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_width="fill_parent"
|
||||
@ -129,10 +152,14 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/message"
|
||||
android:inputType="textShortMessage|textMultiLine|textCapSentences"
|
||||
android:focusable="false"
|
||||
android:focusableInTouchMode="false"
|
||||
android:clickable="true"
|
||||
android:layout_span="2"
|
||||
android:layout_column="0" />
|
||||
</TableRow>
|
||||
|
||||
</TableLayout>
|
||||
|
||||
</ScrollView>
|
BIN
HypoAlarm/src/main/res/raw/fallbackring.ogg
Normal file
33
HypoAlarm/src/main/res/values-small/dimens.xml
Normal file
@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Default screen margins, per the Android Design guidelines. -->
|
||||
<dimen name="activity_horizontal_margin">8dp</dimen>
|
||||
<dimen name="activity_vertical_margin">8dp</dimen>
|
||||
|
||||
|
||||
<!-- Default target placement radius for GlowPadView. Should be 1/2 of outerring diameter. -->
|
||||
<dimen name="glowpadview_target_placement_radius">110dip</dimen>
|
||||
|
||||
<!-- Default glow radius for GlowPadView -->
|
||||
<dimen name="glowpadview_glow_radius">50dip</dimen>
|
||||
|
||||
<!-- Default distance beyond which GlowPadView snaps to the matching target -->
|
||||
<dimen name="glowpadview_snap_margin">20dip</dimen>
|
||||
|
||||
<!-- Default distance from each snap target that GlowPadView considers a "hit" -->
|
||||
<dimen name="glowpadview_inner_radius">10dip</dimen>
|
||||
|
||||
<!-- Size of lockscreen outerring -->
|
||||
<dimen name="alarm_outerring_diameter">220dp</dimen>
|
||||
|
||||
<!-- Circle size for incoming call widget's each item. -->
|
||||
<dimen name="alarm_widget_circle_size">72dp</dimen>
|
||||
|
||||
<!-- Margin used for alarm widget's icon for each item.
|
||||
This should be same as "(alarm_widget_circle_size - icon_size)/2".
|
||||
Right now answer/decline/reject icons have 38dp width/height.
|
||||
So, (72 - 38)/2 ==> 17dp -->
|
||||
<dimen name="alarm_widget_asset_margin">11dp</dimen>
|
||||
|
||||
<dimen name="alarm_widget_vertical_margin">20dp</dimen>
|
||||
</resources>
|
4
HypoAlarm/src/main/res/values-small/styles.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="borderless_button"></style>
|
||||
</resources>
|
9
HypoAlarm/src/main/res/values/arrays.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<array name="glowpad_target">
|
||||
<item>@null</item>
|
||||
<item>@null</item>
|
||||
<item>@null</item>
|
||||
<item>@drawable/ic_alarm</item>
|
||||
</array>
|
||||
</resources>
|
@ -3,4 +3,31 @@
|
||||
<!-- Default screen margins, per the Android Design guidelines. -->
|
||||
<dimen name="activity_horizontal_margin">16dp</dimen>
|
||||
<dimen name="activity_vertical_margin">16dp</dimen>
|
||||
|
||||
<!-- Default target placement radius for GlowPadView. Should be 1/2 of outerring diameter. -->
|
||||
<dimen name="glowpadview_target_placement_radius">135dip</dimen>
|
||||
|
||||
<!-- Default glow radius for GlowPadView -->
|
||||
<dimen name="glowpadview_glow_radius">75dip</dimen>
|
||||
|
||||
<!-- Default distance beyond which GlowPadView snaps to the matching target -->
|
||||
<dimen name="glowpadview_snap_margin">40dip</dimen>
|
||||
|
||||
<!-- Default distance from each snap target that GlowPadView considers a "hit" -->
|
||||
<dimen name="glowpadview_inner_radius">15dip</dimen>
|
||||
|
||||
<!-- Size of lockscreen outerring -->
|
||||
<dimen name="alarm_outerring_diameter">270dp</dimen>
|
||||
|
||||
<!-- Circle size for incoming call widget's each item. -->
|
||||
<dimen name="alarm_widget_circle_size">94dp</dimen>
|
||||
|
||||
<!-- Margin used for alarm widget's icon for each item.
|
||||
This should be same as "(alarm_widget_circle_size - icon_size)/2".
|
||||
Right now answer/decline/reject icons have 38dp width/height.
|
||||
So, (94 - 38)/2 ==> 28dp -->
|
||||
<dimen name="alarm_widget_asset_margin">11dp</dimen>
|
||||
|
||||
<dimen name="alarm_widget_vertical_margin">60dp</dimen>
|
||||
|
||||
</resources>
|
@ -7,6 +7,8 @@
|
||||
|
||||
<string name="alarm_notification">Text message pending</string>
|
||||
|
||||
<string name="pre_alarm_notification">Upcoming alarm</string>
|
||||
|
||||
<string-array name="grace_period_array">
|
||||
<item>10 minutes</item>
|
||||
<item>15 minutes</item>
|
||||
@ -27,6 +29,8 @@
|
||||
|
||||
<string name="phone_number_text">Phone number</string>
|
||||
|
||||
<string name="ringtone_text">Alarm Tone</string>
|
||||
|
||||
<string name="message_text">Message</string>
|
||||
|
||||
<string name="AlarmActivePref">AlarmActive</string>
|
||||
@ -35,6 +39,8 @@
|
||||
|
||||
<string name="GracePeriodPref">GracePeriod</string>
|
||||
|
||||
<string name="RingtonePref">Ringtone</string>
|
||||
|
||||
<string name="PhoneNumberPref">PhoneNumber</string>
|
||||
|
||||
<string name="MessagePref">Message</string>
|
||||
@ -47,7 +53,9 @@
|
||||
|
||||
<string name="alarmSetToast">HypoAlarm set to </string>
|
||||
|
||||
<string name="alarmCancelToast">HypoAlarm text message cancelled</string>
|
||||
<string name="alarmCancelToast">HypoAlarm cancelled</string>
|
||||
|
||||
<string name="graceCancelToast">HypoAlarm text message cancelled</string>
|
||||
|
||||
<string name="defaultMessage">Hi, I haven\'t responded to my alarm today. Please contact me to make sure I\'m awake.</string>
|
||||
|
||||
@ -55,6 +63,10 @@
|
||||
|
||||
<string name="notificationCancellation">Cancel</string>
|
||||
|
||||
<string name="preNotificationTitle">Upcoming HypoAlarm</string>
|
||||
|
||||
<string name="preNotificationCancellation">Dismiss Now</string>
|
||||
|
||||
<string name="alarmCancelled">All HypoAlarms cancelled</string>
|
||||
|
||||
</resources>
|
||||
|
@ -1,8 +1,8 @@
|
||||
<resources>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat">
|
||||
<!-- Customize your theme here. -->
|
||||
</style>
|
||||
|
||||
<style name="borderless_button">?android:attr/borderlessButtonStyle</style>
|
||||
</resources>
|
||||
|
@ -1 +1,3 @@
|
||||
include ':HypoAlarm', ':GlowPadBackport'
|
||||
//include ':HypoAlarm', ':GlowPadBackport', ':SeekArc'
|
||||
//include ':HypoAlarm', ':GlowPadBackport'
|
||||
include ':HypoAlarm'
|