diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/ImportDatabaseActivity.java b/app/src/main/java/com/eveningoutpost/dexdrip/ImportDatabaseActivity.java index e4c3ba51d3..dd74be3c80 100644 --- a/app/src/main/java/com/eveningoutpost/dexdrip/ImportDatabaseActivity.java +++ b/app/src/main/java/com/eveningoutpost/dexdrip/ImportDatabaseActivity.java @@ -4,6 +4,7 @@ import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; +import android.content.SharedPreferences; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.database.sqlite.SQLiteDatabase; @@ -11,9 +12,11 @@ import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; +import android.preference.PreferenceManager; import android.support.annotation.NonNull; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.widget.ArrayAdapter; @@ -24,6 +27,7 @@ import com.eveningoutpost.dexdrip.utils.DatabaseUtil; import com.eveningoutpost.dexdrip.utils.FileUtils; import com.eveningoutpost.dexdrip.utils.ListActivityWithMenu; +import com.eveningoutpost.dexdrip.wearintegration.WatchUpdaterService; import java.io.File; import java.io.FileFilter; @@ -39,11 +43,13 @@ public class ImportDatabaseActivity extends ListActivityWithMenu { private ArrayList databaseNames; private ArrayList databases; private final static int MY_PERMISSIONS_REQUEST_STORAGE = 132; + private SharedPreferences mPrefs; @Override protected void onCreate(Bundle savedInstanceState) { setTheme(R.style.OldAppTheme); // or null actionbar super.onCreate(savedInstanceState); + mPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); mHandler = new Handler(); setContentView(R.layout.activity_import_db); @@ -217,6 +223,12 @@ public void importDB(int position) { } protected void postImportDB(String result) { + + if (mPrefs.getBoolean("wear_sync", false)) {//KS + Log.d(TAG, "start WatchUpdaterService with ACTION_SYNC_DB"); + startService(new Intent(this, WatchUpdaterService.class).setAction(WatchUpdaterService.ACTION_SYNC_DB)); + } + AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/Models/BgReading.java b/app/src/main/java/com/eveningoutpost/dexdrip/Models/BgReading.java index 0bde34accc..b3999be010 100644 --- a/app/src/main/java/com/eveningoutpost/dexdrip/Models/BgReading.java +++ b/app/src/main/java/com/eveningoutpost/dexdrip/Models/BgReading.java @@ -403,6 +403,9 @@ public static BgReading create(double raw_data, double filtered_data, Context co } else { BgReading lastBgReading = BgReading.last(); if (lastBgReading != null && lastBgReading.calibration != null) { + Log.d(TAG, "Create calibration.uuid=" + calibration.uuid + " bgReading.uuid: " + bgReading.uuid + " lastBgReading.calibration_uuid: " + lastBgReading.calibration_uuid + " lastBgReading.calibration.uuid: " + lastBgReading.calibration.uuid); + Log.d(TAG, "Create lastBgReading.calibration_flag=" + lastBgReading.calibration_flag + " bgReading.timestamp: " + bgReading.timestamp + " lastBgReading.timestamp: " + lastBgReading.timestamp + " lastBgReading.calibration.timestamp: " + lastBgReading.calibration.timestamp); + Log.d(TAG, "Create lastBgReading.calibration_flag=" + lastBgReading.calibration_flag + " bgReading.timestamp: " + JoH.dateTimeText(bgReading.timestamp) + " lastBgReading.timestamp: " + JoH.dateTimeText(lastBgReading.timestamp) + " lastBgReading.calibration.timestamp: " + JoH.dateTimeText(lastBgReading.calibration.timestamp)); if (lastBgReading.calibration_flag == true && ((lastBgReading.timestamp + (60000 * 20)) > bgReading.timestamp) && ((lastBgReading.calibration.timestamp + (60000 * 20)) > bgReading.timestamp)) { lastBgReading.calibration.rawValueOverride(BgReading.weightedAverageRaw(lastBgReading.timestamp, bgReading.timestamp, lastBgReading.calibration.timestamp, lastBgReading.age_adjusted_raw_value, bgReading.age_adjusted_raw_value), context); newCloseSensorData(); diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/Models/Calibration.java b/app/src/main/java/com/eveningoutpost/dexdrip/Models/Calibration.java index 7c8738a133..f4c501044a 100644 --- a/app/src/main/java/com/eveningoutpost/dexdrip/Models/Calibration.java +++ b/app/src/main/java/com/eveningoutpost/dexdrip/Models/Calibration.java @@ -214,71 +214,6 @@ public class Calibration extends Model { @Column(name = "second_scale") public double second_scale; - public static void createCalibration(//KS - /*int _ID, long timestamp, double sensor_age_at_time_of_estimation, Sensor sensor, double bg, double raw_value, double adjusted_raw_value, - double sensor_confidence, double slope_confidence, long raw_timestamp, double slope, double intercept, double distance_from_estimate, - double estimate_raw_at_time_of_calibration, double estimate_bg_at_time_of_calibration, String uuid,String sensor_uuid, Boolean possible_bad, - boolean check_in, double first_decay, double second_decay, double first_slope, double second_slope, double first_intercept, - double second_intercept, double first_scale, double second_scale*/ - double adjusted_raw_value, - double bg, - boolean check_in, - double distance_from_estimate, - double estimate_bg_at_time_of_calibration, - double estimate_raw_at_time_of_calibration, - double first_decay, - double first_intercept, - double first_scale, - double first_slope, - double intercept, - Boolean possible_bad, - long raw_timestamp, - double raw_value, - double second_decay, - double second_intercept, - double second_scale, - double second_slope, - Sensor sensor, - double sensor_age_at_time_of_estimation, - double sensor_confidence, - String sensor_uuid, - double slope, - double slope_confidence, - long timestamp, - String uuid - ) - { - Calibration newCalibration = new Calibration(); - //newCalibration._ID = _ID ; - newCalibration.timestamp = timestamp ; - newCalibration.sensor_age_at_time_of_estimation = sensor_age_at_time_of_estimation ; - newCalibration.sensor = sensor ; - newCalibration.bg = bg ; - newCalibration.raw_value = raw_value ; - newCalibration.adjusted_raw_value = adjusted_raw_value ; - newCalibration.sensor_confidence = sensor_confidence ; - newCalibration.slope_confidence = slope_confidence ; - newCalibration.raw_timestamp = raw_timestamp ; - newCalibration.slope = slope ; - newCalibration.intercept = intercept ; - newCalibration.distance_from_estimate = distance_from_estimate ; - newCalibration.estimate_raw_at_time_of_calibration = estimate_raw_at_time_of_calibration ; - newCalibration.estimate_bg_at_time_of_calibration = estimate_bg_at_time_of_calibration ; - newCalibration.uuid = uuid ; - newCalibration.sensor_uuid = sensor_uuid ; - newCalibration.possible_bad = possible_bad ; - newCalibration.check_in = check_in ; - newCalibration.first_decay = first_decay ; - newCalibration.second_decay = second_decay ; - newCalibration.first_slope = first_slope ; - newCalibration.second_slope = second_slope ; - newCalibration.first_intercept = first_intercept ; - newCalibration.second_intercept = second_intercept ; - newCalibration.first_scale = first_scale ; - newCalibration.second_scale = second_scale ; - newCalibration.save(); - } - public static void initialCalibration(double bg1, double bg2, Context context) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); String unit = prefs.getString("units", "mgdl"); diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/Services/G5CollectionService.java b/app/src/main/java/com/eveningoutpost/dexdrip/Services/G5CollectionService.java index 0b563400c3..ae068f3e3c 100644 --- a/app/src/main/java/com/eveningoutpost/dexdrip/Services/G5CollectionService.java +++ b/app/src/main/java/com/eveningoutpost/dexdrip/Services/G5CollectionService.java @@ -270,13 +270,11 @@ public void onDestroy() { Log.d(TAG, "onDestroy"); SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); - if (sharedPrefs.getBoolean("use_wear_connectG5", false)) {//KS - scan_interval_timer.cancel(); - if (pendingIntent != null) { - Log.d(TAG, "onDestroy stop Alarm pendingIntent"); - AlarmManager alarm = (AlarmManager) getSystemService(ALARM_SERVICE); - alarm.cancel(pendingIntent); - } + scan_interval_timer.cancel(); + if (pendingIntent != null) { + Log.d(TAG, "onDestroy stop Alarm pendingIntent"); + AlarmManager alarm = (AlarmManager) getSystemService(ALARM_SERVICE); + alarm.cancel(pendingIntent); } // close(); diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/CollectionServiceStarter.java b/app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/CollectionServiceStarter.java index 270c4a2033..8c577981b8 100644 --- a/app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/CollectionServiceStarter.java +++ b/app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/CollectionServiceStarter.java @@ -177,8 +177,10 @@ public void start(Context context, String collection_method) { stopBtShareService(); if (prefs.getBoolean("wear_sync", false)) {//KS + boolean enable_wearG5 = prefs.getBoolean("enable_wearG5", false); + boolean force_wearG5 = prefs.getBoolean("force_wearG5", false); this.mContext.startService(new Intent(context, WatchUpdaterService.class)); - if (!prefs.getBoolean("use_wear_connectG5", false)) { //don't start if Wear G5 Collector Service is active + if (!enable_wearG5 || (enable_wearG5 && !force_wearG5)) { //don't start if Wear G5 Collector Service is active startBtG5Service(); } } diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/wearintegration/WatchUpdaterService.java b/app/src/main/java/com/eveningoutpost/dexdrip/wearintegration/WatchUpdaterService.java index dffc5333ae..4b8597426a 100644 --- a/app/src/main/java/com/eveningoutpost/dexdrip/wearintegration/WatchUpdaterService.java +++ b/app/src/main/java/com/eveningoutpost/dexdrip/wearintegration/WatchUpdaterService.java @@ -7,7 +7,6 @@ import android.os.Bundle; import android.os.PowerManager; import android.preference.PreferenceManager; -import android.support.v4.content.LocalBroadcastManager; import android.util.Log; import com.eveningoutpost.dexdrip.Home; @@ -24,6 +23,8 @@ import com.eveningoutpost.dexdrip.xdrip; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.api.GoogleApiClient; +import com.google.android.gms.wearable.CapabilityApi; +import com.google.android.gms.wearable.CapabilityInfo; import com.google.android.gms.wearable.DataEvent; import com.google.android.gms.wearable.DataEventBuffer; import com.google.android.gms.wearable.DataMap; @@ -38,7 +39,6 @@ import com.google.gson.Gson;//KS import com.google.gson.GsonBuilder; -import com.google.gson.annotations.Expose; import com.google.gson.internal.bind.DateTypeAdapter; import java.io.UnsupportedEncodingException; @@ -46,6 +46,7 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.Set; import static com.eveningoutpost.dexdrip.utils.DexCollectionType.getDexCollectionType; @@ -57,15 +58,15 @@ public class WatchUpdaterService extends WearableListenerService implements public static final String ACTION_SYNC_DB = WatchUpdaterService.class.getName().concat(".SyncDB");//KS public static final String ACTION_SYNC_SENSOR = WatchUpdaterService.class.getName().concat(".SyncSensor");//KS public static final String ACTION_SYNC_CALIBRATION = WatchUpdaterService.class.getName().concat(".SyncCalibration");//KS - public static final String SYNC_DB_PATH = "/syncweardb";//KS + private static final String SYNC_DB_PATH = "/syncweardb";//KS private static final String SYNC_BGS_PATH = "/syncwearbgs";//KS - public static final String WEARABLE_CALIBRATION_DATA_PATH = "/nightscout_watch_cal_data";//KS - public static final String WEARABLE_BG_DATA_PATH = "/nightscout_watch_bg_data";//KS - public static final String WEARABLE_SENSOR_DATA_PATH = "/nightscout_watch_sensor_data";//KS - public static final String WEARABLE_PREF_DATA_PATH = "/nightscout_watch_pref_data";//KS - public static final String DATA_ITEM_RECEIVED_PATH = "/data-item-received";//KS - public static final String WEARABLE_DATA_PATH = "/nightscout_watch_data"; - public static final String WEARABLE_RESEND_PATH = "/nightscout_watch_data_resend"; + private static final String WEARABLE_CALIBRATION_DATA_PATH = "/nightscout_watch_cal_data";//KS + private static final String WEARABLE_BG_DATA_PATH = "/nightscout_watch_bg_data";//KS + private static final String WEARABLE_SENSOR_DATA_PATH = "/nightscout_watch_sensor_data";//KS + private static final String WEARABLE_PREF_DATA_PATH = "/nightscout_watch_pref_data";//KS + private static final String DATA_ITEM_RECEIVED_PATH = "/data-item-received";//KS + private static final String WEARABLE_DATA_PATH = "/nightscout_watch_data"; + private static final String WEARABLE_RESEND_PATH = "/nightscout_watch_data_resend"; public static final String WEARABLE_VOICE_PAYLOAD = "/xdrip_plus_voice_payload"; public static final String WEARABLE_APPROVE_TREATMENT = "/xdrip_plus_approve_treatment"; public static final String WEARABLE_CANCEL_TREATMENT = "/xdrip_plus_cancel_treatment"; @@ -73,16 +74,24 @@ public class WatchUpdaterService extends WearableListenerService implements private static final String WEARABLE_TOAST_NOTIFICATON = "/xdrip_plus_toast"; private static final String OPEN_SETTINGS_PATH = "/openwearsettings"; + // Phone + private static final String CAPABILITY_PHONE_APP = "phone_app_sync_bgs"; + private static final String MESSAGE_PATH_PHONE = "/phone_message_path"; + // Wear + private static final String CAPABILITY_WEAR_APP = "wear_app_sync_bgs"; + private static final String MESSAGE_PATH_WEAR = "/wear_message_path"; + private String mWearNodeId = null; + private static final String TAG = "jamorham watchupdater"; private static GoogleApiClient googleApiClient; private static long lastRequest = 0;//KS - private static Integer sendCalibrationCount = 3;//KS - private static Integer sendBgCount = 4;//KS - boolean wear_integration = false; - boolean pebble_integration = false; - boolean is_using_g5 = false; - SharedPreferences mPrefs; - SharedPreferences.OnSharedPreferenceChangeListener mPreferencesListener; + private static final Integer sendCalibrationCount = 3;//KS + private final static Integer sendBgCount = 4;//KS + private boolean wear_integration = false; + private boolean pebble_integration = false; + private boolean is_using_g5 = false; + private SharedPreferences mPrefs; + private SharedPreferences.OnSharedPreferenceChangeListener mPreferencesListener; public static void receivedText(Context context, String text) { startHomeWithExtra(context, WEARABLE_VOICE_PAYLOAD, text); @@ -104,11 +113,7 @@ private static void startHomeWithExtra(Context context, String extra, String tex } private void sendDataReceived(String path, String notification, long timeOfLastBG) {//KS - java.text.DateFormat df = new SimpleDateFormat("MM.dd.yyyy HH:mm:ss"); - Date date = new Date(); - - date.setTime(timeOfLastBG); - Log.d(TAG, "sendDataReceived timeOfLastBG=" + df.format(date) + " Path=" + path); + Log.d(TAG, "sendDataReceived timeOfLastBG=" + JoH.dateTimeText(timeOfLastBG) + " Path=" + path); if (googleApiClient.isConnected()) { PutDataMapRequest dataMapRequest = PutDataMapRequest.create(path); dataMapRequest.setUrgent(); @@ -122,46 +127,64 @@ private void sendDataReceived(String path, String notification, long timeOfLastB } } - public void syncPrefData(DataMap dataMap) { - boolean connectG5 = dataMap.getBoolean("connectG5"); - boolean use_connectG5 = dataMap.getBoolean("use_connectG5"); + private void syncPrefData(DataMap dataMap) { + boolean enable_wearG5 = dataMap.getBoolean("enable_wearG5", false); + boolean force_wearG5 = dataMap.getBoolean("force_wearG5", false); + String node_wearG5 = dataMap.getString("node_wearG5", ""); + String dex_txid = dataMap.getString("dex_txid", ""); + boolean change = false; + SharedPreferences.Editor prefs = PreferenceManager.getDefaultSharedPreferences(this).edit(); - Log.d(TAG, "syncPrefData connectG5: " + connectG5 + " use_connectG5:" + use_connectG5); + Log.d(TAG, "syncPrefData enable_wearG5: " + enable_wearG5 + " force_wearG5: " + force_wearG5 + " node_wearG5:" + node_wearG5 + " dex_txid: " + dex_txid); + + if (!node_wearG5.equals(mPrefs.getString("node_wearG5", ""))) { + change = true; + prefs.putString("node_wearG5", node_wearG5); + Log.d(TAG, "syncPrefData node_wearG5:" + node_wearG5); + } - if (use_connectG5 != mPrefs.getBoolean("use_wear_connectG5", false)) { - prefs.putBoolean("use_wear_connectG5", use_connectG5); - Log.d(TAG, "syncPrefData commit use_connectG5:" + use_connectG5); + if (/*force_wearG5 &&*/ force_wearG5 != mPrefs.getBoolean("force_wearG5", false)) { + change = true; + prefs.putBoolean("force_wearG5", force_wearG5); + Log.d(TAG, "syncPrefData commit force_wearG5:" + force_wearG5); } - if (connectG5 != mPrefs.getBoolean("wear_connectG5", false)) { - prefs.putBoolean("wear_connectG5", connectG5); - Log.d(TAG, "syncPrefData commit connectG5: " + connectG5); + if (/*enable_wearG5 &&*/ enable_wearG5 != mPrefs.getBoolean("enable_wearG5", false)) { + change = true; + prefs.putBoolean("enable_wearG5", enable_wearG5); + Log.d(TAG, "syncPrefData commit enable_wearG5: " + enable_wearG5); } - prefs.commit(); + if (change) { + prefs.commit(); + } + else if (!dex_txid.equals(mPrefs.getString("dex_txid", "default"))) { + sendPrefSettings(); + processConnectG5(); + } } //Assumes Wear is connected to phone - public void processConnectG5() {//KS + private void processConnectG5() {//KS Log.d(TAG, "processConnectG5 enter"); wear_integration = mPrefs.getBoolean("wear_sync", false); - boolean connectG5 = mPrefs.getBoolean("wear_connectG5", false); - boolean use_connectG5 = mPrefs.getBoolean("use_wear_connectG5", false); + boolean enable_wearG5 = mPrefs.getBoolean("enable_wearG5", false); + boolean force_wearG5 = mPrefs.getBoolean("force_wearG5", false); if (wear_integration) { - if (connectG5) { + if (enable_wearG5) { initWearData(); - if (use_connectG5) { - Log.d(TAG, "processConnectG5 use_connectG5=true - stopBtG5Service"); + if (force_wearG5) { + Log.d(TAG, "processConnectG5 force_wearG5=true - stopBtG5Service"); stopBtG5Service(); } else { - Log.d(TAG, "processConnectG5 use_connectG5=false - startBtG5Service"); + Log.d(TAG, "processConnectG5 force_wearG5=false - startBtG5Service"); startBtG5Service(); } } else { - Log.d(TAG, "processConnectG5 connectG5=false - startBtG5Service"); + Log.d(TAG, "processConnectG5 enable_wearG5=false - startBtG5Service"); startBtG5Service(); } } @@ -171,10 +194,8 @@ public void processConnectG5() {//KS } } - public void syncTransmitterData(DataMap dataMap) {//KS + private synchronized void syncTransmitterData(DataMap dataMap) {//KS Log.d(TAG, "syncTransmitterData"); - java.text.DateFormat df = new SimpleDateFormat("MM.dd.yyyy HH:mm:ss"); - Date date = new Date(); ArrayList entries = dataMap.getDataMapArrayList("entries"); long timeOfLastBG = 0; @@ -201,12 +222,11 @@ public void syncTransmitterData(DataMap dataMap) {//KS //TransmitterData bgData = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create().fromJson(bgrecord, TransmitterData.class); TransmitterData exists = TransmitterData.getForTimestamp(bgData.timestamp); TransmitterData uuidexists = TransmitterData.findByUuid(bgData.uuid); - date.setTime(bgData.timestamp); timeOfLastBG = bgData.timestamp + 1; if (exists != null || uuidexists != null) { - Log.d(TAG, "syncTransmitterData BG already exists for uuid=" + bgData.uuid + " timestamp=" + bgData.timestamp + " timeString=" + df.format(date) + " raw_data=" + bgData.raw_data); + Log.d(TAG, "syncTransmitterData BG already exists for uuid=" + bgData.uuid + " timestamp=" + bgData.timestamp + " timeString=" + JoH.dateTimeText(bgData.timestamp) + " raw_data=" + bgData.raw_data); } else { - Log.d(TAG, "syncTransmitterData add BG; does NOT exist for uuid=" + bgData.uuid + " timestamp=" + bgData.timestamp + " timeString=" + df.format(date) + " raw_data=" + bgData.raw_data); + Log.d(TAG, "syncTransmitterData add BG; does NOT exist for uuid=" + bgData.uuid + " timestamp=" + bgData.timestamp + " timeString=" + JoH.dateTimeText(bgData.timestamp) + " raw_data=" + bgData.raw_data); bgData.save(); //Check @@ -273,7 +293,7 @@ public static void sendTreatment(double carbs, double insulin, double bloodtest, } } - public static boolean doMgdl(SharedPreferences sPrefs) { + private static boolean doMgdl(SharedPreferences sPrefs) { String unit = sPrefs.getString("units", "mgdl"); if (unit.compareTo("mgdl") == 0) { return true; @@ -290,37 +310,35 @@ public void onCreate() { if (wear_integration) { googleApiConnect(); } - listenForChangeInSettings(); setSettings(); + listenForChangeInSettings(); } - public void listenForChangeInSettings() { + private void listenForChangeInSettings() { mPreferencesListener = new SharedPreferences.OnSharedPreferenceChangeListener() { public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { - setSettings(); + Log.d(TAG, "onSharedPreferenceChanged enter key=" + key); + pebble_integration = mPrefs.getBoolean("pebble_sync", false); + sendPrefSettings(); + processConnectG5(); } }; mPrefs.registerOnSharedPreferenceChangeListener(mPreferencesListener); } - public void setSettings() { + private void setSettings() { Log.d(TAG, "setSettings enter"); - //wear_integration = mPrefs.getBoolean("wear_sync", false); // if mPrefs is set so will this be already pebble_integration = mPrefs.getBoolean("pebble_sync", false); - boolean connectG5 = mPrefs.getBoolean("wear_connectG5", false); - boolean use_connectG5 = mPrefs.getBoolean("use_wear_connectG5", false); processConnectG5(); if (wear_integration) { if (googleApiClient == null) googleApiConnect(); Log.d(TAG, "setSettings wear_sync changed to True."); sendPrefSettings(); - } else { - this.stopService(new Intent(this, WatchUpdaterService.class)); } } - public void googleApiConnect() { + private void googleApiConnect() { if (googleApiClient != null && (googleApiClient.isConnected() || googleApiClient.isConnecting())) { googleApiClient.disconnect(); } @@ -343,15 +361,16 @@ public void onPeerConnected(com.google.android.gms.wearable.Node peer) {//KS String id = peer.getId(); String name = peer.getDisplayName(); Log.d(TAG, "onPeerConnected peer name & ID: " + name + "|" + id); - if (mPrefs.getBoolean("wear_connectG5", false)) {//watch_integration + sendPrefSettings(); + if (mPrefs.getBoolean("enable_wearG5", false)) {//watch_integration Log.d(TAG, "onPeerConnected call initWearData for node=" + peer.getDisplayName()); initWearData(); //Only stop service if Phone will rely on Wear Collection Service - if (mPrefs.getBoolean("use_wear_connectG5", false)) { - Log.d(TAG, "onPeerConnected use_wear_connectG5=true Phone stopBtG5Service and continue to use Wear G5 BT Collector"); + if (mPrefs.getBoolean("force_wearG5", false)) { + Log.d(TAG, "onPeerConnected force_wearG5=true Phone stopBtG5Service and continue to use Wear G5 BT Collector"); stopBtG5Service(); } else { - Log.d(TAG, "onPeerConnected onPeerConnected use_wear_connectG5=false Phone startBtG5Service"); + Log.d(TAG, "onPeerConnected onPeerConnected force_wearG5=false Phone startBtG5Service"); startBtG5Service(); } } @@ -372,6 +391,7 @@ public void onPeerDisconnected(com.google.android.gms.wearable.Node peer) {//KS private void startBtG5Service() {//KS Log.d(TAG, "startBtG5Service"); + is_using_g5 = (getDexCollectionType() == DexCollectionType.DexcomG5); if (is_using_g5) { Context myContext = getApplicationContext(); Log.d(TAG, "startBtG5Service start G5CollectionService"); @@ -391,10 +411,6 @@ private void stopBtG5Service() {//KS @Override public int onStartCommand(Intent intent, int flags, int startId) { final PowerManager.WakeLock wl = JoH.getWakeLock("watchupdate-onstart",60000); - double timestamp = 0; - if (intent != null) { - timestamp = intent.getDoubleExtra("timestamp", 0); - } String action = null; if (intent != null) { @@ -417,12 +433,17 @@ public int onStartCommand(Intent intent, int flags, int startId) { sendSensorData(); } else if (ACTION_SYNC_CALIBRATION.equals(action)) {//KS Log.d(TAG, "onStartCommand Action=" + ACTION_SYNC_CALIBRATION + " Path=" + WEARABLE_CALIBRATION_DATA_PATH); + sendWearCalibrationData(sendCalibrationCount); + final boolean adjustPast = mPrefs.getBoolean("rewrite_history", true); + Log.d(TAG, "onStartCommand adjustRecentBgReadings for rewrite_history=" + adjustPast); + sendWearBgData(adjustPast ? 30 : 2);//wear may not have all BGs if force_wearG5=false, so send BGs from phone + } else { - if (!mPrefs.getBoolean("use_wear_connectG5", false) - || !mPrefs.getBoolean("wear_connectG5",false) - || (!is_using_g5)) { //KS only send BGs if using Phone's G5 Collector Server - sendData(); + sendData(); + if (!mPrefs.getBoolean("force_wearG5", false) + && mPrefs.getBoolean("enable_wearG5",false) + && (is_using_g5)) { //KS only send BGs if using Phone's G5 Collector Server sendWearBgData(1); Log.d(TAG, "onStartCommand Action=" + " Path=" + WEARABLE_BG_DATA_PATH); } @@ -449,12 +470,43 @@ public int onStartCommand(Intent intent, int flags, int startId) { return START_STICKY; } + private void updateWearSyncBgsCapability(CapabilityInfo capabilityInfo) { + Set connectedNodes = capabilityInfo.getNodes(); + mWearNodeId = pickBestNodeId(connectedNodes); + } + + private String pickBestNodeId(Set nodes) { + String bestNodeId = null; + // Find a nearby node or pick one arbitrarily + for (Node node : nodes) { + if (node.isNearby()) { + return node.getId(); + } + bestNodeId = node.getId(); + } + return bestNodeId; + } + @Override public void onConnected(Bundle connectionHint) { Log.d(TAG, "onConnected entered");//KS - new CheckWearableConnected().execute(); + CapabilityApi.CapabilityListener capabilityListener = + new CapabilityApi.CapabilityListener() { + @Override + public void onCapabilityChanged(CapabilityInfo capabilityInfo) { + updateWearSyncBgsCapability(capabilityInfo); + Log.d(TAG, "onConnected onCapabilityChanged mWearNodeID:" + mWearNodeId); + new CheckWearableConnected().execute(); + } + }; + + Wearable.CapabilityApi.addCapabilityListener( + googleApiClient, + capabilityListener, + CAPABILITY_WEAR_APP); sendData(); } + private class CheckWearableConnected extends AsyncTask { @Override @@ -462,42 +514,66 @@ protected Void doInBackground(Void... voids) { if (googleApiClient.isConnected()) { if (System.currentTimeMillis() - lastRequest > 20 * 1000) { // enforce 20-second debounce period lastRequest = System.currentTimeMillis(); - NodeApi.GetConnectedNodesResult nodes = - Wearable.NodeApi.getConnectedNodes(googleApiClient).await(); + //NodeApi.GetConnectedNodesResult nodes = + // Wearable.NodeApi.getConnectedNodes(googleApiClient).await(); + NodeApi.GetLocalNodeResult localnodes = Wearable.NodeApi.getLocalNode(googleApiClient).await(); + Node node = localnodes != null ? localnodes.getNode() : null; + String localnode = node != null ? node.getDisplayName() + "|" + node.getId() : ""; + Log.d(TAG, "doInBackground. getLocalNode name=" + localnode); + Log.d(TAG, "doInBackground connected. localnode=" + localnode);//KS + CapabilityApi.GetCapabilityResult capResult = + Wearable.CapabilityApi.getCapability( + googleApiClient, CAPABILITY_WEAR_APP, + CapabilityApi.FILTER_REACHABLE).await(); + CapabilityInfo nodes = capResult.getCapability(); + updateWearSyncBgsCapability(nodes); + int count = nodes.getNodes().size();//KS + Log.d(TAG, "doInBackground connected. CapabilityApi.GetCapabilityResult mWearNodeID=" + (mWearNodeId != null ? mWearNodeId : "") + " count=" + count);//KS + SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + SharedPreferences.Editor prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).edit(); + boolean enable_wearG5 = sharedPrefs.getBoolean("enable_wearG5", false); + boolean force_wearG5 = sharedPrefs.getBoolean("force_wearG5", false); + String node_wearG5 = mPrefs.getString("node_wearG5", ""); if (nodes != null && nodes.getNodes().size() > 0) { - //isConnectedToWearable = true; + boolean isConnectedToWearable = false; for (Node peer : nodes.getNodes()) { //onPeerConnected - String id = peer.getId(); - String name = peer.getDisplayName(); - Log.d(TAG, "CheckWearableConnected onPeerConnected peer name & ID: " + name + "|" + id); - SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); - sendPrefSettings(); - if (sharedPrefs.getBoolean("wear_connectG5", false)) {//watch_integration + String wearNode = peer.getDisplayName() + "|" + peer.getId(); + Log.d(TAG, "CheckWearableConnected onPeerConnected peer name & ID: " + wearNode); + if (wearNode.equals(node_wearG5)) { + isConnectedToWearable = true; + sendPrefSettings(); + } + else if (node_wearG5.equals("")) { + isConnectedToWearable = true; + prefs.putString("node_wearG5", wearNode); + prefs.commit(); + } + else + sendPrefSettings(); + if (enable_wearG5) {//watch_integration Log.d(TAG, "CheckWearableConnected onPeerConnected call initWearData for node=" + peer.getDisplayName()); initWearData(); - //Only stop service if Phone will rely on Wear Collection Service - if (sharedPrefs.getBoolean("use_wear_connectG5", false)) { - Log.d(TAG, "CheckWearableConnected onPeerConnected use_wear_connectG5=true Phone stopBtG5Service and continue to use Wear G5 BT Collector"); - stopBtG5Service(); - } - else { - Log.d(TAG, "CheckWearableConnected onPeerConnected use_wear_connectG5=false Phone startBtG5Service"); - startBtG5Service(); - } + } + } + if (enable_wearG5) { + //Only stop service if Phone will rely on Wear Collection Service + if (force_wearG5 && isConnectedToWearable) { + Log.d(TAG, "CheckWearableConnected onPeerConnected force_wearG5=true Phone stopBtG5Service and continue to use Wear G5 BT Collector"); + stopBtG5Service(); + } else { + Log.d(TAG, "CheckWearableConnected onPeerConnected force_wearG5=false Phone startBtG5Service"); + startBtG5Service(); } } } else { //onPeerDisconnected - //String id = peer.getId(); - //String name = peer.getDisplayName(); Log.d(TAG, "CheckWearableConnected onPeerDisconnected"); - SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); - if (sharedPrefs.getBoolean("watch_integration", false)) { - Log.d(TAG, "CheckWearableConnected onPeerDisconnected watch_integration=true Phone startBtG5Service"); + if (sharedPrefs.getBoolean("wear_sync", false)) { + Log.d(TAG, "CheckWearableConnected onPeerDisconnected wear_sync=true Phone startBtG5Service"); startBtG5Service(); } } @@ -522,7 +598,6 @@ protected Void doInBackground(Void... voids) { if (event.getType() == DataEvent.TYPE_CHANGED) { String path = event.getDataItem().getUri().getPath(); - //String nodeId = event.getDataItem().getUri().getHost(); switch (path) { case WEARABLE_PREF_DATA_PATH: @@ -570,7 +645,6 @@ public void onMessageReceived(MessageEvent event) { cancelTreatment(getApplicationContext(), ""); break; case SYNC_BGS_PATH://KS - //String message = new String(event.getData()); DataMap dataMap = DataMap.fromByteArray(event.getData()); if (dataMap != null) { Log.d(TAG, "onMessageReceived SYNC_BGS_PATH dataMap=" + dataMap); @@ -586,14 +660,16 @@ public void onMessageReceived(MessageEvent event) { break; default: Log.d(TAG, "Unknown wearable path: " + event.getPath()); - break; + super.onMessageReceived(event); } } JoH.releaseWakeLock(wl); + } else { + super.onMessageReceived(event); } } - public void sendData() { + private void sendData() { BgReading bg = BgReading.last(); if (bg != null) { if (googleApiClient != null && !googleApiClient.isConnected() && !googleApiClient.isConnecting()) { @@ -660,35 +736,46 @@ private DataMap dataMap(BgReading bg, SharedPreferences sPrefs, BgGraphBuilder b dataMap.putDouble("sgvDouble", bg.calculated_value); dataMap.putDouble("high", inMgdl(highMark, sPrefs)); dataMap.putDouble("low", inMgdl(lowMark, sPrefs)); - //dataMap.putString("dex_txid", sPrefs.getString("dex_txid", "ABCDEF"));//KS - //dataMap.putString("units", sPrefs.getString("units", "mgdl"));//KS //TODO: Add raw again //dataMap.putString("rawString", threeRaw((prefs.getString("units", "mgdl").equals("mgdl")))); return dataMap; } - private void sendPrefSettings() {//KS if(googleApiClient != null && !googleApiClient.isConnected() && !googleApiClient.isConnecting()) { googleApiConnect(); } + DataMap dataMap = new DataMap(); + String dexCollector = "None"; + boolean enable_wearG5 = false; + boolean force_wearG5 = false; + String node_wearG5 = ""; + wear_integration = mPrefs.getBoolean("wear_sync", false); if (wear_integration) { - Double highMark = Double.parseDouble(mPrefs.getString("highValue", "170")); - Double lowMark = Double.parseDouble(mPrefs.getString("lowValue", "70")); - DataMap dataMap = new DataMap(); - boolean connectG5 = mPrefs.getBoolean("wear_connectG5", false); - boolean use_connectG5 = mPrefs.getBoolean("use_wear_connectG5", false); - Log.d(TAG, "sendPrefSettings connectG5: " + connectG5 + " use_connectG5:" + use_connectG5); - dataMap.putBoolean("connectG5", connectG5); - dataMap.putBoolean("use_connectG5", use_connectG5); - dataMap.putString("dex_txid", mPrefs.getString("dex_txid", "ABCDEF")); - dataMap.putString("units", mPrefs.getString("units", "mgdl")); - dataMap.putDouble("high", inMgdl(highMark, mPrefs)); - dataMap.putDouble("low", inMgdl(lowMark, mPrefs)); - new SendToDataLayerThread(WEARABLE_PREF_DATA_PATH, googleApiClient).executeOnExecutor(xdrip.executor, dataMap); - } - } - - public void sendSensorData() {//KS + Log.d(TAG, "sendPrefSettings wear_sync=true"); + dexCollector = mPrefs.getString("dex_collection_method", "DexcomG5"); + enable_wearG5 = mPrefs.getBoolean("enable_wearG5", false); + force_wearG5 = mPrefs.getBoolean("force_wearG5", false); + node_wearG5 = mPrefs.getString("node_wearG5", ""); + dataMap.putString("dex_collection_method", dexCollector); + dataMap.putBoolean("rewrite_history", mPrefs.getBoolean("rewrite_history", true)); + dataMap.putBoolean("enable_wearG5", enable_wearG5); + dataMap.putBoolean("force_wearG5", force_wearG5); + dataMap.putString("node_wearG5", node_wearG5); + } + is_using_g5 = (getDexCollectionType() == DexCollectionType.DexcomG5); + + Double highMark = Double.parseDouble(mPrefs.getString("highValue", "170")); + Double lowMark = Double.parseDouble(mPrefs.getString("lowValue", "70")); + Log.d(TAG, "sendPrefSettings enable_wearG5: " + enable_wearG5 + " force_wearG5:" + force_wearG5 + " node_wearG5:" + node_wearG5 + " dex_collection_method:" + dexCollector); + dataMap.putLong("time", new Date().getTime()); // MOST IMPORTANT LINE FOR TIMESTAMP + dataMap.putString("dex_txid", mPrefs.getString("dex_txid", "ABCDEF")); + dataMap.putString("units", mPrefs.getString("units", "mgdl")); + dataMap.putDouble("high", inMgdl(highMark, mPrefs)); + dataMap.putDouble("low", inMgdl(lowMark, mPrefs)); + new SendToDataLayerThread(WEARABLE_PREF_DATA_PATH, googleApiClient).executeOnExecutor(xdrip.executor, dataMap); + } + + private void sendSensorData() {//KS if (is_using_g5) { if (googleApiClient != null && !googleApiClient.isConnected() && !googleApiClient.isConnecting()) { googleApiConnect(); @@ -697,10 +784,9 @@ public void sendSensorData() {//KS if (sensor != null) { if (wear_integration) { DataMap dataMap = new DataMap(); - Log.d(TAG, "Sensor sendSensorData uuid=" + sensor.uuid + " started_at=" + sensor.started_at + " active=" + sensor.isActive() + " battery=" + sensor.latest_battery_level + " location=" + sensor.sensor_location + " stopped_at=" + sensor.stopped_at); + Log.d(TAG, "Sensor sendSensorData uuid=" + sensor.uuid + " started_at=" + sensor.started_at + " active=" + Sensor.isActive() + " battery=" + sensor.latest_battery_level + " location=" + sensor.sensor_location + " stopped_at=" + sensor.stopped_at); String json = sensor.toS(); Log.d(TAG, "dataMap sendSensorData GSON: " + json); - //dataMap.putString("data", json); dataMap.putLong("time", new Date().getTime()); // MOST IMPORTANT LINE FOR TIMESTAMP @@ -719,66 +805,54 @@ public void sendSensorData() {//KS } private void sendWearCalibrationData(Integer count) {//KS - if (is_using_g5) { + try { + if (count == null) return; if (googleApiClient != null && !googleApiClient.isConnected() && !googleApiClient.isConnecting()) { googleApiConnect(); } Log.d(TAG, "sendWearCalibrationData"); - Calibration last = Calibration.last(); - List lastest = Calibration.latest(count); - if (lastest != null && !lastest.isEmpty()) { - Log.d(TAG, "sendWearCalibrationData lastest count = " + lastest.size()); - DataMap entries = dataMap(last); - final ArrayList dataMaps = new ArrayList<>(lastest.size()); - for (Calibration cal : lastest) { - dataMaps.add(dataMap(cal)); + final Sensor sensor = Sensor.currentSensor(); + final Calibration last = Calibration.last(); + + List latest; + BgReading lastBgReading = BgReading.last(); + //From BgReading: if (lastBgReading.calibration_flag == true && ((lastBgReading.timestamp + (60000 * 20)) > bgReading.timestamp) && ((lastBgReading.calibration.timestamp + (60000 * 20)) > bgReading.timestamp)) + //From BgReading: lastBgReading.calibration.rawValueOverride() + if (lastBgReading != null && lastBgReading.calibration != null && lastBgReading.calibration_flag == true) { + Log.d(TAG, "sendWearCalibrationData lastBgReading.calibration_flag=" + lastBgReading.calibration_flag + " lastBgReading.timestamp: " + lastBgReading.timestamp + " lastBgReading.calibration.timestamp: " + lastBgReading.calibration.timestamp); + latest = Calibration.allForSensor(); + } + else { + latest = Calibration.latest(count); + } + + if ((sensor != null) && (last != null) && (latest != null && !latest.isEmpty())) { + Log.d(TAG, "sendWearCalibrationData latest count = " + latest.size()); + final DataMap entries = dataMap(last); + final ArrayList dataMaps = new ArrayList<>(latest.size()); + if (sensor.uuid != null) { + for (Calibration bg : latest) { + if ((bg != null) && (bg.sensor_uuid != null) && (bg.sensor_uuid.equals(sensor.uuid))) { + dataMaps.add(dataMap(bg)); + } + } } entries.putLong("time", new Date().getTime()); // MOST IMPORTANT LINE FOR TIMESTAMP entries.putDataMapArrayList("entries", dataMaps); - new SendToDataLayerThread(WEARABLE_CALIBRATION_DATA_PATH, googleApiClient).executeOnExecutor(xdrip.executor, entries); + if (googleApiClient != null) + new SendToDataLayerThread(WEARABLE_CALIBRATION_DATA_PATH, googleApiClient).executeOnExecutor(xdrip.executor, entries); } else - Log.d(TAG, "sendWearCalibrationData lastest count = 0"); - } else { - Log.d(TAG, "Not sending calibration data as G5 is not our data source"); + Log.d(TAG, "sendWearCalibrationData latest count = 0"); + } catch (NullPointerException e) { + Log.e(TAG, "Nullpointer exception in sendWearBgData: " + e); } } - private DataMap dataMap(Calibration cal) {//KS - + private DataMap dataMap(Calibration bg) {//KS DataMap dataMap = new DataMap(); - String json = cal.toS(); - Log.d(TAG, "dataMap Calibration GSON: " + json); - - Sensor sensor = Sensor.currentSensor(); - if (sensor != null && cal.sensor_uuid.equals(sensor.uuid)) { - dataMap.putLong("timestamp", cal.timestamp);////Long.valueOf("1472590518540").longValue() - dataMap.putDouble("sensor_age_at_time_of_estimation", cal.sensor_age_at_time_of_estimation); - dataMap.putDouble("bg", cal.bg); - dataMap.putDouble("raw_value", cal.raw_value); - dataMap.putDouble("adjusted_raw_value", cal.adjusted_raw_value); - dataMap.putDouble("sensor_confidence", cal.sensor_confidence); - dataMap.putDouble("slope_confidence", cal.slope_confidence); - dataMap.putLong("raw_timestamp", cal.raw_timestamp);//Long.valueOf("1472590518540").longValue() - dataMap.putDouble("slope", cal.slope); - dataMap.putDouble("intercept", cal.intercept); - dataMap.putDouble("distance_from_estimate", cal.distance_from_estimate); - dataMap.putDouble("estimate_raw_at_time_of_calibration", cal.estimate_raw_at_time_of_calibration); - dataMap.putDouble("estimate_bg_at_time_of_calibration", cal.estimate_bg_at_time_of_calibration); - dataMap.putString("uuid", cal.uuid); - dataMap.putString("sensor_uuid", sensor.uuid); - dataMap.putBoolean("possible_bad", (cal.possible_bad != null ? cal.possible_bad : true)); - dataMap.putBoolean("check_in", cal.check_in); - dataMap.putDouble("first_decay", cal.first_decay); - dataMap.putDouble("second_decay", cal.second_decay); - dataMap.putDouble("first_slope", cal.first_slope); - dataMap.putDouble("second_slope", cal.second_slope); - dataMap.putDouble("first_intercept", cal.first_intercept); - dataMap.putDouble("second_intercept", cal.second_intercept); - dataMap.putDouble("first_scale", cal.first_scale); - dataMap.putDouble("second_scale", cal.second_scale); - } - else - Log.d(TAG, "dataMap Calibration sensor does not exist."); + String json = bg.toS(); + Log.d(TAG, "dataMap BG GSON: " + json); + dataMap.putString("bgs", json); return dataMap; } @@ -790,14 +864,14 @@ private void sendWearBgData(Integer count) {//KS } Log.d(TAG, "sendWearBgData"); final BgReading last = BgReading.last(); - final List lastest = BgReading.latest(count); - if ((last != null) && (lastest != null && !lastest.isEmpty())) { - Log.d(TAG, "sendWearBgData lastest count = " + lastest.size()); + final List latest = BgReading.latest(count); + if ((last != null) && (latest != null && !latest.isEmpty())) { + Log.d(TAG, "sendWearBgData latest count = " + latest.size()); final DataMap entries = dataMap(last); - final ArrayList dataMaps = new ArrayList<>(lastest.size()); + final ArrayList dataMaps = new ArrayList<>(latest.size()); final Sensor sensor = Sensor.currentSensor(); if ((sensor != null) && (sensor.uuid != null)) { - for (BgReading bg : lastest) { + for (BgReading bg : latest) { if ((bg != null) && (bg.sensor_uuid != null) && (bg.sensor_uuid.equals(sensor.uuid))) { dataMaps.add(dataMap(bg)); } @@ -816,6 +890,12 @@ private void sendWearBgData(Integer count) {//KS private DataMap dataMap(BgReading bg) {//KS DataMap dataMap = new DataMap(); + //KS Fix for calibration_uuid not being set in Calibration.create which updates bgReading to new calibration ln 497 + //if (bg.calibration_flag == true) { + // bg.calibration_uuid = bg.calibration.uuid; + //} + dataMap.putString("calibrationUuid", bg.calibration.uuid); + String json = bg.toS(); Log.d(TAG, "dataMap BG GSON: " + json); dataMap.putString("bgs", json); @@ -833,7 +913,7 @@ private void initWearData() { } } - public long sgvLevel(double sgv_double, SharedPreferences prefs, BgGraphBuilder bgGB) { + private long sgvLevel(double sgv_double, SharedPreferences prefs, BgGraphBuilder bgGB) { Double highMark = Double.parseDouble(prefs.getString("highValue", "170")); Double lowMark = Double.parseDouble(prefs.getString("lowValue", "70")); if (bgGB.unitized(sgv_double) >= highMark) { @@ -845,7 +925,7 @@ public long sgvLevel(double sgv_double, SharedPreferences prefs, BgGraphBuilder } } - public double inMgdl(double value, SharedPreferences sPrefs) { + private double inMgdl(double value, SharedPreferences sPrefs) { if (!doMgdl(sPrefs)) { return value * Constants.MMOLL_TO_MGDL; } else { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 29ac121d3e..8cf930d994 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -227,10 +227,12 @@ Wear Integration Send data to Android Wear Watchface. Android Wear Integration - Connect Wear to G5 - Connect Wear directly to G5 - Use Wear G5 Collection Service - Force phone to use Wear G5 Collection Service + Enable Wear G5 Collection Service + Connect Wear to G5 when phone is out-of-range + Force Wear G5 Collection Service + Force phone to use Wear G5 Collection Service + Device running G5 Collection Service + Force phone to use this Wear G5 Collection Service Pebble Integration Send data to Pebble Watchface. Pebble Watch Integration diff --git a/app/src/main/res/values/wear.xml b/app/src/main/res/values/wear.xml new file mode 100644 index 0000000000..fa62dc1a8a --- /dev/null +++ b/app/src/main/res/values/wear.xml @@ -0,0 +1,19 @@ + + + + + + phone_app_sync_bgs + + \ No newline at end of file diff --git a/app/src/main/res/xml/pref_advanced_settings.xml b/app/src/main/res/xml/pref_advanced_settings.xml index b450cee100..f77eb19e1b 100644 --- a/app/src/main/res/xml/pref_advanced_settings.xml +++ b/app/src/main/res/xml/pref_advanced_settings.xml @@ -18,15 +18,21 @@ + android:key="enable_wearG5" + android:summary="@string/pref_summary_enable_wearG5" + android:title="@string/pref_enable_wearG5"/> + android:dependency="enable_wearG5" + android:key="force_wearG5" + android:summary="@string/pref_summary_force_wearG5" + android:title="@string/pref_force_wearG5"/> + 0 && cardWidth > 0 && getCurrentWatchMode() != WatchMode.INTERACTIVE) { + Paint paint = new Paint(); + paint.setColor(Color.BLACK); + paint.setStrokeWidth(0); + canvas.drawRect(mCardRect, paint); + } } } @Override protected void onTimeChanged(WatchFaceTime oldTime, WatchFaceTime newTime) { - if (layoutSet && (newTime.hasHourChanged(oldTime) || newTime.hasMinuteChanged(oldTime))) { - wakeLock.acquire(50); - final java.text.DateFormat timeFormat = DateFormat.getTimeFormat(BIGChart.this); - mTime.setText(timeFormat.format(System.currentTimeMillis())); - showAgoRawBatt(); + if (newTime.hasHourChanged(oldTime) || newTime.hasMinuteChanged(oldTime)) { + if (layoutSet) { + wakeLock.acquire(50); + final java.text.DateFormat timeFormat = DateFormat.getTimeFormat(BIGChart.this); + mTime.setText(timeFormat.format(System.currentTimeMillis())); + showAgoRawBatt(); - if(ageLevel()<=0) { - mSgv.setPaintFlags(mSgv.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG); - } else { - mSgv.setPaintFlags(mSgv.getPaintFlags() & ~Paint.STRIKE_THRU_TEXT_FLAG); - } + if (ageLevel() <= 0) { + mSgv.setPaintFlags(mSgv.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG); + } else { + mSgv.setPaintFlags(mSgv.getPaintFlags() & ~Paint.STRIKE_THRU_TEXT_FLAG); + } - missedReadingAlert(); - mRelativeLayout.measure(specW, specH); - mRelativeLayout.layout(0, 0, mRelativeLayout.getMeasuredWidth(), - mRelativeLayout.getMeasuredHeight()); + missedReadingAlert(); + mRelativeLayout.measure(specW, specH); + mRelativeLayout.layout(0, 0, mRelativeLayout.getMeasuredWidth(), + mRelativeLayout.getMeasuredHeight()); + } + else { + missedReadingAlert();//KS TEST otherwise, it can be 10+ minutes before missedReadingAlert is called; hwr, aggressive restart does not always resolve ble connection + } } } @@ -265,6 +283,16 @@ private void showAgoRawBatt() { } public void setColor() { + if (getCurrentWatchMode() == WatchMode.INTERACTIVE) { + lowColorWatchMode = Color.RED; + } + else { + //RED is not supported in Ambient mode on WatchMode=LOW_BIT sa Sony SmartWatch 3 + //Therefore, use a cold color to indicate a low value + int prefColor = Integer.parseInt(sharedPrefs.getString("ambient_lowcolor", "3")); + int[] rainbow = {Color.CYAN, Color.GREEN, Color.RED, Color.WHITE}; + lowColorWatchMode = rainbow[prefColor-1]; + } if (sharedPrefs.getBoolean("dark", false)) { setColorDark(); } else { @@ -338,8 +366,53 @@ public void run() { animator.start(); } + private void resetRelativeLayout() { + mRelativeLayout.measure(specW, specH); + mRelativeLayout.layout(0, 0, mRelativeLayout.getMeasuredWidth(), + mRelativeLayout.getMeasuredHeight()); + Log.d("resetRelativeLayout", "specW=" + specW + " specH=" + specH + " mRelativeLayout.getMeasuredWidth()=" + mRelativeLayout.getMeasuredWidth() + " mRelativeLayout.getMeasuredHeight()=" + mRelativeLayout.getMeasuredHeight()); + } + + private void displayCard() { + int cardWidth = mCardRect.width(); + int cardHeight = mCardRect.height(); + Log.d("displayCard", "WatchFace.onCardPeek: getWidth()=" + getWidth() + " getHeight()=" + getHeight() + " cardWidth=" + cardWidth + " cardHeight=" + cardHeight); + + if (cardHeight > 0 && cardWidth > 0) { + if (getCurrentWatchMode() != WatchMode.INTERACTIVE) { + // get height of visible area (not including card) + int visibleWidth = getWidth() - cardWidth; + int visibleHeight = getHeight() - cardHeight; + Log.d("onCardPeek", "WatchFace.onCardPeek: visibleWidth=" + visibleWidth + " visibleHeight=" + visibleHeight); + mRelativeLayout.layout(0, 0, visibleWidth, visibleHeight); + } + else + resetRelativeLayout(); + } + else + resetRelativeLayout(); + invalidate(); + } + + @Override + protected void onCardPeek(Rect peekCardRect) { + mCardRect = peekCardRect; + displayCard(); + int cardWidth = peekCardRect.width(); + int cardHeight = peekCardRect.height(); + Log.d("onCardPeek", "WatchFace.onCardPeek: getWidth()=" + getWidth() + " getHeight()=" + getHeight() + " cardWidth=" + cardWidth + " cardHeight=" + cardHeight); + } + + @Override + protected void onWatchModeChanged(WatchMode watchMode) { + Log.d("onWatchModeChanged", "WatchFace.onWatchModeChanged: watchMode=" + watchMode.name()); + invalidate(); + setColor(); + } protected void setColorDark() { + Log.d("setColorDark", "WatchMode=" + getCurrentWatchMode()); + mTime.setTextColor(Color.WHITE); mRelativeLayout.setBackgroundColor(Color.BLACK); if (sgvLevel == 1) { @@ -349,15 +422,15 @@ protected void setColorDark() { mSgv.setTextColor(Color.WHITE); mDelta.setTextColor(Color.WHITE); } else if (sgvLevel == -1) { - mSgv.setTextColor(Color.RED); - mDelta.setTextColor(Color.RED); + mSgv.setTextColor(lowColorWatchMode); + mDelta.setTextColor(lowColorWatchMode); } if (ageLevel == 1) { mTimestamp.setTextColor(Color.WHITE); } else { - mTimestamp.setTextColor(Color.RED); + mTimestamp.setTextColor(lowColorWatchMode); } if (batteryLevel == 1) { @@ -365,7 +438,7 @@ protected void setColorDark() { } if (chart != null) { highColor = Color.YELLOW; - lowColor = Color.RED; + lowColor = lowColorWatchMode; midColor = Color.WHITE; singleLine = false; pointSize = 2; @@ -377,6 +450,7 @@ protected void setColorDark() { protected void setColorBright() { + Log.d("setColorBright", "WatchMode=" + getCurrentWatchMode()); if (getCurrentWatchMode() == WatchMode.INTERACTIVE) { mRelativeLayout.setBackgroundColor(Color.WHITE); if (sgvLevel == 1) { @@ -407,6 +481,8 @@ protected void setColorBright() { setupCharts(); } } else { + //RED is not supported in Ambient mode on WatchMode=LOW_BIT sa Sony SmartWatch 3 + //Therefore, use a cold color to indicate a low value mRelativeLayout.setBackgroundColor(Color.BLACK); if (sgvLevel == 1) { mSgv.setTextColor(Color.YELLOW); @@ -415,8 +491,8 @@ protected void setColorBright() { mSgv.setTextColor(Color.WHITE); mDelta.setTextColor(Color.WHITE); } else if (sgvLevel == -1) { - mSgv.setTextColor(Color.RED); - mDelta.setTextColor(Color.RED); + mSgv.setTextColor(lowColorWatchMode); + mDelta.setTextColor(lowColorWatchMode); } mTimestamp.setTextColor(Color.WHITE); @@ -424,7 +500,7 @@ protected void setColorBright() { if (chart != null) { highColor = Color.YELLOW; midColor = Color.WHITE; - lowColor = Color.RED; + lowColor = lowColorWatchMode; singleLine = true; pointSize = 2; setupCharts(); @@ -436,10 +512,13 @@ protected void setColorBright() { public void missedReadingAlert() { int minutes_since = (int) Math.floor(timeSince() / (1000 * 60)); - // if(minutes_since >= 16 && ((minutes_since - 16) % 5) == 0) { - Log.d("BIGChart", "missedReadingAlert Enter minutes_since " + minutes_since + " call requestData if >= 4 minutes mod 5");//KS - //if(minutes_since >= 16 && ((minutes_since - 16) % 5) == 0) { - if (minutes_since >= 4 && ((minutes_since - 4) % 5) == 0) {//KS TODO reduce time for debugging; add notifications + int maxDelay = 16; + if (sharedPrefs.getBoolean("enable_wearG5", false)) { + maxDelay = 4; + Log.d("BIGChart", "missedReadingAlert Enter minutes_since " + minutes_since + " call requestData if >= 4 minutes mod 5");//KS + } + + if (minutes_since >= maxDelay && ((minutes_since - maxDelay) % 5) == 0) {//KS TODO reduce time for debugging; add notifications /*NotificationCompat.Builder notification = new NotificationCompat.Builder(getApplicationContext()) .setContentTitle("Missed BG Readings") .setVibrate(vibratePattern); @@ -449,37 +528,44 @@ public void missedReadingAlert() { } } + public void addDataMap(DataMap dataMap) {//KS + double sgv = dataMap.getDouble("sgvDouble"); + double high = dataMap.getDouble("high"); + double low = dataMap.getDouble("low"); + double timestamp = dataMap.getDouble("timestamp"); + + Log.d("addToWatchSet", "entry=" + dataMap); + + final int size = bgDataList.size(); + BgWatchData bgdata = new BgWatchData(sgv, high, low, timestamp); + if (size > 0) { + if (bgDataList.contains(bgdata)) { + int i = bgDataList.indexOf(bgdata); + BgWatchData bgd = bgDataList.get(bgDataList.indexOf(bgdata)); + Log.d("addToWatchSet", "replace indexOf=" + i + " bgDataList.sgv=" + bgd.sgv + " bgDataList.timestamp" + bgd.timestamp); + bgDataList.set(i, bgdata); + } else { + Log.d("addToWatchSet", "add " + " entry.sgv=" + bgdata.sgv + " entry.timestamp" + bgdata.timestamp); + bgDataList.add(bgdata); + } + } + else { + bgDataList.add(bgdata); + } + } + public void addToWatchSet(DataMap dataMap) { + Log.d("addToWatchSet", "bgDataList.size()=" + bgDataList.size()); + ArrayList entries = dataMap.getDataMapArrayList("entries"); if (entries != null) { + Log.d("addToWatchSet", "entries.size()=" + entries.size()); for (DataMap entry : entries) { - double sgv = entry.getDouble("sgvDouble"); - double high = entry.getDouble("high"); - double low = entry.getDouble("low"); - double timestamp = entry.getDouble("timestamp"); - - final int size = bgDataList.size(); - if (size > 0) { - if (bgDataList.get(size - 1).timestamp == timestamp) - continue; // Ignore duplicates. - } - - bgDataList.add(new BgWatchData(sgv, high, low, timestamp)); + addDataMap(entry); } } else { - double sgv = dataMap.getDouble("sgvDouble"); - double high = dataMap.getDouble("high"); - double low = dataMap.getDouble("low"); - double timestamp = dataMap.getDouble("timestamp"); - - final int size = bgDataList.size(); - if (size > 0) { - if (bgDataList.get(size - 1).timestamp == timestamp) - return; // Ignore duplicates. - } - - bgDataList.add(new BgWatchData(sgv, high, low, timestamp)); + addDataMap(dataMap); } for (int i = 0; i < bgDataList.size(); i++) { diff --git a/wear/src/main/java/com/eveningoutpost/dexdrip/BaseWatchFace.java b/wear/src/main/java/com/eveningoutpost/dexdrip/BaseWatchFace.java index 22a8b5fcd4..e4355c95b2 100644 --- a/wear/src/main/java/com/eveningoutpost/dexdrip/BaseWatchFace.java +++ b/wear/src/main/java/com/eveningoutpost/dexdrip/BaseWatchFace.java @@ -29,6 +29,7 @@ import com.google.android.gms.wearable.DataMap; import com.ustwo.clockwise.WatchFace; import com.ustwo.clockwise.WatchFaceTime; +import com.ustwo.clockwise.WatchMode; import com.ustwo.clockwise.WatchShape; import java.util.ArrayList; @@ -51,6 +52,7 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferen public int highColor = Color.YELLOW; public int lowColor = Color.RED; public int midColor = Color.WHITE; + public int lowColorWatchMode = Color.RED; public int pointSize = 2; public boolean singleLine = false; public boolean layoutSet = false; @@ -72,6 +74,7 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferen private String rawString = "000 | 000 | 000"; private String batteryString = "--"; private String sgvString = "--"; + private Rect mCardRect = new Rect(0,0,0,0); @Override public void onCreate() { @@ -171,27 +174,39 @@ protected void onDraw(Canvas canvas) { if(layoutSet) { this.mRelativeLayout.draw(canvas); Log.d("onDraw", "draw"); + int cardWidth = mCardRect.width(); + int cardHeight = mCardRect.height(); + if (cardHeight > 0 && cardWidth > 0 && getCurrentWatchMode() != WatchMode.INTERACTIVE) { + Paint paint = new Paint(); + paint.setColor(Color.BLACK); + paint.setStrokeWidth(0); + canvas.drawRect(mCardRect, paint); + } } } @Override protected void onTimeChanged(WatchFaceTime oldTime, WatchFaceTime newTime) { - if (layoutSet && (newTime.hasHourChanged(oldTime) || newTime.hasMinuteChanged(oldTime))) { - wakeLock.acquire(50); - final java.text.DateFormat timeFormat = DateFormat.getTimeFormat(BaseWatchFace.this); - mTime.setText(timeFormat.format(System.currentTimeMillis())); - showAgoRawBatt(); + if (newTime.hasHourChanged(oldTime) || newTime.hasMinuteChanged(oldTime)) { + if (layoutSet) { + wakeLock.acquire(50); + final java.text.DateFormat timeFormat = DateFormat.getTimeFormat(BaseWatchFace.this); + mTime.setText(timeFormat.format(System.currentTimeMillis())); + showAgoRawBatt(); - if(ageLevel()<=0) { - mSgv.setPaintFlags(mSgv.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG); + if (ageLevel() <= 0) { + mSgv.setPaintFlags(mSgv.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG); + } else { + mSgv.setPaintFlags(mSgv.getPaintFlags() & ~Paint.STRIKE_THRU_TEXT_FLAG); + } + + missedReadingAlert(); + mRelativeLayout.measure(specW, specH); + mRelativeLayout.layout(0, 0, mRelativeLayout.getMeasuredWidth(), + mRelativeLayout.getMeasuredHeight()); } else { - mSgv.setPaintFlags(mSgv.getPaintFlags() & ~Paint.STRIKE_THRU_TEXT_FLAG); + missedReadingAlert();//KS TEST otherwise, it can be 10+ minutes before missedReadingAlert is called; hwr, aggressive restart does not always resolve ble connection } - - missedReadingAlert(); - mRelativeLayout.measure(specW, specH); - mRelativeLayout.layout(0, 0, mRelativeLayout.getMeasuredWidth(), - mRelativeLayout.getMeasuredHeight()); } } @@ -259,6 +274,16 @@ private void showAgoRawBatt() { } public void setColor() { + if (getCurrentWatchMode() == WatchMode.INTERACTIVE) { + lowColorWatchMode = Color.RED; + } + else { + //RED is not supported in Ambient mode on WatchMode=LOW_BIT sa Sony SmartWatch 3 + //Therefore, use a cold color to indicate a low value + int prefColor = Integer.parseInt(sharedPrefs.getString("ambient_lowcolor", "3")); + int[] rainbow = {Color.CYAN, Color.GREEN, Color.RED, Color.WHITE}; + lowColorWatchMode = rainbow[prefColor-1]; + } if (sharedPrefs.getBoolean("dark", false)) { setColorDark(); } else { @@ -280,13 +305,63 @@ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, Strin } invalidate(); } -protected abstract void setColorDark(); + + private void resetRelativeLayout() { + mRelativeLayout.measure(specW, specH); + mRelativeLayout.layout(0, 0, mRelativeLayout.getMeasuredWidth(), + mRelativeLayout.getMeasuredHeight()); + Log.d("resetRelativeLayout", "specW=" + specW + " specH=" + specH + " mRelativeLayout.getMeasuredWidth()=" + mRelativeLayout.getMeasuredWidth() + " mRelativeLayout.getMeasuredHeight()=" + mRelativeLayout.getMeasuredHeight()); + } + + private void displayCard() { + int cardWidth = mCardRect.width(); + int cardHeight = mCardRect.height(); + Log.d("displayCard", "WatchFace.onCardPeek: getWidth()=" + getWidth() + " getHeight()=" + getHeight() + " cardWidth=" + cardWidth + " cardHeight=" + cardHeight); + + if (cardHeight > 0 && cardWidth > 0) { + if (getCurrentWatchMode() != WatchMode.INTERACTIVE) { + // get height of visible area (not including card) + int visibleWidth = getWidth() - cardWidth; + int visibleHeight = getHeight() - cardHeight; + Log.d("onCardPeek", "WatchFace.onCardPeek: visibleWidth=" + visibleWidth + " visibleHeight=" + visibleHeight); + mRelativeLayout.layout(0, 0, visibleWidth, visibleHeight); + } + else + resetRelativeLayout(); + } + else + resetRelativeLayout(); + invalidate(); + } + + @Override + protected void onCardPeek(Rect peekCardRect) { + mCardRect = peekCardRect; + displayCard(); + int cardWidth = peekCardRect.width(); + int cardHeight = peekCardRect.height(); + Log.d("onCardPeek", "WatchFace.onCardPeek: getWidth()=" + getWidth() + " getHeight()=" + getHeight() + " cardWidth=" + cardWidth + " cardHeight=" + cardHeight); + } + + @Override + protected void onWatchModeChanged(WatchMode watchMode) { + Log.d("onWatchModeChanged", "WatchFace.onWatchModeChanged: watchMode=" + watchMode.name()); + invalidate(); + setColor(); + } + protected abstract void setColorDark(); protected abstract void setColorBright(); public void missedReadingAlert() { int minutes_since = (int) Math.floor(timeSince()/(1000*60)); - if(minutes_since >= 16 && ((minutes_since - 16) % 5) == 0) { + int maxDelay = 16; + if (sharedPrefs.getBoolean("enable_wearG5", false)) { + maxDelay = 4; + Log.d("BIGChart", "missedReadingAlert Enter minutes_since " + minutes_since + " call requestData if >= 4 minutes mod 5");//KS + } + + if (minutes_since >= maxDelay && ((minutes_since - maxDelay) % 5) == 0) {//KS TODO reduce time for debugging; add notifications /*NotificationCompat.Builder notification = new NotificationCompat.Builder(getApplicationContext()) .setContentTitle("Missed BG Readings") .setVibrate(vibratePattern); @@ -296,37 +371,44 @@ public void missedReadingAlert() { } } + public void addDataMap(DataMap dataMap) {//KS + double sgv = dataMap.getDouble("sgvDouble"); + double high = dataMap.getDouble("high"); + double low = dataMap.getDouble("low"); + double timestamp = dataMap.getDouble("timestamp"); + + Log.d("addToWatchSet", "entry=" + dataMap); + + final int size = bgDataList.size(); + BgWatchData bgdata = new BgWatchData(sgv, high, low, timestamp); + if (size > 0) { + if (bgDataList.contains(bgdata)) { + int i = bgDataList.indexOf(bgdata); + BgWatchData bgd = bgDataList.get(bgDataList.indexOf(bgdata)); + Log.d("addToWatchSet", "replace indexOf=" + i + " bgDataList.sgv=" + bgd.sgv + " bgDataList.timestamp" + bgd.timestamp); + bgDataList.set(i, bgdata); + } else { + Log.d("addToWatchSet", "add " + " entry.sgv=" + bgdata.sgv + " entry.timestamp" + bgdata.timestamp); + bgDataList.add(bgdata); + } + } + else { + bgDataList.add(bgdata); + } + } + public void addToWatchSet(DataMap dataMap) { + Log.d("addToWatchSet", "bgDataList.size()=" + bgDataList.size()); + ArrayList entries = dataMap.getDataMapArrayList("entries"); if (entries != null) { + Log.d("addToWatchSet", "entries.size()=" + entries.size()); for (DataMap entry : entries) { - double sgv = entry.getDouble("sgvDouble"); - double high = entry.getDouble("high"); - double low = entry.getDouble("low"); - double timestamp = entry.getDouble("timestamp"); - - final int size = bgDataList.size(); - if (size > 0) { - if (bgDataList.get(size - 1).timestamp == timestamp) - continue; // Ignore duplicates. - } - - bgDataList.add(new BgWatchData(sgv, high, low, timestamp)); + addDataMap(entry); } } else { - double sgv = dataMap.getDouble("sgvDouble"); - double high = dataMap.getDouble("high"); - double low = dataMap.getDouble("low"); - double timestamp = dataMap.getDouble("timestamp"); - - final int size = bgDataList.size(); - if (size > 0) { - if (bgDataList.get(size - 1).timestamp == timestamp) - return; // Ignore duplicates. - } - - bgDataList.add(new BgWatchData(sgv, high, low, timestamp)); + addDataMap(dataMap); } for (int i = 0; i < bgDataList.size(); i++) { diff --git a/wear/src/main/java/com/eveningoutpost/dexdrip/CircleWatchface.java b/wear/src/main/java/com/eveningoutpost/dexdrip/CircleWatchface.java index 109d9a4b25..eb8456a0bb 100644 --- a/wear/src/main/java/com/eveningoutpost/dexdrip/CircleWatchface.java +++ b/wear/src/main/java/com/eveningoutpost/dexdrip/CircleWatchface.java @@ -30,6 +30,7 @@ import java.util.ArrayList; import java.util.Calendar; +import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.TreeSet; @@ -69,7 +70,8 @@ public class CircleWatchface extends WatchFace implements SharedPreferences.OnSh private double datetime = 0; private String direction = ""; private String delta = ""; - public TreeSet bgDataList = new TreeSet(); + //public TreeSet bgDataList = new TreeSet(); + public ArrayList bgDataList = new ArrayList<>(); private View layoutView; private int specW; @@ -544,6 +546,55 @@ public void onReceive(Context context, Intent intent) { } } + public void addDataMap(DataMap dataMap) {//KS + double sgv = dataMap.getDouble("sgvDouble"); + double high = dataMap.getDouble("high"); + double low = dataMap.getDouble("low"); + double timestamp = dataMap.getDouble("timestamp"); + + Log.d("addToWatchSet", "entry=" + dataMap); + + final int size = bgDataList.size(); + BgWatchData bgdata = new BgWatchData(sgv, high, low, timestamp); + if (size > 0) { + if (bgDataList.contains(bgdata)) { + int i = bgDataList.indexOf(bgdata); + BgWatchData bgd = bgDataList.get(bgDataList.indexOf(bgdata)); + Log.d("addToWatchSet", "replace indexOf=" + i + " bgDataList.sgv=" + bgd.sgv + " bgDataList.timestamp" + bgd.timestamp); + bgDataList.set(i, bgdata); + } else { + Log.d("addToWatchSet", "add " + " entry.sgv=" + bgdata.sgv + " entry.timestamp" + bgdata.timestamp); + bgDataList.add(bgdata); + } + } + else { + bgDataList.add(bgdata); + } + } + + public void addToWatchSet(DataMap dataMap) { + + Log.d("addToWatchSet", "bgDataList.size()=" + bgDataList.size()); + + ArrayList entries = dataMap.getDataMapArrayList("entries"); + if (entries != null) { + Log.d("addToWatchSet", "entries.size()=" + entries.size()); + for (DataMap entry : entries) { + addDataMap(entry); + } + } else { + addDataMap(dataMap); + } + + for (int i = 0; i < bgDataList.size(); i++) { + if (bgDataList.get(i).timestamp < (new Date().getTime() - (1000 * 60 * 60 * 5))) { + bgDataList.remove(i); //Get rid of anything more than 5 hours old + break; + } + } + Collections.sort(bgDataList); + } + /* public synchronized void addToWatchSet(DataMap dataMap) { if(!sharedPrefs.getBoolean("showRingHistory", false)){ @@ -586,6 +637,7 @@ public synchronized void addToWatchSet(DataMap dataMap) { removeSet = null; System.gc(); } + */ public int darken(int color, double fraction) { int red = Color.red(color); diff --git a/wear/src/main/java/com/eveningoutpost/dexdrip/Home.java b/wear/src/main/java/com/eveningoutpost/dexdrip/Home.java index a1f39cfa50..240051f1d5 100644 --- a/wear/src/main/java/com/eveningoutpost/dexdrip/Home.java +++ b/wear/src/main/java/com/eveningoutpost/dexdrip/Home.java @@ -8,11 +8,12 @@ import android.view.LayoutInflater; import android.widget.Toast; -import com.eveningoutpost.dexdrip.Models.UserError; import com.ustwo.clockwise.WatchMode; import lecho.lib.hellocharts.util.ChartUtils; +import com.eveningoutpost.dexdrip.utils.DexCollectionType; + public class Home extends BaseWatchFace { //KS the following were copied from app/home private static Context context;//KS @@ -37,6 +38,7 @@ public void onCreate() { } protected void setColorDark() { + Log.d("setColorDark", "WatchMode=" + getCurrentWatchMode()); mTime.setTextColor(Color.WHITE); mRelativeLayout.setBackgroundColor(Color.BLACK); mLinearLayout.setBackgroundColor(Color.WHITE); @@ -49,9 +51,9 @@ protected void setColorDark() { mDirection.setTextColor(Color.WHITE); mDelta.setTextColor(Color.WHITE); } else if (sgvLevel == -1) { - mSgv.setTextColor(Color.RED); - mDirection.setTextColor(Color.RED); - mDelta.setTextColor(Color.RED); + mSgv.setTextColor(lowColorWatchMode); + mDirection.setTextColor(lowColorWatchMode); + mDelta.setTextColor(lowColorWatchMode); } if (ageLevel == 1) { mTimestamp.setTextColor(Color.BLACK); @@ -67,7 +69,7 @@ protected void setColorDark() { mRaw.setTextColor(Color.BLACK); if (chart != null) { highColor = Color.YELLOW; - lowColor = Color.RED; + lowColor = lowColorWatchMode; midColor = Color.WHITE; singleLine = false; pointSize = 2; @@ -79,6 +81,7 @@ protected void setColorDark() { protected void setColorBright() { + Log.d("setColorBright", "WatchMode=" + getCurrentWatchMode()); if (getCurrentWatchMode() == WatchMode.INTERACTIVE) { mRelativeLayout.setBackgroundColor(Color.WHITE); mLinearLayout.setBackgroundColor(Color.BLACK); @@ -129,9 +132,9 @@ protected void setColorBright() { mDirection.setTextColor(Color.WHITE); mDelta.setTextColor(Color.WHITE); } else if (sgvLevel == -1) { - mSgv.setTextColor(Color.RED); - mDirection.setTextColor(Color.RED); - mDelta.setTextColor(Color.RED); + mSgv.setTextColor(lowColorWatchMode); + mDirection.setTextColor(lowColorWatchMode); + mDelta.setTextColor(lowColorWatchMode); } mRaw.setTextColor(Color.BLACK); mUploaderBattery.setTextColor(Color.BLACK); @@ -141,7 +144,7 @@ protected void setColorBright() { if (chart != null) { highColor = Color.YELLOW; midColor = Color.WHITE; - lowColor = Color.RED; + lowColor = lowColorWatchMode; singleLine = true; pointSize = 2; setupCharts(); @@ -231,6 +234,17 @@ public static String getPreferencesStringWithDefault(final String pref, final St return ""; } + public static boolean setPreferencesString(final String pref, final String str) { + if ((prefs == null) && (xdrip.getAppContext() != null)) { + prefs = PreferenceManager.getDefaultSharedPreferences(xdrip.getAppContext()); + } + if (prefs != null) { + prefs.edit().putString(pref, str).apply(); + return true; + } + return false; + } + public static double convertToMgDlIfMmol(double value) { if (!getPreferencesStringWithDefault("units", "mgdl").equals("mgdl")) { return value * com.eveningoutpost.dexdrip.UtilityModels.Constants.MMOLL_TO_MGDL; @@ -239,7 +253,6 @@ public static double convertToMgDlIfMmol(double value) { } } - public static boolean setPreferencesLong(final String pref, final long lng) { if ((prefs == null) && (Home.getAppContext() != null)) { prefs = PreferenceManager.getDefaultSharedPreferences(Home.getAppContext()); @@ -251,5 +264,11 @@ public static boolean setPreferencesLong(final String pref, final long lng) { return false; } + public static long stale_data_millis() + { + if (DexCollectionType.getDexCollectionType() == DexCollectionType.LibreAlarm) return (60000 * 13); + return (60000 * 11); + } + } diff --git a/wear/src/main/java/com/eveningoutpost/dexdrip/LargeHome.java b/wear/src/main/java/com/eveningoutpost/dexdrip/LargeHome.java index dd0a3b3a2b..a6f4cb0523 100644 --- a/wear/src/main/java/com/eveningoutpost/dexdrip/LargeHome.java +++ b/wear/src/main/java/com/eveningoutpost/dexdrip/LargeHome.java @@ -18,6 +18,7 @@ public void onCreate() { @Override protected void setColorDark(){ + //Log.d("setColorDark", "WatchMode=" + getCurrentWatchMode()); mTime.setTextColor(Color.WHITE); mRelativeLayout.setBackgroundColor(Color.BLACK); mLinearLayout.setBackgroundColor(Color.WHITE); @@ -30,9 +31,9 @@ protected void setColorDark(){ mDirection.setTextColor(Color.WHITE); mDelta.setTextColor(Color.WHITE); } else if (sgvLevel == -1) { - mSgv.setTextColor(Color.RED); - mDirection.setTextColor(Color.RED); - mDelta.setTextColor(Color.RED); + mSgv.setTextColor(lowColorWatchMode); + mDirection.setTextColor(lowColorWatchMode); + mDelta.setTextColor(lowColorWatchMode); } if (ageLevel == 1) { mTimestamp.setTextColor(Color.BLACK); @@ -84,6 +85,8 @@ protected void setColorBright() { mRaw.setTextColor(Color.WHITE); mTime.setTextColor(Color.BLACK); } else { + //RED is not supported in Ambient mode on WatchMode=LOW_BIT sa Sony SmartWatch 3 + //Therefore, use a cold color to indicate a low value mRelativeLayout.setBackgroundColor(Color.BLACK); mLinearLayout.setBackgroundColor(Color.LTGRAY); if (sgvLevel == 1) { @@ -95,9 +98,9 @@ protected void setColorBright() { mDirection.setTextColor(Color.WHITE); mDelta.setTextColor(Color.WHITE); } else if (sgvLevel == -1) { - mSgv.setTextColor(Color.RED); - mDirection.setTextColor(Color.RED); - mDelta.setTextColor(Color.RED); + mSgv.setTextColor(lowColorWatchMode); + mDirection.setTextColor(lowColorWatchMode); + mDelta.setTextColor(lowColorWatchMode); } mUploaderBattery.setTextColor(Color.BLACK); diff --git a/wear/src/main/java/com/eveningoutpost/dexdrip/ListenerService.java b/wear/src/main/java/com/eveningoutpost/dexdrip/ListenerService.java index b1e782c6f9..9db8d59d1d 100644 --- a/wear/src/main/java/com/eveningoutpost/dexdrip/ListenerService.java +++ b/wear/src/main/java/com/eveningoutpost/dexdrip/ListenerService.java @@ -2,10 +2,12 @@ import com.eveningoutpost.dexdrip.Models.BgReading;//KS import com.eveningoutpost.dexdrip.Models.Calibration;//KS +import com.eveningoutpost.dexdrip.Models.JoH; import com.eveningoutpost.dexdrip.Models.Sensor;//KS import com.eveningoutpost.dexdrip.Models.TransmitterData; -import com.eveningoutpost.dexdrip.Models.UserError; import com.eveningoutpost.dexdrip.Services.G5CollectionService;//KS +import com.eveningoutpost.dexdrip.UtilityModels.BgSendQueue; +import com.eveningoutpost.dexdrip.utils.DexCollectionType; import android.Manifest; import android.content.Context; @@ -14,6 +16,8 @@ import android.content.pm.PackageManager; import android.os.AsyncTask; import android.os.Bundle; +import android.os.PowerManager; +import android.preference.Preference; import android.preference.PreferenceManager; import android.support.v4.app.ActivityCompat; import android.support.v4.content.LocalBroadcastManager; @@ -24,7 +28,8 @@ import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.common.api.PendingResult; import com.google.android.gms.common.api.ResultCallback; -import com.google.android.gms.wearable.DataApi; +import com.google.android.gms.wearable.CapabilityApi; +import com.google.android.gms.wearable.CapabilityInfo; import com.google.android.gms.wearable.DataEvent; import com.google.android.gms.wearable.DataEventBuffer; import com.google.android.gms.wearable.DataMap; @@ -32,8 +37,6 @@ import com.google.android.gms.wearable.MessageApi; import com.google.android.gms.wearable.Node; import com.google.android.gms.wearable.NodeApi; -import com.google.android.gms.wearable.PutDataMapRequest; -import com.google.android.gms.wearable.PutDataRequest; import com.google.android.gms.wearable.Wearable; import com.google.android.gms.wearable.WearableListenerService; @@ -46,7 +49,6 @@ import java.util.Date; import java.util.List; import java.util.Set; -import java.util.concurrent.TimeUnit; /** * Created by stephenblack on 12/26/14. @@ -61,33 +63,40 @@ public class ListenerService extends WearableListenerService implements GoogleAp private static final String WEARABLE_BG_DATA_PATH = "/nightscout_watch_bg_data";//KS private static final String WEARABLE_CALIBRATION_DATA_PATH = "/nightscout_watch_cal_data";//KS private static final String WEARABLE_SENSOR_DATA_PATH = "/nightscout_watch_sensor_data";//KS - public static final String WEARABLE_PREF_DATA_PATH = "/nightscout_watch_pref_data";//KS - public static final String DATA_ITEM_RECEIVED_PATH = "/data-item-received";//KS + private static final String WEARABLE_PREF_DATA_PATH = "/nightscout_watch_pref_data";//KS + private static final String DATA_ITEM_RECEIVED_PATH = "/data-item-received";//KS private static final String ACTION_RESEND = "com.dexdrip.stephenblack.nightwatch.RESEND_DATA"; private static final String ACTION_SENDDATA = "com.dexdrip.stephenblack.nightwatch.SEND_DATA"; - private static final String ACTION_RESEND_BULK = "com.dexdrip.stephenblack.nightwatch.RESEND_BULK_DATA"; private static final String FIELD_SENDPATH = "field_xdrip_plus_sendpath"; private static final String FIELD_PAYLOAD = "field_xdrip_plus_payload"; private static final String WEARABLE_TREATMENT_PAYLOAD = "/xdrip_plus_treatment_payload"; private static final String WEARABLE_TOAST_NOTIFICATON = "/xdrip_plus_toast"; + + // Phone + private static final String CAPABILITY_PHONE_APP = "phone_app_sync_bgs"; + private static final String MESSAGE_PATH_PHONE = "/phone_message_path"; + // Wear + private static final String CAPABILITY_WEAR_APP = "wear_app_sync_bgs"; + private static final String MESSAGE_PATH_WEAR = "/wear_message_path"; + private String mPhoneNodeId = null; + private String localnode= null; + private static final String TAG = "jamorham listener"; - SharedPreferences mPrefs;//KS - Context mContext;//KS - public static boolean mLocationPermissionApproved;//KS - public static long last_send_previous = 0;//KS - public static long last_send_sucess = 0;//KS - public static String pref_last_send_previous = "last_send_previous"; - - GoogleApiClient googleApiClient; + private SharedPreferences mPrefs;//KS + private static boolean mLocationPermissionApproved;//KS + private static long last_send_previous = 0;//KS + final private static String pref_last_send_previous = "last_send_previous"; + private boolean is_using_g5 = false; + private static int aggressive_backoff_timer = 120; + + private GoogleApiClient googleApiClient; private static long lastRequest = 0; public class DataRequester extends AsyncTask { - Context mContext; final String path; final byte[] payload; DataRequester(Context context, String thispath, byte[] thispayload) { - mContext = context; path = thispath; payload = thispayload; Sensor.InitDb(context);//ensure database has already been initialized @@ -97,20 +106,33 @@ public class DataRequester extends AsyncTask { @Override protected Void doInBackground(Void... params) { SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());//KS - boolean connectG5 = sharedPrefs.getBoolean("connectG5", false); //KS - boolean use_connectG5 = sharedPrefs.getBoolean("use_connectG5", false); //KS + boolean enable_wearG5 = sharedPrefs.getBoolean("enable_wearG5", false); //KS + boolean force_wearG5 = sharedPrefs.getBoolean("force_wearG5", false); //KS + String node_wearG5 = sharedPrefs.getString("node_wearG5", ""); //KS + Log.d(TAG, "doInBackground enter enable_wearG5=" + enable_wearG5 + " force_wearG5=" + force_wearG5 + " node_wearG5=" + node_wearG5);//KS if ((googleApiClient != null) && (googleApiClient.isConnected())) { if (!path.equals(ACTION_RESEND) || (System.currentTimeMillis() - lastRequest > 20 * 1000)) { // enforce 20-second debounce period lastRequest = System.currentTimeMillis(); - NodeApi.GetConnectedNodesResult nodes = - Wearable.NodeApi.getConnectedNodes(googleApiClient).await(); + //NodeApi.GetConnectedNodesResult nodes = + // Wearable.NodeApi.getConnectedNodes(googleApiClient).await(); + NodeApi.GetLocalNodeResult localnodes = Wearable.NodeApi.getLocalNode(googleApiClient).await(); + Node getnode = localnodes != null ? localnodes.getNode() : null; + localnode = getnode != null ? getnode.getDisplayName() + "|" + getnode.getId() : ""; + Log.d(TAG, "doInBackground. getLocalNode name=" + localnode); + CapabilityApi.GetCapabilityResult capResult = + Wearable.CapabilityApi.getCapability( + googleApiClient, CAPABILITY_PHONE_APP, + CapabilityApi.FILTER_REACHABLE).await(); + CapabilityInfo nodes = capResult.getCapability(); + updatePhoneSyncBgsCapability(nodes); + int count = nodes.getNodes().size();//KS - Log.d(TAG, "doInBackground connected. NodeApi.GetConnectedNodesResult await count=" + count);//KS + Log.d(TAG, "doInBackground connected. CapabilityApi.GetCapabilityResult mPhoneNodeID=" + (mPhoneNodeId != null ? mPhoneNodeId : "") + " count=" + count);//KS if (count > 0) {//KS - if (connectG5) { - if (use_connectG5) { + if (enable_wearG5) { + if (force_wearG5) { startBtG5Service(); } else { @@ -120,15 +142,12 @@ protected Void doInBackground(Void... params) { for (Node node : nodes.getNodes()) { - if (connectG5) {//KS + if (enable_wearG5) {//KS DataMap datamap = getWearTransmitterData(288);//KS 36 data for last 3 hours; 288 for 1 day if (datamap != null) {//while - Log.d(TAG, "doInBackground send Wear Data BGs to phone at path:" + SYNC_BGS_PATH + " and node:" + node.getId()); + Log.d(TAG, "doInBackground send Wear Data BGs to phone path:" + SYNC_BGS_PATH + " and node:" + node.getId() + " and node:" + node.getDisplayName()); Log.d(TAG, "doInBackground send Wear datamap:" + datamap); - //onDataChanged doesn't ever get triggered on phone using putDataItem. Therefore, use MessageAPI instead. - //sendToDataLayer(SYNC_BGS_PATH, datamap, node); - PendingResult result = Wearable.MessageApi.sendMessage(googleApiClient, node.getId(), SYNC_BGS_PATH, datamap.toByteArray()); result.setResultCallback(new ResultCallback() { @Override @@ -137,20 +156,17 @@ public void onResult(MessageApi.SendMessageResult sendMessageResult) { Log.e(TAG, "ERROR: failed to send Wear BGs to phone: " + sendMessageResult.getStatus().getStatusMessage()); } else { - //last_send_previous = last_send_sucess; //Set this in onDataChanged event DATA_ITEM_RECEIVED_PATH Log.i(TAG, "Sent Wear BGs to phone: " + sendMessageResult.getStatus().getStatusMessage()); } } }); } } - //if (!use_connectG5 && path.equals(WEARABLE_RESEND_PATH)) {//KS don't request Resend if wear collector is active Wearable.MessageApi.sendMessage(googleApiClient, node.getId(), path, payload); - //} } } else { - if (connectG5) {//KS + if (enable_wearG5) {//KS Log.d(TAG, "doInBackground connected but getConnectedNodes returns 0. start G5 service"); startBtG5Service(); } @@ -168,58 +184,18 @@ public void onResult(MessageApi.SendMessageResult sendMessageResult) { } } - private void sendToDataLayer(String path, DataMap dataMap, Node node) {//KS - if (googleApiClient.isConnected()) { - Log.d(TAG, "sendToDataLayer send to path=" + path + "node=" + node.getDisplayName()); - Log.d(TAG, "sendToDataLayer send dataMap=" + dataMap); - PutDataMapRequest dataMapRequest = PutDataMapRequest.create(path); - dataMapRequest.setUrgent(); - //unique content - //dataMapRequest.getDataMap().putDouble("timestamp", System.currentTimeMillis()); - //dataMapRequest.getDataMap().putString(notification, notification); - //PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest(); - //Wearable.DataApi.putDataItem(googleApiClient, putDataRequest); - - dataMapRequest.getDataMap().putAll(dataMap); - PutDataRequest request = dataMapRequest.asPutDataRequest(); - DataApi.DataItemResult result = Wearable.DataApi.putDataItem(googleApiClient, request).await(15, TimeUnit.SECONDS); - if (result.getStatus().isSuccess()) { - Log.d(TAG, "sendToDataLayer sent dataMap: " + dataMap); - Log.d(TAG, "sendToDataLayer sent to node: " + node.getDisplayName()); - last_send_previous = last_send_sucess; - } else { - Log.e(TAG, "sendToDataLayer ERROR: failed to send DataMap"); - result = Wearable.DataApi.putDataItem(googleApiClient, request).await(25, TimeUnit.SECONDS); - if (result.getStatus().isSuccess()) { - Log.d(TAG, "sendToDataLayer RETRY sent dataMap: " + dataMap); - Log.d(TAG, "sendToDataLayer RETRY sent to node: " + node.getDisplayName()); - last_send_previous = last_send_sucess; - } else { - Log.e(TAG, "sendToDataLayer ERROR on retry: failed to send DataMap"); - } - } - } else { - Log.e(TAG, "sendToDataLayer No connection to phone available!"); - } - } - private DataMap getWearTransmitterData(int count) {//KS - java.text.DateFormat df = new SimpleDateFormat("MM.dd.yyyy HH:mm:ss"); - Date date = new Date(); if(googleApiClient != null && !googleApiClient.isConnected() && !googleApiClient.isConnecting()) { googleApiConnect(); } - date.setTime(last_send_previous); - Log.d(TAG, "getWearTransmitterData last_send_previous:" + df.format(date)); + Log.d(TAG, "getWearTransmitterData last_send_previous:" + JoH.dateTimeText(last_send_previous)); TransmitterData last_bg = TransmitterData.last(); if (last_bg != null) { - date.setTime(last_bg.timestamp); - Log.d(TAG, "getWearTransmitterData last_bg.timestamp:" + df.format(date)); + Log.d(TAG, "getWearTransmitterData last_bg.timestamp:" + JoH.dateTimeText(last_bg.timestamp)); } if (last_bg != null && last_send_previous <= last_bg.timestamp) {//startTime - date.setTime(last_bg.timestamp); - Log.d(TAG, "getWearTransmitterData last_send_previous < last_bg.timestamp:" + df.format(date)); + Log.d(TAG, "getWearTransmitterData last_send_previous < last_bg.timestamp:" + JoH.dateTimeText(last_bg.timestamp)); List graph_bgs = TransmitterData.latestForGraphAsc(count, last_send_previous); if (!graph_bgs.isEmpty()) { Log.d(TAG, "getWearTransmitterData graph_bgs count = " + graph_bgs.size()); @@ -227,11 +203,9 @@ private DataMap getWearTransmitterData(int count) {//KS final ArrayList dataMaps = new ArrayList<>(graph_bgs.size()); for (TransmitterData bg : graph_bgs) { dataMaps.add(dataMap(bg)); - date.setTime(bg.timestamp); - Log.d(TAG, "getWearTransmitterData bg.timestamp:" + df.format(date)); - last_send_sucess = bg.timestamp + 1; - date.setTime(last_send_sucess); - Log.d(TAG, "getWearTransmitterData set last_send_sucess:" + df.format(date)); + Log.d(TAG, "getWearTransmitterData bg.timestamp:" + JoH.dateTimeText(bg.timestamp)); + long last_send_sucess = bg.timestamp + 1; + Log.d(TAG, "getWearTransmitterData set last_send_sucess:" + JoH.dateTimeText(last_send_sucess)); Log.d(TAG, "getWearTransmitterData bg getId:" + bg.getId() + " raw_data:" + bg.raw_data + " filtered_data:" + bg.filtered_data + " timestamp:" + bg.timestamp + " uuid:" + bg.uuid); } entries.putLong("time", new Date().getTime()); // MOST IMPORTANT LINE FOR TIMESTAMP @@ -248,84 +222,38 @@ private void sendPrefSettings() {//KS if(googleApiClient != null && !googleApiClient.isConnected() && !googleApiClient.isConnecting()) { googleApiConnect(); } DataMap dataMap = new DataMap(); - boolean connectG5 = mPrefs.getBoolean("connectG5", false); - boolean use_connectG5 = mPrefs.getBoolean("use_connectG5", false); - Log.d(TAG, "sendPrefSettings connectG5: " + connectG5 + " use_connectG5:" + use_connectG5); - dataMap.putBoolean("connectG5", connectG5); - dataMap.putBoolean("use_connectG5", use_connectG5); - sendData(WEARABLE_PREF_DATA_PATH, dataMap.toByteArray()); - -/* - final SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());//KS TODO - new Thread(){ - public void run(){ - sendPrefSettingsAsync(sharedPrefs); + boolean enable_wearG5 = mPrefs.getBoolean("enable_wearG5", false); + boolean force_wearG5 = mPrefs.getBoolean("force_wearG5", false); + String node_wearG5 = mPrefs.getString("node_wearG5", ""); + String dex_txid = mPrefs.getString("dex_txid", "ABCDEF"); + + Log.d(TAG, "sendPrefSettings enable_wearG5: " + enable_wearG5 + " force_wearG5:" + force_wearG5 + " node_wearG5:" + node_wearG5 + " localnode:" + localnode + " dex_txid:" + dex_txid); + dataMap.putLong("time", new Date().getTime()); // MOST IMPORTANT LINE FOR TIMESTAMP + dataMap.putBoolean("enable_wearG5", enable_wearG5); + dataMap.putBoolean("force_wearG5", force_wearG5); + if (force_wearG5) { + dataMap.putString("node_wearG5", localnode); + } + else { + if (node_wearG5.equals(localnode)) { + dataMap.putString("node_wearG5", ""); + } + else { + dataMap.putString("node_wearG5", node_wearG5); } - }.start(); -*/ - } - - private void sendPrefSettingsAsync(final SharedPreferences sharedPrefs) {//KS - final PutDataMapRequest request = PutDataMapRequest.create(WEARABLE_PREF_DATA_PATH); - final DataMap dataMap = request.getDataMap(); - boolean connectG5 = sharedPrefs.getBoolean("connectG5", false); - boolean use_connectG5 = sharedPrefs.getBoolean("use_connectG5", false); - dataMap.putBoolean("connectG5", connectG5); - dataMap.putBoolean("use_connectG5", use_connectG5); - request.setUrgent(); - Wearable.DataApi.putDataItem(googleApiClient, request.asPutDataRequest()); - } - - private DataMap dataMap(TransmitterData bg) {//KS - DataMap dataMap = new DataMap(); - String json = bg.toS(); - Log.d(TAG, "dataMap BG GSON: " + json); - dataMap.putString("bgs", json); - return dataMap; - } - - private DataMap getWearBGData(int count) {//KS - java.text.DateFormat df = new SimpleDateFormat("MM.dd.yyyy HH:mm:ss"); - Date date = new Date(); - if(googleApiClient != null && !googleApiClient.isConnected() && !googleApiClient.isConnecting()) { googleApiConnect(); } - long currentTime = new Date().getTime() - (60000 * 60 * 24); - - date.setTime(last_send_previous); - Log.d(TAG, "getWearBGData last_send_previous:" + df.format(date)); - - BgReading last_bg = BgReading.last(); - if (last_bg != null) { - date.setTime(last_bg.timestamp); - Log.d(TAG, "getWearBGData last_bg.timestamp:" + df.format(date)); } + dataMap.putString("dex_txid", dex_txid); + sendData(WEARABLE_PREF_DATA_PATH, dataMap.toByteArray()); - if (last_bg != null && last_send_previous <= last_bg.timestamp) {//startTime - date.setTime(last_bg.timestamp); - Log.d(TAG, "getWearBGData last_send_previous < last_bg.timestamp:" + df.format(date)); - List graph_bgs = BgReading.latestForGraphAsc(count, last_send_previous); - if (!graph_bgs.isEmpty()) { - Log.d(TAG, "getWearBGData graph_bgs count = " + graph_bgs.size()); - DataMap entries = dataMap(last_bg); - final ArrayList dataMaps = new ArrayList<>(graph_bgs.size()); - for (BgReading bg : graph_bgs) { - dataMaps.add(dataMap(bg)); - date.setTime(bg.timestamp); - Log.d(TAG, "getWearBGData bg.timestamp:" + df.format(date)); - last_send_previous = bg.timestamp + 1; - date.setTime(last_send_previous); - Log.d(TAG, "getWearBGData set last_send_previous:" + df.format(date)); - } - entries.putLong("time", new Date().getTime()); // MOST IMPORTANT LINE FOR TIMESTAMP - entries.putDataMapArrayList("entries", dataMaps); - return entries; - } - else - Log.d(TAG, "getWearBGData graph_bgs count = 0"); + SharedPreferences.Editor prefs = PreferenceManager.getDefaultSharedPreferences(this).edit(); + if (!node_wearG5.equals(dataMap.getString("node_wearG5", ""))) { + Log.d(TAG, "syncPrefData save to SharedPreferences - node_wearG5:" + dataMap.getString("node_wearG5", "")); + prefs.putString("node_wearG5", node_wearG5); + prefs.commit(); } - return null; } - private DataMap dataMap(BgReading bg) {//KS + private DataMap dataMap(TransmitterData bg) {//KS DataMap dataMap = new DataMap(); String json = bg.toS(); Log.d(TAG, "dataMap BG GSON: " + json); @@ -333,16 +261,16 @@ private DataMap dataMap(BgReading bg) {//KS return dataMap; } - public void requestData() { + private void requestData() { sendData(WEARABLE_RESEND_PATH, null); } - public void sendData(String path, byte[] payload) { + private void sendData(String path, byte[] payload) { if (path == null) return; new DataRequester(this, path, payload).execute(); } - public void googleApiConnect() { + private void googleApiConnect() { googleApiClient = new GoogleApiClient.Builder(this) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) @@ -357,9 +285,9 @@ public void onPeerConnected(Node peer) {//KS String id = peer.getId(); String name = peer.getDisplayName(); Log.d(TAG, "onPeerConnected peer name & ID: " + name + "|" + id); + mPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); sendPrefSettings(); - SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); - if (sharedPrefs.getBoolean("connectG5", false) && !sharedPrefs.getBoolean("use_connectG5", false)) { + if (mPrefs.getBoolean("enable_wearG5", false) && !mPrefs.getBoolean("force_wearG5", false)) { stopBtG5Service(); ListenerService.requestData(this); } @@ -371,8 +299,8 @@ public void onPeerDisconnected(Node peer) {//KS String id = peer.getId(); String name = peer.getDisplayName(); Log.d(TAG, "onPeerDisconnected peer name & ID: " + name + "|" + id); - SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); - if (sharedPrefs.getBoolean("connectG5", false)) { + mPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + if (mPrefs.getBoolean("enable_wearG5", false)) { startBtG5Service(); } } @@ -382,11 +310,11 @@ public int onStartCommand(Intent intent, int flags, int startId) { Log.d(TAG, "onStartCommand entered"); Home.setAppContext(getApplicationContext()); xdrip.checkAppContext(getApplicationContext()); + final PowerManager.WakeLock wl = JoH.getWakeLock("watchlistener-onstart",60000); last_send_previous = PersistentStore.getLong(pref_last_send_previous); // 0 if undef mPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());//KS listenForChangeInSettings();//KS - //sendPrefSettings(); - mContext = getApplicationContext();//KS + is_using_g5 = mPrefs.getBoolean("g5_collection_method", false);//DexCollectionType.DexcomG5 if (intent != null && ACTION_RESEND.equals(intent.getAction())) { googleApiConnect(); requestData(); @@ -394,16 +322,17 @@ public int onStartCommand(Intent intent, int flags, int startId) { final Bundle bundle = intent.getExtras(); sendData(bundle.getString(FIELD_SENDPATH), bundle.getByteArray(FIELD_PAYLOAD)); } + JoH.releaseWakeLock(wl); return START_STICKY; } - public SharedPreferences.OnSharedPreferenceChangeListener prefListener = new SharedPreferences.OnSharedPreferenceChangeListener() {//KS + final private SharedPreferences.OnSharedPreferenceChangeListener prefListener = new SharedPreferences.OnSharedPreferenceChangeListener() {//KS public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { Log.d(TAG, "OnSharedPreferenceChangeListener entered"); - if(key.compareTo("connectG5") == 0 || key.compareTo("use_connectG5") == 0) { - Log.i(TAG, "OnSharedPreferenceChangeListener connectG5 || use_connectG5 changed!"); - processConnectG5(); + if(key.compareTo("enable_wearG5") == 0 || key.compareTo("force_wearG5") == 0 || key.compareTo("node_wearG5") == 0) { + Log.i(TAG, "OnSharedPreferenceChangeListener enable_wearG5 || force_wearG5 changed!"); sendPrefSettings(); + processConnectG5(); } else if(key.compareTo("dex_txid") == 0){ processConnectG5(); @@ -411,7 +340,7 @@ else if(key.compareTo("dex_txid") == 0){ } }; - public void listenForChangeInSettings() {//KS + private void listenForChangeInSettings() {//KS mPrefs.registerOnSharedPreferenceChangeListener(prefListener); // TODO do we need an unregister!? } @@ -454,6 +383,13 @@ public void onDataChanged(DataEventBuffer dataEvents) { getApplicationContext().startActivity(intent); } else if (path.equals(SYNC_DB_PATH)) {//KS Log.d(TAG, "onDataChanged SYNC_DB_PATH=" + path); + final PowerManager.WakeLock wl = JoH.getWakeLock("watchlistener-SYNC_DB_PATH",120000); + TransmitterData last_bg = TransmitterData.last(); + if (last_bg != null && last_send_previous <= last_bg.timestamp) { + Log.d(TAG, "onDataChanged SYNC_DB_PATH requestData for last_send_previous < last_bg.timestamp:" + JoH.dateTimeText(last_send_previous) + "<="+ JoH.dateTimeText(last_bg.timestamp)); + requestData(); + } + JoH.releaseWakeLock(wl); Sensor.DeleteAndInitDb(getApplicationContext()); PersistentStore.setLong(pref_last_send_previous, 0); } else if (path.equals(WEARABLE_SENSOR_DATA_PATH)) {//KS @@ -463,11 +399,11 @@ public void onDataChanged(DataEventBuffer dataEvents) { } else if (path.equals(WEARABLE_CALIBRATION_DATA_PATH)) {//KS dataMap = DataMapItem.fromDataItem(event.getDataItem()).getDataMap(); Log.d(TAG, "onDataChanged path=" + path + " DataMap=" + dataMap); - syncCalibrationData(dataMap); + syncCalibrationData(dataMap, getApplicationContext()); } else if (path.equals(WEARABLE_BG_DATA_PATH)) {//KS dataMap = DataMapItem.fromDataItem(event.getDataItem()).getDataMap(); Log.d(TAG, "onDataChanged path=" + path + " DataMap=" + dataMap); - syncBgData(dataMap); + syncBgData(dataMap, getApplicationContext()); } else if (path.equals(WEARABLE_PREF_DATA_PATH)) {//KS dataMap = DataMapItem.fromDataItem(event.getDataItem()).getDataMap(); Log.d(TAG, "onDataChanged path=" + path + " DataMap=" + dataMap); @@ -477,40 +413,63 @@ public void onDataChanged(DataEventBuffer dataEvents) { Log.d(TAG, "onDataChanged path=" + path + " DataMap=" + dataMap); long timeOfLastBG = dataMap.getLong("timeOfLastBG", 0); if (timeOfLastBG > 0) { - java.text.DateFormat df = new SimpleDateFormat("MM.dd.yyyy HH:mm:ss"); - Date date = new Date(); - date.setTime(last_send_previous); - Log.d(TAG, "onDataChanged received from sendDataReceived current last_send_previous=" + df.format(date)); - date.setTime(timeOfLastBG); - Log.d(TAG, "onDataChanged received from sendDataReceived timeOfLastBG=" + df.format(date) + " Path=" + path); + Log.d(TAG, "onDataChanged received from sendDataReceived current last_send_previous=" + JoH.dateTimeText(last_send_previous)); + Log.d(TAG, "onDataChanged received from sendDataReceived timeOfLastBG=" + JoH.dateTimeText(timeOfLastBG) + " Path=" + path); last_send_previous = timeOfLastBG; PersistentStore.setLong(pref_last_send_previous, last_send_previous); - date.setTime(last_send_previous); - Log.d(TAG, "onDataChanged received from sendDataReceived update last_send_previous=" + df.format(date)); + Log.d(TAG, "onDataChanged received from sendDataReceived update last_send_previous=" + JoH.dateTimeText(last_send_previous)); } } } } } - public void syncPrefData(DataMap dataMap) {//KS + private void syncPrefData(DataMap dataMap) {//KS SharedPreferences.Editor prefs = PreferenceManager.getDefaultSharedPreferences(this).edit(); Log.d(TAG, "syncPrefData dataMap=" + dataMap); - boolean connectG5 = dataMap.getBoolean("connectG5", false); - boolean use_connectG5 = dataMap.getBoolean("use_connectG5", false); + String dexCollector = dataMap.getString("dex_collection_method", "DexcomG5");//BluetoothWixel + DexCollectionType collectionType = DexCollectionType.getType( dexCollector); + is_using_g5 = (collectionType == DexCollectionType.DexcomG5); + Log.d(TAG, "syncPrefData is_using_g5:" + is_using_g5); + prefs.putBoolean("g5_collection_method", is_using_g5); + + boolean enable_wearG5 = is_using_g5 && dataMap.getBoolean("enable_wearG5", false); + boolean force_wearG5 = is_using_g5 && dataMap.getBoolean("force_wearG5", false); + String node_wearG5 = dataMap.getString("node_wearG5", ""); + String prefs_node_wearG5 = mPrefs.getString("node_wearG5", ""); + boolean change = false; + Log.d(TAG, "syncPrefData enter enable_wearG5: " + enable_wearG5 + " force_wearG5:" + force_wearG5 + " node_wearG5:" + node_wearG5 + " prefs_node_wearG5:" + prefs_node_wearG5 + " localnode:" + localnode); + + if (!node_wearG5.equals(prefs_node_wearG5)) { + change = true; + prefs.putString("node_wearG5", node_wearG5); + Log.d(TAG, "syncPrefData node_wearG5 pref set to dataMap:" + node_wearG5); + } + if (force_wearG5 && node_wearG5.equals("")) { + change = true; + prefs.putString("node_wearG5", localnode); + node_wearG5 = localnode; + Log.d(TAG, "syncPrefData node_wearG5 set empty string to localnode:" + localnode); + } + if (!node_wearG5.equals(localnode)) { + //change = true; + force_wearG5 = false; + } - if (use_connectG5 != mPrefs.getBoolean("use_connectG5", false)) { - Log.d(TAG, "syncPrefData use_connectG5:" + use_connectG5); - prefs.putBoolean("use_connectG5", use_connectG5); + if (force_wearG5 != mPrefs.getBoolean("force_wearG5", false)) { + change = true; + Log.d(TAG, "syncPrefData force_wearG5:" + force_wearG5); + prefs.putBoolean("force_wearG5", force_wearG5); } - if (connectG5 != mPrefs.getBoolean("connectG5", false)) { - Log.d(TAG, "syncPrefData connectG5:" + use_connectG5); - prefs.putBoolean("connectG5", connectG5); + if (enable_wearG5 != mPrefs.getBoolean("enable_wearG5", false)) { + change = true; + Log.d(TAG, "syncPrefData enable_wearG5:" + force_wearG5); + prefs.putBoolean("enable_wearG5", enable_wearG5); } - String dex_txid = dataMap.getString("dex_txid", "ABCDEF");//KS 4023GU + String dex_txid = dataMap.getString("dex_txid", "ABCDEF"); Log.d(TAG, "syncPrefData dataMap dex_txid=" + dex_txid); if (!dex_txid.equals(mPrefs.getString("dex_txid", "ABCDEF"))) { Log.d(TAG, "syncPrefData dex_txid:" + dex_txid); @@ -518,60 +477,58 @@ public void syncPrefData(DataMap dataMap) {//KS stopBtG5Service(); } - String units = dataMap.getString("units", "ABCDEF");//KS + final boolean adjustPast = dataMap.getBoolean("rewrite_history", true); + prefs.putBoolean("rewrite_history", adjustPast); + + String units = dataMap.getString("units", "mgdl"); Log.d(TAG, "syncPrefData dataMap units=" + units); prefs.putString("units", units); - Log.d(TAG, "syncPrefData prefs units=" + mPrefs.getString("units", "")); + Log.d(TAG, "syncPrefData prefs units=" + mPrefs.getString("units", "mgdl")); - Double high = dataMap.getDouble("high"); - Double low = dataMap.getDouble("low"); + Double high = dataMap.getDouble("high", 170.0); + Double low = dataMap.getDouble("low", 70.0); Log.d(TAG, "syncPrefData dataMap highMark=" + high + " highMark=" + low); prefs.putString("highValue", high.toString()); prefs.putString("lowValue", low.toString()); - prefs.commit(); + if (change) { + prefs.commit(); + //sendPrefSettings(); + //processConnectG5(); + } + enable_wearG5 = mPrefs.getBoolean("enable_wearG5", false); + force_wearG5 = mPrefs.getBoolean("force_wearG5", false); + node_wearG5 = mPrefs.getString("node_wearG5", ""); + Log.d(TAG, "syncPrefData exit enable_wearG5: " + enable_wearG5 + " force_wearG5:" + force_wearG5 + " node_wearG5:" + node_wearG5); } //Assumes Wear is connected to phone - public void processConnectG5() {//KS + private void processConnectG5() {//KS Log.d(TAG, "processConnectG5 enter"); - boolean connectG5 = mPrefs.getBoolean("connectG5", false); - boolean use_connectG5 = mPrefs.getBoolean("use_connectG5", false); - if (connectG5) { - Log.d(TAG, "processConnectG5 connectG5=true"); - if (!use_connectG5){ - Log.d(TAG, "processConnectG5 use_connectG5=false - stopBtG5Service and requestData"); + boolean enable_wearG5 = mPrefs.getBoolean("enable_wearG5", false); + boolean force_wearG5 = mPrefs.getBoolean("force_wearG5", false); + if (enable_wearG5) { + Log.d(TAG, "processConnectG5 enable_wearG5=true"); + if (!force_wearG5){ + Log.d(TAG, "processConnectG5 force_wearG5=false - stopBtG5Service and requestData"); stopBtG5Service(); ListenerService.requestData(this); } else { - Log.d(TAG, "processConnectG5 use_connectG5=true - startBtG5Service"); + Log.d(TAG, "processConnectG5 force_wearG5=true - startBtG5Service"); startBtG5Service(); } } else { - Log.d(TAG, "processConnectG5 connectG5=false - stopBtG5Service and requestData"); + Log.d(TAG, "processConnectG5 enable_wearG5=false - stopBtG5Service and requestData"); stopBtG5Service(); ListenerService.requestData(this); } } - public void syncSensorData(DataMap dataMap, Context context) {//KS + private void syncSensorData(DataMap dataMap, Context context) {//KS Log.d(TAG, "syncSensorData"); - java.text.DateFormat df = new SimpleDateFormat("MM.dd.yyyy HH:mm:ss"); - Date date = new Date(); if (dataMap != null) { - - //Get Transmittor ID required to connect to sensor via Bluetooth - /* - String dex_txid = dataMap.getString("dex_txid", "ABCDEF");//KS 4023GU - Log.d(TAG, "syncSensorData dataMap dex_txid=" + dex_txid); - SharedPreferences.Editor prefs = PreferenceManager.getDefaultSharedPreferences(this).edit(); - prefs.putString("dex_txid", dex_txid); - prefs.commit(); - Log.d(TAG, "syncSensorData prefs set dex_txid=" + mPrefs.getString("dex_txid", "ABCDEF")); - */ - String uuid = dataMap.getString("uuid"); Log.d(TAG, "syncSensorData add Sensor for uuid=" + uuid); long started_at = dataMap.getLong("started_at"); @@ -579,8 +536,7 @@ public void syncSensorData(DataMap dataMap, Context context) {//KS String sensor_location = dataMap.getString("sensor_location"); Sensor.InitDb(context);//ensure database has already been initialized if (uuid != null && !uuid.isEmpty()) { - date.setTime(started_at); - Log.d(TAG, "syncSensorData add Sensor for uuid=" + uuid + " timestamp=" + started_at + " timeString=" + df.format(date)); + Log.d(TAG, "syncSensorData add Sensor for uuid=" + uuid + " timestamp=" + started_at + " timeString=" + JoH.dateTimeText(started_at)); Sensor sensor = Sensor.getByUuid(uuid); if (sensor == null) { Log.d(TAG, "syncSensorData createUpdate new Sensor..."); @@ -596,79 +552,78 @@ public void syncSensorData(DataMap dataMap, Context context) {//KS } } - public void syncCalibrationData(DataMap dataMap) {//KS + private synchronized void syncCalibrationData(DataMap dataMap, Context context) {//KS Log.d(TAG, "syncCalibrationData"); - java.text.DateFormat df = new SimpleDateFormat("MM.dd.yyyy HH:mm:ss"); - Date date = new Date(); + ArrayList entries = dataMap.getDataMapArrayList("entries"); if (entries != null) { + Gson gson = new GsonBuilder() .excludeFieldsWithoutExposeAnnotation() .registerTypeAdapter(Date.class, new DateTypeAdapter()) .serializeSpecialFloatingPointValues() .create(); + Log.d(TAG, "syncCalibrationData add Calibration Table entries count=" + entries.size()); + Sensor.InitDb(context);//ensure database has already been initialized Sensor sensor = Sensor.currentSensor(); if (sensor != null) { for (DataMap entry : entries) { if (entry != null) { - Log.d(TAG, "syncCalibrationData add Calibration Table entry=" + entry); - Calibration calibration = new Calibration(); - - Calibration uuidexists = Calibration.byuuid(entry.getString("uuid"));//entry.getLong("timestamp") - if (uuidexists == null) { - date.setTime(entry.getLong("timestamp")); - Log.d(TAG, "syncCalibrationData create Calibration for uuid=" + entry.getString("uuid") + " timestamp=" + entry.getLong("timestamp") + " timeString=" + df.format(date)); - Calibration.createCalibration( - entry.getDouble("adjusted_raw_value"), - entry.getDouble("bg"), - entry.getBoolean("check_in"), - entry.getDouble("distance_from_estimate"), - entry.getDouble("estimate_bg_at_time_of_calibration"), - entry.getDouble("estimate_raw_at_time_of_calibration"), - entry.getDouble("first_decay"), - entry.getDouble("first_intercept"), - entry.getDouble("first_scale"), - entry.getDouble("first_slope"), - entry.getDouble("intercept"), - entry.getBoolean("possible_bad"), - entry.getLong("raw_timestamp"), - entry.getDouble("raw_value"), - entry.getDouble("second_decay"), - entry.getDouble("second_intercept"), - entry.getDouble("second_scale"), - entry.getDouble("second_slope"), - sensor, - entry.getDouble("sensor_age_at_time_of_estimation"), - entry.getDouble("sensor_confidence"), - entry.getString("sensor_uuid"), - entry.getDouble("slope"), - entry.getDouble("slope_confidence"), - entry.getLong("timestamp"), - entry.getString("uuid")); + String bgrecord = entry.getString("bgs"); + if (bgrecord != null) { + Calibration bgData = gson.fromJson(bgrecord, Calibration.class); + Calibration exists = Calibration.findByUuid(bgData.uuid); + bgData.sensor = sensor; + if (exists != null) { + Log.d(TAG, "syncCalibrationData Calibration exists for uuid=" + bgData.uuid + " bg=" + bgData.bg + " timestamp=" + bgData.timestamp + " timeString=" + JoH.dateTimeText(bgData.timestamp)); + exists.adjusted_raw_value = bgData.adjusted_raw_value; + exists.bg = bgData.bg; + exists.check_in = bgData.check_in; + exists.distance_from_estimate = bgData.distance_from_estimate; + exists.estimate_bg_at_time_of_calibration = bgData.estimate_bg_at_time_of_calibration; + exists.estimate_raw_at_time_of_calibration = bgData.estimate_raw_at_time_of_calibration; + exists.first_decay = bgData.first_decay; + exists.first_intercept = bgData.first_intercept; + exists.first_scale = bgData.first_scale; + exists.first_slope = bgData.first_slope; + exists.intercept = bgData.intercept; + exists.possible_bad = bgData.possible_bad; + exists.raw_timestamp = bgData.raw_timestamp; + exists.raw_value = bgData.raw_value; + exists.second_decay = bgData.second_decay; + exists.second_intercept = bgData.second_intercept; + exists.second_scale = bgData.second_scale; + exists.second_slope = bgData.second_slope; + exists.sensor = sensor; + exists.sensor_age_at_time_of_estimation = bgData.sensor_age_at_time_of_estimation; + exists.sensor_confidence = bgData.sensor_confidence; + exists.sensor_uuid = bgData.sensor_uuid; + exists.slope = bgData.slope; + exists.slope_confidence = bgData.slope_confidence; + exists.timestamp = bgData.timestamp; + exists.save(); + } + else { + bgData.save(); + //final boolean adjustPast = mPrefs.getBoolean("rewrite_history", true); + Log.d(TAG, "syncCalibrationData Calibration does not exist for uuid=" + bgData.uuid + " timestamp=" + bgData.timestamp + " timeString=" + JoH.dateTimeText(bgData.timestamp)); + //Calibration.adjustRecentBgReadings(adjustPast ? 30 : 2); + } + exists = Calibration.findByUuid(bgData.uuid); + if (exists != null) + Log.d(TAG, "syncCalibrationData Calibration GSON saved BG: " + exists.toS()); + else + Log.d(TAG, "syncCalibrationData Calibration GSON NOT saved"); } - else - Log.d(TAG, "syncCalibrationData Calibration already exists for uuid=" + entry.getString("uuid") + " timestamp=" + entry.getLong("timestamp")); } } } - - //KS Debug only - List cals = Calibration.latest(6);//1 days worth 12 * 24hr OR Long.MAX_VALUE for all records - if (cals != null && !cals.isEmpty()) { - Log.d(TAG, "syncCalibrationData cals in wear db count = " + cals.size()); - for (Calibration cal : cals) { - String json = cal.toS(); - Log.d(TAG, "syncCalibrationData cal: " + json); - } - } } } - public void syncBgData(DataMap dataMap) {//KS + private synchronized void syncBgData(DataMap dataMap, Context context) {//KS Log.d(TAG, "syncBGData"); - java.text.DateFormat df = new SimpleDateFormat("MM.dd.yyyy HH:mm:ss"); - Date date = new Date(); ArrayList entries = dataMap.getDataMapArrayList("entries"); Log.d(TAG, "syncBGData add BgReading Table" ); @@ -681,49 +636,109 @@ public void syncBgData(DataMap dataMap) {//KS .create(); Log.d(TAG, "syncBGData add BgReading Table entries count=" + entries.size()); + Sensor.InitDb(context);//ensure database has already been initialized Sensor sensor = Sensor.currentSensor(); - for (DataMap entry : entries) { - if (entry != null) { - Log.d(TAG, "syncBGData add BgReading Table entry=" + entry); - BgReading bgReading = new BgReading(); - String bgrecord = entry.getString("bgs"); - if (bgrecord != null) { - Log.d(TAG, "syncBGData add BgReading Table bgrecord=" + bgrecord); - BgReading bgData = gson.fromJson(bgrecord, BgReading.class); - BgReading exists = BgReading.getForTimestamp(bgData.timestamp); - BgReading uuidexists = BgReading.findByUuid(bgData.uuid); - date.setTime(bgData.timestamp); - if (exists != null || uuidexists != null) { - Log.d(TAG, "syncBGData BG already exists for uuid=" + bgData.uuid + " timestamp=" + bgData.timestamp + " timeString=" + df.format(date)); - } - else { - Calibration calibration = Calibration.byuuid(bgData.calibration_uuid); - if (sensor != null && calibration != null) { - bgData.calibration = calibration; - bgData.sensor = sensor; - Log.d(TAG, "syncBGData add BG; does NOT exist for uuid=" + bgData.uuid + " timestamp=" + bgData.timestamp + " timeString=" + df.format(date)); - bgData.save(); - //BgSendQueue.handleNewBgReading(bgReading, "create", getApplicationContext() ); - exists = BgReading.findByUuid(bgData.uuid); - if (exists != null) - Log.d(TAG, "syncBGData BG GSON saved BG: " + exists.toS()); - else - Log.d(TAG, "syncBGData BG GSON NOT saved"); + if (sensor != null) { + for (DataMap entry : entries) { + if (entry != null) { + String bgrecord = entry.getString("bgs"); + if (bgrecord != null) { + BgReading bgData = gson.fromJson(bgrecord, BgReading.class); + BgReading exists = BgReading.getForTimestampExists(bgData.timestamp); + exists = exists != null ? exists : BgReading.findByUuid(bgData.uuid); + if (exists != null) { + Log.d(TAG, "syncBGData BG already exists for uuid=" + bgData.uuid + " timestamp=" + bgData.timestamp + " timeString=" + JoH.dateTimeText(bgData.timestamp)); + Log.d(TAG, "syncBGData exists timeString=" + JoH.dateTimeText(exists.timestamp) + " exists.calibration.uuid=" + exists.calibration.uuid + " exists=" + exists.toS()); + + exists.filtered_calculated_value = bgData.filtered_calculated_value; + exists.calculated_value = bgData.calculated_value; + exists.hide_slope = bgData.hide_slope; + + exists.filtered_data = bgData.filtered_data; + exists.raw_data = bgData.raw_data; + exists.raw_calculated = bgData.raw_calculated; + exists.calculated_value_slope = bgData.calculated_value_slope; + exists.age_adjusted_raw_value = bgData.age_adjusted_raw_value; + exists.calibration_flag = bgData.calibration_flag; + exists.ignoreForStats = bgData.ignoreForStats; + exists.time_since_sensor_started = bgData.time_since_sensor_started; + exists.ra = bgData.ra; + exists.rb = bgData.rb; + exists.rc = bgData.rc; + exists.a = bgData.a; + exists.b = bgData.b; + exists.c = bgData.c; + exists.noise = bgData.noise; + exists.time_since_sensor_started = bgData.time_since_sensor_started; + + String calibrationUuid = entry.getString("calibrationUuid"); + if (calibrationUuid != null && !calibrationUuid.isEmpty()) { + Calibration calibration = Calibration.byuuid(calibrationUuid); + if (calibration != null) { + exists.calibration = calibration; + exists.sensor = sensor; + exists.save(); + } + else { + Log.e(TAG, "syncBGData calibrationUuid not found by byuuid; calibrationUuid=" + calibrationUuid + " bgData.calibration_uuid=" + bgData.calibration_uuid); + } + } + else { + Log.e(TAG, "syncBGData calibrationUuid not sent"); + } + } else { + Calibration calibration = Calibration.byuuid(bgData.calibration_uuid); + if (calibration != null) { + bgData.calibration = calibration; + bgData.sensor = sensor; + Log.d(TAG, "syncBGData add BG; does NOT exist for uuid=" + bgData.uuid + " timestamp=" + bgData.timestamp + " timeString=" + JoH.dateTimeText(bgData.timestamp)); + String calibrationUuid = entry.getString("calibrationUuid"); + if (calibrationUuid != null && !calibrationUuid.isEmpty()) { + calibration = Calibration.byuuid(calibrationUuid); + if (calibration != null) { + bgData.calibration = calibration; + bgData.sensor = sensor; + bgData.save(); + } + else { + Log.e(TAG, "syncBGData calibrationUuid not found by byuuid; calibrationUuid=" + calibrationUuid + " bgData.calibration_uuid=" + bgData.calibration_uuid); + } + } + else { + Log.e(TAG, "syncBGData calibrationUuid not sent"); + } + + //BgSendQueue.handleNewBgReading(bgData, "create", getApplicationContext() ); + exists = BgReading.findByUuid(bgData.uuid); + if (exists != null) + Log.d(TAG, "syncBGData BG GSON saved BG: " + exists.toS()); + else + Log.e(TAG, "syncBGData BG GSON NOT saved"); + } + else { + Log.e(TAG, "syncBGData bgData.calibration_uuid not found by byuuid; calibration_uuid=" + bgData.calibration_uuid); + } } } } } + BgSendQueue.resendData(getApplicationContext()); } } } private void startBtG5Service() {//KS Log.d(TAG, "startBtG5Service"); - Context myContext = getApplicationContext(); - if (checkLocationPermissions()) { - Log.d(TAG, "startBtG5Service start G5CollectionService"); - myContext.startService(new Intent(myContext, G5CollectionService.class)); - Log.d(TAG, "startBtG5Service AFTER startService G5CollectionService mLocationPermissionApproved " + mLocationPermissionApproved); + if (is_using_g5) { + Context myContext = getApplicationContext(); + if (checkLocationPermissions()) { + Log.d(TAG, "startBtG5Service start G5CollectionService"); + if (restartWatchDog()) + stopBtG5Service(); + G5CollectionService.keep_running = true; + myContext.startService(new Intent(myContext, G5CollectionService.class)); + Log.d(TAG, "startBtG5Service AFTER startService G5CollectionService mLocationPermissionApproved " + mLocationPermissionApproved); + } } } @@ -750,17 +765,27 @@ private boolean checkLocationPermissions() {//KS return mLocationPermissionApproved; } - private void stopBtG5Service() {//KS - Log.d(TAG, "stopBtG5Service"); - SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());//KS - boolean connectG5 = sharedPrefs.getBoolean("connectG5", false); //KS - - if (connectG5) { - Context myContext = getApplicationContext(); - Log.d(TAG, "stopBtG5Service call stopService"); - myContext.stopService(new Intent(myContext, G5CollectionService.class)); - Log.d(TAG, "stopBtG5Service should have called onDestroy"); + private boolean restartWatchDog() {//KS from app/MissedReadingService.java + final long stale_millis = Home.stale_data_millis(); + if (is_using_g5) {//(prefs.getBoolean("aggressive_service_restart", false) || DexCollectionType.isFlakey()) { + if (!BgReading.last_within_millis(stale_millis)) { + if (JoH.ratelimit("aggressive-restart", aggressive_backoff_timer)) { + Log.e(TAG, "Aggressively restarting wear G5 collector service due to lack of reception: backoff: "+aggressive_backoff_timer); + if (aggressive_backoff_timer < 1200) aggressive_backoff_timer+=60; + return true;//CollectionServiceStarter.restartCollectionService + } else { + aggressive_backoff_timer = 120; // reset + } + } } + return false; + } + + private void stopBtG5Service() {//KS + Context myContext = getApplicationContext(); + Log.d(TAG, "stopBtG5Service call stopService"); + myContext.stopService(new Intent(myContext, G5CollectionService.class)); + Log.d(TAG, "stopBtG5Service should have called onDestroy"); } public static void requestData(Context context) { @@ -778,8 +803,39 @@ public static void SendData(Context context, String path, byte[] payload) { context.startService(intent); } + private void updatePhoneSyncBgsCapability(CapabilityInfo capabilityInfo) { + Set connectedNodes = capabilityInfo.getNodes(); + mPhoneNodeId = pickBestNodeId(connectedNodes); + } + + private String pickBestNodeId(Set nodes) { + String bestNodeId = null; + // Find a nearby node or pick one arbitrarily + for (Node node : nodes) { + if (node.isNearby()) { + return node.getId(); + } + bestNodeId = node.getId(); + } + return bestNodeId; + } + @Override public void onConnected(Bundle bundle) { + CapabilityApi.CapabilityListener capabilityListener = + new CapabilityApi.CapabilityListener() { + @Override + public void onCapabilityChanged(CapabilityInfo capabilityInfo) { + updatePhoneSyncBgsCapability(capabilityInfo); + Log.d(TAG, "onConnected onCapabilityChanged mPhoneNodeID:" + mPhoneNodeId); + } + }; + + Wearable.CapabilityApi.addCapabilityListener( + googleApiClient, + capabilityListener, + CAPABILITY_PHONE_APP); + requestData(); } diff --git a/wear/src/main/java/com/eveningoutpost/dexdrip/Models/BgReading.java b/wear/src/main/java/com/eveningoutpost/dexdrip/Models/BgReading.java index e1f18650f4..2b3ece32cc 100644 --- a/wear/src/main/java/com/eveningoutpost/dexdrip/Models/BgReading.java +++ b/wear/src/main/java/com/eveningoutpost/dexdrip/Models/BgReading.java @@ -118,7 +118,7 @@ public class BgReading extends Model implements ShareUploadableBg { @Column(name = "rc") public double rc; @Expose - @Column(name = "uuid", unique = true, onUniqueConflicts = Column.ConflictAction.IGNORE) + @Column(name = "uuid", unique = true, onUniqueConflicts = Column.ConflictAction.REPLACE)//KS replace IGNORE with REPLACE public String uuid; @Expose @@ -145,6 +145,10 @@ public class BgReading extends Model implements ShareUploadableBg { @Column(name = "noise") public String noise; + public BgReading () { + super (); + } + public double calculated_value_mmol() { return mmolConvert(calculated_value); } @@ -291,6 +295,24 @@ public static void create(EGVRecord egvRecord, long addativeOffset, Context cont } } + public static BgReading getForTimestampExists(double timestamp) { + Sensor sensor = Sensor.currentSensor(); + if (sensor != null) { + BgReading bgReading = new Select() + .from(BgReading.class) + .where("Sensor = ? ", sensor.getId()) + .where("timestamp <= ?", (timestamp + (60 * 1000))) // 1 minute padding (should never be that far off, but why not) + .orderBy("timestamp desc") + .executeSingle(); + if (bgReading != null && Math.abs(bgReading.timestamp - timestamp) < (3 * 60 * 1000)) { //cool, so was it actually within 4 minutes of that bg reading? + Log.i(TAG, "getForTimestamp: Found a BG timestamp match"); + return bgReading; + } + } + Log.d(TAG, "getForTimestamp: No luck finding a BG timestamp match"); + return null; + } + public static BgReading getForTimestamp(double timestamp) { Sensor sensor = Sensor.currentSensor(); if (sensor != null) { @@ -377,6 +399,7 @@ public static BgReading create(double raw_data, double filtered_data, Context co bgReading.save(); bgReading.perform_calculations(); + BgSendQueue.sendToPhone(context);//KS send back to phone } else { Log.d(TAG, "Calibrations, so doing everything: " + calibration.uuid); bgReading.sensor = sensor; @@ -401,6 +424,9 @@ public static BgReading create(double raw_data, double filtered_data, Context co } else { BgReading lastBgReading = BgReading.last(); if (lastBgReading != null && lastBgReading.calibration != null) { + Log.d(TAG, "Create calibration.uuid=" + calibration.uuid + " bgReading.uuid: " + bgReading.uuid + " lastBgReading.calibration_uuid: " + lastBgReading.calibration_uuid + " lastBgReading.calibration.uuid: " + lastBgReading.calibration.uuid); + Log.d(TAG, "Create lastBgReading.calibration_flag=" + lastBgReading.calibration_flag + " bgReading.timestamp: " + bgReading.timestamp + " lastBgReading.timestamp: " + lastBgReading.timestamp + " lastBgReading.calibration.timestamp: " + lastBgReading.calibration.timestamp); + Log.d(TAG, "Create lastBgReading.calibration_flag=" + lastBgReading.calibration_flag + " bgReading.timestamp: " + JoH.dateTimeText(bgReading.timestamp) + " lastBgReading.timestamp: " + JoH.dateTimeText(lastBgReading.timestamp) + " lastBgReading.calibration.timestamp: " + JoH.dateTimeText(lastBgReading.calibration.timestamp)); if (lastBgReading.calibration_flag == true && ((lastBgReading.timestamp + (60000 * 20)) > bgReading.timestamp) && ((lastBgReading.calibration.timestamp + (60000 * 20)) > bgReading.timestamp)) { lastBgReading.calibration.rawValueOverride(BgReading.weightedAverageRaw(lastBgReading.timestamp, bgReading.timestamp, lastBgReading.calibration.timestamp, lastBgReading.age_adjusted_raw_value, bgReading.age_adjusted_raw_value), context); } diff --git a/wear/src/main/java/com/eveningoutpost/dexdrip/Models/Calibration.java b/wear/src/main/java/com/eveningoutpost/dexdrip/Models/Calibration.java index 8e13b3d74b..680ae45ef6 100644 --- a/wear/src/main/java/com/eveningoutpost/dexdrip/Models/Calibration.java +++ b/wear/src/main/java/com/eveningoutpost/dexdrip/Models/Calibration.java @@ -212,68 +212,8 @@ public class Calibration extends Model { @Column(name = "second_scale") public double second_scale; - public static void createCalibration(//KS - /*int _ID, long timestamp, double sensor_age_at_time_of_estimation, Sensor sensor, double bg, double raw_value, double adjusted_raw_value, - double sensor_confidence, double slope_confidence, long raw_timestamp, double slope, double intercept, double distance_from_estimate, - double estimate_raw_at_time_of_calibration, double estimate_bg_at_time_of_calibration, String uuid,String sensor_uuid, Boolean possible_bad, - boolean check_in, double first_decay, double second_decay, double first_slope, double second_slope, double first_intercept, - double second_intercept, double first_scale, double second_scale*/ - double adjusted_raw_value, - double bg, - boolean check_in, - double distance_from_estimate, - double estimate_bg_at_time_of_calibration, - double estimate_raw_at_time_of_calibration, - double first_decay, - double first_intercept, - double first_scale, - double first_slope, - double intercept, - Boolean possible_bad, - long raw_timestamp, - double raw_value, - double second_decay, - double second_intercept, - double second_scale, - double second_slope, - Sensor sensor, - double sensor_age_at_time_of_estimation, - double sensor_confidence, - String sensor_uuid, - double slope, - double slope_confidence, - long timestamp, - String uuid - ) - { - Calibration newCalibration = new Calibration(); - newCalibration.timestamp = timestamp ; - newCalibration.sensor_age_at_time_of_estimation = sensor_age_at_time_of_estimation ; - newCalibration.sensor = sensor ; - newCalibration.bg = bg ; - newCalibration.raw_value = raw_value ; - newCalibration.adjusted_raw_value = adjusted_raw_value ; - newCalibration.sensor_confidence = sensor_confidence ; - newCalibration.slope_confidence = slope_confidence ; - newCalibration.raw_timestamp = raw_timestamp ; - newCalibration.slope = slope ; - newCalibration.intercept = intercept ; - newCalibration.distance_from_estimate = distance_from_estimate ; - newCalibration.estimate_raw_at_time_of_calibration = estimate_raw_at_time_of_calibration ; - newCalibration.estimate_bg_at_time_of_calibration = estimate_bg_at_time_of_calibration ; - newCalibration.uuid = uuid ; - newCalibration.sensor_uuid = sensor_uuid ; - newCalibration.possible_bad = possible_bad ; - newCalibration.check_in = check_in ; - newCalibration.first_decay = first_decay ; - newCalibration.second_decay = second_decay ; - newCalibration.first_slope = first_slope ; - newCalibration.second_slope = second_slope ; - newCalibration.first_intercept = first_intercept ; - newCalibration.second_intercept = second_intercept ; - newCalibration.first_scale = first_scale ; - newCalibration.second_scale = second_scale ; - newCalibration.save(); + public Calibration () { + super (); } public static void initialCalibration(double bg1, double bg2, Context context) { @@ -455,6 +395,13 @@ public static boolean is_new(CalSubrecord calSubrecord, long addativeOffset) { } } + public static Calibration findByUuid(String uuid) { + return new Select() + .from(Calibration.class) + .where("uuid = ?", uuid) + .executeSingle(); + } + public static Calibration getForTimestamp(double timestamp) { Sensor sensor = Sensor.currentSensor(); return new Select() @@ -915,7 +862,7 @@ public static Calibration lastValid() { .where("Sensor = ? ", sensor.getId()) .where("slope_confidence != 0") .where("sensor_confidence != 0") - .where("( slope !=0 and intercept !=0 )") + .where("slope != 0") .orderBy("timestamp desc") .executeSingle(); } @@ -978,6 +925,22 @@ public static List latest(int number) { .execute(); } + public static List latestValid(int number) { + Sensor sensor = Sensor.currentSensor(); + if (sensor == null) { + return null; + } + return new Select() + .from(Calibration.class) + .where("Sensor = ? ", sensor.getId()) + .where("slope_confidence != 0") + .where("sensor_confidence != 0") + .where("slope != 0") + .orderBy("timestamp desc") + .limit(number) + .execute(); + } + public static List latestForGraph(int number, long startTime, long endTime) { return new Select() .from(Calibration.class) diff --git a/wear/src/main/java/com/eveningoutpost/dexdrip/Models/TransmitterData.java b/wear/src/main/java/com/eveningoutpost/dexdrip/Models/TransmitterData.java index a7016d457c..1fde5c0ec4 100644 --- a/wear/src/main/java/com/eveningoutpost/dexdrip/Models/TransmitterData.java +++ b/wear/src/main/java/com/eveningoutpost/dexdrip/Models/TransmitterData.java @@ -49,6 +49,10 @@ public class TransmitterData extends Model { @Column(name = "uuid", index = true) public String uuid; + public TransmitterData () { + super (); + } + public static synchronized TransmitterData create(byte[] buffer, int len, Long timestamp) { if (len < 6) { return null; } TransmitterData transmitterData = new TransmitterData(); @@ -168,27 +172,37 @@ public static List latestForGraphAsc(int number, long startTime } public static TransmitterData getForTimestamp(double timestamp) {//KS - Sensor sensor = Sensor.currentSensor(); - if (sensor != null) { - TransmitterData bgReading = new Select() - .from(TransmitterData.class) - .where("timestamp <= ?", (timestamp + (60 * 1000))) // 1 minute padding (should never be that far off, but why not) - .orderBy("timestamp desc") - .executeSingle(); - if (bgReading != null && Math.abs(bgReading.timestamp - timestamp) < (3 * 60 * 1000)) { //cool, so was it actually within 4 minutes of that bg reading? - Log.i(TAG, "getForTimestamp: Found a BG timestamp match"); - return bgReading; + try { + Sensor sensor = Sensor.currentSensor(); + if (sensor != null) { + TransmitterData bgReading = new Select() + .from(TransmitterData.class) + .where("timestamp <= ?", (timestamp + (60 * 1000))) // 1 minute padding (should never be that far off, but why not) + .orderBy("timestamp desc") + .executeSingle(); + if (bgReading != null && Math.abs(bgReading.timestamp - timestamp) < (3 * 60 * 1000)) { //cool, so was it actually within 4 minutes of that bg reading? + Log.i(TAG, "getForTimestamp: Found a BG timestamp match"); + return bgReading; + } } + } catch (Exception e) { + Log.e(TAG,"getForTimestamp() Got exception on Select : "+e.toString()); + return null; } Log.d(TAG, "getForTimestamp: No luck finding a BG timestamp match"); return null; } public static TransmitterData findByUuid(String uuid) {//KS - return new Select() + try { + return new Select() .from(TransmitterData.class) .where("uuid = ?", uuid) .executeSingle(); + } catch (Exception e) { + Log.e(TAG,"findByUuid() Got exception on Select : "+e.toString()); + return null; + } } public String toS() {//KS diff --git a/wear/src/main/java/com/eveningoutpost/dexdrip/NWPreferences.java b/wear/src/main/java/com/eveningoutpost/dexdrip/NWPreferences.java index 4463ca343f..96f9132c50 100644 --- a/wear/src/main/java/com/eveningoutpost/dexdrip/NWPreferences.java +++ b/wear/src/main/java/com/eveningoutpost/dexdrip/NWPreferences.java @@ -1,18 +1,66 @@ package com.eveningoutpost.dexdrip; +import android.content.SharedPreferences; import android.os.Bundle; +import android.preference.Preference; import android.preference.PreferenceActivity; +import android.preference.PreferenceCategory; +import android.preference.PreferenceManager; +import android.preference.PreferenceScreen; +import android.util.Log; import com.eveningoutpost.dexdrip.R; public class NWPreferences extends PreferenceActivity { + private SharedPreferences mPrefs; + public PreferenceScreen screen; + public PreferenceCategory category; + public Preference collectionMethod; + @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.preferences); + + mPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + screen = (PreferenceScreen) findPreference("preferenceScreen"); + category = (PreferenceCategory) findPreference("collection_category"); + collectionMethod = findPreference("g5_collection_method"); + listenForChangeInSettings(); + setCollectionPrefs(); + } + + public SharedPreferences.OnSharedPreferenceChangeListener prefListener = new SharedPreferences.OnSharedPreferenceChangeListener() { + public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { + + if(key.compareTo("g5_collection_method") == 0) { + setCollectionPrefs(); + } + + } + }; + + public void listenForChangeInSettings() { + mPrefs.registerOnSharedPreferenceChangeListener(prefListener); + // TODO do we need an unregister!? } + public void setCollectionPrefs() { + if (mPrefs.getBoolean("g5_collection_method", false)) {//DexCollectionType.DexcomG5 + screen.addPreference(category); + Log.d("NWPreferences", "setCollectionPrefs addPreference category"); + } + else { + screen.removePreference(category); + Log.d("NWPreferences", "setCollectionPrefs removePreference category"); + } + + if (collectionMethod != null && category != null) { + category.removePreference(collectionMethod); + } + + } } \ No newline at end of file diff --git a/wear/src/main/java/com/eveningoutpost/dexdrip/Services/G5CollectionService.java b/wear/src/main/java/com/eveningoutpost/dexdrip/Services/G5CollectionService.java index fa670ffa08..84a2167405 100644 --- a/wear/src/main/java/com/eveningoutpost/dexdrip/Services/G5CollectionService.java +++ b/wear/src/main/java/com/eveningoutpost/dexdrip/Services/G5CollectionService.java @@ -33,6 +33,7 @@ import android.os.ParcelUuid; import android.os.PowerManager; import android.preference.PreferenceManager; +import android.support.v4.content.WakefulBroadcastReceiver; import com.eveningoutpost.dexdrip.G5Model.AuthChallengeRxMessage; import com.eveningoutpost.dexdrip.G5Model.AuthChallengeTxMessage; @@ -207,7 +208,6 @@ public int onStartCommand(Intent intent, int flags, int startId) { return START_STICKY; } else { Log.e(TAG,"jamorham service already active!"); - keep_running = false;//KS test to stop wear BT upon re-connecting to phone keepAlive(); return START_NOT_STICKY; } @@ -217,13 +217,13 @@ public int onStartCommand(Intent intent, int flags, int startId) { } } - private void getTransmitterDetails() { + private synchronized void getTransmitterDetails() { prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); Log.d(TAG, "Transmitter: " + prefs.getString("dex_txid", "ABCDEF")); defaultTransmitter = new Transmitter(prefs.getString("dex_txid", "ABCDEF")); isBondedOrBonding = false; Set pairedDevices = mBluetoothAdapter.getBondedDevices(); - if (pairedDevices.size() > 0) { + if ((pairedDevices != null) && (pairedDevices.size() > 0)) { for (BluetoothDevice device : pairedDevices) { if (device.getName() != null) { @@ -249,14 +249,21 @@ public void onDestroy() { Log.d(TAG, "onDestroy"); SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); - if (!sharedPrefs.getBoolean("use_connectG5", false)) {//KS - scan_interval_timer.cancel(); - if (pendingIntent != null) { - Log.d(TAG, "onDestroy stop Alarm pendingIntent"); - AlarmManager alarm = (AlarmManager) getSystemService(ALARM_SERVICE); - alarm.cancel(pendingIntent); + scan_interval_timer.cancel(); + if (pendingIntent != null) { + Log.d(TAG, "onDestroy stop Alarm pendingIntent"); + AlarmManager alarm = (AlarmManager) getSystemService(ALARM_SERVICE); + alarm.cancel(pendingIntent); + } + // close gatt + if (mGatt != null) { + try { + mGatt.close(); + } catch (NullPointerException e) { + Log.d(TAG, "concurrency related null pointer exception in close"); } } + // close(); // setRetryTimer(); // foregroundServiceStarter.stop(); @@ -295,7 +302,6 @@ public synchronized void keepAlive(int wake_in_ms) { } } - @Override public IBinder onBind(Intent intent) { throw new UnsupportedOperationException("Not yet implemented"); @@ -799,9 +805,13 @@ public void run() { stopScan(); } Log.e(TAG, "STATE_DISCONNECTED: " + status); - if (mGatt != null) - mGatt.close(); - mGatt = null; + if (mGatt != null) { + try { + mGatt.close(); + } catch (NullPointerException e) { // + } + } + mGatt = null; if (status == 0 && !encountered133) {// || status == 59) { android.util.Log.i(TAG, "clean disconnect"); max133RetryCounter = 0; diff --git a/wear/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/BgSendQueue.java b/wear/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/BgSendQueue.java index 822bc2b398..a29b636422 100644 --- a/wear/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/BgSendQueue.java +++ b/wear/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/BgSendQueue.java @@ -22,6 +22,7 @@ import com.eveningoutpost.dexdrip.ListenerService; import com.eveningoutpost.dexdrip.Models.BgReading; //KS import com.eveningoutpost.dexdrip.Models.Calibration; +import com.eveningoutpost.dexdrip.Models.JoH; import com.eveningoutpost.dexdrip.Models.UserError.Log; @@ -230,10 +231,10 @@ public static void handleNewBgReading(BgReading bgReading, String operation_type */ // if executing on watch; send to watchface - if (prefs.getBoolean("connectG5", false)) {//KS + if (prefs.getBoolean("enable_wearG5", false)) {//KS Log.d("BgSendQueue", "handleNewBgReading Broadcast BG data to watch"); resendData(context); - if (prefs.getBoolean("use_connectG5", false)) { + if (prefs.getBoolean("force_wearG5", false)) { ListenerService.requestData(context); } } @@ -244,17 +245,22 @@ public static void handleNewBgReading(BgReading bgReading, String operation_type } } + public static void sendToPhone(Context context) {//KS + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + + if (prefs.getBoolean("enable_wearG5", false) && prefs.getBoolean("force_wearG5", false)) { + ListenerService.requestData(context); + } + } + //KS start from WatchUpdaterService - private static void resendData(Context context) {//KS + public static void resendData(Context context) {//KS long startTime = new Date().getTime() - (60000 * 60 * 24); Log.d("BgSendQueue", "resendData enter"); - java.text.DateFormat df = new SimpleDateFormat("MM.dd.yyyy HH:mm:ss"); - Date date = new Date(); BgReading last_bg = BgReading.last(); if (last_bg != null) { - date.setTime(last_bg.timestamp); - Log.d("BgSendQueue", "resendData last_bg.timestamp:" + df.format(date)); + Log.d("BgSendQueue", "resendData last_bg.timestamp:" + JoH.dateTimeText(last_bg.timestamp)); } List graph_bgs = BgReading.latestForGraph(60, startTime); @@ -268,6 +274,7 @@ private static void resendData(Context context) {//KS dataMaps.add(dataMap(bg, sharedPrefs, bgGraphBuilder, context)); } entries.putDataMapArrayList("entries", dataMaps); + Log.d("BgSendQueue", "resendData entries=" + entries); Intent messageIntent = new Intent(); messageIntent.setAction(Intent.ACTION_SEND); diff --git a/wear/src/main/java/com/eveningoutpost/dexdrip/utils/DexCollectionType.java b/wear/src/main/java/com/eveningoutpost/dexdrip/utils/DexCollectionType.java new file mode 100644 index 0000000000..52985066bf --- /dev/null +++ b/wear/src/main/java/com/eveningoutpost/dexdrip/utils/DexCollectionType.java @@ -0,0 +1,111 @@ +package com.eveningoutpost.dexdrip.utils; + +import com.eveningoutpost.dexdrip.Home; + +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; + +/** + * Created by andy on 01/06/16. + */ +public enum DexCollectionType { + + None("None"), + BluetoothWixel("BluetoothWixel"), + DexcomShare("DexcomShare"), + DexbridgeWixel("DexbridgeWixel"), + LimiTTer("LimiTTer"), + WifiBlueToothWixel("WifiBlueToothWixel"), + WifiWixel("WifiWixel"), + DexcomG5("DexcomG5"), + WifiDexBridgeWixel("WifiDexbridgeWixel"), + Follower("Follower"), + LibreAlarm("LibreAlarm"), + Manual("Manual"); + + String internalName; + private static final Map mapToInternalName; + private static final HashSet usesBluetooth = new HashSet<>(); + private static final HashSet usesBtWixel = new HashSet<>(); + private static final HashSet usesWifi = new HashSet<>(); + private static final HashSet usesXbridge = new HashSet<>(); + private static final HashSet usesFiltered = new HashSet<>(); + private static final HashSet usesLibre = new HashSet<>(); + private static final HashSet usesBattery = new HashSet<>(); + + private static final String DEX_COLLECTION_METHOD = "dex_collection_method"; + + public static boolean does_have_filtered = false; // TODO this could get messy with GC + + + static { + mapToInternalName = new HashMap<>(); + + for (DexCollectionType dct : values()) { + mapToInternalName.put(dct.internalName, dct); + } + + Collections.addAll(usesBluetooth, BluetoothWixel, DexcomShare, DexbridgeWixel, LimiTTer, WifiBlueToothWixel, DexcomG5, WifiDexBridgeWixel); + Collections.addAll(usesBtWixel, BluetoothWixel, LimiTTer, WifiBlueToothWixel); + Collections.addAll(usesWifi, WifiBlueToothWixel,WifiWixel,WifiDexBridgeWixel); + Collections.addAll(usesXbridge, DexbridgeWixel,WifiDexBridgeWixel); + Collections.addAll(usesFiltered, DexbridgeWixel, WifiDexBridgeWixel, DexcomG5, WifiWixel, Follower); // Bluetooth and Wifi+Bluetooth need dynamic mode + Collections.addAll(usesLibre, LimiTTer, LibreAlarm); + Collections.addAll(usesBattery, BluetoothWixel, DexbridgeWixel, WifiBlueToothWixel, WifiDexBridgeWixel, Follower, LimiTTer, LibreAlarm); // parakeet separate + } + + + DexCollectionType(String name) { + this.internalName = name; + } + + + public static DexCollectionType getType(String dexCollectionType) { + + if (mapToInternalName.containsKey(dexCollectionType)) + return mapToInternalName.get(dexCollectionType); + else + return None; + } + + public static DexCollectionType getDexCollectionType() { + return getType(Home.getPreferencesStringWithDefault(DEX_COLLECTION_METHOD, "BluetoothWixel")); + } + + public static void setDexCollectionType(DexCollectionType t) { + Home.setPreferencesString(DEX_COLLECTION_METHOD, t.internalName); + } + + public static boolean hasBluetooth() { + return usesBluetooth.contains(getDexCollectionType()); + } + + public static boolean hasBtWixel() { return usesBtWixel.contains(getDexCollectionType()); } + + public static boolean hasXbridgeWixel() { + return usesXbridge.contains(getDexCollectionType()); + } + + public static boolean hasWifi() { + return usesWifi.contains(getDexCollectionType()); + } + + public static boolean hasLibre() { return usesLibre.contains(getDexCollectionType()); } + + public static boolean hasLibre(DexCollectionType t) { return usesLibre.contains(t); } + + public static boolean hasBattery() { return usesBattery.contains(getDexCollectionType()); } + + public static boolean hasSensor() { + return getDexCollectionType() != DexCollectionType.Manual; + } + + public static boolean isFlakey() { return getDexCollectionType() == DexCollectionType.DexcomG5; } + + public static boolean hasFiltered() { + return does_have_filtered || usesFiltered.contains(getDexCollectionType()); + } + +} diff --git a/wear/src/main/res/values/strings.xml b/wear/src/main/res/values/strings.xml index 11fcaa2168..39107dcfbc 100644 --- a/wear/src/main/res/values/strings.xml +++ b/wear/src/main/res/values/strings.xml @@ -3,6 +3,20 @@ XDrip Prefs. + + CYAN + GREEN + RED + WHITE + + + + 1 + 2 + 3 + 4 + + 1 hour 2 hours @@ -46,10 +60,21 @@ Location Permission xDrip requires Location access permission - Connect to G5 - Connect directly to G5 - Use Wear G5 - Force phone to use Wear G5 Collection Service + XDrip G5 Settings + Enable G5 Collection + Connect to G5 when phone is out-of-range + Force G5 Collection + Force phone to use Wear G5 Collection Service + Scan for G5 constantly + Some devices work better when scanning constantly, others do not. If reading is reliable when this setting is not selected, you should have improved battery life. Turn this setting on if you are missing readings at high rates and unexpected times. + Force G5 to UI Thread + This is crucial for some Android devices to properly connect, but can cause missed readings when other UI intensive activities are in use. + Authenticate G5 before each read + This will attempt a full authentication each read attempt. Redundant if Unbond before each read is also selected. + Unbond G5 before each read" + This will remove the G5 from your device\'s paired device list, and attempt a full authentication and bonding with each read attempt. + Ambient Low Color + Ambient Low Color. Note, RED is not supported on LOW-BIT devices, eg., Sony SmartWatch 3. Location Is Not Enabled diff --git a/wear/src/main/res/values/wear.xml b/wear/src/main/res/values/wear.xml new file mode 100644 index 0000000000..d2a1f76350 --- /dev/null +++ b/wear/src/main/res/values/wear.xml @@ -0,0 +1,19 @@ + + + + + + wear_app_sync_bgs + + \ No newline at end of file diff --git a/wear/src/main/res/xml/preferences.xml b/wear/src/main/res/xml/preferences.xml index 18422cb247..f29588dd7d 100644 --- a/wear/src/main/res/xml/preferences.xml +++ b/wear/src/main/res/xml/preferences.xml @@ -1,27 +1,71 @@ - + + + + + + android:dependency="enable_wearG5" + android:key="run_G5_ble_tasks_on_uithread" + android:summary="@string/pref_summary_run_G5_ble_tasks_on_uithread" + android:title="@string/pref_run_G5_ble_tasks_on_uithread"/> + android:dependency="enable_wearG5" + android:key="always_get_new_keys" + android:summary="@string/pref_summary_always_get_new_keys" + android:title="@string/pref_always_get_new_keys"/> + + + + + +