Yama ichi version with working Service

This commit is contained in:
Ruben van de Ven 2018-11-13 11:49:28 +01:00
parent c9e31bf9f0
commit 8361439a9a
3 changed files with 103 additions and 27 deletions

View file

@ -8,6 +8,7 @@
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.VIBRATE" />
<application <application
android:allowBackup="true" android:allowBackup="true"

View file

@ -47,9 +47,9 @@ public class MainActivity extends AppCompatActivity {
public void onClick(View v) { public void onClick(View v) {
serviceButton.setEnabled(false); serviceButton.setEnabled(false);
if(HeartRateService.isRunning()) { if(HeartRateService.isRunning()) {
startHeartRateMonitor();
} else {
stopHeartRateMonitor(); stopHeartRateMonitor();
} else {
startHeartRateMonitor();
} }
} }
}); });
@ -80,6 +80,7 @@ public class MainActivity extends AppCompatActivity {
} }
public void startHeartRateMonitor() { public void startHeartRateMonitor() {
Log.d(TAG, "Start HR");
if(HeartRateService.isRunning()) { if(HeartRateService.isRunning()) {
Toast.makeText(this, "Already running", Toast.LENGTH_LONG); Toast.makeText(this, "Already running", Toast.LENGTH_LONG);
} else { } else {
@ -100,9 +101,9 @@ public class MainActivity extends AppCompatActivity {
public void stopHeartRateMonitor() { public void stopHeartRateMonitor() {
// stop tracking // stop tracking
Intent intent = new Intent(MainActivity.this, HeartRateService.class); // Intent intent = new Intent(MainActivity.this, HeartRateService.class);
intent.setAction(HeartRateService.ACTION_STOP); Log.d(TAG, "Stop HR");
startService(intent); stopService(new Intent(this, HeartRateService.class));
} }
/** /**

View file

@ -4,13 +4,17 @@ import android.app.AlertDialog;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.app.Service; import android.app.Service;
import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.Build;
import android.os.Handler; import android.os.Handler;
import android.os.HandlerThread; import android.os.HandlerThread;
import android.os.IBinder; import android.os.IBinder;
import android.os.Looper; import android.os.Looper;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationCompat;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
@ -38,8 +42,11 @@ import java.math.BigDecimal;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols; import java.text.DecimalFormatSymbols;
import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Timer;
import java.util.TimerTask;
public class HeartRateService extends Service { public class HeartRateService extends Service {
private static final String TAG = HeartRateService.class.getSimpleName(); private static final String TAG = HeartRateService.class.getSimpleName();
@ -69,11 +76,19 @@ public class HeartRateService extends Service {
NotificationCompat.Builder builder; NotificationCompat.Builder builder;
NotificationManager notificationManager; NotificationManager notificationManager;
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Timer lifelineTimer;
DeviceState currentDeviceState;
boolean restartService = false;
@Override @Override
public void onCreate() { public void onCreate() {
notificationManager = notificationManager =
(NotificationManager) getSystemService(Service.NOTIFICATION_SERVICE); (NotificationManager) getSystemService(Service.NOTIFICATION_SERVICE);
startLifelineTimer();
setRunning(true); setRunning(true);
requestAccessToPcc(); requestAccessToPcc();
@ -103,7 +118,6 @@ public class HeartRateService extends Service {
*/ */
@Override @Override
public int onStartCommand(Intent intent, int flags, int startId) { public int onStartCommand(Intent intent, int flags, int startId) {
if (intent.getAction().equals(ACTION_START)) {
Log.i(TAG, "Received start id " + startId + ": " + intent); Log.i(TAG, "Received start id " + startId + ": " + intent);
Intent notificationIntent = new Intent(this, MainActivity.class); Intent notificationIntent = new Intent(this, MainActivity.class);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
@ -124,11 +138,6 @@ public class HeartRateService extends Service {
startForeground(NOTIFICATION_ID, startForeground(NOTIFICATION_ID,
builder.build()); builder.build());
} else if (intent.getAction().equals(ACTION_STOP)) {
Log.i(TAG, "Received stop id " + startId + ": " + intent);
stopForeground(true);
stopSelf();
}
return START_STICKY; return START_STICKY;
} }
@ -138,14 +147,18 @@ public class HeartRateService extends Service {
@Override @Override
public void onDeviceStateChange(final DeviceState state) public void onDeviceStateChange(final DeviceState state)
{ {
currentDeviceState = state;
if(DeviceState.DEAD.equals(state) || DeviceState.CLOSED.equals(state)) { if(DeviceState.DEAD.equals(state) || DeviceState.CLOSED.equals(state)) {
sendBroadcast(new Intent(BROADCAST_MONITOR_DISCONNECTED)); sendBroadcast(new Intent(BROADCAST_MONITOR_DISCONNECTED));
updateNotification("Disconnected");
waitAndReconnect(); waitAndReconnect();
} else if (DeviceState.TRACKING.equals(state)) { } else if (DeviceState.TRACKING.equals(state)) {
sendBroadcast(new Intent(BROADCAST_MONITOR_CONNECTED)); sendBroadcast(new Intent(BROADCAST_MONITOR_CONNECTED));
updateNotification("Connected!");
} else { } else {
Intent i = new Intent(BROADCAST_MONITOR_UNKNOWN); Intent i = new Intent(BROADCAST_MONITOR_UNKNOWN);
i.putExtra("status", state.getIntValue()); i.putExtra("status", state.getIntValue());
updateNotification("Unknown status: "+ String.valueOf(state.getIntValue()));
sendBroadcast(i); sendBroadcast(i);
} }
} }
@ -162,24 +175,29 @@ public class HeartRateService extends Service {
switch (resultCode) { switch (resultCode) {
case SUCCESS: case SUCCESS:
i.putExtra("msg", "Success"); i.putExtra("msg", "Success");
updateNotification("Access");
connectHr(result); connectHr(result);
break; break;
case CHANNEL_NOT_AVAILABLE: case CHANNEL_NOT_AVAILABLE:
showNotification("Channel Not Available"); showNotification("Channel Not Available");
i.putExtra("msg", "Channel Not Available"); i.putExtra("msg", "Channel Not Available");
updateNotification("Channel not available");
break; break;
case OTHER_FAILURE: case OTHER_FAILURE:
showNotification("RequestAccess failed. See logcat for details."); showNotification("RequestAccess failed. See logcat for details.");
i.putExtra("msg", "RequestAccess failed. See logcat for details."); i.putExtra("msg", "RequestAccess failed. See logcat for details.");
updateNotification("RequestAccess failed");
break; break;
case USER_CANCELLED: case USER_CANCELLED:
showNotification("Cancelled. Do reset."); showNotification("Cancelled. Do reset.");
i.putExtra("msg", "Cancelled. Do reset."); i.putExtra("msg", "Cancelled. Do reset.");
updateNotification("Cancelled, do reset");
break; break;
case UNRECOGNIZED: case UNRECOGNIZED:
default: default:
showNotification("Unknown error. Do reset."); showNotification("Unknown error. Do reset.");
i.putExtra("msg", "unknown error. Do reset."); i.putExtra("msg", "unknown error. Do reset.");
updateNotification("Unknown error, do reset");
break; break;
} }
sendBroadcast(i); sendBroadcast(i);
@ -195,6 +213,8 @@ public class HeartRateService extends Service {
final int computedHeartRate, final long heartBeatCount, final int computedHeartRate, final long heartBeatCount,
final BigDecimal heartBeatEventTime, final AntPlusHeartRatePcc.DataState dataState) final BigDecimal heartBeatEventTime, final AntPlusHeartRatePcc.DataState dataState)
{ {
currentDeviceState = DeviceState.TRACKING;
DecimalFormatSymbols otherSymbols = new DecimalFormatSymbols(); DecimalFormatSymbols otherSymbols = new DecimalFormatSymbols();
otherSymbols.setDecimalSeparator('.'); otherSymbols.setDecimalSeparator('.');
DecimalFormat df = new DecimalFormat("#.##", otherSymbols); DecimalFormat df = new DecimalFormat("#.##", otherSymbols);
@ -216,8 +236,8 @@ public class HeartRateService extends Service {
intent.putExtra("time", textHeartBeatEventTime); intent.putExtra("time", textHeartBeatEventTime);
sendBroadcast(intent); sendBroadcast(intent);
builder.setContentText(textHeartRate + " bpm"); updateNotification(textHeartRate + " bpm / " + textHeartBeatCount + " beats / " + textHeartBeatEventTime );
notificationManager.notify(NOTIFICATION_ID, builder.build());
JSONObject jObjectData = new JSONObject(); JSONObject jObjectData = new JSONObject();
// final String msg = String.format("{\"rate\":\"%s\", \"count\":\"%s\", \"time\":\"%s\"}", textHeartRate, textHeartBeatCount, textHeartBeatEventTime); // final String msg = String.format("{\"rate\":\"%s\", \"count\":\"%s\", \"time\":\"%s\"}", textHeartRate, textHeartBeatCount, textHeartBeatEventTime);
@ -226,7 +246,7 @@ public class HeartRateService extends Service {
jObjectData.put("rate", textHeartRate); jObjectData.put("rate", textHeartRate);
jObjectData.put("count", textHeartBeatCount); jObjectData.put("count", textHeartBeatCount);
jObjectData.put("time", textHeartBeatEventTime); jObjectData.put("time", textHeartBeatEventTime);
jObjectData.put("timestamp", DateFormat.getDateTimeInstance().format(new Date())); jObjectData.put("timestamp", dateFormat.format(new Date()));
jObjectData.put("token", getToken()); jObjectData.put("token", getToken());
msg = jObjectData.toString(); msg = jObjectData.toString();
@ -248,6 +268,11 @@ public class HeartRateService extends Service {
} }
public void updateNotification(String msg) {
builder.setContentText(msg);
notificationManager.notify(NOTIFICATION_ID, builder.build());
}
String token = null; String token = null;
/** /**
@ -272,8 +297,9 @@ public class HeartRateService extends Service {
return null; return null;
} }
try { try {
Log.d(TAG, "JSON: "+ json);
JSONObject jsonObject = new JSONObject(json); JSONObject jsonObject = new JSONObject(json);
token = jsonObject.getString("token'"); token = jsonObject.getString("token");
} catch (JSONException e) { } catch (JSONException e) {
e.printStackTrace(); e.printStackTrace();
return null; return null;
@ -312,6 +338,40 @@ public class HeartRateService extends Service {
}); });
} }
protected void startLifelineTimer() {
lifelineTimer = new Timer();
lifelineTimer.scheduleAtFixedRate(new TimerTask(){
@Override
public void run(){
Log.d(TAG, "A Kiss every 10 seconds");
if(DeviceState.TRACKING.equals(currentDeviceState)) {
Log.i(TAG, "Alive and kicking!");
return;
}
Log.w(TAG, "Device status different... ");
String val;
if(currentDeviceState == null) {
val = "null";
} else {
val = String.valueOf(currentDeviceState.getIntValue());
}
Log.w(TAG, "Device status: '"+ val +"'");
// something is off: warn & attempt restart
Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
v.vibrate(VibrationEffect.createOneShot(1000, VibrationEffect.DEFAULT_AMPLITUDE));
} else {
//deprecated in API 26
v.vibrate(1000);
}
restart();
}
},20000,10000);
}
/** /**
* wait to reconnect to dead HR-monitor * wait to reconnect to dead HR-monitor
*/ */
@ -322,14 +382,20 @@ public class HeartRateService extends Service {
hrPcc.subscribeHeartRateDataEvent(null); hrPcc.subscribeHeartRateDataEvent(null);
} }
new android.os.Handler().postDelayed( // triggers: "sending message to a handler on a dead thread"
new Runnable() { // new android.os.Handler().postDelayed(
public void run() { // new Runnable() {
Log.i(TAG, "Attempt reconnect"); // public void run() {
requestAccessToPcc(); // Log.i(TAG, "Attempt reconnect");
} requestAccessToPcc();
}, // }
20000); // 20 sec delay for connection // },
// 20000); // 20 sec delay for connection
}
protected void restart(){
restartService = true;
stopSelf();
} }
/** /**
@ -337,9 +403,10 @@ public class HeartRateService extends Service {
*/ */
protected void requestAccessToPcc() protected void requestAccessToPcc()
{ {
if(hrPcc != null) { // if(hrPcc != null) {
hrPcc.subscribeHeartRateDataEvent(null); // hrPcc.subscribeHeartRateDataEvent(null);
} // }
Log.d(TAG, "Request Access To PCC");
sendBroadcast( new Intent(BROADCAST_MONITOR_CONNECT_ATTEMPT) ); sendBroadcast( new Intent(BROADCAST_MONITOR_CONNECT_ATTEMPT) );
releaseHandle = AntPlusHeartRatePcc.requestAccess(this, 4818, 0, resultReceiver, stateChangeReceiver); releaseHandle = AntPlusHeartRatePcc.requestAccess(this, 4818, 0, resultReceiver, stateChangeReceiver);
} }
@ -352,12 +419,19 @@ public class HeartRateService extends Service {
@Override @Override
public void onDestroy() { public void onDestroy() {
Log.i(TAG, "Stop service");
stopForeground(true);
lifelineTimer.cancel();
if(releaseHandle != null) if(releaseHandle != null)
{ {
releaseHandle.close(); releaseHandle.close();
} }
setRunning(false); setRunning(false);
super.onDestroy(); super.onDestroy();
if(restartService ) {
startService(new Intent(this, HeartRateService.class));
}
} }
public static boolean isRunning() { public static boolean isRunning() {