package com.jsbogang.womp.health;
|
|
import android.content.Context;
|
import android.content.Intent;
|
import android.util.Log;
|
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
|
import com.jsbogang.womp.ble.AlarmPrefs;
|
import com.jsbogang.womp.ble.DevicePrefs;
|
import com.jsbogang.womp.workbench.UploadPolicy;
|
import com.jsbogang.womp.workbench.WompApi;
|
import com.jsbogang.womp.workbench.WompConfig;
|
import com.jsbogang.womp.workbench.WompSession;
|
|
import org.json.JSONObject;
|
|
import java.util.List;
|
|
public final class HealthUploader {
|
private static final HealthUploader INSTANCE = new HealthUploader();
|
private static final String TAG = "HealthUploader";
|
private Context app;
|
private long lastAbnormalAt;
|
private volatile boolean flushing;
|
|
private HealthUploader() {}
|
|
public static HealthUploader get() {
|
return INSTANCE;
|
}
|
|
public void attach(Context context) {
|
app = context.getApplicationContext();
|
}
|
|
public void flush() {
|
if (app == null || flushing || !UploadPolicy.shouldUpload(app)) {
|
return;
|
}
|
List<HealthSample> pending = AppDatabase.dao().pendingUpload();
|
if (pending == null || pending.isEmpty()) {
|
return;
|
}
|
flushing = true;
|
uploadNext(pending, 0, pending.size());
|
}
|
|
private void uploadNext(List<HealthSample> list, int index, int total) {
|
if (index >= list.size()) {
|
flushing = false;
|
if (WompConfig.DEBUG_UPLOAD_TOAST && total > 0) {
|
UploadPolicy.debugToast(app, "健康数据已同步 " + total + " 条");
|
}
|
return;
|
}
|
HealthSample s = list.get(index);
|
postOne(s, "周期".equals(s.dataType) ? "周期" : s.dataType, () -> {
|
AppDatabase.dao().markUploaded(s.timestamp, s.deviceMac, s.dataType);
|
if ("异常".equals(s.dataType)) {
|
lastAbnormalAt = System.currentTimeMillis();
|
} else if (AlarmPrefs.isAbnormal(app, s.heartRate, s.bpHigh, s.bpLow, s.spo2)) {
|
long now = System.currentTimeMillis();
|
if (now - lastAbnormalAt >= WompConfig.ABNORMAL_INTERVAL_MS) {
|
lastAbnormalAt = now;
|
postOne(s, "异常", () -> uploadNext(list, index + 1, total));
|
return;
|
}
|
}
|
uploadNext(list, index + 1, total);
|
});
|
}
|
|
private void postOne(HealthSample s, String dataType, Runnable ok) {
|
try {
|
JSONObject body = new JSONObject();
|
body.put("sorterId", WompSession.getSorterId(app));
|
body.put("uploadTime", s.timestamp);
|
if (s.heartRate > 0) {
|
body.put("heartRate", s.heartRate);
|
}
|
long dayStart = HealthSyncer.startOfDay(new java.util.Date(s.timestamp));
|
body.put("stepCount", HealthSyncer.daySteps(app, s.deviceMac, dayStart, dayStart + 86400000L));
|
if (s.bpHigh > 0) {
|
body.put("bloodPressureHigh", s.bpHigh);
|
}
|
if (s.bpLow > 0) {
|
body.put("bloodPressureLow", s.bpLow);
|
}
|
if (s.spo2 > 0) {
|
body.put("bloodOxygen", s.spo2);
|
}
|
if (s.temperature > 0) {
|
body.put("temperature", s.temperature);
|
}
|
body.put("dataType", dataType);
|
WompApi.post("/app/push/sorter/health", body, (success, resp) -> {
|
if (success) {
|
if (WompConfig.DEBUG_UPLOAD_TOAST && "异常".equals(dataType)) {
|
UploadPolicy.debugToast(app, "异常健康已同步 心率" + s.heartRate
|
+ " 血压" + s.bpHigh + "/" + s.bpLow
|
+ " 血氧" + (int) s.spo2);
|
}
|
ok.run();
|
} else {
|
Log.w(TAG, "upload fail " + resp);
|
flushing = false;
|
}
|
});
|
} catch (Exception e) {
|
flushing = false;
|
}
|
}
|
|
public int latestHeart() {
|
if (app == null || !DevicePrefs.isBound(app)) {
|
return 0;
|
}
|
long start = HealthSyncer.startOfDay(new java.util.Date());
|
HealthSample s = AppDatabase.dao().latestHeart(DevicePrefs.getMac(app), start, start + 86400000L);
|
return s == null ? 0 : s.heartRate;
|
}
|
|
public int todaySteps() {
|
if (app == null || !DevicePrefs.isBound(app)) {
|
return 0;
|
}
|
long start = HealthSyncer.startOfDay(new java.util.Date());
|
return HealthSyncer.daySteps(app, DevicePrefs.getMac(app), start, start + 86400000L);
|
}
|
|
/**
|
* 模拟手表上报一条异常测量,写入本地库并尝试上报服务端。
|
* @param kind hr / bp / spo2
|
*/
|
public void simulateAbnormal(String kind) {
|
if (app == null || AppDatabase.get() == null) {
|
return;
|
}
|
String mac = DevicePrefs.isBound(app) ? DevicePrefs.getMac(app) : "SIMULATOR";
|
HealthSample s = new HealthSample();
|
s.timestamp = System.currentTimeMillis();
|
s.deviceMac = mac;
|
s.dataType = "异常";
|
s.uploaded = 0;
|
s.stepValue = 0;
|
s.calories = 1;
|
s.wear = 1;
|
if ("bp".equals(kind)) {
|
s.heartRate = 88;
|
s.bpHigh = 178;
|
s.bpLow = 112;
|
s.spo2 = 97;
|
} else if ("spo2".equals(kind)) {
|
s.heartRate = 76;
|
s.bpHigh = 118;
|
s.bpLow = 76;
|
s.spo2 = 82;
|
} else {
|
s.heartRate = 168;
|
s.bpHigh = 122;
|
s.bpLow = 78;
|
s.spo2 = 96;
|
}
|
AppDatabase.dao().upsertSample(s);
|
Intent ui = new Intent(HealthSyncer.ACTION_HEALTH);
|
ui.putExtra(HealthSyncer.EXTRA_MSG, "已模拟" + kindLabel(kind) + "异常");
|
LocalBroadcastManager.getInstance(app).sendBroadcast(ui);
|
if (!UploadPolicy.shouldUpload(app)) {
|
UploadPolicy.debugToast(app, "已模拟入库,当前未在工作时段,暂不同步");
|
return;
|
}
|
postOne(s, "异常", () -> {
|
AppDatabase.dao().markUploaded(s.timestamp, s.deviceMac, s.dataType);
|
UploadPolicy.debugToast(app, "已模拟" + kindLabel(kind) + "异常");
|
});
|
}
|
|
private static String kindLabel(String kind) {
|
if ("bp".equals(kind)) {
|
return "血压";
|
}
|
if ("spo2".equals(kind)) {
|
return "血氧";
|
}
|
return "心率";
|
}
|
}
|