Yama ichi version with working Service
This commit is contained in:
parent
c9e31bf9f0
commit
8361439a9a
3 changed files with 103 additions and 27 deletions
|
@ -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"
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
Loading…
Reference in a new issue