Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,15 @@
# android
<b>Testing Hospitalization</b>
<br>
<br>
1. You can add custom 'hospitals' (locations that will trigger the survey) in addHospitalForDebugging() of HospitalizationService.java. There should already be 1 custom hospital, so you can just follow that format to add as many as you'd like.
<br><br>
2. You'll probably want to change the trigger times so you're not sitting around for 5 hours. You'll want to change <b>Constants.GEOFENCE_LOITER_TIME_MILLIS</b> (amount of time to mark user as hospitalized) and <b>Constants.SURVEY_TRIGGER_MILLIS</b> (amount of time to wait after user exits hospital before displaying survey) in Constants.java.
<br><br>
3. Install the app on your device once you've set the above variables.
3a. If this is NOT a fresh install (i.e. you previously installed the app and decided to change some variables and re-install), you'll need to press the 'RESTART SERVICE' button after installation.
<br><br>
4. Assuming you've placed a hospital where your current location is, wait for <b>GEOFENCE_LOITER_TIME_MILLIS</b> (I would wait an extra minute or two to account for the geofence setup time). This will mark the user as hospitalized (you will NOT receive any indication of this on your phone, but it will display in the Android Studio logs).
<br><br>
5. To mimic a user exiting a location, I use a third-party application called "Mock Locations" (https://play.google.com/store/apps/details?id=ru.gavrikov.mocklocations&hl=en). You need to enable 'Allow mock locations' in your phone's developer options (Settings -> Developer Options). Follow the app's instructions to mimic leaving the 'hospital'.
<br><br>
6. Wait for <b>SURVEY_TRIGGER_MILLIS</b> and you should receive a notification that upon clicking will take you to the app and display a survey.
66 changes: 61 additions & 5 deletions app/app.iml
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,34 @@
<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/exploded-aar/com.android.support/appcompat-v7/22.2.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-v4/22.2.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.afollestad/material-dialogs/0.6.4.7/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/appcompat-v7/22.2.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/mediarouter-v7/22.0.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/recyclerview-v7/22.0.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-v4/22.2.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.google.android.gms/play-services-ads/7.5.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.google.android.gms/play-services-analytics/7.5.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.google.android.gms/play-services-appindexing/7.5.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.google.android.gms/play-services-appinvite/7.5.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.google.android.gms/play-services-appstate/7.5.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.google.android.gms/play-services-base/7.5.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.google.android.gms/play-services-cast/7.5.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.google.android.gms/play-services-drive/7.5.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.google.android.gms/play-services-fitness/7.5.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.google.android.gms/play-services-games/7.5.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.google.android.gms/play-services-gcm/7.5.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.google.android.gms/play-services-identity/7.5.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.google.android.gms/play-services-location/7.5.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.google.android.gms/play-services-maps/7.5.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.google.android.gms/play-services-nearby/7.5.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.google.android.gms/play-services-panorama/7.5.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.google.android.gms/play-services-plus/7.5.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.google.android.gms/play-services-safetynet/7.5.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.google.android.gms/play-services-wallet/7.5.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.google.android.gms/play-services-wearable/7.5.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.google.android.gms/play-services/7.5.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.scottyab/aes-crypto/0.0.3/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.scottyab/secure-preferences-lib/0.1.3/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jacoco" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/javaResources" />
Expand All @@ -84,11 +110,41 @@
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
</content>
<orderEntry type="jdk" jdkName="Android API 22 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" exported="" name="support-v4-22.2.0" level="project" />
<orderEntry type="library" exported="" name="support-annotations-22.2.0" level="project" />
<orderEntry type="library" exported="" name="appcompat-v7-22.2.0" level="project" />
<orderEntry type="library" exported="" name="material-dialogs-0.6.4.7" level="project" />
<orderEntry type="library" exported="" name="play-services-base-7.5.0" level="project" />
<orderEntry type="library" exported="" name="play-services-appinvite-7.5.0" level="project" />
<orderEntry type="library" exported="" name="play-services-panorama-7.5.0" level="project" />
<orderEntry type="library" exported="" name="play-services-drive-7.5.0" level="project" />
<orderEntry type="library" exported="" name="aes-crypto-0.0.3" level="project" />
<orderEntry type="library" exported="" name="play-services-gcm-7.5.0" level="project" />
<orderEntry type="library" exported="" name="library-1.0.18" level="project" />
<orderEntry type="library" exported="" name="play-services-appindexing-7.5.0" level="project" />
<orderEntry type="library" exported="" name="timber-3.1.0" level="project" />
<orderEntry type="library" exported="" name="play-services-wearable-7.5.0" level="project" />
<orderEntry type="library" exported="" name="play-services-safetynet-7.5.0" level="project" />
<orderEntry type="library" exported="" name="recyclerview-v7-22.0.0" level="project" />
<orderEntry type="library" exported="" name="play-services-games-7.5.0" level="project" />
<orderEntry type="library" exported="" name="play-services-maps-7.5.0" level="project" />
<orderEntry type="library" exported="" name="play-services-plus-7.5.0" level="project" />
<orderEntry type="library" exported="" name="play-services-fitness-7.5.0" level="project" />
<orderEntry type="library" exported="" name="secure-preferences-lib-0.1.3" level="project" />
<orderEntry type="library" exported="" name="play-services-analytics-7.5.0" level="project" />
<orderEntry type="library" exported="" name="play-services-7.5.0" level="project" />
<orderEntry type="library" exported="" name="gson-2.2.4" level="project" />
<orderEntry type="library" exported="" name="mediarouter-v7-22.0.0" level="project" />
<orderEntry type="library" exported="" name="play-services-wallet-7.5.0" level="project" />
<orderEntry type="library" exported="" name="play-services-identity-7.5.0" level="project" />
<orderEntry type="library" exported="" name="support-annotations-22.2.1" level="project" />
<orderEntry type="library" exported="" name="play-services-appstate-7.5.0" level="project" />
<orderEntry type="library" exported="" name="play-services-nearby-7.5.0" level="project" />
<orderEntry type="library" exported="" name="support-v4-22.2.1" level="project" />
<orderEntry type="library" exported="" name="play-services-cast-7.5.0" level="project" />
<orderEntry type="library" exported="" name="appcompat-v7-22.2.1" level="project" />
<orderEntry type="library" exported="" name="play-services-ads-7.5.0" level="project" />
<orderEntry type="library" exported="" name="play-services-location-7.5.0" level="project" />
</component>
</module>
16 changes: 11 additions & 5 deletions app/build.gradle
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
apply plugin: 'com.android.application'

android {
compileSdkVersion 22
buildToolsVersion "22.0.1"
compileSdkVersion 23
buildToolsVersion "23"

defaultConfig {
applicationId "org.healtheheartstudy"
minSdkVersion 9
targetSdkVersion 22
minSdkVersion 10
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
Expand All @@ -21,5 +21,11 @@ android {

dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:22.2.0'
compile 'com.android.support:appcompat-v7:23.+'
compile 'com.google.android.gms:play-services:7.5.0'
compile 'com.mcxiaoke.volley:library:1.0.+'
compile 'com.google.code.gson:gson:2.2.+'
compile 'com.jakewharton.timber:timber:3.1.0'
compile 'com.scottyab:secure-preferences-lib:0.1.3'
compile 'com.afollestad:material-dialogs:0.7.9.1'
}
22 changes: 22 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.healtheheartstudy" >

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

<application
android:name=".MainApp"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
Expand All @@ -16,6 +22,22 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<receiver android:name=".CustomBroadcastReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>

<service
android:name=".HospitalizationService"
android:enabled="true"
android:exported="false" >
</service>
<service
android:name=".GeofenceIntentService"
android:exported="false" >
</service>
</application>

</manifest>
53 changes: 53 additions & 0 deletions app/src/main/java/org/healtheheartstudy/AlarmHelper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package org.healtheheartstudy;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.SystemClock;

import java.text.SimpleDateFormat;
import java.util.Calendar;

/**
* AlarmManager wrapper
*/
public class AlarmHelper {

private Context context;
private Intent intent;

public AlarmHelper(Context context, String intentAction) {
this.context = context;
intent = new Intent(context, CustomBroadcastReceiver.class);
intent.setAction(intentAction);
}

public void putExtra(String key, String value) {
intent.putExtra(key, value);
}

public void set(long triggerAtMillis) {
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + triggerAtMillis, pi);
}

public void setRepeating(long triggerAtMillis, long intervalMillis) {
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
am.setRepeating(
AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + triggerAtMillis,
intervalMillis,
pi);
}

// Returns a date formatted in mm-dd-yyyy (e.g. 05-26-1992)
public static String getCurrentDate() {
Calendar c = Calendar.getInstance();
SimpleDateFormat df = new SimpleDateFormat("MM-dd-yyyy");
return df.format(c.getTime());
}

}
34 changes: 34 additions & 0 deletions app/src/main/java/org/healtheheartstudy/Constants.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package org.healtheheartstudy;

/**
* Created by dannypark on 7/1/15.
*/
public class Constants {

public static final String KEY_FIRST_APP_OPEN = "first_app_open";
public static final String KEY_SERVICE_ACTION = "service_action";
public static final String KEY_HOSPITAL_NAME = "hospital_name";
public static final String KEY_HOSPITAL_LAT = "hospital_lat";
public static final String KEY_HOSPITAL_LNG = "hospital_lng";
public static final String KEY_TRANSITION_TYPE = "transition_type";
public static final String KEY_PREV_USER_LAT = "prev_user_lat";
public static final String KEY_PREV_USER_LNG = "prev_user_lng";
public static final String KEY_DATE = "date";
public static final String KEY_PERSISTENT_SURVEY_HOSPITAL = "persistent_hospital_name";
public static final String KEY_PERSISTENT_SURVEY_DATE = "persistent_date";

public static final String ACTION_CREATE_GEOFENCES = "service_create_geofences";
public static final String ACTION_UPDATE_TRANSITION_TYPE = "update_transition_type";
public static final String ACTION_SURVEY_ALARM = "survey_alarm";
public static final String ACTION_CHECK_LOCATION = "check_location";

public static final long ONE_HOUR_MILLIS = 1000 * 60 * 60;
public static final long ONE_DAY_MILLIS = ONE_HOUR_MILLIS * 24;
public static final int TWO_MINUTES_MILLIS = 1000 * 60 * 2;

public static final long SURVEY_TRIGGER_MILLIS = ONE_HOUR_MILLIS;

public static final int GEOFENCE_RADIUS_METERS = 100;
public static final int GEOFENCE_LOITER_TIME_MILLIS = 1000 * 60 * 60 * 4;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't it better to set the value instead the operation?

public static final long ONE_HOUR_MILLIS = 3600000;
...
public static final int GEOFENCE_LOITER_TIME_MILLIS = 14400000;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package org.healtheheartstudy;

import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationManagerCompat;

import com.securepreferences.SecurePreferences;

import timber.log.Timber;

/**
* CustomBroadcastReceiver handles three events. The first is BOOT_COMPLETED, which is when the
* device boots up. During this event, we need to recreate all geofences because they don't
* persist when the device shuts off. The second event is prompted 1-hour after a user
* leaves a hospital (after dwelling at a hospital for 4 hours). During this event, we need to
* display a notification that asks the user a few questions about their hospital visit. The
* third event is prompted by a daily alarm that launches our service to check if we need to
* find new hospitals because the user moved a significant distance.
*/
public class CustomBroadcastReceiver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action != null) {
if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
Timber.d("BOOT COMPLETED");
// Create geofences
Intent serviceIntent = new Intent(context, HospitalizationService.class);
serviceIntent.putExtra(Constants.KEY_SERVICE_ACTION, Constants.ACTION_CREATE_GEOFENCES);
context.startService(serviceIntent);

// Start alarm to check user's location every day
AlarmHelper ah = new AlarmHelper(context, Constants.ACTION_CHECK_LOCATION);
ah.setRepeating(Constants.ONE_DAY_MILLIS, Constants.ONE_DAY_MILLIS);
} else if (action.equals(Constants.ACTION_SURVEY_ALARM)) {
Timber.d("ALARM TRIGGERED FOR SURVEY");
String hospitalName = intent.getStringExtra(Constants.KEY_HOSPITAL_NAME);
buildNotification(context, hospitalName);
} else if (action.equals(Constants.ACTION_CHECK_LOCATION)) {
Timber.d("ALARM TRIGGERED FOR CHECK LOCATION");
Intent serviceIntent = new Intent(context, HospitalizationService.class);
serviceIntent.putExtra(Constants.KEY_SERVICE_ACTION, action);
context.startService(serviceIntent);
}
}
}

private void buildNotification(Context context, String hospitalName) {
// Need to store this in SharedPreferences in case user clears notification
String date = AlarmHelper.getCurrentDate();
SharedPreferences prefs = new SecurePreferences(context.getApplicationContext());
SharedPreferences.Editor editor = prefs.edit();
editor.putString(Constants.KEY_PERSISTENT_SURVEY_HOSPITAL, hospitalName);
editor.putString(Constants.KEY_PERSISTENT_SURVEY_DATE, date);
editor.apply();

Intent displayIntent = new Intent(context, MainActivity.class);
displayIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
displayIntent.putExtra(Constants.KEY_HOSPITAL_NAME, hospitalName);
displayIntent.putExtra(Constants.KEY_DATE, date);
PendingIntent displayPendingIntent = PendingIntent.getActivity(
context,
0,
displayIntent,
PendingIntent.FLAG_UPDATE_CURRENT
);

NotificationCompat.Builder notifBuilder = new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_media_pause)
.setContentTitle("Health eHeart Study")
.setContentText("We noticed that you're near a hospital and would like you to fill out a survey.")
.setContentIntent(displayPendingIntent)
.setAutoCancel(true)
.setVibrate(new long[]{500, 500, 500, 500});

NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
notificationManager.notify(1, notifBuilder.build());
}

}
Loading