//help from https://developer.android.com/guide/components/services.html package com.twolf.stressball11; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.media.RingtoneManager; import android.net.Uri; import android.os.AsyncTask; import android.os.IBinder; import android.os.SystemClock; import android.support.v4.app.NotificationCompat; import android.widget.Toast; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.concurrent.ExecutionException; /****************************************************************** * This is the most important service and at the moment is the driving force behind the hole * application. * This service once started should repeat every 10 min. Even though the fitbit heart data is only * updated every 15 min the first time this service runs it will collect data from fit bit. * With the timer var the next time it runs it will compare heart rates to the resting heart rate. * * After wearing the fitbit long enough I found my stress levels and non active levels for heart rate * were between 60-75bpm * * -Thomas Wolf * * help from: https://www.youtube.com/watch?v=tyVaPHv-RGo ****setting up a service * https://developer.android.com/reference/android/util/JsonReader.html ****json parsing * https://www.youtube.com/watch?v=4asV24BnsXQ **** more json parsing * www.youtube.com/watch?v=gm5n_hRIR-c && www.youtube.com/watch?v=tyVaPHv-RGo ****Shared Pref * DR. McVey ****json parsing & html/server request help */ public class HeartService extends Service { public int [] heartData;//filled by json depending how many heart rates where recorded public int restHeart;// stores the resting heart rate Boolean isTime = false;// boolean to check if enough time has passed to make call to fitbit //this data is stored in shared preferences and can be used in other parts of the app if need be @Override public IBinder onBind(Intent intent) { return null; } /*************************************************************************** * Function Name: onCreate() * Purpose: If time is up then this service will make a call to fitbit to update the data. If * not enough time passed then it will compare heart rate to resting heart rat * Usage: called when service starts. */ @Override public void onCreate() { isTime = checkTime(); if(isTime) { new contactFitbit().execute();// if need be contact fitbit to update data } else { try { String result = new getJsonData().execute().get();// wait so array can be filled } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } for (int i = 0; i < heartData.length; i++) if (heartData[i] < restHeart + 11 && heartData[i] > restHeart) { final Uri sound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); final NotificationManager NM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); Intent intent = new Intent(this.getApplicationContext(), HeartData.class); // where to go when clicked on final PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0); NotificationCompat.Builder notificationCompat = new NotificationCompat.Builder(HeartService.this) .setSmallIcon(R.drawable.icon) .setContentTitle("Heart Levels") .setContentText("You May Be experiencing Stress") .setTicker("Heart Stress Detection") .setContentIntent(pendingIntent) .setSound(sound) .setAutoCancel(true); NM.notify(1, notificationCompat.build());//Posts to the screen my notification break; } } stopSelf();// use this to stop the service so the alarm can reset!!!!!! //return; did not work to produce antother alarm //onDestroy(); did not work calling the destroy function } @Override public void onDestroy() { /*********************************************************************************************** * Function Name: onDestroy() * Purpose: Destroys the notification * Usage: Call this function when you want notification to be destroyed ***********************************************************************************************/ super.onDestroy(); //Toast.makeText(this,"in desotry", Toast.LENGTH_LONG).show(); return; } @Override public void onStart(Intent intent, int startId) { /*********************************************************************************************** * Function Name: onStart(Intent intent, int startID) * Purpose: Creates the notification * Usage: Call this function when you want creating notification process to begin ***********************************************************************************************/ super.onCreate(); //Toast.makeText(HeartService.this, "Service started", Toast.LENGTH_LONG).show(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { /*********************************************************************************************** * Function Name: onStartCommand(Intent intent, int flags, int startId) * Purpose: The system invokes this method by calling startService() when another component * (such as an activity) requests that the service be started. When this method executes, * the service is started and can run in the background indefinitely * * help from https://developer.android.com/guide/components/services.html ***********************************************************************************************/ // TODO do something useful return Service.START_NOT_STICKY;//https://developer.android.com/reference/android/app/Service.html Only while needed; } public class getJsonData extends AsyncTask { @Override protected void onPreExecute() { super.onPreExecute(); } @Override protected void onPostExecute(String s) { super.onPostExecute(s); //Toast.makeText(HeartService.this, "in Postexecute", Toast.LENGTH_LONG).show(); } @Override protected String doInBackground(String... params) { HttpURLConnection con=null; try { //Get resting heart rate stored in the active.json URL url = new URL("http://compsci02.snc.edu/cs460/2017/wolftd/oauth2/active.json"); con = (HttpURLConnection) url.openConnection(); con.connect(); InputStream stream = con.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); StringBuffer sb = new StringBuffer(); String line = ""; while ((line = reader.readLine()) != null) { sb.append(line); } String finalJson = sb.toString(); JSONObject parentObject = new JSONObject(finalJson); JSONObject stepps = parentObject.getJSONObject("summary"); int restingHeart = stepps.getInt("restingHeartRate"); restHeart = restingHeart; } catch (MalformedURLException e) { e.printStackTrace(); } catch (JSONException e1) { e1.printStackTrace(); } catch (IOException e1) { e1.printStackTrace(); } finally { if(con!=null) con.disconnect(); } try { //Connect to the heart rate json URL url= new URL("http://compsci02.snc.edu/cs460/2017/wolftd/oauth2/heartrate.json"); con = (HttpURLConnection) url.openConnection(); con.connect(); InputStream stream = con.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); StringBuffer sb = new StringBuffer(); String line=""; while ((line =reader.readLine())!=null) { sb.append(line); } //Create json object go to the correct entry and grab data String finalJson =sb.toString(); JSONObject parentObject = new JSONObject(finalJson); JSONObject heartJson= parentObject.getJSONObject("activities-heart-intraday"); JSONArray heartArray=heartJson.getJSONArray("dataset"); //The ammount of heart data varies so now we intialize it to size of json data heartData=new int[heartArray.length()]; for(int i=0; i{ @Override //OAuth2 connection-Updates Fitbit data using Google Chrome and place it into 02data.txt protected String doInBackground(String... params) { String urlString="http://compsci02.snc.edu/cs460/2017/wolftd/" + "oauth2/index.php"; Intent intent=new Intent(Intent.ACTION_VIEW,Uri.parse(urlString)); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setPackage("com.android.chrome"); //forces connection through google chrome try{ HeartService.this.startActivity(intent); } catch (ActivityNotFoundException ex) { Toast.makeText(HeartService.this,"GOOGLE CRHOME NEEDS TO BE INSTALLED", Toast.LENGTH_LONG).show(); } return null; } } /*************************************************************************************** * Function namees: CheckTime() * Purpose: check time stores previous current time from system in shared preference. If * current is greater than the saved time return true stating enough time has passed to connect * to fitibit. Also call timeManagment(). * Usage:Called everytime the servie runs to ensure that calls to fitbit are not continously made */ public boolean checkTime() { SharedPreferences sharedPref= getSharedPreferences("timeFile",Context.MODE_PRIVATE); long timeManager= sharedPref.getLong("timeManager",1);//if file was not found will return //default of 1 long timeNow=SystemClock.elapsedRealtime(); if (timeManager==1 || timeManager